Merge remote-tracking branch 'origin/staging' into origin/production
This commit is contained in:
@@ -22,6 +22,8 @@ import TableMoreMenu from '@/components/table/TableMoreMenu';
|
||||
*/
|
||||
import { fDate } from "@/utils/formatTime";
|
||||
import { ClaimListType } from "../Model/Types";
|
||||
import { ClearOutlined, LoopOutlined } from "@mui/icons-material";
|
||||
import DialogConfirmation from "./DialogConfirmation";
|
||||
|
||||
type Props = {
|
||||
row: ClaimListType,
|
||||
@@ -30,6 +32,14 @@ type Props = {
|
||||
|
||||
export default function ClaimListRow ({ ...props }: Props) {
|
||||
const navigate = useNavigate()
|
||||
const [openDialogSubmit, setOpenDialogSubmit] = useState(false);
|
||||
const [code, setCode] = useState('');
|
||||
const [member_id, setMemberId] = useState('');
|
||||
const handleUpdate = (code: string, member_id: string) => {
|
||||
setOpenDialogSubmit(true)
|
||||
setMemberId(member_id)
|
||||
setCode(code)
|
||||
}
|
||||
|
||||
return (
|
||||
<React.Fragment>
|
||||
@@ -87,21 +97,45 @@ export default function ClaimListRow ({ ...props }: Props) {
|
||||
</TableCell>
|
||||
<TableCell align="right" onClick={(e) => e.stopPropagation()}>
|
||||
<Stack direction="row" justifyContent="flex-end" spacing={1}>
|
||||
<TableMoreMenu actions={
|
||||
<>
|
||||
<MenuItem onClick={() => navigate(`/case_management/daily_monitoring/${props.row.member_id}/claims/${props.row.claim_code}/list_monitoring`)}>
|
||||
<Visibility />
|
||||
View
|
||||
</MenuItem>
|
||||
<MenuItem onClick={() => navigate(`/case_management/daily_monitoring/${props.row.member_id}/claims/${props.row.claim_code}/add_monitoring`)}>
|
||||
<AddIcon />
|
||||
Daily Monitoring
|
||||
</MenuItem>
|
||||
</>
|
||||
} />
|
||||
{props.row.discharge_date == null ?
|
||||
(
|
||||
<TableMoreMenu actions={
|
||||
<>
|
||||
<MenuItem onClick={() => navigate(`/case_management/daily_monitoring/${props.row.member_id}/claims/${props.row.code}/list_monitoring`)}>
|
||||
<Visibility />
|
||||
View
|
||||
</MenuItem>
|
||||
<MenuItem onClick={() => navigate(`/case_management/daily_monitoring/${props.row.member_id}/claims/${props.row.code}/add_monitoring`)}>
|
||||
<AddIcon />
|
||||
Daily Monitoring
|
||||
</MenuItem>
|
||||
<MenuItem onClick={() => handleUpdate(props.row.code, props.row.member_id)}>
|
||||
<LoopOutlined />
|
||||
Update Status
|
||||
</MenuItem>
|
||||
</>
|
||||
} />
|
||||
) :
|
||||
(
|
||||
<TableMoreMenu actions={
|
||||
<>
|
||||
<MenuItem onClick={() => navigate(`/case_management/daily_monitoring/${props.row.member_id}/claims/${props.row.code}/list_monitoring`)}>
|
||||
<Visibility />
|
||||
View
|
||||
</MenuItem>
|
||||
</>
|
||||
} />
|
||||
)
|
||||
}
|
||||
|
||||
</Stack>
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
<DialogConfirmation
|
||||
setOpenDialog={setOpenDialogSubmit}
|
||||
row={props.row}
|
||||
openDialog={openDialogSubmit}
|
||||
/>
|
||||
|
||||
</React.Fragment>
|
||||
);
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
*/
|
||||
import { useFieldArray, useForm } from 'react-hook-form';
|
||||
import { useNavigate, useParams } from 'react-router-dom';
|
||||
import { Box, IconButton, Typography, Grid, Card, Button } from '@mui/material';
|
||||
import { Box, IconButton, Typography, Grid, Card, Button, ButtonBase, Stack } from '@mui/material';
|
||||
import { LoadingButton } from "@mui/lab";
|
||||
|
||||
/**
|
||||
@@ -13,6 +13,7 @@ import { LoadingButton } from "@mui/lab";
|
||||
*/
|
||||
import Page from '@/components/Page';
|
||||
import { FormProvider, RHFTextField } from '@/components/hook-form';
|
||||
import RHFDatePickerV2 from '@/components/hook-form/RHFDatePickerV2';
|
||||
|
||||
/**
|
||||
* Icon
|
||||
@@ -21,6 +22,7 @@ import { FormProvider, RHFTextField } from '@/components/hook-form';
|
||||
import ArrowBackIosNew from '@mui/icons-material/ArrowBackIosNew';
|
||||
import AddIcon from '@mui/icons-material/Add';
|
||||
import RemoveIcon from '@mui/icons-material/Remove';
|
||||
import InsertDriveFileIcon from '@mui/icons-material/InsertDriveFile';
|
||||
|
||||
/**
|
||||
* Utils, Types, Functions
|
||||
@@ -28,11 +30,18 @@ import RemoveIcon from '@mui/icons-material/Remove';
|
||||
*/
|
||||
import { AddMonitoringDetail } from '../Model/Functions';
|
||||
import { DetailMonitoringListType} from '../Model/Types';
|
||||
import FormCreateFilesUpload from '@/pages/CustomerService/FinalLog/Components/FormCreateFilesUpload';
|
||||
import MultiFilePreview from '@/components/upload/MultiFilePreview';
|
||||
import Iconify from '@/components/Iconify';
|
||||
import { useRef } from 'react';
|
||||
|
||||
export default function DetailMonitoringList() {
|
||||
const { member_id, claim_code } = useParams();
|
||||
const navigate = useNavigate()
|
||||
const pageTitle = claim_code??'_ _ _ _';
|
||||
const fileInput1 = useRef<HTMLInputElement>(null);
|
||||
const fileInput2 = useRef<HTMLInputElement>(null);
|
||||
const fileInput3 = useRef<HTMLInputElement>(null);
|
||||
|
||||
// setup form
|
||||
// ====================================
|
||||
@@ -50,16 +59,99 @@ export default function DetailMonitoringList() {
|
||||
medical_plan : [{
|
||||
medical_plan_str: ''
|
||||
}],
|
||||
created_at : ''
|
||||
non_medikamentosa_plan : [{
|
||||
non_medikamentosa_plan_str: ''
|
||||
}],
|
||||
confirmation_medical_leter : [],
|
||||
medical_action_letter : [],
|
||||
result : [],
|
||||
created_at : '',
|
||||
lab_date : '',
|
||||
provider : '',
|
||||
examination : '',
|
||||
};
|
||||
|
||||
const methods = useForm<any>({
|
||||
defaultValues
|
||||
});
|
||||
|
||||
const {fields, append, remove} = useFieldArray({name: 'medical_plan',control: methods.control})
|
||||
const {fields: fields1, append: append1, remove: remove1} = useFieldArray({name: 'medical_plan',control: methods.control})
|
||||
const {fields: fields2, append: append2, remove: remove2} = useFieldArray({name: 'non_medikamentosa_plan',control: methods.control})
|
||||
|
||||
const { handleSubmit, reset, formState: { isDirty, isSubmitting } } = methods;
|
||||
const { handleSubmit, reset, watch, setValue, formState: { isDirty, isSubmitting } } = methods;
|
||||
const formValues = watch();
|
||||
// Handle File Input
|
||||
// =====================================
|
||||
const handleInputChangeConfirmationMedicalLeter = (event: any) => {
|
||||
if (event.target.files[0]) {
|
||||
|
||||
let arr_confirmation_medical_leter_file = formValues.confirmation_medical_leter;
|
||||
arr_confirmation_medical_leter_file.push(event.target.files[0]);
|
||||
|
||||
setValue('confirmation_medical_leter', arr_confirmation_medical_leter_file);
|
||||
}
|
||||
else {
|
||||
console.log('NO FILE');
|
||||
}
|
||||
};
|
||||
const handleInputChangeMedicalActionLetter = (event: any) => {
|
||||
if (event.target.files[0]) {
|
||||
|
||||
let arr_medical_action_letter = formValues.medical_action_letter;
|
||||
arr_medical_action_letter.push(event.target.files[0]);
|
||||
|
||||
setValue('medical_action_letter', arr_medical_action_letter)
|
||||
console.log('test2')
|
||||
}
|
||||
else {
|
||||
console.log('NO FILE');
|
||||
}
|
||||
};
|
||||
|
||||
const handleInputChangeResult = (event: any) => {
|
||||
if (event.target.files[0]) {
|
||||
|
||||
let arr_result = formValues.result;
|
||||
arr_result.push(event.target.files[0]);
|
||||
|
||||
setValue('result', arr_result)
|
||||
console.log('test3')
|
||||
}
|
||||
else {
|
||||
console.log('NO FILE');
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
// Handle Remove File
|
||||
// =====================================
|
||||
const handleRemoveFileConfirmationMedicalLeter = (target_index: number) => {
|
||||
let arr_confirmation_medical_leter_file = formValues.confirmation_medical_leter.filter((file: any, index: number) =>{
|
||||
if (target_index !== index) {
|
||||
return file;
|
||||
}
|
||||
});
|
||||
|
||||
setValue('confirmation_medical_leter', arr_confirmation_medical_leter_file)
|
||||
};
|
||||
const handleRemoveFileMedicalActionLetter = (target_index: number) => {
|
||||
let arr_medical_action_letter = formValues.medical_action_letter.filter((file: any, index: number) =>{
|
||||
if (target_index !== index) {
|
||||
return file;
|
||||
}
|
||||
});
|
||||
|
||||
setValue('medical_action_letter', arr_medical_action_letter)
|
||||
};
|
||||
const handleRemoveFileResult = (target_index: number) => {
|
||||
let arr_result = formValues.result.filter((file: any, index: number) =>{
|
||||
if (target_index !== index) {
|
||||
return file;
|
||||
}
|
||||
});
|
||||
|
||||
setValue('result', arr_result)
|
||||
};
|
||||
|
||||
// Submit Form
|
||||
// =====================================
|
||||
@@ -70,8 +162,8 @@ export default function DetailMonitoringList() {
|
||||
|
||||
if (response == true) {
|
||||
reset();
|
||||
navigate('case_management/daily_monitoring/'+claim_code+'claims');
|
||||
window.location.reload()
|
||||
navigate('/case_management/daily_monitoring/'+member_id+'/claims', { replace: true });
|
||||
// window.location.reload()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -197,7 +289,7 @@ export default function DetailMonitoringList() {
|
||||
</Grid>
|
||||
|
||||
{/* Complaints */}
|
||||
<Grid item xs={12}>
|
||||
{/* <Grid item xs={12}>
|
||||
<Grid container spacing={3}>
|
||||
<Grid item xs={12}>
|
||||
<Typography variant="body1" component="div">
|
||||
@@ -212,7 +304,7 @@ export default function DetailMonitoringList() {
|
||||
/>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</Grid> */}
|
||||
|
||||
{/* Analysis */}
|
||||
<Grid item xs={12}>
|
||||
@@ -242,7 +334,7 @@ export default function DetailMonitoringList() {
|
||||
</Grid>
|
||||
<Grid item xs={12}>
|
||||
{
|
||||
fields.map((field,index) => {
|
||||
fields1.map((field,index) => {
|
||||
return (
|
||||
<Grid key={field.id} container sx={{ mb: 3 }}>
|
||||
<Grid item xs={11}>
|
||||
@@ -253,10 +345,10 @@ export default function DetailMonitoringList() {
|
||||
/>
|
||||
</Grid>
|
||||
{
|
||||
index == (fields.length-1) ?
|
||||
index == (fields1.length-1) ?
|
||||
(
|
||||
<Grid item xs={1} sx={{ textAlign: 'center' }}>
|
||||
<IconButton size='large' color='primary' onClick={() => append({medical_plan_str: ''})}>
|
||||
<IconButton size='large' color='primary' onClick={() => append1({medical_plan_str: ''})}>
|
||||
<AddIcon />
|
||||
</IconButton>
|
||||
</Grid>
|
||||
@@ -264,7 +356,7 @@ export default function DetailMonitoringList() {
|
||||
:
|
||||
(
|
||||
<Grid item xs={1} sx={{ textAlign: 'center' }}>
|
||||
<IconButton size='large' color='error' onClick={() => remove(index)}>
|
||||
<IconButton size='large' color='error' onClick={() => remove1(index)}>
|
||||
<RemoveIcon />
|
||||
</IconButton>
|
||||
</Grid>
|
||||
@@ -278,7 +370,268 @@ export default function DetailMonitoringList() {
|
||||
</Grid>
|
||||
</Grid>
|
||||
|
||||
{/* Button Cancle & Save */}
|
||||
{/* Non Medikamentosa Plan* */}
|
||||
<Grid item xs={12}>
|
||||
<Grid container spacing={3}>
|
||||
<Grid item xs={12}>
|
||||
<Typography variant="body1" component="div">
|
||||
Non Medikamentosa Plan* :
|
||||
</Typography>
|
||||
</Grid>
|
||||
<Grid item xs={12}>
|
||||
{
|
||||
fields2.map((field,index) => {
|
||||
return (
|
||||
<Grid key={field.id} container sx={{ mb: 3 }}>
|
||||
<Grid item xs={11}>
|
||||
<RHFTextField
|
||||
id="analysis"
|
||||
name={`non_medikamentosa_plan.${index}.non_medikamentosa_plan_str`}
|
||||
placeholder='Non Medikamentosa'
|
||||
/>
|
||||
</Grid>
|
||||
{
|
||||
index == (fields2.length-1) ?
|
||||
(
|
||||
<Grid item xs={1} sx={{ textAlign: 'center' }}>
|
||||
<IconButton size='large' color='primary' onClick={() => append2({non_medikamentosa_plan_str: ''})}>
|
||||
<AddIcon />
|
||||
</IconButton>
|
||||
</Grid>
|
||||
)
|
||||
:
|
||||
(
|
||||
<Grid item xs={1} sx={{ textAlign: 'center' }}>
|
||||
<IconButton size='large' color='error' onClick={() => remove2(index)}>
|
||||
<RemoveIcon />
|
||||
</IconButton>
|
||||
</Grid>
|
||||
)
|
||||
}
|
||||
</Grid>
|
||||
)
|
||||
})
|
||||
}
|
||||
</Grid>
|
||||
</Grid>
|
||||
</Grid>
|
||||
|
||||
{/* Confirmation Medical Letter */}
|
||||
<Grid item xs={12}>
|
||||
<Grid container spacing={3}>
|
||||
<Grid item xs={12}>
|
||||
<Typography variant="body1" component="div">
|
||||
Confirmation Medical Letter*
|
||||
</Typography>
|
||||
</Grid>
|
||||
<Grid item xs={12}>
|
||||
{
|
||||
formValues.confirmation_medical_leter.map((file: any, index: number) => (
|
||||
<Stack direction="row" justifyContent={'space-between'} key={index} sx={{ mb: '16px' }}>
|
||||
<Stack direction="row" spacing={1} sx={{color: '#19BBBB'}}>
|
||||
<InsertDriveFileIcon />
|
||||
<Typography variant="body2" gutterBottom>{file.name ? file.name : '-'}</Typography>
|
||||
</Stack>
|
||||
<Iconify
|
||||
icon="eva:trash-2-outline"
|
||||
color={'darkred'}
|
||||
onClick={() => handleRemoveFileConfirmationMedicalLeter(index)}
|
||||
sx={{cursor: 'pointer'}}
|
||||
></Iconify>
|
||||
</Stack>
|
||||
))
|
||||
}
|
||||
</Grid>
|
||||
<Grid item xs={12} sx={{display: 'flex', gap: 1}}>
|
||||
<ButtonBase sx={{ p: 4, border: '2px dashed #F9FAFB',bgcolor: '#919EAB52',borderRadius: '8px',width: '100%', height: '60px'}} onClick={() => fileInput1.current?.click()}>
|
||||
<Box
|
||||
sx={{
|
||||
display: 'flex',
|
||||
placeItems: 'center',
|
||||
gap: 1,
|
||||
placeContent: 'center',
|
||||
}}
|
||||
>
|
||||
<Iconify icon="icon-park-outline:upload-one" fontSize="3em" />
|
||||
<Typography variant="body1" fontWeight="bold">
|
||||
Upload File
|
||||
</Typography>
|
||||
</Box>
|
||||
<input
|
||||
type="file"
|
||||
id="file_input"
|
||||
ref={fileInput1}
|
||||
style={{ display: 'none' }}
|
||||
multiple
|
||||
onChange={(e) => handleInputChangeConfirmationMedicalLeter(e)}
|
||||
accept="application/pdf"
|
||||
/>
|
||||
</ButtonBase>
|
||||
</Grid>
|
||||
|
||||
</Grid>
|
||||
</Grid>
|
||||
|
||||
{/* Medical Action Letter */}
|
||||
<Grid item xs={12}>
|
||||
<Grid container spacing={3}>
|
||||
<Grid item xs={12}>
|
||||
<Typography variant="body1" component="div">
|
||||
Medical Action Letter*
|
||||
</Typography>
|
||||
</Grid>
|
||||
<Grid item xs={12}>
|
||||
{
|
||||
formValues.medical_action_letter.map((file: any, index: number) => (
|
||||
<Stack direction="row" justifyContent={'space-between'} key={index} sx={{ mb: '16px' }}>
|
||||
<Stack direction="row" spacing={1} sx={{color: '#19BBBB'}}>
|
||||
<InsertDriveFileIcon />
|
||||
<Typography variant="body2" gutterBottom>{file.name ? file.name : '-'}</Typography>
|
||||
</Stack>
|
||||
<Iconify
|
||||
icon="eva:trash-2-outline"
|
||||
color={'darkred'}
|
||||
onClick={() => handleRemoveFileMedicalActionLetter(index)}
|
||||
sx={{cursor: 'pointer'}}
|
||||
></Iconify>
|
||||
</Stack>
|
||||
))
|
||||
}
|
||||
</Grid>
|
||||
<Grid item xs={12} sx={{display: 'flex', gap: 1}}>
|
||||
<ButtonBase sx={{ p: 4, border: '2px dashed #F9FAFB',bgcolor: '#919EAB52',borderRadius: '8px',width: '100%', height: '60px'}} onClick={() => fileInput2.current?.click()}>
|
||||
<Box
|
||||
sx={{
|
||||
display: 'flex',
|
||||
placeItems: 'center',
|
||||
gap: 1,
|
||||
placeContent: 'center',
|
||||
}}
|
||||
>
|
||||
<Iconify icon="icon-park-outline:upload-one" fontSize="3em" />
|
||||
<Typography variant="body1" fontWeight="bold">
|
||||
Upload File
|
||||
</Typography>
|
||||
</Box>
|
||||
<input
|
||||
type="file"
|
||||
id="file_2"
|
||||
ref={fileInput2}
|
||||
style={{ display: 'none' }}
|
||||
multiple
|
||||
onChange={handleInputChangeMedicalActionLetter}
|
||||
accept="application/pdf"
|
||||
/>
|
||||
</ButtonBase>
|
||||
</Grid>
|
||||
|
||||
</Grid>
|
||||
</Grid>
|
||||
|
||||
|
||||
{/* Laboratorium */}
|
||||
<Grid item xs={12}>
|
||||
<Grid container spacing={3}>
|
||||
<Grid item xs={12}>
|
||||
<Typography variant="body1" component="div">
|
||||
Laboratorium Result*
|
||||
</Typography>
|
||||
</Grid>
|
||||
<Grid item xs={6}>
|
||||
<Typography variant="body1" component="div">
|
||||
Date*
|
||||
</Typography>
|
||||
</Grid>
|
||||
<Grid item xs={6}>
|
||||
<Typography variant="body1" component="div">
|
||||
Provider*
|
||||
</Typography>
|
||||
</Grid>
|
||||
|
||||
<Grid item xs={6} sx={{display: 'flex', gap: 1}}>
|
||||
<RHFDatePickerV2
|
||||
label='Date'
|
||||
name="lab_date"
|
||||
dateFormat='dd MMM yyyy'
|
||||
fullWidth
|
||||
/>
|
||||
</Grid>
|
||||
<Grid item xs={6} sx={{display: 'flex', gap: 1}}>
|
||||
<RHFTextField
|
||||
id="provider"
|
||||
name='provider'
|
||||
placeholder='Provider'
|
||||
label='Provider'
|
||||
/>
|
||||
</Grid>
|
||||
<Grid item xs={12}>
|
||||
<Typography variant="body1" component="div">
|
||||
Examination*
|
||||
</Typography>
|
||||
</Grid>
|
||||
<Grid item xs={12} sx={{display: 'flex', gap: 1}}>
|
||||
<RHFTextField
|
||||
id="examination"
|
||||
name='examination'
|
||||
placeholder='examination'
|
||||
label='Examination'
|
||||
/>
|
||||
</Grid>
|
||||
<Grid item xs={12}>
|
||||
<Typography variant="body1" component="div">
|
||||
Laboratorium Result*
|
||||
</Typography>
|
||||
</Grid>
|
||||
<Grid item xs={12}>
|
||||
{
|
||||
formValues.result.map((file: any, index: number) => (
|
||||
<Stack direction="row" justifyContent={'space-between'} key={index} sx={{ mb: '16px' }}>
|
||||
<Stack direction="row" spacing={1} sx={{color: '#19BBBB'}}>
|
||||
<InsertDriveFileIcon />
|
||||
<Typography variant="body2" gutterBottom>{file.name ? file.name : '-'}</Typography>
|
||||
</Stack>
|
||||
<Iconify
|
||||
icon="eva:trash-2-outline"
|
||||
color={'darkred'}
|
||||
onClick={() => handleRemoveFileResult(index)}
|
||||
sx={{cursor: 'pointer'}}
|
||||
></Iconify>
|
||||
</Stack>
|
||||
))
|
||||
}
|
||||
</Grid>
|
||||
<Grid item xs={12} sx={{display: 'flex', gap: 1}}>
|
||||
<ButtonBase sx={{ p: 4, border: '2px dashed #F9FAFB',bgcolor: '#919EAB52',borderRadius: '8px',width: '100%', height: '60px'}} onClick={() => fileInput3.current?.click()}>
|
||||
<Box
|
||||
sx={{
|
||||
display: 'flex',
|
||||
placeItems: 'center',
|
||||
gap: 1,
|
||||
placeContent: 'center',
|
||||
}}
|
||||
>
|
||||
<Iconify icon="icon-park-outline:upload-one" fontSize="3em" />
|
||||
<Typography variant="body1" fontWeight="bold">
|
||||
Upload File
|
||||
</Typography>
|
||||
</Box>
|
||||
<input
|
||||
type="file"
|
||||
id="file_3"
|
||||
ref={fileInput3}
|
||||
style={{ display: 'none' }}
|
||||
multiple
|
||||
onChange={handleInputChangeResult}
|
||||
accept="application/pdf"
|
||||
/>
|
||||
</ButtonBase>
|
||||
</Grid>
|
||||
|
||||
</Grid>
|
||||
</Grid>
|
||||
|
||||
|
||||
{/* Button Cancel & Save */}
|
||||
<Grid item xs={12} md={12}>
|
||||
<Box display="flex" justifyContent={'flex-end'}>
|
||||
<Box display="flex" gap={1}>
|
||||
@@ -286,7 +639,7 @@ export default function DetailMonitoringList() {
|
||||
Cancel
|
||||
</Button>
|
||||
<LoadingButton disabled={!isDirty} type="submit" variant="contained" loading={isSubmitting}>
|
||||
Save Changes
|
||||
Add
|
||||
</LoadingButton>
|
||||
</Box>
|
||||
</Box>
|
||||
|
||||
@@ -27,7 +27,7 @@ import FiberManualRecord from '@mui/icons-material/FiberManualRecord';
|
||||
* Utils, Types, Functions
|
||||
* ============================================
|
||||
*/
|
||||
import { fDate } from "@/utils/formatTime";
|
||||
import { fDate, fDateOnly } from '@/utils/formatTime';
|
||||
import { getMonitoringDetailList } from '../Model/Functions';
|
||||
import { DetailMonitoringListType } from '../Model/Types';
|
||||
|
||||
@@ -87,6 +87,22 @@ export default function DetailMonitoringList() {
|
||||
>
|
||||
{row.created_at ? fDate(row.created_at) : '-'}
|
||||
</Label>
|
||||
|
||||
{row.discharge_date.discharge_date ?
|
||||
(<Label
|
||||
variant="ghost"
|
||||
color="success"
|
||||
sx={{marginLeft: '85%'}}
|
||||
>
|
||||
Close Monitoring
|
||||
</Label>) : (<Label
|
||||
variant="ghost"
|
||||
color="warning"
|
||||
sx={{marginLeft: '77%'}}
|
||||
>
|
||||
On Monitoring
|
||||
</Label>)}
|
||||
|
||||
</Box>
|
||||
|
||||
{/* card body */}
|
||||
@@ -160,21 +176,6 @@ export default function DetailMonitoringList() {
|
||||
</Grid>
|
||||
</Grid>
|
||||
|
||||
<Grid item xs={12}>
|
||||
<Grid container gap={1}>
|
||||
<Grid item xs={12}>
|
||||
<Typography variant="body1" sx={{ fontWeight: 'bold' }}>
|
||||
Subject :
|
||||
</Typography>
|
||||
</Grid>
|
||||
<Grid item xs={12}>
|
||||
<Typography variant="body2" color={"GrayText"}>
|
||||
{row.subject}
|
||||
</Typography>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</Grid>
|
||||
|
||||
<Grid item xs={12}>
|
||||
<Grid container gap={1}>
|
||||
<Grid item xs={12}>
|
||||
@@ -190,21 +191,6 @@ export default function DetailMonitoringList() {
|
||||
</Grid>
|
||||
</Grid>
|
||||
|
||||
<Grid item xs={12}>
|
||||
<Grid container gap={1}>
|
||||
<Grid item xs={12}>
|
||||
<Typography variant="body1" sx={{ fontWeight: 'bold' }}>
|
||||
Complaints :
|
||||
</Typography>
|
||||
</Grid>
|
||||
<Grid item xs={12}>
|
||||
<Typography variant="body2" color={"GrayText"}>
|
||||
{row.complaints}
|
||||
</Typography>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</Grid>
|
||||
|
||||
<Grid item xs={12}>
|
||||
<Grid container gap={1}>
|
||||
<Grid item xs={12}>
|
||||
@@ -215,7 +201,7 @@ export default function DetailMonitoringList() {
|
||||
<Grid item xs={12}>
|
||||
<List sx={{ color: 'GrayText' }}>
|
||||
{
|
||||
row.medical_plan.map((data, index) => {
|
||||
row.medical_plan?.map((data, index) => {
|
||||
return (
|
||||
<ListItem key={index}>
|
||||
<FiberManualRecord sx={{ fontSize: '8px', mr: '10px' }} /> {data.medical_plan_str}
|
||||
@@ -227,6 +213,164 @@ export default function DetailMonitoringList() {
|
||||
</Grid>
|
||||
</Grid>
|
||||
</Grid>
|
||||
|
||||
<Grid item xs={12}>
|
||||
<Grid container gap={1}>
|
||||
<Grid item xs={12}>
|
||||
<Typography variant="body1" sx={{ fontWeight: 'bold' }}>
|
||||
Non Medikamentosa Plan :
|
||||
</Typography>
|
||||
</Grid>
|
||||
<Grid item xs={12}>
|
||||
<List sx={{ color: 'GrayText' }}>
|
||||
{
|
||||
row.non_medikamentosa_plan?.map((data, index) => {
|
||||
return (
|
||||
<ListItem key={index}>
|
||||
<FiberManualRecord sx={{ fontSize: '8px', mr: '10px' }} /> {data.non_medikamentosa_plan_str}
|
||||
</ListItem>
|
||||
)
|
||||
})
|
||||
}
|
||||
</List>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</Grid>
|
||||
|
||||
<Grid item xs={12}>
|
||||
<Grid container gap={1}>
|
||||
<Grid item xs={12}>
|
||||
<Typography variant="body1" sx={{ fontWeight: 'bold' }}>
|
||||
Laboratorium Result :
|
||||
</Typography>
|
||||
</Grid>
|
||||
<Grid container spacing={2}>
|
||||
<Grid item xs={6}>
|
||||
<Typography variant="body1" sx={{ fontWeight: 'bold' }}>
|
||||
Date
|
||||
</Typography>
|
||||
</Grid>
|
||||
<Grid item xs={6}>
|
||||
<Typography variant="body2" color={"GrayText"}>
|
||||
{ row.lab_date != null ? fDate(row.lab_date) : '-'}
|
||||
</Typography>
|
||||
</Grid>
|
||||
</Grid>
|
||||
<Grid container spacing={2}>
|
||||
<Grid item xs={6}>
|
||||
<Typography variant="body1" sx={{ fontWeight: 'bold' }}>
|
||||
Location
|
||||
</Typography>
|
||||
</Grid>
|
||||
<Grid item xs={6}>
|
||||
<Typography variant="body2" color={"GrayText"}>
|
||||
{row.provider}
|
||||
</Typography>
|
||||
</Grid>
|
||||
</Grid>
|
||||
<Grid container spacing={2}>
|
||||
<Grid item xs={6}>
|
||||
<Typography variant="body1" sx={{ fontWeight: 'bold' }}>
|
||||
Examination
|
||||
</Typography>
|
||||
</Grid>
|
||||
<Grid item xs={6}>
|
||||
<Typography variant="body2" color={"GrayText"}>
|
||||
{row.examination}
|
||||
</Typography>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</Grid>
|
||||
|
||||
<Grid item xs={12}>
|
||||
<Grid container gap={1}>
|
||||
<Grid item xs={12}>
|
||||
<Typography variant="body1" sx={{ fontWeight: 'bold' }}>
|
||||
Document Confirmation Medical Letter:
|
||||
</Typography>
|
||||
</Grid>
|
||||
<Grid item xs={12}>
|
||||
<List sx={{ color: 'GrayText' }}>
|
||||
{row.document?.map((data, index) => (
|
||||
<ListItem key={index}>
|
||||
{data.type === 'confirmation-medical-letter' ? (
|
||||
<>
|
||||
<FiberManualRecord sx={{ fontSize: '8px', mr: '10px' }} />
|
||||
<a
|
||||
href={data.path} // Replace 'data.download_link' with the actual download link
|
||||
target="_blank" // Optional: Open the link in a new tab
|
||||
rel="noopener noreferrer" // Recommended when using target="_blank"
|
||||
>
|
||||
{data.file_name}
|
||||
</a>
|
||||
</>
|
||||
) : null}
|
||||
</ListItem>
|
||||
))}
|
||||
</List>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</Grid>
|
||||
<Grid item xs={12}>
|
||||
<Grid container gap={1}>
|
||||
<Grid item xs={12}>
|
||||
<Typography variant="body1" sx={{ fontWeight: 'bold' }}>
|
||||
Document Medical Action Letter:
|
||||
</Typography>
|
||||
</Grid>
|
||||
<Grid item xs={12}>
|
||||
<List sx={{ color: 'GrayText' }}>
|
||||
{row.document?.map((data, index) => (
|
||||
<ListItem key={index}>
|
||||
{data.type === 'medical-action-letter' ? (
|
||||
<>
|
||||
<FiberManualRecord sx={{ fontSize: '8px', mr: '10px' }} />
|
||||
<a
|
||||
href={data.path} // Replace 'data.download_link' with the actual download link
|
||||
target="_blank" // Optional: Open the link in a new tab
|
||||
rel="noopener noreferrer" // Recommended when using target="_blank"
|
||||
>
|
||||
{data.file_name}
|
||||
</a>
|
||||
</>
|
||||
) : null}
|
||||
</ListItem>
|
||||
))}
|
||||
</List>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</Grid>
|
||||
<Grid item xs={12}>
|
||||
<Grid container gap={1}>
|
||||
<Grid item xs={12}>
|
||||
<Typography variant="body1" sx={{ fontWeight: 'bold' }}>
|
||||
Document Laboratorium Result:
|
||||
</Typography>
|
||||
</Grid>
|
||||
<Grid item xs={12}>
|
||||
<List sx={{ color: 'GrayText' }}>
|
||||
{row.document?.map((data, index) => (
|
||||
<ListItem key={index}>
|
||||
{data.type === 'laboratorium-result' ? (
|
||||
<>
|
||||
<FiberManualRecord sx={{ fontSize: '8px', mr: '10px' }} />
|
||||
<a
|
||||
href={data.path} // Replace 'data.download_link' with the actual download link
|
||||
target="_blank" // Optional: Open the link in a new tab
|
||||
rel="noopener noreferrer" // Recommended when using target="_blank"
|
||||
>
|
||||
{data.file_name}
|
||||
</a>
|
||||
</>
|
||||
) : null}
|
||||
</ListItem>
|
||||
))}
|
||||
</List>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</Grid>
|
||||
|
||||
</Grid>
|
||||
</Card>
|
||||
</Grid>
|
||||
|
||||
@@ -0,0 +1,92 @@
|
||||
import MuiDialog from "@/components/MuiDialog";
|
||||
import { Button, Card, Checkbox, DialogActions, Grid, Typography } from "@mui/material";
|
||||
import { Paper } from "@mui/material";
|
||||
import { Stack } from '@mui/material';
|
||||
import React, { useState } from 'react';
|
||||
import { fDate, fDateTimesecond, toTitleCase } from "@/utils/formatTime";
|
||||
import axios from "@/utils/axios";
|
||||
import { enqueueSnackbar } from "notistack";
|
||||
import { useNavigate } from "react-router";
|
||||
import { replace } from "lodash";
|
||||
import { ClaimListType } from "../Model/Types";
|
||||
import Label from "@/components/Label";
|
||||
|
||||
|
||||
type DialogConfirmationType = {
|
||||
openDialog: boolean;
|
||||
setOpenDialog: any;
|
||||
onSubmit?: void;
|
||||
row: ClaimListType;
|
||||
}
|
||||
|
||||
export default function DialogConfirmation({ setOpenDialog, openDialog, row} : DialogConfirmationType ) {
|
||||
|
||||
const navigate = useNavigate();
|
||||
const handleSubmit = () => {
|
||||
axios
|
||||
.post(`case_management/daily_monitoring/detail/${row.code}/update-status`)
|
||||
.then((response) => {
|
||||
enqueueSnackbar('Close Monitoring Success', { variant: 'success' });
|
||||
setOpenDialog(false);
|
||||
navigate(`/case_management/daily_monitoring/${row.member_id}/claims`, { replace: true })
|
||||
window.location.reload();
|
||||
})
|
||||
.catch(({ response }) => {
|
||||
enqueueSnackbar(response.data.message ?? 'Something went wrong!', { variant: 'error' });
|
||||
});
|
||||
}
|
||||
|
||||
const style1 = {
|
||||
color: '#919EAB',
|
||||
width: '30%'
|
||||
}
|
||||
const style2 = {
|
||||
width: '70%'
|
||||
}
|
||||
const marginBottom1 = {
|
||||
marginBottom: 1,
|
||||
}
|
||||
|
||||
const handleCloseDialog = () => {
|
||||
setOpenDialog(false);
|
||||
}
|
||||
|
||||
const getContent = () => (
|
||||
<Stack spacing={1} marginTop={2}>
|
||||
<Typography variant="subtitle2">Are you sure to closed this monitoring ?</Typography>
|
||||
<Grid item xs={12} md={12} marginTop={4}>
|
||||
<Card sx={{padding:2, marginTop:2}} >
|
||||
<Stack direction='row' spacing={2} sx={marginBottom1}>
|
||||
<Typography variant='subtitle2' sx={style1} gutterBottom>Name</Typography>
|
||||
<Typography variant='subtitle2' sx={style2} gutterBottom>{row.name}</Typography>
|
||||
</Stack>
|
||||
<Stack direction='row' spacing={2} sx={marginBottom1}>
|
||||
<Typography variant='subtitle2' sx={style1} gutterBottom>Code</Typography>
|
||||
<Typography variant='subtitle2' sx={style2} gutterBottom>{row.code}</Typography>
|
||||
</Stack>
|
||||
<Stack direction='row' spacing={2} sx={marginBottom1}>
|
||||
<Typography variant='subtitle2' sx={style1} gutterBottom>Admision Date</Typography>
|
||||
<Typography variant='subtitle2' sx={style2} gutterBottom> <Label variant="ghost">{fDate(row.admission_date)}</Label></Typography>
|
||||
</Stack>
|
||||
</Card>
|
||||
</Grid>
|
||||
<DialogActions>
|
||||
<Button variant="outlined" sx={{color: '#212B36', borderColor: '#919EAB52'}} onClick={handleCloseDialog}>Cancel</Button>
|
||||
<Button color="primary" variant="contained" onClick={handleSubmit}>Yes</Button>
|
||||
|
||||
|
||||
</DialogActions>
|
||||
</Stack>
|
||||
);
|
||||
|
||||
|
||||
return (
|
||||
<MuiDialog
|
||||
title={{name: "Confirmation"}}
|
||||
openDialog={openDialog}
|
||||
setOpenDialog={setOpenDialog}
|
||||
content={getContent()}
|
||||
maxWidth="sm"
|
||||
/>
|
||||
);
|
||||
}
|
||||
@@ -1,6 +1,8 @@
|
||||
import axios from '@/utils/axios';
|
||||
import { makeFormData } from '@/utils/jsonToFormData';
|
||||
import { enqueueSnackbar } from 'notistack';
|
||||
import { DailyMonitoringListType, DetailMonitoringListType, ResponseListingClaimType } from "./Types";
|
||||
import { fDate, fDateOnly } from '@/utils/formatTime';
|
||||
|
||||
/**
|
||||
* Listing Daily Monitoring
|
||||
@@ -44,9 +46,11 @@ export const getClaimList = async ( member_id: string ): Promise<ResponseListing
|
||||
* Add Monitoring Detail
|
||||
*/
|
||||
export const AddMonitoringDetail = async ( claim_code: string,data: DetailMonitoringListType ): Promise<boolean> => {
|
||||
const response = await axios.post(`/case_management/daily_monitoring/detail/${claim_code}/add`, {
|
||||
...data
|
||||
})
|
||||
data.lab_date = data.lab_date != '' && data.lab_date != null ? fDateOnly(data.lab_date) : '';
|
||||
|
||||
const formData = makeFormData({...data});
|
||||
|
||||
const response = await axios.post(`/case_management/daily_monitoring/detail/${claim_code}/add-request`, formData)
|
||||
.then((res) =>{
|
||||
enqueueSnackbar(res.data.message, {
|
||||
variant: 'success',
|
||||
|
||||
@@ -35,6 +35,9 @@ export type ClaimListType = {
|
||||
admission_date : string,
|
||||
discharge_date : string,
|
||||
claim_code : string,
|
||||
name : string,
|
||||
code : string,
|
||||
service_name : string,
|
||||
claim_status : string,
|
||||
service_type : string,
|
||||
member_id : string
|
||||
@@ -54,10 +57,32 @@ export type DetailMonitoringListType = {
|
||||
diastole : string
|
||||
analysis : string,
|
||||
complaints : string,
|
||||
lab_date : string,
|
||||
provider : string,
|
||||
examination : string,
|
||||
medical_plan : MedicalPlanStrType[],
|
||||
non_medikamentosa_plan : NonMedikamentosaPlanType[],
|
||||
confirmation_medical_leter : files[],
|
||||
medical_action_letter : files[],
|
||||
result : files[],
|
||||
document : document[],
|
||||
created_at : string|null
|
||||
}
|
||||
|
||||
export type MedicalPlanStrType = {
|
||||
medical_plan_str: string
|
||||
}
|
||||
|
||||
export type NonMedikamentosaPlanType = {
|
||||
non_medikamentosa_plan_str: string
|
||||
}
|
||||
|
||||
export type files = {
|
||||
file: string
|
||||
}
|
||||
|
||||
export type document = {
|
||||
file_name: string,
|
||||
path: string,
|
||||
type: string
|
||||
}
|
||||
|
||||
@@ -94,6 +94,7 @@ export default function CorporatePlanList({handleSubmitSuccess}) {
|
||||
const { corporate_id } = useParams();
|
||||
const [searchParams, setSearchParams] = useSearchParams();
|
||||
const [importResult, setImportResult] = useState(null);
|
||||
const [sendResult, setSendResult] = useState(null);
|
||||
|
||||
const [openDialog, setOpenDialog] = useState(false);
|
||||
const [isDialog, setIsDialog] = useState('');
|
||||
@@ -267,6 +268,25 @@ export default function CorporatePlanList({handleSubmitSuccess}) {
|
||||
});
|
||||
}
|
||||
|
||||
const handleSendAllEcard = () => {
|
||||
setImportLoading(true);
|
||||
setDataTableLoading(true);
|
||||
axios
|
||||
.get(`send_card/${corporate_id}`)
|
||||
.then((response) => {
|
||||
loadDataTableData();
|
||||
})
|
||||
|
||||
.catch((response) => {
|
||||
enqueueSnackbar(
|
||||
'Looks like something went wrong. Please check your data and try again.',
|
||||
{ variant: 'error' }
|
||||
);
|
||||
setImportLoading(false);
|
||||
loadDataTableData();
|
||||
});
|
||||
}
|
||||
|
||||
const handleCancelImportButton = () => {
|
||||
importPlan.current.value = '';
|
||||
importPlan.current.dispatchEvent(new Event('change', { bubbles: true }));
|
||||
@@ -363,6 +383,9 @@ export default function CorporatePlanList({handleSubmitSuccess}) {
|
||||
<MenuItem onClick={handleMemberList}>
|
||||
<Typography variant='body2'>Download Member</Typography>
|
||||
</MenuItem>
|
||||
<MenuItem onClick={handleSendAllEcard}>
|
||||
<Typography variant='body2'>Send All Ecard</Typography>
|
||||
</MenuItem>
|
||||
</Menu>
|
||||
</Stack>
|
||||
)}
|
||||
@@ -413,6 +436,7 @@ export default function CorporatePlanList({handleSubmitSuccess}) {
|
||||
</Box>
|
||||
</Stack>
|
||||
)}
|
||||
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -470,6 +494,21 @@ export default function CorporatePlanList({handleSubmitSuccess}) {
|
||||
const style1 = {
|
||||
color: '#637381'
|
||||
}
|
||||
|
||||
|
||||
const handleDownloadEcard = (id: number) => {
|
||||
axios
|
||||
.get(`view_card/${id}`, {
|
||||
responseType: 'blob',
|
||||
})
|
||||
.then((response) => {
|
||||
window.open(URL.createObjectURL(response.data));
|
||||
})
|
||||
.catch((response) => {
|
||||
enqueueSnackbar(response.message, { variant: 'error' });
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
return (
|
||||
<React.Fragment>
|
||||
@@ -527,6 +566,10 @@ export default function CorporatePlanList({handleSubmitSuccess}) {
|
||||
<CachedOutlinedIcon />
|
||||
Update Status
|
||||
</MenuItem>
|
||||
<MenuItem onClick={() => handleDownloadEcard(row.id)}>
|
||||
<DownloadIcon />
|
||||
Download E-card
|
||||
</MenuItem>
|
||||
<MenuItem onClick={() => navigate ('/corporates/'+corporate_id+'/members/'+row.id+'/history')}>
|
||||
<HistoryIcon />
|
||||
History
|
||||
|
||||
@@ -98,8 +98,8 @@ export default function Router() {
|
||||
element: <Claim />,
|
||||
},
|
||||
{
|
||||
path: '/detail/:id',
|
||||
element: <DetailClaimReport />,
|
||||
path: '/claim/detail/:id',
|
||||
element: <DetailClaim />,
|
||||
},
|
||||
],
|
||||
},
|
||||
@@ -126,3 +126,4 @@ const Claim = Loadable(lazy(() => import('@/pages/Claim')));
|
||||
const NotFound = Loadable(lazy(() => import('@/pages/Page404')));
|
||||
|
||||
const DetailClaimReport = Loadable(lazy(()=> import('@/sections/dashboard/Detail')));
|
||||
const DetailClaim = Loadable(lazy(()=> import('@/sections/claim/Detail')));
|
||||
|
||||
69
frontend/hospital-portal/src/sections/claim/Detail.tsx
Normal file
69
frontend/hospital-portal/src/sections/claim/Detail.tsx
Normal file
@@ -0,0 +1,69 @@
|
||||
// mui
|
||||
import { Container, Grid, Stack, Typography } from '@mui/material';
|
||||
// components
|
||||
import Page from '../../components/Page';
|
||||
// utils
|
||||
import useSettings from '../../hooks/useSettings';
|
||||
// section
|
||||
import CardFamilyInformation from '../../sections/alarm-center/user-profile/CardFamilyInformation';
|
||||
// react
|
||||
import { useNavigate, useParams } from 'react-router-dom';
|
||||
import ButtonBack from '../../components/ButtonBack';
|
||||
import { useEffect, useState, useContext } from 'react';
|
||||
import axios from '../../utils/axios';
|
||||
// pages
|
||||
import DetailTimeline from '../../sections/dashboard/DetailTimeline';
|
||||
import DetailStepper from '../../sections/dashboard/DetailStepper';
|
||||
import { format } from 'date-fns';
|
||||
import ArrowBackIosIcon from '@mui/icons-material/ArrowBackIos';
|
||||
import { LanguageContext } from '@/contexts/LanguageContext';
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
export default function Detail() {
|
||||
const { localeData }: any = useContext(LanguageContext);
|
||||
const navigate = useNavigate();
|
||||
const { themeStretch } = useSettings();
|
||||
const [data, setData] = useState();
|
||||
|
||||
const { id } = useParams();
|
||||
|
||||
useEffect(() => {
|
||||
axios
|
||||
.get('/detail-claim-requests/' + id)
|
||||
.then((response) => {
|
||||
setData(response.data);
|
||||
})
|
||||
.catch((error) => {
|
||||
console.error(error);
|
||||
});
|
||||
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<Page title="Detail">
|
||||
<Container maxWidth={themeStretch ? false : 'xl'}>
|
||||
<Stack direction="row" alignItems="center" sx={{ marginBottom: 3 }}>
|
||||
<ArrowBackIosIcon onClick={() => navigate(-1)} sx={{cursor:'pointer'}}/>
|
||||
<Typography variant="h5" sx={{marginLeft:2}}>Detail</Typography>
|
||||
{data ? (
|
||||
<Stack direction="row" spacing={2} ml="auto">
|
||||
<Typography variant="body2" sx={{color: '#757575'}}>{localeData.txtDialogMember5}</Typography>
|
||||
<Typography variant="body2" fontWeight="bold">{(data && data.data) ? format(new Date(data.data.status.submission_date), "d MMM yyyy") : ''}</Typography>
|
||||
</Stack>
|
||||
) : ''}
|
||||
</Stack>
|
||||
{data ? (
|
||||
<Grid container spacing={2}>
|
||||
<Grid item xs={12} md={12}>
|
||||
<DetailStepper data={data}/>
|
||||
</Grid>
|
||||
<Grid item xs={12} md={12}>
|
||||
<DetailTimeline data={data}/>
|
||||
</Grid>
|
||||
</Grid>
|
||||
) : ''}
|
||||
</Container>
|
||||
</Page>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
import * as React from 'react';
|
||||
import Box from '@mui/material/Box';
|
||||
import Stepper from '@mui/material/Stepper';
|
||||
import Step from '@mui/material/Step';
|
||||
import StepLabel from '@mui/material/StepLabel';
|
||||
import { useEffect, useState } from 'react';
|
||||
import ClearIcon from '@mui/icons-material/Clear';
|
||||
|
||||
const steps = [
|
||||
'Request',
|
||||
'Review',
|
||||
'Approval',
|
||||
'Decline',
|
||||
];
|
||||
|
||||
export default function HorizontalLinearAlternativeLabelStepper({data}) {
|
||||
const [active, setActive] = useState(0);
|
||||
const [status, SetStatus] = useState(null);
|
||||
let updatedSteps = [...steps];
|
||||
useEffect(() => {
|
||||
if (data && data.data) {
|
||||
if (data.data.status.status === 'requested') {
|
||||
setActive(1);
|
||||
updatedSteps = updatedSteps.filter(step => step !== 'Decline');
|
||||
}
|
||||
else if (data.data.status.status === 'reviewed') {
|
||||
setActive(2);
|
||||
updatedSteps = updatedSteps.filter(step => step !== 'Decline');
|
||||
}
|
||||
else if (data.data.status.status === 'approved')
|
||||
{
|
||||
setActive(3);
|
||||
updatedSteps = updatedSteps.filter(step => step !== 'Decline');
|
||||
}
|
||||
else if(data.data.status.status === 'declined')
|
||||
{
|
||||
setActive(4)
|
||||
updatedSteps = updatedSteps.filter(step => step !== 'Approval');
|
||||
}
|
||||
}
|
||||
SetStatus(updatedSteps);
|
||||
}, [data]);
|
||||
|
||||
|
||||
|
||||
|
||||
return (
|
||||
<Box sx={{ width: '100%', marginBottom: 2 }}>
|
||||
<Stepper activeStep={active} alternativeLabel>
|
||||
{status?.map((label) => (
|
||||
<Step key={label}>
|
||||
<StepLabel icon={label==='Decline' ? <ClearIcon sx={{ color: 'white', backgroundColor: 'red', borderRadius: '50%' }} /> : ''}>{label}</StepLabel>
|
||||
</Step>
|
||||
))}
|
||||
</Stepper>
|
||||
</Box>
|
||||
);
|
||||
}
|
||||
386
frontend/hospital-portal/src/sections/claim/DetailTimeline.tsx
Normal file
386
frontend/hospital-portal/src/sections/claim/DetailTimeline.tsx
Normal file
@@ -0,0 +1,386 @@
|
||||
import * as React from 'react';
|
||||
import Timeline from '@mui/lab/Timeline';
|
||||
import TimelineItem, { timelineItemClasses } from '@mui/lab/TimelineItem';
|
||||
import TimelineSeparator from '@mui/lab/TimelineSeparator';
|
||||
import TimelineConnector from '@mui/lab/TimelineConnector';
|
||||
import TimelineContent from '@mui/lab/TimelineContent';
|
||||
import TimelineDot from '@mui/lab/TimelineDot';
|
||||
import {Typography, Card, Stack, ButtonBase, Box, Divider} from '@mui/material';
|
||||
import { styled } from '@mui/material/styles';
|
||||
import Paper from '@mui/material/Paper';
|
||||
import Button from '@mui/material/Button';
|
||||
import AddIcon from '@mui/icons-material/Add';
|
||||
import Iconify from '../../components/Iconify';
|
||||
import { useEffect, useState, useRef } from 'react';
|
||||
import { format } from 'date-fns';
|
||||
import { LoadingButton } from '@mui/lab';
|
||||
import axios from '../../utils/axios';
|
||||
import { makeFormData } from '@/utils/jsonToFormData';
|
||||
import { enqueueSnackbar } from 'notistack';
|
||||
import { useParams} from 'react-router-dom';
|
||||
import InsertDriveFileIcon from '@mui/icons-material/InsertDriveFile';
|
||||
|
||||
const Item1 = styled(Paper)(({ theme }) => ({
|
||||
...theme.typography.body2,
|
||||
padding: theme.spacing(1),
|
||||
textAlign: 'center',
|
||||
backgroundColor: '#919EAB29',
|
||||
color: '#637381',
|
||||
width: 'fit-content',
|
||||
marginRight: 'auto',
|
||||
}));
|
||||
|
||||
const Item2 = styled(Paper)(({ theme }) => ({
|
||||
backgroundColor: theme.palette.mode === 'dark' ? '#1A2027' : '#fff',
|
||||
...theme.typography.body2,
|
||||
padding: theme.spacing(1),
|
||||
textAlign: 'center',
|
||||
color: theme.palette.text.secondary,
|
||||
width: 'fit-content',
|
||||
marginLeft: 'auto',
|
||||
}));
|
||||
|
||||
export default function NoOppositeContent({data}) {
|
||||
const [timeline, setTimeline] = useState(null);
|
||||
const [requestFile, setRequestFile] = useState(null);
|
||||
useEffect(() => {
|
||||
if (data && data.data) {
|
||||
setTimeline(data.data.timeline);
|
||||
setRequestFile(data.data.request_files);
|
||||
}
|
||||
|
||||
}, [data]);
|
||||
|
||||
// Diagnosis
|
||||
const fileRequestDocumentInputDiagnosis = useRef<HTMLInputElement>(null);
|
||||
const [fileDiagnosis, setFileDiagnosis] = useState([]);
|
||||
const handleRequestDocumentInputChangeDiagnosis = (event) => {
|
||||
if (event.target.files[0]) {
|
||||
setFileDiagnosis([...fileDiagnosis, ...event.target.files]);
|
||||
}
|
||||
};
|
||||
const removeFileDiagnois = (filesState, index) => {
|
||||
setFileDiagnosis(
|
||||
filesState.filter((file, fileIndex) => {
|
||||
return fileIndex != index;
|
||||
})
|
||||
);
|
||||
};
|
||||
// Kondisi
|
||||
const fileRequestDocumentInputKondisi = useRef<HTMLInputElement>(null);
|
||||
const [fileKondisi, setFileKondisi] = useState([]);
|
||||
const handleRequestDocumentInputChangeKondisi = (event) => {
|
||||
if (event.target.files[0]) {
|
||||
setFileKondisi([...fileKondisi, ...event.target.files]);
|
||||
}
|
||||
};
|
||||
const removeFileKondisi = (filesState, index) => {
|
||||
setFileKondisi(
|
||||
filesState.filter((file, fileIndex) => {
|
||||
return fileIndex != index;
|
||||
})
|
||||
);
|
||||
};
|
||||
// Result
|
||||
const fileRequestDocumentInputResult = useRef<HTMLInputElement>(null);
|
||||
const [fileResult, setFileResult] = useState([]);
|
||||
const handleRequestDocumentInputChangeResult = (event) => {
|
||||
if (event.target.files[0]) {
|
||||
setFileResult([...fileResult, ...event.target.files]);
|
||||
}
|
||||
};
|
||||
const removeFileResult = (filesState, index) => {
|
||||
setFileResult(
|
||||
filesState.filter((file, fileIndex) => {
|
||||
return fileIndex != index;
|
||||
})
|
||||
);
|
||||
};
|
||||
const { id } = useParams();
|
||||
const [submitLoading, setSubmitLoading] = useState(false);
|
||||
const submitRequestFiles = () => {
|
||||
setSubmitLoading(true);
|
||||
const formData = makeFormData({
|
||||
fileDiagnosis: fileDiagnosis,
|
||||
fileKondisis: fileKondisi,
|
||||
fileResults: fileResult
|
||||
});
|
||||
axios
|
||||
.post('claim-requests/'+id+'/request-files', formData)
|
||||
.then((response) => {
|
||||
window.location.reload();
|
||||
})
|
||||
.catch(({ response }) => {
|
||||
enqueueSnackbar(response.data.message ?? 'Something Went Wrong', { variant: 'error' });
|
||||
});
|
||||
}
|
||||
const submitButton = requestFile?.find((dataRequestFile) => dataRequestFile.check_files === null);
|
||||
return (
|
||||
<>
|
||||
{timeline?.map((dataTimeline, index) => (
|
||||
<Timeline
|
||||
sx={{
|
||||
[`& .${timelineItemClasses.root}:before`]: {
|
||||
flex: 0,
|
||||
padding: 0,
|
||||
},
|
||||
}}
|
||||
key={index}
|
||||
>
|
||||
<Typography variant="body2" gutterBottom fontWeight="bold">{dataTimeline.date ? format(new Date(dataTimeline.date), "d MMM yyyy") : ''}</Typography>
|
||||
<TimelineItem>
|
||||
<TimelineSeparator>
|
||||
<TimelineDot />
|
||||
<TimelineConnector />
|
||||
</TimelineSeparator>
|
||||
<TimelineContent spacing={3}>
|
||||
<Card sx={{ borderRadius: '6px', paddingY: 2 }}>
|
||||
<Stack sx={{marginLeft: 2, marginRight: 2, marginTop: 2 }}>
|
||||
<Stack direction="row" spacing={2} sx={{marginBottom: 2, paddingBottom: 2, borderBottom: '1px solid #919EAB52' }}>
|
||||
<Item1>{dataTimeline.date ? format(new Date(dataTimeline.date), "HH : mm") : ''}</Item1>
|
||||
<Item2 sx={{backgroundColor: dataTimeline.txt_status_backgroundColor, color: dataTimeline.txt_status_color}}>{dataTimeline.txt_status}</Item2>
|
||||
</Stack>
|
||||
<Stack direction="row" spacing={2} sx={{marginBottom: 2}}>
|
||||
<Typography variant="body2" gutterBottom>Detail:</Typography>
|
||||
<Typography variant="body2" gutterBottom>{dataTimeline.description}</Typography>
|
||||
</Stack>
|
||||
{dataTimeline.status === 'reviewed' && requestFile ? (
|
||||
<>
|
||||
{submitButton ? (
|
||||
<Typography variant="body2" gutterBottom>Request Document</Typography>
|
||||
) : (
|
||||
<Typography sx={{color: '#19BBBB'}} variant="body2" gutterBottom>Request Document Success Uploaded</Typography>
|
||||
)}
|
||||
{/* Diagnosis */}
|
||||
{requestFile?.map((dataRequestFile, index) => {
|
||||
if(dataRequestFile.type !== 'claim-diagnosis' || dataRequestFile.check_files !== null){
|
||||
return null;
|
||||
}
|
||||
return (
|
||||
<Stack spacing={2} sx={{marginBottom: 2}} key={index}>
|
||||
<Typography variant="body2" gutterBottom fontWeight="bold">
|
||||
Diagnosis
|
||||
</Typography>
|
||||
<Stack
|
||||
divider={<Divider orientation="horizontal" flexItem />}
|
||||
spacing={1}
|
||||
sx={{ marginY: 2 }}
|
||||
>
|
||||
{fileDiagnosis &&
|
||||
fileDiagnosis.map((file, index) => (
|
||||
<Stack direction="row" justifyContent={'space-between'} key={index}>
|
||||
<Stack direction="row" spacing={1} sx={{color: '#19BBBB'}}>
|
||||
<InsertDriveFileIcon />
|
||||
<Typography variant="body2" gutterBottom>{file.name ? file.name : '-'}</Typography>
|
||||
</Stack>
|
||||
<Iconify
|
||||
icon="eva:trash-2-outline"
|
||||
color={'darkred'}
|
||||
onClick={() => {
|
||||
removeFileDiagnois(fileDiagnosis, index);
|
||||
}}
|
||||
sx={{cursor: 'pointer'}}
|
||||
></Iconify>
|
||||
</Stack>
|
||||
))}
|
||||
</Stack>
|
||||
<ButtonBase
|
||||
sx={{
|
||||
p: 4,
|
||||
border: '2px dashed #F9FAFB',
|
||||
bgcolor: '#919EAB52',
|
||||
borderRadius: '8px',
|
||||
width: '100%',
|
||||
height: '60px',
|
||||
}}
|
||||
onClick={() => fileRequestDocumentInputDiagnosis.current?.click()}
|
||||
>
|
||||
<Box
|
||||
sx={{
|
||||
display: 'flex',
|
||||
placeItems: 'center',
|
||||
gap: 1,
|
||||
placeContent: 'center',
|
||||
}}
|
||||
>
|
||||
<Iconify icon="icon-park-outline:upload-one" fontSize="3em" />
|
||||
<Typography variant="body1" fontWeight="bold">
|
||||
Add Result
|
||||
</Typography>
|
||||
</Box>
|
||||
<input
|
||||
type="file"
|
||||
id={`file-${index}`}
|
||||
ref={fileRequestDocumentInputDiagnosis}
|
||||
style={{ display: 'none' }}
|
||||
multiple
|
||||
onChange={(event) => handleRequestDocumentInputChangeDiagnosis(event)}
|
||||
accept=".csv, application/vnd.openxmlformats-officedocument.spreadsheetml.sheet, application/vnd.ms-excel, text/plain, application/pdf"
|
||||
/>
|
||||
</ButtonBase>
|
||||
</Stack>
|
||||
);
|
||||
})}
|
||||
{/* Kondisi */}
|
||||
{requestFile?.map((dataRequestFile, index) => {
|
||||
if(dataRequestFile.type !== 'claim-kondisi' || dataRequestFile.check_files !== null){
|
||||
return null;
|
||||
}
|
||||
return (
|
||||
<Stack spacing={2} sx={{marginBottom: 2}} key={index}>
|
||||
<Typography variant="body2" gutterBottom fontWeight="bold">
|
||||
Condition
|
||||
</Typography>
|
||||
<Stack
|
||||
divider={<Divider orientation="horizontal" flexItem />}
|
||||
spacing={1}
|
||||
sx={{ marginY: 2 }}
|
||||
>
|
||||
{fileKondisi &&
|
||||
fileKondisi.map((file, index) => (
|
||||
<Stack direction="row" justifyContent={'space-between'} key={index}>
|
||||
<Stack direction="row" spacing={1} sx={{color: '#19BBBB'}}>
|
||||
<InsertDriveFileIcon />
|
||||
<Typography variant="body2" gutterBottom>{file.name ? file.name : '-'}</Typography>
|
||||
</Stack>
|
||||
<Iconify
|
||||
icon="eva:trash-2-outline"
|
||||
color={'darkred'}
|
||||
onClick={() => {
|
||||
removeFileKondisi(fileKondisi, index);
|
||||
}}
|
||||
sx={{cursor: 'pointer'}}
|
||||
></Iconify>
|
||||
</Stack>
|
||||
))}
|
||||
</Stack>
|
||||
<ButtonBase
|
||||
sx={{
|
||||
p: 4,
|
||||
border: '2px dashed #F9FAFB',
|
||||
bgcolor: '#919EAB52',
|
||||
borderRadius: '8px',
|
||||
width: '100%',
|
||||
height: '60px',
|
||||
}}
|
||||
onClick={() => fileRequestDocumentInputKondisi.current?.click()}
|
||||
>
|
||||
<Box
|
||||
sx={{
|
||||
display: 'flex',
|
||||
placeItems: 'center',
|
||||
gap: 1,
|
||||
placeContent: 'center',
|
||||
}}
|
||||
>
|
||||
<Iconify icon="icon-park-outline:upload-one" fontSize="3em" />
|
||||
<Typography variant="body1" fontWeight="bold">
|
||||
Add Result
|
||||
</Typography>
|
||||
</Box>
|
||||
<input
|
||||
type="file"
|
||||
id={`file-${index}`}
|
||||
ref={fileRequestDocumentInputKondisi}
|
||||
style={{ display: 'none' }}
|
||||
multiple
|
||||
onChange={(event) => handleRequestDocumentInputChangeKondisi(event)}
|
||||
accept=".csv, application/vnd.openxmlformats-officedocument.spreadsheetml.sheet, application/vnd.ms-excel, text/plain, application/pdf"
|
||||
/>
|
||||
</ButtonBase>
|
||||
</Stack>
|
||||
);
|
||||
})}
|
||||
{/* Supporting Result */}
|
||||
{requestFile?.map((dataRequestFile, index) => {
|
||||
if(dataRequestFile.type !== 'claim-result' || dataRequestFile.check_files !== null){
|
||||
return null;
|
||||
}
|
||||
return (
|
||||
<Stack spacing={2} sx={{marginBottom: 2}} key={index}>
|
||||
<Typography variant="body2" gutterBottom fontWeight="bold">
|
||||
Supporting Result
|
||||
</Typography>
|
||||
<Stack
|
||||
divider={<Divider orientation="horizontal" flexItem />}
|
||||
spacing={1}
|
||||
sx={{ marginY: 2 }}
|
||||
>
|
||||
{fileResult &&
|
||||
fileResult.map((file, index) => (
|
||||
<Stack direction="row" justifyContent={'space-between'} key={index}>
|
||||
<Stack direction="row" spacing={1} sx={{color: '#19BBBB'}}>
|
||||
<InsertDriveFileIcon />
|
||||
<Typography variant="body2" gutterBottom>{file.name ? file.name : '-'}</Typography>
|
||||
</Stack>
|
||||
<Iconify
|
||||
icon="eva:trash-2-outline"
|
||||
color={'darkred'}
|
||||
onClick={() => {
|
||||
removeFileResult(fileResult, index);
|
||||
}}
|
||||
sx={{cursor: 'pointer'}}
|
||||
></Iconify>
|
||||
</Stack>
|
||||
))}
|
||||
</Stack>
|
||||
<ButtonBase
|
||||
sx={{
|
||||
p: 4,
|
||||
border: '2px dashed #F9FAFB',
|
||||
bgcolor: '#919EAB52',
|
||||
borderRadius: '8px',
|
||||
width: '100%',
|
||||
height: '60px',
|
||||
}}
|
||||
onClick={() => fileRequestDocumentInputResult.current?.click()}
|
||||
>
|
||||
<Box
|
||||
sx={{
|
||||
display: 'flex',
|
||||
placeItems: 'center',
|
||||
gap: 1,
|
||||
placeContent: 'center',
|
||||
}}
|
||||
>
|
||||
<Iconify icon="icon-park-outline:upload-one" fontSize="3em" />
|
||||
<Typography variant="body1" fontWeight="bold">
|
||||
Add Result
|
||||
</Typography>
|
||||
</Box>
|
||||
<input
|
||||
type="file"
|
||||
id={`file-${index}`}
|
||||
ref={fileRequestDocumentInputResult}
|
||||
style={{ display: 'none' }}
|
||||
multiple
|
||||
onChange={(event) => handleRequestDocumentInputChangeResult(event)}
|
||||
accept=".csv, application/vnd.openxmlformats-officedocument.spreadsheetml.sheet, application/vnd.ms-excel, text/plain, application/pdf"
|
||||
/>
|
||||
</ButtonBase>
|
||||
</Stack>
|
||||
);
|
||||
})}
|
||||
{submitButton ? (
|
||||
<LoadingButton
|
||||
variant="contained"
|
||||
sx={{ marginTop: 2, p: 2, backgroundColor: '#19BBBB' }}
|
||||
onClick={() => {
|
||||
submitRequestFiles();
|
||||
}}
|
||||
loading={submitLoading}
|
||||
>
|
||||
Submit
|
||||
</LoadingButton>
|
||||
) : ''}
|
||||
</>
|
||||
) : ''}
|
||||
</Stack>
|
||||
</Card>
|
||||
</TimelineContent>
|
||||
</TimelineItem>
|
||||
</Timeline>
|
||||
))}
|
||||
</>
|
||||
);
|
||||
}
|
||||
@@ -313,7 +313,7 @@ export default function TableList() {
|
||||
action:
|
||||
<TableMoreMenu actions={
|
||||
<>
|
||||
<MenuItem>
|
||||
<MenuItem onClick={() => navigate ('/claim/detail/'+obj.claim_request_id)}>
|
||||
<Iconify icon="eva:eye-fill" />
|
||||
View
|
||||
</MenuItem>
|
||||
|
||||
@@ -44,7 +44,6 @@ export default function FormRequestClaim({ member, handleSubmitSuccess }: FormRe
|
||||
axios
|
||||
.post('/request-log', formData)
|
||||
.then((response) => {
|
||||
console.log(response);
|
||||
if (response && response.data && response.data.meta) {
|
||||
enqueueSnackbar(response.data.meta.message, { variant: 'success' });
|
||||
handleSubmitSuccess();
|
||||
|
||||
@@ -51,23 +51,16 @@ function handleChangeTab(event: React.SyntheticEvent, newValue: string) {
|
||||
const [data, setData] = useState([]);
|
||||
|
||||
// Download LOG
|
||||
async function handleDownloadLog(claimRequest:any) {
|
||||
async function handleDownloadLog(request_log_id:any) {
|
||||
return axios
|
||||
.get(`claim-requests/${claimRequest}/log`, {
|
||||
.get(`download-log/${request_log_id}`, {
|
||||
responseType: 'blob',
|
||||
})
|
||||
.then((response) => {
|
||||
window.open(URL.createObjectURL(response.data));
|
||||
// setLoadingLog(false);
|
||||
window.open(URL.createObjectURL(response.data), '_blank');
|
||||
})
|
||||
// .then((blobFile) => {
|
||||
// new File([blobFile], 'asdads.pdf', { type: blobFile.type })
|
||||
// setLoadingLog(false);
|
||||
// })
|
||||
.catch((response) => {
|
||||
console.log(response);
|
||||
enqueueSnackbar(response.message, { variant: 'error' });
|
||||
// setLoadingLog(false);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -357,13 +350,13 @@ function handleChangeTab(event: React.SyntheticEvent, newValue: string) {
|
||||
<Iconify icon="eva:eye-fill" />
|
||||
View
|
||||
</MenuItem>
|
||||
{obj.status === 'approved' ? (
|
||||
<MenuItem onClick={() => handleDownloadLog(obj.claim_request_id)}>
|
||||
{/* {obj.status === 'approved' ? ( */}
|
||||
<MenuItem onClick={() => handleDownloadLog(obj.id)}>
|
||||
<Iconify icon="eva:download-fill" />
|
||||
Download LOG
|
||||
</MenuItem>
|
||||
):''}
|
||||
{obj.final_log === 0 ? (
|
||||
{/* ):''} */}
|
||||
{obj.final_log === 0 && obj.status === 'approved' ? (
|
||||
<MenuItem onClick={() => handleRequestFinalLog(obj.id, obj.full_name, obj.no_polis, obj.submission_date) }>
|
||||
<Iconify icon="fa:file-text" />
|
||||
Request Final LOG
|
||||
|
||||
@@ -355,7 +355,7 @@ export default function TableListFinalLog() {
|
||||
Download LOG
|
||||
</MenuItem>
|
||||
):''}
|
||||
{!obj.check_claim ? (
|
||||
{!obj.check_claim && obj.status === 'approved' ? (
|
||||
<MenuItem onClick={() => handleRequestClaimSubmit(obj.member_id, obj.service_code, obj.id, obj.full_name, obj.no_polis, obj.submission_date) }>
|
||||
<Iconify icon="fa:file-text" />
|
||||
Submit Claim
|
||||
|
||||
Reference in New Issue
Block a user