implement claim submit

This commit is contained in:
lasteinsa
2023-10-09 17:25:16 +07:00
parent b49f78858f
commit 1700e8ebfb
9 changed files with 691 additions and 232 deletions

View File

@@ -14,6 +14,7 @@ import {
Stack,
Grid,
Avatar,
ButtonBase,
} from '@mui/material';
import { Add } from '@mui/icons-material';
// components
@@ -23,10 +24,17 @@ import ArrowBackIosIcon from '@mui/icons-material/ArrowBackIos';
// theme
import palette from '../../theme/palette';
// React
import { ReactElement, useRef, useState } from 'react';
import { Fragment, ReactElement, useEffect, useRef, useState } from 'react';
import { useSearchParams, useNavigate, Link } from 'react-router-dom';
import { fPostFormat } from '../../utils/formatTime';
import { fCurrency } from '../../utils/formatNumber';
import { LoadingButton } from '@mui/lab';
import Iconify from '../../components/Iconify';
import { useSelector } from 'react-redux';
import { RootState } from '../../store';
import { makeFormData } from '../../utils/jsonToFormData';
import { useSnackbar } from 'notistack';
import axiosInstance from '../../utils/axios';
// -------------------------------- type --------------------------------------
type DataContentType = {
@@ -44,6 +52,24 @@ type DataContentType = {
};
};
type ClaimSubmission = {
id: number;
personID: string;
personName: string;
typePatient: string;
limit: {
current: number;
total: number;
percentage: number;
};
avatar: {
url: string;
};
fileRealInvoice: any[];
anotherDocument: any[];
laboratoryResult: any[];
};
type MuiDialogProps = {
title?: {
name?: string;
@@ -69,188 +95,435 @@ const BorderLinearProgress = styled(LinearProgress)(({ theme }) => ({
}));
/* -------------------------------------------------------------------------- */
const steps = ['Review', 'Approval', 'Disbursement'];
const DialogDetailClaim = ({ title, openDialog, setOpenDialog, data }: MuiDialogProps) => {
function clickHandler(arg0: string) {
throw new Error('Function not implemented.');
}
const navigate = useNavigate();
const [serviceCode, setServiceCode] = useState('IP');
const { enqueueSnackbar } = useSnackbar();
// const getContent = () => (
const [submitLoading, setSubmitLoading] = useState(false);
const selectedData = useSelector((state: RootState) => state.claims.data);
const [dataContent, setDataContent] = useState<ClaimSubmission[]>([]);
// );
useEffect(() => {
if (selectedData.length > 0) {
let temp: ClaimSubmission[] = selectedData.map((item) => ({
id: item.id,
avatar: {
url: '',
},
limit: item.limit,
personID: item.memberId,
personName: item.fullName,
typePatient: 'IP',
anotherDocument: [],
fileRealInvoice: [],
laboratoryResult: [],
}));
setDataContent(temp);
} else {
navigate('/claim-submit', { replace: true });
}
}, [selectedData]);
const handleServiceCode = (data: ClaimSubmission, index?: number) => {
let temp = dataContent.map((item) => {
if (item.personID === data.personID) {
return {
...item,
typePatient: item.typePatient === 'IP' ? 'OP' : 'IP',
};
} else {
return item;
}
});
setDataContent(temp);
};
const handleInputFile = (
event: any,
data: ClaimSubmission,
typeFile: 'invoice' | 'another' | 'lab'
) => {
if (event.target.files[0]) {
let temp = dataContent.map((item) => {
if (item.personID === data.personID) {
if (typeFile === 'invoice') {
return {
...item,
fileRealInvoice: [...item.fileRealInvoice, event.target.files[0]],
};
} else if (typeFile === 'another') {
return {
...item,
anotherDocument: [...item.anotherDocument, event.target.files[0]],
};
} else {
return {
...item,
laboratoryResult: [...item.laboratoryResult, event.target.files[0]],
};
}
} else {
return item;
}
});
setDataContent(temp);
} else {
console.log('NO FILE');
}
};
const handleRemoveFile = (
data: ClaimSubmission,
typeFile: 'invoice' | 'another' | 'lab',
index: number
) => {
let temp = dataContent.map((item) => {
if (item.personID === data.personID) {
if (typeFile === 'invoice') {
return {
...item,
fileRealInvoice: item.fileRealInvoice.filter((file, fileIndex) => fileIndex != index),
};
} else if (typeFile === 'another') {
return {
...item,
anotherDocument: item.anotherDocument.filter((file, fileIndex) => fileIndex != index),
};
} else {
return {
...item,
laboratoryResult: item.laboratoryResult.filter((file, fileIndex) => fileIndex != index),
};
}
} else {
return item;
}
});
setDataContent(temp);
};
const onSubmit = () => {
setSubmitLoading(true);
const mapArrayToFormData = (claims: ClaimSubmission[]): FormData => {
const formData = new FormData();
claims.forEach((claim, index) => {
formData.append(`member_id[${index}]`, claim.id.toString());
formData.append(`service_code[${index}]`, claim.typePatient);
claim.laboratoryResult.forEach((file, fileIndex) => {
formData.append(`laboratorium[${index}][${fileIndex}]`, file);
});
claim.anotherDocument.forEach((file, fileIndex) => {
formData.append(`prescription[${index}][${fileIndex}]`, file);
});
claim.fileRealInvoice.forEach((file, fileIndex) => {
formData.append(`invoice[${index}][${fileIndex}]`, file);
});
});
return formData;
};
const formData = mapArrayToFormData(dataContent);
axiosInstance
.post('/claim-requests', formData)
.then((response) => {
enqueueSnackbar(response.data.message ?? 'Berhasil membuat data', { variant: 'success' });
navigate('/claim-submit', { replace: true });
})
.catch(({ response }) => {
enqueueSnackbar(response.data.message ?? 'Something Went Wrong', { variant: 'error' });
})
.finally(() => {
setSubmitLoading(false);
});
};
return (
<>
<Grid container>
<Grid container spacing={8}>
{/* Field 1 */}
<Grid item xs={12} paddingX="24px" paddingY="20px">
<Stack direction="row" alignItems="center">
<ArrowBackIosIcon onClick={() => navigate(`/corporate`)} sx={{ cursor: "pointer" }} />
<Typography variant="h5" sx={{ flexGrow: 1 }}>Claim Submission </Typography>
<Typography variant="inherit" sx={{ textAlign: "center", flexBasis: "15%" }}>Submission Date </Typography>
<Typography textAlign={'right'} variant="h6" sx={{ textAlign: "right" }}>
<ArrowBackIosIcon
onClick={() => navigate(`/claim-submit`)}
sx={{ cursor: 'pointer' }}
/>
<Typography variant="h5" sx={{ flexGrow: 1 }}>
Claim Submission{' '}
</Typography>
<Typography variant="inherit" sx={{ textAlign: 'center', flexBasis: '15%' }}>
Submission Date{' '}
</Typography>
<Typography textAlign={'right'} variant="h6" sx={{ textAlign: 'right' }}>
{fPostFormat(new Date(), 'dd MMM yyyy')}
</Typography>
</Stack>
</Grid>
<Grid item xs={12} paddingX="24px" paddingY="20px">
<Stack direction="row" spacing={4}>
<Button
sx={{ padding: 2, width: '50%', border: serviceCode === 'OP' ? '1px solid #919EAB52' : '1px solid #19BBBB' }}
variant={serviceCode == 'IP' ? 'outlined' : ''}
onClick={() => {
setServiceCode('IP');
}}
>
Inpatient
</Button>
<Button
sx={{ padding: 2, width: '50%',border: serviceCode === 'IP' ? '1px solid #919EAB52' : '1px solid #19BBBB' }}
variant={serviceCode == 'OP' ? 'outlined' : ''}
onClick={() => {
setServiceCode('OP');
}}
>
Outpatient
</Button>
</Stack>
</Grid>
<Grid item xs={12}>
<Card sx={{ p: 2, marginBottom: 2 }}>
<Stack direction="row" alignContent={'center'}>
<Avatar
src="https://minimal-assets-api.vercel.app/assets/images/avatars/avatar_5.jpg"
alt={'test'}
sx={{ margin: 1, width: 56, height: 56 }}
/>
<Stack sx={{ p: 1 }}>
<Typography variant='h5'>{'Alexandra Rhea Putranto'}</Typography>
<Typography variant='subtitle1' color={'#637381'}>{'KM002-01'}</Typography>
</Stack>
<Stack sx={{ p: 1 }}>
<Typography variant="body1" sx={{ marginBottom: 1, fontWeight: 600 }}>
Total Limit
</Typography>
<BorderLinearProgress variant="determinate" value={80} />
<Typography sx={{ textAlign: 'right', marginTop: 1 }}>
{fCurrency(8000000)} / {fCurrency(100000)}
</Typography>
</Stack>
</Stack>
</Card>
</Grid>
{dataContent.map((row, index) => {
return (
<Grid item xs={12} key={index}>
<Card sx={{ p: 3 }}>
<Grid container spacing={4} key={index}>
<Grid item xs={12} paddingX="24px" paddingY="20px">
<Stack direction="row" spacing={4}>
<Button
sx={{
padding: 2,
width: '50%',
border:
row.typePatient === 'OP' ? '1px solid #919EAB52' : '1px solid #19BBBB',
}}
variant="outlined"
color={row.typePatient === 'IP' ? 'primary' : 'inherit'}
onClick={() => {
handleServiceCode(row);
}}
>
Inpatient
</Button>
<Button
sx={{
padding: 2,
width: '50%',
border:
row.typePatient === 'IP' ? '1px solid #919EAB52' : '1px solid #19BBBB',
}}
variant="outlined"
color={row.typePatient === 'OP' ? 'primary' : 'inherit'}
onClick={() => {
handleServiceCode(row);
}}
>
Outpatient
</Button>
</Stack>
</Grid>
<Grid item xs={12}>
<Card sx={{ p: 2 }}>
<Stack direction="row" alignContent={'center'}>
<Avatar
src="https://minimal-assets-api.vercel.app/assets/images/avatars/avatar_5.jpg"
alt={'test'}
sx={{ margin: 1, width: 56, height: 56 }}
/>
<Stack sx={{ p: 1 }}>
<Typography variant="h5">{row.personName}</Typography>
<Typography variant="subtitle1" color="#637381">
{row.personID}
</Typography>
</Stack>
<Stack sx={{ p: 1 }}>
<Typography variant="body1" sx={{ marginBottom: 1, fontWeight: 600 }}>
Total Limit
</Typography>
<BorderLinearProgress
variant="determinate"
value={row.limit && row.limit.percentage}
sx={{ mb: 1 }}
/>
<Typography sx={{ textAlign: 'right', marginTop: 1 }}>
{fCurrency(8000000)} / {fCurrency(100000)}
</Typography>
</Stack>
</Stack>
</Card>
</Grid>
{/* REAL INVOICE */}
<Grid item xs={12}>
<Grid container spacing={2}>
<Grid item xs={12}>
<Typography variant="h6">Real Invoice</Typography>
</Grid>
{row.fileRealInvoice &&
row.fileRealInvoice.map((file, fileIndex) => (
<Grid item xs={12} key={fileIndex}>
<Stack direction="row" justifyContent={'space-between'}>
<Typography sx={{ color: 'text.secondary' }}>{file.name}</Typography>
<Iconify
icon="eva:trash-2-outline"
color={'darkred'}
onClick={() => {
handleRemoveFile(row, 'invoice', fileIndex);
}}
/>
</Stack>
</Grid>
))}
<Grid item xs={12}>
<Box
sx={{
display: 'flex',
placeContent: 'center',
placeItems: 'center',
border: '2px dashed #F9FAFB',
bgcolor: '#919EAB52',
borderRadius: '8px',
p: 0,
}}
>
<Buttons handle={handleInputFile} row={row} type="invoice" />
</Box>
</Grid>
</Grid>
</Grid>
{/* DOCTOR'S PRESCRIPTION AND ANOTHER DOCUMENTS */}
<Grid item xs={12}>
<Grid container spacing={2}>
<Grid item xs={12}>
<Typography variant="h6">
Doctor's Prescription and Another Documents
</Typography>
</Grid>
{row.anotherDocument &&
row.anotherDocument.map((file, fileIndex) => (
<Grid item xs={12} key={fileIndex}>
<Stack direction="row" justifyContent={'space-between'}>
<Typography sx={{ color: 'text.secondary' }}>{file.name}</Typography>
<Iconify
icon="eva:trash-2-outline"
color={'darkred'}
onClick={() => {
handleRemoveFile(row, 'another', fileIndex);
}}
/>
</Stack>
</Grid>
))}
<Grid item xs={12}>
<Box
sx={{
display: 'flex',
placeContent: 'center',
placeItems: 'center',
border: '2px dashed #F9FAFB',
bgcolor: '#919EAB52',
borderRadius: '8px',
p: 0,
}}
>
<Buttons handle={handleInputFile} row={row} type="another" />
</Box>
</Grid>
</Grid>
</Grid>
{/* LABORATORY RESULTS */}
<Grid item xs={12}>
<Grid container spacing={2}>
<Grid item xs={12}>
<Typography variant="h6">Laboraroty Results</Typography>
</Grid>
{row.laboratoryResult &&
row.laboratoryResult.map((file, fileIndex) => (
<Grid item xs={12} key={fileIndex}>
<Stack direction="row" justifyContent={'space-between'}>
<Typography sx={{ color: 'text.secondary' }}>{file.name}</Typography>
<Iconify
icon="eva:trash-2-outline"
color={'darkred'}
onClick={() => {
handleRemoveFile(row, 'lab', fileIndex);
}}
/>
</Stack>
</Grid>
))}
</Grid>
<Grid item xs={12}>
<Box
sx={{
display: 'flex',
placeContent: 'center',
placeItems: 'center',
border: '2px dashed #F9FAFB',
bgcolor: '#919EAB52',
borderRadius: '8px',
p: 0,
}}
>
<Buttons handle={handleInputFile} row={row} type="lab" />
</Box>
</Grid>
</Grid>
</Grid>
</Card>
</Grid>
);
})}
<Grid item xs={12}>
<LoadingButton
variant="contained"
sx={{ marginTop: 2, p: 2, margin: '10px' }}
fullWidth
onClick={onSubmit}
loading={submitLoading}
>
Claim Submit
</LoadingButton>
</Grid>
</Grid>
<Stack marginTop={2}>
<Typography variant="subtitle1" paddingY={2}>
17 Mei 2022
</Typography>
</Stack>
<Stack direction="row" spacing={2}>
<Divider orientation="vertical" flexItem sx={{ borderStyle: 'dashed' }} />
<Stack spacing={2} sx={{ flex: 1, maxWidth: '100%' }}>
{/* Item 1 */}
<Card sx={{ paddingY: 2, paddingX: 3 }}>
<Stack direction="row" justifyContent="space-between" alignItems="center">
<Typography variant="body1">09:10 WIB</Typography>
<Typography
sx={{
backgroundColor: palette.light.warning.lighter,
color: palette.light.warning.dark,
borderColor: palette.light.warning.dark,
border: '1px solid',
borderRadius: '6px',
padding: 1,
}}
variant="caption"
>
Approval
</Typography>
</Stack>
<Divider sx={{ marginY: 2 }} />
<Stack>
<Typography variant="subtitle2" color="#404040">
Details : mohon melengkapi kekurangan dokumen
</Typography>
<Typography variant="caption" color="#757575" sx={{ marginTop: 2, marginBottom: 1 }}>
Lab pemeriksaan darah
</Typography>
<Button
variant="outlined"
startIcon={<Add />}
fullWidth
sx={{ typography: 'subtitle2', borderColor: '#F5F5F5' }}
// onClick={() => clickHandler('topUpLimit')}
>
Hasil Pemeriksaan Laboratorium
</Button>
</Stack>
</Card>
{/* Item 2 */}
<Card sx={{ flex: 1, maxWidth: '100%', paddingY: 2, paddingX: 3 }}>
<Stack direction="row" justifyContent="space-between" alignItems="center">
<Typography variant="body1">09:00 WIB</Typography>
<Typography
sx={{
backgroundColor: palette.light.warning.lighter,
color: palette.light.warning.dark,
borderColor: palette.light.warning.dark,
border: '1px solid',
borderRadius: '6px',
padding: 1,
}}
variant="caption"
>
Approval
</Typography>
</Stack>
<Divider sx={{ marginY: 2 }} />
<Stack>
<Typography variant="subtitle2" color="#404040">
Details : Penilaian Dokter
</Typography>
</Stack>
</Card>
{/* Item 3 */}
<Card sx={{ flex: 1, maxWidth: '100%', paddingY: 2, paddingX: 3 }}>
<Stack direction="row" justifyContent="space-between" alignItems="center">
<Typography variant="body1">08:00 WIB</Typography>
<Typography
sx={{
backgroundColor: '#F5F5F5',
color: '#757575',
borderColor: '#757575',
border: '1px solid',
borderRadius: '6px',
padding: 1,
}}
variant="caption"
>
Review
</Typography>
</Stack>
<Divider sx={{ marginY: 2 }} />
<Stack>
<Typography variant="subtitle2" color="#404040">
Details : Klaim Diajukan
</Typography>
</Stack>
</Card>
</Stack>
</Stack>
</>
// <MuiDialog
// title={title}
// openDialog={openDialog}
// setOpenDialog={setOpenDialog}
// content={getContent()}
// />
);
};
// let temp = [
// {
// member: "",
// result_file: [
// "file.pdf",
// "file2.pdf"
// ]
// }
// ]
export default DialogDetailClaim;
type ButtonIProp = {
row: ClaimSubmission;
type: 'invoice' | 'another' | 'lab';
handle: (event: any, row: any, type: any) => void;
};
const Buttons = ({ handle, row, type }: ButtonIProp) => {
const ref = useRef<HTMLInputElement>(null);
return (
<ButtonBase sx={{ p: 4 }} onClick={() => ref.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 Invoice
</Typography>
</Box>
<input
ref={ref}
hidden
accept="application/pdf"
type="file"
name="file"
multiple
onChange={(event) => handle(event, row, type)}
/>
</ButtonBase>
);
};

View File

@@ -106,7 +106,6 @@ export default function List() {
handleSearchSubmit: handleSearchSubmit,
};
/* ------------------------------------------------------------------------- */
/*-------------------------------- handlle checkbox ------------------------ */
const handleCheckboxChange = async (event: React.FormEvent<HTMLFormElement>) => {
@@ -122,18 +121,11 @@ export default function List() {
}
};
/* -------------------------------- headCell -------------------------------- */
return (
<Stack>
<CardClaimSubmit
rows={data}
loadings={loadings}
params={params}
searchs={searchs}
/>
<CardClaimSubmit rows={data} loadings={loadings} params={params} searchs={searchs} />
</Stack>
);
}