Update Add Input Hospital Portal

This commit is contained in:
ivan-sim
2026-02-10 10:03:28 +07:00
parent 7e42a5ecfd
commit 127ef3ff50
31 changed files with 5674 additions and 86 deletions

View File

@@ -0,0 +1,105 @@
import { Card, Typography } from "@mui/material";
import { Stack } from '@mui/material';
import { DetailFinalLogType } from "../Model/Types";
import { fDate, fDateTimesecond, toTitleCase } from "@/utils/formatTime";
import Label from '@/components/Label';
type CardDetail = {
requestLog: DetailFinalLogType|undefined;
isFinalLog: boolean
}
const style1 = {
color: '#919EAB',
width: '30%'
}
const style2 = {
width: '70%'
}
const marginBottom1 = {
marginBottom: 1,
}
const marginBottom2 = {
marginBottom: 2,
}
export default function CardService({requestLog, isFinalLog = true} : CardDetail ) {
return (
<Card sx={{padding:2}} >
<Typography variant='subtitle1' sx={{color: '#19BBBB', marginBottom: 4}} gutterBottom>Service</Typography>
<Stack direction='row' spacing={2} sx={marginBottom1}>
<Typography variant='subtitle2' sx={style1} gutterBottom>Service Type</Typography>
<Typography variant='subtitle2' sx={style2} gutterBottom>{requestLog?.service_type}</Typography>
</Stack>
<Stack direction='row' spacing={2} sx={marginBottom1}>
<Typography variant='subtitle2' sx={style1} gutterBottom>Claim Method</Typography>
<Typography variant='subtitle2' sx={style2} gutterBottom>{toTitleCase(requestLog?.claim_method ?? '-')}</Typography>
</Stack>
{/* <Stack direction='row' spacing={2} sx={marginBottom1}>
<Typography variant='subtitle2' sx={{width:'35%', color: '#919EAB'}} gutterBottom>Benefit</Typography>
<Typography variant='subtitle2' sx={style2} gutterBottom>
<ul>
{requestLog?.benefit.length > 0 ? requestLog?.benefit.map((r, index) => (
<li key={index}>{r.code } - {r.description}</li>
)) : <li>-</li>}
</ul>
</Typography>
</Stack> */}
{/* General Practitioner */}
<Stack direction='row' spacing={2} sx={marginBottom1}>
<Typography variant='subtitle2' sx={style1} gutterBottom>General Practitioner</Typography>
<Typography variant='subtitle2' sx={style2} gutterBottom>External Doctor :
{requestLog?.config_service?.gp_external_doctor_online == '1' ? (<Label sx={{marginLeft:2}}> Online</Label>) : '-'}
{requestLog?.config_service?.gp_external_doctor_offline == '1' ? (<Label sx={{marginLeft:1}}> Offfline</Label>) : '-'}
</Typography>
</Stack>
<Stack direction='row' spacing={2} sx={marginBottom2}>
<Typography variant='subtitle2' sx={style1} gutterBottom></Typography>
<Typography variant='subtitle2' sx={style2} gutterBottom>Internal Doctor :
{requestLog?.config_service?.gp_internal_doctor_online == '1' ? (<Label sx={{marginLeft:2}}> Online</Label>) : '-'}
{requestLog?.config_service?.gp_internal_doctor_offline == '1' ? (<Label sx={{marginLeft:1}}> Offfline</Label>) : '-'}
</Typography>
</Stack>
{/* Specialist Practitioner */}
<Stack direction='row' spacing={2} sx={marginBottom1}>
<Typography variant='subtitle2' sx={style1} gutterBottom>Specialist Practitioner</Typography>
<Typography variant='subtitle2' sx={style2} gutterBottom>External Doctor :
{requestLog?.config_service?.sp_external_doctor_online == '1' ? (<Label sx={{marginLeft:2}}> Online</Label>) : '-'}
{requestLog?.config_service?.sp_external_doctor_offline == '1' ? (<Label sx={{marginLeft:1}}> Offfline</Label>) : '-'}
</Typography>
</Stack>
<Stack direction='row' spacing={2} sx={marginBottom2}>
<Typography variant='subtitle2' sx={style1} gutterBottom></Typography>
<Typography variant='subtitle2' sx={style2} gutterBottom>Internal Doctor :
{requestLog?.config_service?.gp_internal_doctor_online == '1' ? (<Label sx={{marginLeft:2}}> Online</Label>) : '-'}
{requestLog?.config_service?.gp_internal_doctor_offline == '1' ? (<Label sx={{marginLeft:1}}> Offfline</Label>) : '-'}
</Typography>
</Stack>
{/* Medicine */}
{/* <Stack direction='row' spacing={2} sx={marginBottom1}>
<Typography variant='subtitle2' sx={{width:'35%', color: '#919EAB'}} gutterBottom>Medicine</Typography>
<Typography variant='subtitle2' sx={style2} gutterBottom>
<ul>
{requestLog?.config_service?.vitamins == '1' ? (<li>Suplemen</li>) : (<li>-</li>)}
{requestLog?.config_service?.delivery_fee == '1' ? (<li>Delivery Fee</li>) : (<li>-</li>)}
</ul>
</Typography>
</Stack> */}
<Stack direction='row' spacing={2} sx={marginBottom2}>
<Typography variant='subtitle2' sx={style1} gutterBottom>Admin Fee</Typography>
<Typography variant='subtitle2' sx={style2} gutterBottom>
{requestLog?.config_service?.general_practitioner_fee == '1' ? (<Label sx={{marginLeft:2}}> General Practitioner</Label>) : '-'}
{requestLog?.config_service?.specialist_practitioner_fee == '1' ? (<Label sx={{marginLeft:1}}> Specialist Practitioner</Label>) : '-'}
</Typography>
</Stack>
</Card>
)
}

View File

@@ -0,0 +1,682 @@
import * as Yup from 'yup';
import { yupResolver } from '@hookform/resolvers/yup';
import MuiDialog from "@/components/MuiDialog";
import { Checkbox, Typography, FormControl, Card, Grid, DialogActions, IconButton, Autocomplete } from "@mui/material";
import { Paper } from "@mui/material";
import { Stack } from '@mui/material';
import React, { useEffect, useState } from 'react';
import { DetailFinalLogType } from "../Model/Types";
import { BenefitConfigurationListType } from "../Model/Types";
import { InputLabel, Select, FormHelperText } from "@mui/material";
import FormGroup from '@mui/material/FormGroup';
import FormControlLabel from '@mui/material/FormControlLabel';
import Button from '@mui/material/Button';
import { fNumber } from "@/utils/formatNumber";
import palette from "@/theme/palette";
import { Box } from "@mui/material";
import { FormProvider, RHFTextField } from "@/components/hook-form";
import RHFTextFieldMoney from '@/components/hook-form/v2/RHFTextFieldMoney';
import { useFieldArray, useForm, useWatch } from 'react-hook-form';
import { LoadingButton } from '@mui/lab';
import { postAddBenefit } from '../Model/Functions';
import { useNavigate } from 'react-router';
import { description } from '@/_mock/text';
import { Delete } from '@mui/icons-material';
import { TextField } from '@mui/material';
import RHFAutocomplete from '@/components/hook-form/RHFAutocomplete';
type DialogConfirmationType = {
openDialog: boolean;
setOpenDialog: any;
onSubmit?: void;
requestLog: DetailFinalLogType|undefined;
claimInput:boolean
}
type BenefitSelected = {
id: number,
description: string,
benefit_id: number,
family_plan: string,
family_plan_plans: string,
limit_amount: number,
limit_amount_plan: number,
max_frequency_period: number,
}
export default function DialogBenefit({requestLog, setOpenDialog, openDialog, claimInput = false } : DialogConfirmationType ) {
// Add Benefit
const [addBenefit, setAddBenefit] = useState(false)
const navigate = useNavigate()
//Benefit Name
const [valBenefitNames, setValBenefitNames] = useState([]);
const [valBenefitNameError, setValBenefitNameError] = useState('');
const benefitNameData = requestLog?.benefit;
const [benefitSelected, setBenefitSelected] = useState<BenefitSelected[]>([]);
const [isDisabled, setisDisable] = useState(false);
const handleConditionChangeService = (event) => {
const selectedItem = event.target.value;
if (valBenefitNames.includes(selectedItem)) {
// Item is already selected, remove it
setValBenefitNames(valBenefitNames.filter(item => item !== selectedItem));
} else {
// Item is not selected, add it
setValBenefitNames([...valBenefitNames, selectedItem]);
}
};
const reasons = [
{ value: 'Wrong Setting', label: 'Wrong Setting' },
{ value: 'Hospital Request', label: 'Hospital Request' }
];
useEffect(() => {
const datax: any[] = []
valBenefitNames.map((data) => {
benefitNameData?.map((row) => {
if(row.id == data) {
datax.push(row)
}
})
})
// for data information
let temp = datax.map((item, indx) => {
return {
benefit_id: item.id,
description: item.description,
request_log_id: requestLog?.id,
amount_incurred: 0,
amount_approved: 0,
amount_not_approved: 0,
excess_paid: 0,
keterangan: '',
reason: null
}
})
reset({benefit_data: temp})
setBenefitSelected(datax)
}, [valBenefitNames])
const handleCloseDialogBenefit = () => {
setOpenDialog(false);
setAddBenefit(false)
setBenefitSelected([])
setValBenefitNames([])
}
const handleAddDialogBenefit = () => {
setAddBenefit(true)
}
const defaultValues: BenefitConfigurationListType = {
request_log_id: requestLog?.id,
benefit_name: '',
amount_incurred: 0,
amount_approved: 0,
amount_not_approved: 0,
excess_paid: 0,
reason: null
};
const validationSchema = Yup.object().shape({
benefit_data: Yup.array().of(
claimInput ?
Yup.object().shape({
amount_incurred : Yup.number().typeError('').required(''),
amount_approved : Yup.number().typeError('').required(''),
amount_not_approved : Yup.number().typeError('').required(''),
excess_paid : Yup.number().typeError('').required(''),
// reason : Yup.string().required(''),
}) :
Yup.object().shape({
amount_incurred : Yup.number().typeError('').required(''),
amount_approved : Yup.number().typeError('').required(''),
amount_not_approved : Yup.number().typeError('').required(''),
excess_paid : Yup.number().typeError('').required(''),
})
)
})
const methods = useForm<any>({
resolver: yupResolver(validationSchema),
defaultValues,
reValidateMode: "onChange"
});
let width = claimInput ? 2 : 2.36;
const {fields, append, remove} = useFieldArray({name: 'benefit_data',control: methods.control,});
const { handleSubmit, reset, watch, setValue, setError, clearErrors, formState: { isDirty, isSubmitting, errors,isValid } } = methods
const errorsExist = errors ? Object.keys(errors).length > 0 : false;
// Calculate
const benefitData = watch('benefit_data');
const totalAll = () => {
let totalAmountIncurred = (requestLog?.benefit_data || []).reduce((accumulator, item) => {
return accumulator + (item.amount_incurred || 0);
}, 0);
let totalAmountApproved = (requestLog?.benefit_data || []).reduce((accumulator, item) => {
return accumulator + (item.amount_approved || 0);
}, 0);
let totalAmountNotApproved = (requestLog?.benefit_data || []).reduce((accumulator, item) => {
return accumulator + (item.amount_not_approved || 0);
}, 0);
let totalExcessPaid = (requestLog?.benefit_data || []).reduce((accumulator, item) => {
return accumulator + (item.excess_paid || 0);
}, 0);
benefitData?.map((item, index) => {
totalAmountIncurred += parseFloat(item.amount_incurred);
totalAmountApproved += parseFloat(item.amount_approved);
totalAmountNotApproved += parseFloat(item.amount_not_approved);
totalExcessPaid += parseFloat(item.excess_paid);
});
return {
totalAmountIncurred,
totalAmountApproved,
totalAmountNotApproved,
totalExcessPaid
}
}
const totalUsage = () => {
let realTimeUsageMember = 0
for (let key in requestLog?.member_usage_benefit) {
if (requestLog?.member_usage_benefit.hasOwnProperty(key)) {
let value = requestLog?.member_usage_benefit[key];
// Menggunakan parseFloat() untuk mengonversi nilai menjadi angka
let numericValue = parseFloat(value);
// Memeriksa apakah numericValue adalah angka yang valid
if (!isNaN(numericValue)) {
realTimeUsageMember += numericValue;
}
}
}
let totalAmountMember = 0
for (let key in benefitData) {
// Menambahkan nilai amount_approved ke totalAmount
totalAmountMember += Number(benefitData[key].amount_approved);
}
return realTimeUsageMember+totalAmountMember
}
const handleOnChangeNominal = (key) => {
if (benefitSelected[key].family_plan == 'S' || benefitSelected[key].family_plan == 'F'){
if (requestLog?.member_usage_benefit && benefitSelected[key] && benefitData[key]) {
let limitAmount = Number(benefitSelected[key].limit_amount) || 0;
let limitAmountPlan = Number(benefitSelected[key].limit_amount_plan) || 0;
// Periksa apakah limitAmount Benefit lebih besar dari realTimeUsage
if (limitAmountPlan != 999999999){
let realTimeUsage = 0;
let value = 0;
for (let key in requestLog?.member_usage_benefit) {
if (requestLog?.member_usage_benefit.hasOwnProperty(key)) {
let value = requestLog?.member_usage_benefit[key];
// Menggunakan parseFloat() untuk mengonversi nilai menjadi angka
let numericValue = parseFloat(value);
// Memeriksa apakah numericValue adalah angka yang valid
if (!isNaN(numericValue)) {
realTimeUsage += numericValue;
}
}
}
// console.log(benefitData, 'test')
let totalAmount = 0;
for (let key in benefitData) {
// Menambahkan nilai amount_approved ke totalAmount
totalAmount += Number(benefitData[key].amount_approved);
}
// Hitung penggunaan waktu nyata
realTimeUsage += totalAmount;
let excess = realTimeUsage - limitAmountPlan
let incurred = Number(benefitData[key].amount_incurred);
if (realTimeUsage === limitAmountPlan){
setisDisable(true)
setValue(`benefit_data.${key}.amount_not_approved`, incurred);
} else {
setisDisable(false)
}
if (limitAmountPlan < realTimeUsage) {
setValue(`benefit_data.${key}.amount_not_approved`, excess);
setValue(`benefit_data.${key}.amount_approved`, incurred - excess);
setError(`benefit_data.${key}.amount_approved`, { message: `Total Amount Approve sudah melebihi limit ${ fNumber(limitAmountPlan) } , silakan isikan di Amount Excess` });
} else if (totalAll().totalAmountApproved > totalAll().totalAmountIncurred) {
setError(`benefit_data.${key}.amount_approved`, { message: 'Total Amount Approve tidak boleh lebih dari Total Amount Incurred' });
} else {
clearErrors(`benefit_data.${key}.amount_approved`);
}
} else if (limitAmount != 999999999) { // Periksa apakah limitAmount Benefit lebih besar dari realTimeUsage
// Konversi nilai ke angka dengan aman
let memberUsage = Number(requestLog.member_usage_benefit[benefitSelected[key].id]) || 0;
let amountApproved = Number(benefitData[key].amount_approved) || 0;
// Hitung penggunaan waktu nyata
let realTimeUsage = memberUsage + amountApproved;
let value = realTimeUsage - limitAmount
if (limitAmount < realTimeUsage) {
setValue(`benefit_data.${key}.amount_not_approved`, value);
setError(`benefit_data.${key}.amount_approved`, { message: `Total Amount Approve sudah melebihi limit ${ fNumber(limitAmount) } , silakan isikan di Amount Excess` });
} else if (totalAll().totalAmountApproved > totalAll().totalAmountIncurred) {
setError(`benefit_data.${key}.amount_approved`, { message: 'Total Amount Approve tidak boleh lebih dari Total Amount Incurred' });
} else {
clearErrors(`benefit_data.${key}.amount_approved`);
}
} else {
if (totalAll().totalAmountApproved > totalAll().totalAmountIncurred) {
setError(`benefit_data.${key}.amount_approved`, { message: 'Total Amount Approve tidak boleh lebih dari Total Amount Incurred' });
} else {
clearErrors(`benefit_data.${key}.amount_approved`);
}
}
if (totalAll().totalAmountApproved + totalAll().totalAmountNotApproved === totalAll().totalAmountIncurred) {
clearErrors(`benefit_data.${key}.excess_paid`);
} else {
setError(`benefit_data.${key}.excess_paid`, { message: 'Total Amount Excess tidak sama dengan Total Amount Incurred' });
}
}
} else {
if (totalAll().totalAmountApproved > totalAll().totalAmountIncurred){
setError(`benefit_data.${key}.amount_approved`, {message: 'Amount Approve tidak boleh lebih dari Amount Incurred'});
} else {
clearErrors(`benefit_data.${key}.amount_approved`);
}
}
}
const handleOnChangeNotApprove = (key, value) => {
setValue(`benefit_data.${key}.excess_paid`, value);
if (totalAll().totalAmountApproved + totalAll().totalAmountNotApproved === totalAll().totalAmountIncurred) {
clearErrors(`benefit_data.${key}.excess_paid`);
} else {
setError(`benefit_data.${key}.excess_paid`, { message: 'Total Amount Excess tidak sama dengan Total Amount Incurred' });
}
};
// Submit Form
// =====================================
const submitHandler = async (data: BenefitConfigurationListType) => {
const mapData = data.benefit_data.map((item) => ({
...item,
reason: item.reason ? item.reason.value : null
}));
const newData = {
...data,
benefit_data: mapData
};
const response = await postAddBenefit(newData);
if (response == true) {
reset();
// navigate('custormer-service/final-log/detail/'+requestLog?.id);
window.location.reload()
}
}
const getContent = () => !addBenefit ? (
<Stack spacing={2} sx={{marginTop: 2, padding: 2}} direction="column">
<Stack direction="row" spacing={2}>
<Stack spacing={2} sx={{width:'100%'}}>
<Typography variant='subtitle1'>Benefit Name*</Typography>
<FormControl>
<InputLabel htmlFor="benefit_name">
Benefit Name
</InputLabel>
<Select
id="benefit_name"
value={valBenefitNames}
fullWidth
label="Benefit Name"
error={!!valBenefitNameError}
onChange={(e) => {
setValBenefitNameError(!valBenefitNames ? 'At least one item must be selected' : '');
}}
renderValue={(selected) => selected.map(value => {
const selectedOption = benefitNameData?.find(option => String(option.id) === value);
return selectedOption ? selectedOption.description : '';
}).join(', ')}
>
{benefitNameData?.map((item, index) => (
<FormGroup key={index} sx={{ marginLeft: 2 }}>
<FormControlLabel
control={
<Checkbox
checked={valBenefitNames.includes(String(item.id))}
onChange={handleConditionChangeService}
value={String(item.id)}
/>
}
label={item.description}
/>
</FormGroup>
))}
</Select>
<FormHelperText style={{ color: 'red' }}>{valBenefitNameError}</FormHelperText>
</FormControl>
</Stack>
</Stack>
</Stack>
) :
(
<FormProvider methods={methods} onSubmit={handleSubmit(submitHandler)}>
<Stack paddingX={2} paddingY={4}>
{/* <Card sx={{padding:2}}> */}
{fields?.map((item, index) =>
(
<Box sx={{ marginTop:'10px', marginBottom:'10px', py: '8px', px: '12px', border:'1px solid #919EAB52', borderRadius: '6px'}}>
<Grid key={item.id} container spacing={2} alignItems="center">
<Grid item xs={12}>
<Typography variant="subtitle1" sx={{ fontWeight: 'bold'}}>
{item.description}
</Typography>
</Grid>
<Grid item xs={width}>
<Grid container spacing={2}>
<Grid item xs={12}>
<Typography variant="subtitle1" component="div">
Amount Incurred*
</Typography>
</Grid>
<Grid item xs={12} sx={{display: 'flex', gap: 1}}>
<RHFTextFieldMoney
key={item.id}
id='amount_incurred'
name={`benefit_data.${index}.amount_incurred`}
placeholder='Amount Incurred'
required
onChange={(event) => {
setValue(`benefit_data.${index}.amount_incurred`, event.target.value)
handleOnChangeNominal(index)}
}
/>
</Grid>
</Grid>
</Grid>
<Grid item xs={width}>
<Grid container spacing={2}>
<Grid item xs={12}>
<Typography variant="subtitle1" component="div">
Amount Approved*
</Typography>
</Grid>
<Grid item xs={12} sx={{display: 'flex', gap: 1}}>
<RHFTextFieldMoney
// onChange={() => append({amount_approved: ''}) }
id='amount_approved'
key={item.id}
name={`benefit_data.${index}.amount_approved`}
placeholder='Amount Approved'
required
onChange={(event) => {
setValue(`benefit_data.${index}.amount_approved`, event.target.value)
handleOnChangeNominal(index)}
}
disabled={isDisabled}
/>
</Grid>
</Grid>
</Grid>
<Grid item xs={width}>
<Grid container spacing={2}>
<Grid item xs={12}>
<Typography variant="subtitle1" component="div">
Amount Not Approved*
</Typography>
</Grid>
<Grid item xs={12} sx={{display: 'flex', gap: 1}}>
<RHFTextFieldMoney
// onChange={() => append({amount_not_approved: ''}) }
id='amount_not_approved'
key={item.id}
name={`benefit_data.${index}.amount_not_approved`}
placeholder='Amount Not Approved'
required
onChange={(event) => {
setValue(`benefit_data.${index}.amount_not_approved`, event.target.value)
handleOnChangeNotApprove(index, event.target.value)}
}
/>
</Grid>
</Grid>
</Grid>
<Grid item xs={width}>
<Grid container spacing={2}>
<Grid item xs={12}>
<Typography variant="subtitle1" component="div">
Excess Paid*
</Typography>
</Grid>
<Grid item xs={12} sx={{display: 'flex', gap: 1}}>
<RHFTextFieldMoney
// onChange={() => append({excess_paid: ''}) }
id='excess_paid'
key={item.id}
name={`benefit_data.${index}.excess_paid`}
placeholder='Excess Paid'
required
/>
</Grid>
</Grid>
</Grid>
<Grid item xs={2}>
<Grid container spacing={2}>
<Grid item xs={12}>
<Typography variant="subtitle1" component="div">
Keterangan
</Typography>
</Grid>
<Grid item xs={12} sx={{display: 'flex', gap: 1}}>
<RHFTextField
// onChange={() => append({keterangan: ''}) }
id='keterangan'
key={item.id}
name={`benefit_data.${index}.keterangan`}
placeholder='Keterangan'
/>
</Grid>
</Grid>
</Grid>
{claimInput ? (
<Grid item xs={1.4}>
<Grid container spacing={2}>
<Grid item xs={12}>
<Typography variant="subtitle1" component="div">
Reason*
</Typography>
</Grid>
<Grid item xs={12} sx={{display: 'flex', gap: 1}}>
<Autocomplete
options={reasons}
getOptionLabel={(option) => option.label}
fullWidth
value={benefitData[index]?.reason} // Use find to match the default value
onChange={(event, newValue) => {
// Update the value in the form data
setValue(`benefit_data.${index}.reason`, newValue);
}}
renderInput={(params) => (
<TextField
{...params}
label="Reason"
variant="outlined"
required
/>
)}
/>
</Grid>
</Grid>
</Grid>
) : null}
{ fields.length > 1 ? (
<Grid item xs={0} sx={{ textAlign: 'center' }}>
<IconButton size='large' color='error' onClick={() => remove(index)}>
<Delete />
</IconButton>
</Grid>
) : null }
</Grid>
</Box>
))}
<br/>
<hr/>
<br/>
<Grid container spacing={2}>
<Grid item xs={12}>
<Grid container spacing={2}>
<Grid item xs={6}>
<Typography variant="body2" sx={{ fontWeight: 'bold'}}>
Total Benefit
</Typography>
</Grid>
</Grid>
</Grid>
<Grid item xs={12}>
<Box sx={{ py: '8px', px: '12px', background: palette.light.grey[50012], borderRadius: '6px'}}>
<Grid container spacing={1} alignItems={'end'}>
{/* Amount Incurred */}
<Grid item xs={width}>
<Grid container sx={{ borderRight: `0.5px solid ${palette.light.grey[400]}` }}>
<Grid item xs={12}>
<Typography variant="caption" sx={{ textAlign: 'right' }}>
Amount Incurred
</Typography>
</Grid>
<Grid item xs={12}>
<Typography variant="caption" sx={{ fontWeight: 'bold', textAlign: 'right' }}>
{fNumber(totalAll().totalAmountIncurred)}
</Typography>
</Grid>
</Grid>
</Grid>
{/* Amount Approved */}
<Grid item xs={width}>
<Grid container sx={{ borderRight: `0.5px solid ${palette.light.grey[400]}` }}>
<Grid item xs={12}>
<Typography variant="caption" sx={{ textAlign: 'right' }}>
Amount Approved
</Typography>
</Grid>
<Grid item xs={12}>
<Typography variant="caption" sx={{ fontWeight: 'bold', textAlign: 'right' }}>
{fNumber(totalAll().totalAmountApproved)}
</Typography>
</Grid>
</Grid>
</Grid>
{/* Amount Not Approved */}
<Grid item xs={width}>
<Grid container sx={{ borderRight: `0.5px solid ${palette.light.grey[400]}` }}>
<Grid item xs={12}>
<Typography variant="caption" sx={{ textAlign: 'right' }}>
Amount Not Approved
</Typography>
</Grid>
<Grid item xs={12}>
<Typography variant="caption" sx={{ fontWeight: 'bold', textAlign: 'right' }}>
{fNumber(totalAll().totalAmountNotApproved)}
</Typography>
</Grid>
</Grid>
</Grid>
{/* Excess Paid* */}
<Grid item xs={width}>
<Grid container>
<Grid item xs={12}>
<Typography variant="caption" sx={{ textAlign: 'right' }}>
Excess Paid
</Typography>
</Grid>
<Grid item xs={12}>
<Typography variant="caption" sx={{ fontWeight: 'bold', textAlign: 'right' }}>
{fNumber(totalAll().totalExcessPaid)}
</Typography>
</Grid>
</Grid>
</Grid>
</Grid>
</Box>
</Grid>
<Grid item xs={12}>
<Grid container spacing={2}>
<Grid item xs={3}>
<Typography variant="body2" sx={{ fontWeight: 'bold'}}>
Total Usage / Limit
</Typography>
</Grid>
<Grid item xs={6}>
<Typography variant="body2" sx={{ fontWeight: 'bold'}}>
{fNumber(totalUsage())} / {fNumber(benefitSelected[0].limit_amount_plan) }
</Typography>
</Grid>
</Grid>
</Grid>
</Grid>
{/* </Card> */}
<DialogActions>
<Stack direction="row" sx={{marginTop:3}} alignItems="center" justifyContent="space-between" spacing={2}>
<Button variant="outlined" onClick={handleCloseDialogBenefit}><Typography>Cancel</Typography></Button>
<LoadingButton disabled={errorsExist} type="submit" variant="contained" loading={isSubmitting}>
Save
</LoadingButton>
</Stack>
</DialogActions>
</Stack>
</FormProvider>
);
const getAction = () => !addBenefit ? (
<Stack direction="row" alignItems="center" justifyContent="space-between" spacing={2}>
<Button variant="outlined" onClick={handleCloseDialogBenefit}><Typography>Cancel</Typography></Button>
<Button variant="contained" onClick={handleAddDialogBenefit}><Typography>Add</Typography></Button>
</Stack>
) : null;
return (
<MuiDialog
title={{name: "Add Benefit"}}
openDialog={openDialog}
setOpenDialog={setOpenDialog}
content={getContent()}
action={getAction()}
maxWidth="xl"
/>
);
}

View File

@@ -0,0 +1,233 @@
import MuiDialog from "@/components/MuiDialog";
import { Autocomplete, Button, Card, DialogActions, Grid, MenuItem, Select, TextField, Typography } from "@mui/material";
import { Stack } from '@mui/material';
import React, { useEffect, useState } from 'react';
import { DetailFinalLogType } from "../Model/Types";
import { fDateOnly, fDateTimesecond, toTitleCase } from "@/utils/formatTime";
import axios from "@/utils/axios";
import { enqueueSnackbar } from "notistack";
import { useNavigate } from "react-router";
type DialogConfirmationType = {
openDialog: boolean;
setOpenDialog: any;
onSubmit?: void;
approve: string;
requestLog: DetailFinalLogType|undefined;
}
export default function DialogConfirmation({requestLog, setOpenDialog, openDialog, approve, onSubmit} : DialogConfirmationType ) {
const navigate = useNavigate();
const [formData, setFormData] = useState({
discharge_date: requestLog?.discharge_date,
id: requestLog?.id,
status: approve || '',
catatan: '',
type_of_member: requestLog?.type_of_member,
// icdCodes: requestLog?.diagnosis.length ? requestLog.diagnosis.map(diagnosis => ({ value: diagnosis.id, label: diagnosis.name })) : []
icdCodes: requestLog?.diagnosis
});
const [error, setError] = useState(false);
const [icdOptions, setIcdOptions] = useState([
{ value: '-', label: '-' }
]);
const [searchIcd, setSearchIcd] = useState('');
useEffect(() => {
// Update formData setiap kali approve berubah
setFormData(prevData => ({
...prevData,
status: approve || '',
}));
}, [approve]);
const handleChange = (field, value) => {
setFormData((prevData) => ({
...prevData,
[field]: value,
}));
};
const handleApprove = () => {
setFormData((prevData) => ({
...prevData,
status: approve,
}));
handleSubmit();
};
const handleSearch = (search) => {
setSearchIcd(search);
axios.get('diagnosis?search=' + search)
.then((response) => {
setIcdOptions(response.data.data);
})
.catch((error) => {
console.error('Error fetching ICD options:', error);
});
}
const handleSubmit = () => {
if (formData.type_of_member == "" && requestLog?.corporate_id == 5) { // corporate vale
setError(true);
alert('Silakan pilih Type Of Member sebelum mengirimkan data.');
}
else {
axios
.post(`customer-service/request/final-log`, formData)
.then((response) => {
enqueueSnackbar('Request Final LOG Successfully', { variant: 'success' });
setOpenDialog(false);
if (requestLog?.service_type === 'Inpatient') {
navigate('/');
} else {
navigate('/');
}
})
.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 marginBottom2 = {
marginBottom: 2,
};
const handleCloseDialog = () => {
setOpenDialog(false);
};
const getContent = () => (
<Stack spacing={1} marginTop={2}>
<Typography variant="subtitle2">Are you sure to {approve === 'approved' || approve === 'requested' ? 'request' : 'decline'} this final log?</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>Member ID</Typography>
<Typography variant='subtitle2' sx={style2} gutterBottom>{requestLog?.member_id}</Typography>
</Stack>
<Stack direction='row' spacing={2} sx={marginBottom1}>
<Typography variant='subtitle2' sx={style1} gutterBottom>Member Of Type</Typography>
<Typography variant='subtitle2' sx={style2} gutterBottom>{requestLog?.type_of_member}</Typography>
</Stack>
<Stack direction='row' spacing={2} sx={marginBottom1}>
<Typography variant='subtitle2' sx={style1} gutterBottom>Policy Number</Typography>
<Typography variant='subtitle2' sx={style2} gutterBottom>{requestLog?.policy_number}</Typography>
</Stack>
<Stack direction='row' spacing={2} sx={marginBottom1}>
<Typography variant='subtitle2' sx={style1} gutterBottom>Name</Typography>
<Typography variant='subtitle2' sx={style2} gutterBottom>{requestLog?.name}</Typography>
</Stack>
<Stack direction='row' spacing={2} sx={marginBottom1}>
<Typography variant='subtitle2' sx={style1} gutterBottom>Submission Date</Typography>
<Typography variant='subtitle2' sx={style2} gutterBottom>{requestLog?.submission_date ? fDateTimesecond(requestLog?.submission_date) : '-'}</Typography>
</Stack>
<Stack direction='row' spacing={2} sx={marginBottom1}>
<Typography variant='subtitle2' sx={style1} gutterBottom>Claim Method</Typography>
<Typography variant='subtitle2' sx={style2} gutterBottom>{requestLog?.claim_method ? toTitleCase(requestLog?.claim_method) : '-'}</Typography>
</Stack>
<Stack direction='row' spacing={2} sx={marginBottom1}>
<Typography variant='subtitle2' sx={style1} gutterBottom>Service Type</Typography>
<Typography variant='subtitle2' sx={style2} gutterBottom>{requestLog?.service_type}</Typography>
</Stack>
</Card>
<Card sx={{ padding: 2, marginTop: 2 }}>
<Stack direction='row' spacing={2} sx={marginBottom2}>
<Typography variant='subtitle2' sx={style1} gutterBottom>Discharge Date</Typography>
<TextField
label="Discharge Date"
variant="outlined"
fullWidth
type="date"
value={formData.discharge_date ? fDateOnly(formData.discharge_date) : ''}
onChange={(e) => handleChange('discharge_date', e.target.value)}
/>
</Stack>
<Stack direction='row' spacing={2} sx={marginBottom2}>
<Typography variant='subtitle2' sx={style1} gutterBottom>Catatan</Typography>
<TextField
label="Catatan"
variant="outlined"
fullWidth
value={formData.catatan}
onChange={(e) => handleChange('catatan', e.target.value)}
/>
</Stack>
<Stack direction='row' spacing={2} sx={marginBottom2}>
<Typography variant='subtitle2' sx={style1} gutterBottom>Diagnosis ICD - X</Typography>
<Autocomplete
multiple
options={icdOptions}
getOptionLabel={(option) => option.label}
fullWidth
value={formData.icdCodes}
onChange={(e, newValues) => handleChange('icdCodes', newValues)}
inputValue={searchIcd}
onInputChange={(e, newInputValue) => handleSearch(newInputValue)}
renderInput={(params) => (
<TextField
{...params}
label="Diagnosis ICD - X"
variant="outlined"
/>
)}
/>
</Stack>
<Stack direction='row' spacing={2} sx={marginBottom2}>
<Typography variant='subtitle2' sx={style1} gutterBottom>Type Of Member*</Typography>
<Select
fullWidth
value={formData.type_of_member}
onChange={(e) => handleChange('type_of_member', e.target.value)}
variant="outlined"
displayEmpty
required
error={error}
>
<MenuItem value="" disabled>
Type Member
</MenuItem>
<MenuItem value="OMT">OMT</MenuItem>
<MenuItem value="Non OMT">Non OMT</MenuItem>
</Select>
</Stack>
</Card>
</Grid>
<DialogActions>
<Button variant="outlined" sx={{ color: '#212B36', borderColor: '#919EAB52' }} onClick={handleCloseDialog}>Cancel</Button>
{approve === 'approved' || approve === 'requested' ? (
<Button color="primary" variant="contained" onClick={handleApprove}>Submit</Button>
) : (
<Button color="error" variant="contained" onClick={handleApprove}>Decline</Button>
)}
</DialogActions>
</Stack>
);
return (
<MuiDialog
title={{ name: "Confirmation" }}
openDialog={openDialog}
setOpenDialog={setOpenDialog}
content={getContent()}
maxWidth="xl"
/>
);
}

View File

@@ -0,0 +1,138 @@
import MuiDialog from "@/components/MuiDialog";
import { Autocomplete, Button, Card, Checkbox, DialogActions, Grid, TextField, Typography } from "@mui/material";
import { Paper } from "@mui/material";
import { Stack } from '@mui/material';
import React, { useEffect, useState } from 'react';
import { DetailFinalLogType } from "../Model/Types";
import { fDateTimesecond, toTitleCase } from "@/utils/formatTime";
import axios from "@/utils/axios";
import { enqueueSnackbar } from "notistack";
import { useNavigate } from "react-router";
type DialogDeleteType = {
openDialog: boolean;
setOpenDialog: any;
onSubmit?: void;
id: number|undefined;
}
export default function DialogDeleteBenefit({id, setOpenDialog, openDialog,onSubmit} : DialogDeleteType ) {
const [formData, setFormData] = useState({
reason: null
});
const resetForm = () => {
setFormData({
reason: null,
});
};
useEffect(() => {
// Update formData setiap kali approve berubah
setFormData(prevData => ({
...prevData,
}));
}, []);
const handleChange = (field, value) => {
setFormData((prevData) => ({
...prevData,
[field]: value,
}));
if (field === 'reason') {
setIsReasonSelected(!!value);
}
};
const handleSubmit = () => {
if (isReasonSelected && formData.reason !== '') {
axios
.post(`customer-service/request/benefit_data/${id}`, formData)
.then((response) => {
enqueueSnackbar('Benefit Data has Deleted', { variant: 'success' });
setOpenDialog(false);
window.location.reload()
})
.catch(({ response }) => {
enqueueSnackbar(response.data.message ?? 'Something went wrong!', { variant: 'error' });
});
} else {
setIsReasonSelected(false);
alert('Silakan pilih alasan sebelum menghapus data.');
}
}
const style1 = {
color: '#919EAB',
width: '30%'
}
const style2 = {
width: '70%'
}
const marginBottom2 = {
marginBottom: 2,
}
const [isReasonSelected, setIsReasonSelected] = useState(false);
const reasons = [
{ value: 'agreement', label: 'Agreement changed' },
{ value: 'endorsement', label: 'Endorsement' },
{ value: 'renewal', label: 'Renewal' },
{ value: 'wrong_setting', label: 'Wrong Setting' },
// Add more options as needed
];
const handleCloseDialog = () => {
setOpenDialog(false);
}
const getContent = () => (
<Stack spacing={1} marginTop={2}>
<Typography variant="subtitle2">Are you sure to delete this detail benefit ?</Typography>
<Grid item xs={12} md={12} marginTop={4}>
<Card sx={{padding:2, marginTop:2}} >
<Stack direction='row' spacing={2} sx={marginBottom2}>
<Typography variant='subtitle2' sx={style1} gutterBottom>Reason*</Typography>
<Autocomplete
options={reasons}
getOptionLabel={(option) => option.label}
fullWidth
value={reasons.find((r) => r.value === formData.reason) || null} // Use find to match the default value
onChange={(e, newValue) => handleChange('reason', newValue?.value)}
renderInput={(params) => (
<TextField
{...params}
label="Reason"
variant="outlined"
required
error={!isReasonSelected} // Menandai input sebagai salah jika opsi tidak dipilih
helperText={!isReasonSelected ? 'Alasan harus dipilih' : ''}
/>
)}
/>
</Stack>
</Card>
</Grid>
<DialogActions>
<Button variant="outlined" sx={{color: '#212B36', borderColor: '#919EAB52'}} onClick={handleCloseDialog}>Cancel</Button>
<Button color="error" variant="contained" onClick={handleSubmit}>Delete</Button>
</DialogActions>
</Stack>
);
return (
<MuiDialog
title={{name: "Delete Benefit"}}
openDialog={openDialog}
setOpenDialog={setOpenDialog}
content={getContent()}
maxWidth="xs"
/>
);
}

View File

@@ -0,0 +1,144 @@
import MuiDialog from "@/components/MuiDialog";
import { Autocomplete, Button, Card, Checkbox, DialogActions, Grid, Typography } from "@mui/material";
import { Paper } from "@mui/material";
import { Stack } from '@mui/material';
import React, { useEffect, useState } from 'react';
import { fDateTimesecond, toTitleCase } from "@/utils/formatTime";
import axios from "@/utils/axios";
import { enqueueSnackbar } from "notistack";
import { useNavigate } from "react-router";
import { TextField } from "@mui/material";
type DialogDeleteType = {
openDialog: boolean;
setOpenDialog: any;
onSubmit?: void;
id: number|undefined;
path: string;
}
export default function DialogDeleteFileLog({id, path, setOpenDialog, openDialog,onSubmit} : DialogDeleteType ) {
const style1 = {
color: '#919EAB',
width: '30%'
}
const style2 = {
width: '70%'
}
const marginBottom2 = {
marginBottom: 2,
}
const handleCloseDialog = () => {
setOpenDialog(false);
resetForm();
}
const [isReasonSelected, setIsReasonSelected] = useState(false);
const reasons = [
{ value: 'agreement', label: 'Agreement changed' },
{ value: 'endorsement', label: 'Endorsement' },
{ value: 'renewal', label: 'Renewal' },
{ value: 'wrong_setting', label: 'Wrong Setting' },
// Add more options as needed
];
const [formData, setFormData] = useState({
path: path,
reason: null
});
const resetForm = () => {
setFormData({
reason: null,
path: path
});
};
useEffect(() => {
// Update formData setiap kali approve berubah
setFormData(prevData => ({
...prevData,
path: path || '',
}));
}, [path]);
const handleChange = (field, value) => {
setFormData((prevData) => ({
...prevData,
[field]: value,
}));
if (field === 'reason') {
setIsReasonSelected(!!value);
}
};
const handleSubmit = () => {
if (isReasonSelected && formData.reason !== '') {
console.log(formData)
axios
.post(`customer-service/request/${id}/delete_file`, formData)
.then((response) => {
enqueueSnackbar('File LOG has Deleted', { variant: 'success' });
setOpenDialog(false);
window.location.reload()
})
.catch(({ response }) => {
enqueueSnackbar(response.data.message ?? 'Something went wrong!', { variant: 'error' });
});
} else {
setIsReasonSelected(false);
alert('Silakan pilih alasan sebelum menghapus data.');
}
}
const getContent = () => (
<Stack spacing={1} marginTop={2}>
<Typography variant="subtitle2">Are you sure to delete this file Final LOG ?</Typography>
<Grid item xs={12} md={12} marginTop={4}>
<Card sx={{padding:2, marginTop:2}} >
<Stack direction='row' spacing={2} sx={marginBottom2}>
<Typography variant='subtitle2' sx={style1} gutterBottom>Reason*</Typography>
<Autocomplete
options={reasons}
getOptionLabel={(option) => option.label}
fullWidth
value={reasons.find((r) => r.value === formData.reason) || null} // Use find to match the default value
onChange={(e, newValue) => handleChange('reason', newValue?.value)}
renderInput={(params) => (
<TextField
{...params}
label="Reason"
variant="outlined"
required
error={!isReasonSelected} // Menandai input sebagai salah jika opsi tidak dipilih
helperText={!isReasonSelected ? 'Alasan harus dipilih' : ''}
/>
)}
/>
</Stack>
</Card>
</Grid>
<DialogActions>
<Button variant="outlined" sx={{color: '#212B36', borderColor: '#919EAB52'}} onClick={handleCloseDialog}>Cancel</Button>
<Button color="error" variant="contained" onClick={handleSubmit}>Delete</Button>
</DialogActions>
</Stack>
);
return (
<MuiDialog
title={{name: "Delete File Final LOG"}}
openDialog={openDialog}
setOpenDialog={setOpenDialog}
content={getContent()}
maxWidth="xs"
/>
);
}

View File

@@ -0,0 +1,69 @@
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 { DetailFinalLogType } from "../Model/Types";
import { fDateTimesecond, toTitleCase } from "@/utils/formatTime";
import axios from "@/utils/axios";
import { enqueueSnackbar } from "notistack";
import { useNavigate } from "react-router";
type DialogDeleteType = {
openDialog: boolean;
setOpenDialog: any;
onSubmit?: void;
id: number|undefined;
}
export default function DialogDeleteMedicine({id, setOpenDialog, openDialog,onSubmit} : DialogDeleteType ) {
const handleSubmit = () => {
axios
.delete(`customer-service/request/medicine-data/${id}`)
.then((response) => {
enqueueSnackbar('Medicine Data has Deleted', { variant: 'success' });
setOpenDialog(false);
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 delete this detail medicine ?</Typography>
<DialogActions>
<Button variant="outlined" sx={{color: '#212B36', borderColor: '#919EAB52'}} onClick={handleCloseDialog}>Cancel</Button>
<Button color="error" variant="contained" onClick={handleSubmit}>Delete</Button>
</DialogActions>
</Stack>
);
return (
<MuiDialog
title={{name: "Delete Medicine"}}
openDialog={openDialog}
setOpenDialog={setOpenDialog}
content={getContent()}
maxWidth="xs"
/>
);
}

View File

@@ -0,0 +1,448 @@
import * as Yup from 'yup';
import { yupResolver } from '@hookform/resolvers/yup';
import MuiDialog from "@/components/MuiDialog";
import { Autocomplete, Box, Button, Card, Checkbox, DialogActions, Grid, TextField, Typography } from "@mui/material";
import { Paper } from "@mui/material";
import { Stack } from '@mui/material';
import React, { useEffect, useState } from 'react';
import { DetailFinalLogType } from "../Model/Types";
import { fDateTimesecond, toTitleCase } from "@/utils/formatTime";
import axios from "@/utils/axios";
import { enqueueSnackbar } from "notistack";
import { useNavigate } from "react-router";
import { BenefitConfigurationListType } from "../Model/Types";
import { postEditBenefit } from "../Model/Functions";
import { useForm } from 'react-hook-form';
import { FormProvider, RHFTextField } from "@/components/hook-form";
import RHFTextFieldMoney from "@/components/hook-form/v2/RHFTextFieldMoney";
import { LoadingButton } from "@mui/lab";
import { find } from 'lodash';
import { fNumber } from '@/utils/formatNumber';
import palette from '@/theme/palette';
type DialogDeleteType = {
openDialog: boolean;
setOpenDialog: any;
onSubmit?: void;
data: BenefitConfigurationListType|undefined;
id: number|undefined;
total: any
}
type BenefitSelected = {
id: number,
description: string,
benefit_id: number,
family_plan: string,
limit_amount: number,
}
export default function DialogEditBenefit({id, data, setOpenDialog, openDialog, onSubmit, total} : DialogDeleteType ) {
const handleCloseDialog = () => {
setOpenDialog(false);
}
const [benefitSelected, setBenefitSelected] = useState<BenefitSelected[]>([]);
// setup form
// ====================================
const defaultValues: BenefitConfigurationListType = {
request_log_id: 0,
benefit_name: '',
amount_incurred: 0,
amount_approved: 0,
amount_not_approved: 0,
excess_paid: 0,
keterangan: '-',
description: '-',
reason: null
};
const validationSchema = Yup.object().shape({
amount_incurred : Yup.string().typeError('').required(''),
amount_approved : Yup.string().typeError('').required(''),
amount_not_approved : Yup.string().typeError('').required(''),
excess_paid : Yup.string().typeError('').required(''),
});
const methods = useForm<any>({
resolver: yupResolver(validationSchema),
defaultValues
});
const { handleSubmit, reset, watch, setValue, setError, clearErrors, formState: { isDirty, isSubmitting, errors } } = methods;
const errorsExist = errors ? Object.keys(errors).length > 0 : false;
const totalAll = () => {
// Ambil nilai dari form menggunakan watch
const amountIncurred = parseFloat(watch('amount_incurred'));
const amountApproved = parseFloat(watch('amount_approved'));
const amountNotApproved = parseFloat(watch('amount_not_approved'));
const excessPaid = parseFloat(watch('excess_paid'));
// Hitung total baru
const totalAmountIncurred = total.totalAmountIncurred - data?.amount_incurred + amountIncurred;
const totalAmountApproved = total.totalAmountApproved - data?.amount_approved + amountApproved;
const totalAmountNotApproved = total.totalAmountNotApproved - data?.amount_not_approved + amountNotApproved;
const totalExcessPaid = total.totalExcessPaid - data?.excess_paid + excessPaid;
return {
totalAmountIncurred,
totalAmountApproved,
totalAmountNotApproved,
totalExcessPaid
}
}
const findItemById = (id) => {
return total.benefit.find(item => item.id === id);
}
const handleOnChangeNominal = (key) => {
let benefitData = findItemById(data?.benefit_id)
if (benefitData.family_plan == 'S' || benefitData.family_plan == 'F'){
// Konversi nilai ke angka dengan aman
let limitAmount = Number(benefitData.limit_amount) || 0;
let limitAmountPlan = Number(benefitData.limit_amount_plan) || 0;
if (limitAmountPlan != 999999999){
let realTimeUsage = totalAll().totalAmountApproved;
console.log(limitAmountPlan, 'test')
if (limitAmountPlan < realTimeUsage) {
setError(`amount_approved`, { message: `Total Amount Approve sudah melebihi limit ${ fNumber(limitAmountPlan) } , silakan isikan di Amount Excess` });
} else if (totalAll().totalAmountApproved > totalAll().totalAmountIncurred) {
setError(`amount_approved`, { message: 'Total Amount Approve tidak boleh lebih dari Total Amount Incurred' });
} else {
clearErrors(`amount_approved`);
}
} else if (limitAmount != 999999999) {
let memberUsage = Number(total.totalLimit[benefitData.id]) || 0;
let amountApproved = Number(parseFloat(watch('amount_approved'))) || 0;
// Hitung penggunaan waktu nyata
let realTimeUsage = memberUsage + amountApproved;
// Periksa apakah limitAmount lebih besar dari realTimeUsage
if (limitAmount < realTimeUsage) {
setError(`amount_approved`, { message: `Total Amount Approve sudah melebihi limit ${ fNumber(limitAmount) } , silakan isikan di Amount Excess` });
} else if (totalAll().totalAmountApproved > totalAll().totalAmountIncurred){
// setValue(`benefit_data.${key}.amount_approved`, 0);
setError(`amount_approved`, {message: 'Amount Approve tidak boleh lebih dari Amount Incurred'});
} else {
clearErrors(`amount_approved`);
}
} else {
if (totalAll().totalAmountApproved > totalAll().totalAmountIncurred) {
setError(`amount_approved`, { message: 'Total Amount Approve tidak boleh lebih dari Total Amount Incurred' });
} else {
clearErrors(`amount_approved`);
}
}
} else {
if (totalAll().totalAmountApproved > totalAll().totalAmountIncurred){
setError(`amount_approved`, {message: 'Amount Approve tidak boleh lebih dari Amount Incurred'});
} else {
clearErrors(`amount_approved`);
}
}
}
const handleOnChangeNotApprove = (key, value) => {
let amountApproved = Number(parseFloat(watch('amount_approved'))) || 0;
let amountNotApproved = Number(parseFloat(watch('amount_not_approved'))) || 0;
let amountIncurred = Number(parseFloat(watch('amount_incurred'))) || 0;
setValue(`excess_paid`, value);
console.log(amountApproved + amountNotApproved, amountIncurred, 'test')
if ((amountApproved + amountNotApproved) !== amountIncurred) {
setError(`amount_not_approved`, {message: 'Amount Not Approve tidak sama dengan total Amount Incurred'});
} else {
clearErrors(`amount_not_approved`);
}
};
// if (totalAmountIncurred !== (totalAmountApproved+totalAmountNotApproved)){
// // alert('Total Incurred tidak sama dengan Total Approve + Total Not Approve')
// // setValue('amount_approved', data?.amount_approved)
// }
// Submit Form
// =====================================
const submitHandler = async (data: BenefitConfigurationListType) => {
const response = await postEditBenefit(id, data);
if (response == true) {
reset();
// navigate('custormer-service/final-log/detail/'+requestLog?.id);
window.location.reload()
}
}
const reasons = [
{ value: 'Wrong Setting', label: 'Wrong Setting' },
{ value: 'Hospital Request', label: 'Hospital Request' }
];
// Set Value Form
// =====================================
useEffect(() => {
setValue('amount_incurred', data?.amount_incurred)
setValue('amount_approved', data?.amount_approved)
setValue('amount_not_approved', data?.amount_not_approved)
setValue('excess_paid', data?.excess_paid)
setValue('keterangan', data?.keterangan)
setValue('reason', data?.reason)
}, [data])
const getContent = () => (
<FormProvider methods={methods} onSubmit={handleSubmit(submitHandler)}>
<Stack paddingX={2} paddingY={4}>
{/* <Card sx={{padding:2}}> */}
<Box sx={{ marginTop:'10px', marginBottom:'10px', py: '8px', px: '12px', border:'1px solid #919EAB52', borderRadius: '6px'}}>
<Grid key={id} container spacing={2}>
<Grid item xs={12}>
<Typography variant="subtitle1" sx={{ fontWeight: 'bold'}}>
{data?.benefit?.description}
</Typography>
</Grid>
<Grid item xs={2}>
<Grid container spacing={2}>
<Grid item xs={12}>
<Typography variant="subtitle1" component="div">
Amount Incurred*
</Typography>
</Grid>
<Grid item xs={12} sx={{display: 'flex', gap: 1}}>
<RHFTextFieldMoney
key={id}
id='amount_incurred'
name={`amount_incurred`}
placeholder='Amount Incurred'
required
onChange={(event) => {
setValue(`amount_incurred`, event.target.value)
handleOnChangeNominal(id)}
}
/>
</Grid>
</Grid>
</Grid>
<Grid item xs={2}>
<Grid container spacing={2}>
<Grid item xs={12}>
<Typography variant="subtitle1" component="div">
Amount Approved*
</Typography>
</Grid>
<Grid item xs={12} sx={{display: 'flex', gap: 1}}>
<RHFTextFieldMoney
// onChange={() => append({amount_approved: ''}) }
id='amount_approved'
key={id}
name={`amount_approved`}
placeholder='Amount Approved'
required
onChange={(event) => {
setValue(`amount_approved`, event.target.value)
handleOnChangeNominal(id)}
}
/>
</Grid>
</Grid>
</Grid>
<Grid item xs={2}>
<Grid container spacing={2}>
<Grid item xs={12}>
<Typography variant="subtitle1" component="div">
Amount Not Approved*
</Typography>
</Grid>
<Grid item xs={12} sx={{display: 'flex', gap: 1}}>
<RHFTextFieldMoney
// onChange={() => append({amount_not_approved: ''}) }
id='amount_not_approved'
key={id}
name={`amount_not_approved`}
placeholder='Amount Not Approved'
required
onChange={(event) => {
setValue(`amount_not_approved`, event.target.value)
handleOnChangeNotApprove(id, event.target.value)}
}
/>
</Grid>
</Grid>
</Grid>
<Grid item xs={2}>
<Grid container spacing={2}>
<Grid item xs={12}>
<Typography variant="subtitle1" component="div">
Excess Paid*
</Typography>
</Grid>
<Grid item xs={12} sx={{display: 'flex', gap: 1}}>
<RHFTextFieldMoney
// onChange={() => append({excess_paid: ''}) }
id='excess_paid'
key={id}
name={`excess_paid`}
placeholder='Excess Paid'
required
/>
</Grid>
</Grid>
</Grid>
<Grid item xs={2}>
<Grid container spacing={2}>
<Grid item xs={12}>
<Typography variant="subtitle1" component="div">
Keterangan
</Typography>
</Grid>
<Grid item xs={12} sx={{display: 'flex', gap: 1}}>
<RHFTextField
// onChange={() => append({keterangan: ''}) }
id='keterangan'
key={id}
name={`keterangan`}
placeholder='Keterangan'
/>
</Grid>
</Grid>
</Grid>
<Grid item xs={2}>
<Grid container spacing={2}>
<Grid item xs={12}>
<Typography variant="subtitle1" component="div">
Reason*
</Typography>
</Grid>
<Grid item xs={12} sx={{display: 'flex', gap: 1}}>
<Autocomplete
options={reasons}
getOptionLabel={(option) => option.label}
fullWidth
value={reasons.find((r) => r.value === watch('reason')) || null}// Use find to match the default value
onChange={(event, newValue) => {
setValue(`reason`, newValue?.value);
}}
renderInput={(params) => (
<TextField
{...params}
label="Reason"
variant="outlined"
required
/>
)}
/>
</Grid>
</Grid>
</Grid>
<Grid item xs={12} marginTop={3}>
<Grid container spacing={2}>
<Grid item xs={12}>
<Typography variant="body2" sx={{ fontWeight: 'bold'}}>
Total Current Benefit
</Typography>
</Grid>
</Grid>
</Grid>
<Grid item xs={12}>
<Box sx={{ py: '8px', px: '12px', background: palette.light.grey[50012], borderRadius: '6px'}}>
<Grid container spacing={1} alignItems={'end'}>
{/* Amount Incurred */}
<Grid item xs={2}>
<Grid container sx={{ borderRight: `0.5px solid ${palette.light.grey[400]}` }}>
<Grid item xs={12}>
<Typography variant="caption" sx={{ textAlign: 'right' }}>
Amount Incurred
</Typography>
</Grid>
<Grid item xs={12}>
<Typography variant="caption" sx={{ fontWeight: 'bold', textAlign: 'right' }}>
{totalAll().totalAmountIncurred ? fNumber(totalAll().totalAmountIncurred) : 0}
</Typography>
</Grid>
</Grid>
</Grid>
{/* Amount Approved */}
<Grid item xs={2}>
<Grid container sx={{ borderRight: `0.5px solid ${palette.light.grey[400]}` }}>
<Grid item xs={12}>
<Typography variant="caption" sx={{ textAlign: 'right' }}>
Amount Approved
</Typography>
</Grid>
<Grid item xs={12}>
<Typography variant="caption" sx={{ fontWeight: 'bold', textAlign: 'right' }}>
{totalAll().totalAmountApproved ? fNumber(totalAll().totalAmountApproved) : 0}
</Typography>
</Grid>
</Grid>
</Grid>
{/* Amount Not Approved */}
<Grid item xs={2}>
<Grid container sx={{ borderRight: `0.5px solid ${palette.light.grey[400]}` }}>
<Grid item xs={12}>
<Typography variant="caption" sx={{ textAlign: 'right' }}>
Amount Not Approved
</Typography>
</Grid>
<Grid item xs={12}>
<Typography variant="caption" sx={{ fontWeight: 'bold', textAlign: 'right' }}>
{totalAll().totalAmountNotApproved ? fNumber(totalAll().totalAmountNotApproved) : 0}
</Typography>
</Grid>
</Grid>
</Grid>
{/* Excess Paid* */}
<Grid item xs={2}>
<Grid container>
<Grid item xs={12}>
<Typography variant="caption" sx={{ textAlign: 'right' }}>
Excess Paid
</Typography>
</Grid>
<Grid item xs={12}>
<Typography variant="caption" sx={{ fontWeight: 'bold', textAlign: 'right' }}>
{totalAll().totalExcessPaid ? fNumber(totalAll().totalExcessPaid) : 0}
</Typography>
</Grid>
</Grid>
</Grid>
</Grid>
</Box>
</Grid>
</Grid>
</Box>
{/* </Card> */}
<DialogActions>
<Stack direction="row" sx={{marginTop:3}} alignItems="center" justifyContent="space-between" spacing={2}>
<Button variant="outlined" onClick={handleCloseDialog}><Typography>Cancel</Typography></Button>
<LoadingButton disabled={errorsExist} type="submit" variant="contained" loading={isSubmitting}>
Save
</LoadingButton>
</Stack>
</DialogActions>
</Stack>
</FormProvider>
);
return (
<MuiDialog
title={{name: "Edit Detail Benefit"}}
openDialog={openDialog}
setOpenDialog={setOpenDialog}
content={getContent()}
maxWidth="xl"
/>
);
}

View File

@@ -0,0 +1,318 @@
import MuiDialog from "@/components/MuiDialog";
import { Autocomplete, Button, Card, Checkbox, DialogActions, Grid, TextField, Typography, Select } from "@mui/material";
import { Paper } from "@mui/material";
import { Stack, MenuItem } from '@mui/material';
import React, { useEffect, useState } from 'react';
import { DetailFinalLogType } from "../Model/Types";
import { fDateOnly, fDateTimesecond, toTitleCase } from "@/utils/formatTime";
import axios from "@/utils/axios";
import { enqueueSnackbar } from "notistack";
import { useNavigate } from "react-router";
type DialogConfirmationType = {
openDialog: boolean;
setOpenDialog: any;
onSubmit?: void;
requestLog: DetailFinalLogType|undefined;
}
export default function DialogEditFinalLOG({requestLog, setOpenDialog, openDialog, onSubmit} : DialogConfirmationType ) {
const navigate = useNavigate();
const [formData, setFormData] = useState({
billing_no: requestLog?.billing_no,
invoice_no: requestLog?.invoice_no,
discharge_date: requestLog?.discharge_date,
id: requestLog?.id,
catatan: requestLog?.catatan,
icdCodes: requestLog?.diagnosis,
reason: requestLog?.reason,
type_of_member: requestLog?.type_of_member,
status: 'requested',
});
const [error, setError] = useState(false);
const [icdOptions, setIcdOptions] = useState([
{ value: '-', label: '-' }
]);
const [searchIcd, setSearchIcd] = useState('');
useEffect(() => {
// Ambil data dari API dan atur opsi ICD
axios.get('diagnosis')
.then((response) => {
setIcdOptions(response.data.data);
})
.catch((error) => {
console.error('Error fetching ICD options:', error);
});
}, []); // useEffect dijalankan hanya sekali saat komponen dimount
useEffect(() => {
setFormData({
discharge_date: requestLog?.discharge_date|| '',
billing_no: requestLog?.billing_no|| '',
invoice_no: requestLog?.invoice_no|| '',
id: requestLog?.id|| 0,
catatan: requestLog?.catatan|| '',
icdCodes: requestLog?.diagnosis|| [],
reason: requestLog?.reason|| '',
type_of_member: requestLog?.type_of_member|| '',
status: 'requested',
});
}, [requestLog]);
const handleChange = (field, value) => {
setFormData((prevData) => ({
...prevData,
[field]: value,
}));
if (field === 'reason') {
setIsReasonSelected(!!value);
}
};
const handleApprove = () => {
setFormData((prevData) => ({
...prevData,
}));
handleSubmit();
};
const handleSearch = (search) => {
setSearchIcd(search);
axios.get('diagnosis?search=' + search)
.then((response) => {
setIcdOptions(response.data.data);
})
.catch((error) => {
console.error('Error fetching ICD options:', error);
});
}
const handleSubmit = () => {
if (formData.type_of_member == "" && requestLog?.corporate_id == 5) {
setError(true);
alert('Silakan pilih Type Of Member sebelum mengirimkan data.');
}
else if (isReasonSelected && formData.reason !== '') {
axios
.post(`customer-service/request/final-log`, formData)
.then((response) => {
enqueueSnackbar('Request Final LOG Success', { variant: 'success' });
setOpenDialog(false);
navigate('/detail-request-final-log/' + requestLog?.id)
window.location.reload()
})
.catch(({ response }) => {
enqueueSnackbar(response.data.message ?? 'Something went wrong!', { variant: 'error' });
});
} else {
setIsReasonSelected(false);
alert('Silakan pilih alasan sebelum mengirimkan data.');
}
}
const style1 = {
color: '#919EAB',
width: '30%'
}
const style2 = {
width: '70%'
}
const marginBottom1 = {
marginBottom: 1,
}
const marginBottom2 = {
marginBottom: 2,
}
const resetForm = () => {
setFormData({
discharge_date: requestLog?.discharge_date ?? '',
id: requestLog?.id ?? 0,
billing_no: requestLog?.billing_no ?? '',
invoice_no: requestLog?.invoice_no ?? '',
catatan: requestLog?.catatan ?? '',
icdCodes: requestLog?.diagnosis ?? [],
reason: requestLog?.reason ?? '',
type_of_member: requestLog?.type_of_member ?? '',
status: 'requested'
});
};
const [isReasonSelected, setIsReasonSelected] = useState(true);
const handleCloseDialog = () => {
setOpenDialog(false);
resetForm();
}
const reasons = [
{ value: 'agreement', label: 'Agreement changed' },
{ value: 'endorsement', label: 'Endorsement' },
{ value: 'renewal', label: 'Renewal' },
{ value: 'wrong_setting', label: 'Wrong Setting' },
// Add more options as needed
];
// console.log(formData.type_of_member)
const getContent = () => (
<Stack spacing={1} marginTop={2}>
<Typography variant="subtitle2">Are you sure to edit this final log ?</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>Member ID</Typography>
<Typography variant='subtitle2' sx={style2} gutterBottom>{requestLog?.member_id}</Typography>
</Stack>
<Stack direction='row' spacing={2} sx={marginBottom1}>
<Typography variant='subtitle2' sx={style1} gutterBottom>Policy Number</Typography>
<Typography variant='subtitle2' sx={style2} gutterBottom>{requestLog?.policy_number}</Typography>
</Stack>
<Stack direction='row' spacing={2} sx={marginBottom1}>
<Typography variant='subtitle2' sx={style1} gutterBottom>Name</Typography>
<Typography variant='subtitle2' sx={style2} gutterBottom>{requestLog?.name}</Typography>
</Stack>
<Stack direction='row' spacing={2} sx={marginBottom1}>
<Typography variant='subtitle2' sx={style1} gutterBottom>Submission Date</Typography>
<Typography variant='subtitle2' sx={style2} gutterBottom>{requestLog?.submission_date ? fDateTimesecond(requestLog?.submission_date) : '-'}</Typography>
</Stack>
<Stack direction='row' spacing={2} sx={marginBottom1}>
<Typography variant='subtitle2' sx={style1} gutterBottom>Claim Method</Typography>
<Typography variant='subtitle2' sx={style2} gutterBottom>{requestLog?.claim_method ? toTitleCase(requestLog?.claim_method) : '-'}</Typography>
</Stack>
<Stack direction='row' spacing={2} sx={marginBottom1}>
<Typography variant='subtitle2' sx={style1} gutterBottom>Service Type</Typography>
<Typography variant='subtitle2' sx={style2} gutterBottom>{requestLog?.service_type}</Typography>
</Stack>
</Card>
<Card sx={{padding:2, marginTop:2}} >
<Stack direction='row' spacing={2} sx={marginBottom2}>
<Typography variant='subtitle2' sx={style1} gutterBottom>Invoice Provider</Typography>
<TextField
label="Invoice Provider"
variant="outlined"
fullWidth
value={formData.invoice_no}
onChange={(e) => handleChange('invoice_no', e.target.value)}
/>
</Stack>
<Stack direction='row' spacing={2} sx={marginBottom2}>
<Typography variant='subtitle2' sx={style1} gutterBottom>Billing Number</Typography>
<TextField
label="Billing Number"
variant="outlined"
fullWidth
value={formData.billing_no}
onChange={(e) => handleChange('billing_no', e.target.value)}
/>
</Stack>
<Stack direction='row' spacing={2} sx={marginBottom2}>
<Typography variant='subtitle2' sx={style1} gutterBottom>Type Of Member*</Typography>
<Select
fullWidth
value={formData.type_of_member}
onChange={(e) => handleChange('type_of_member', e.target.value)}
variant="outlined"
displayEmpty
required
error={error}
>
<MenuItem value="" disabled>
Type Member
</MenuItem>
<MenuItem value="OMT">OMT</MenuItem>
<MenuItem value="Non OMT">Non OMT</MenuItem>
</Select>
</Stack>
<Stack direction='row' spacing={2} sx={marginBottom2}>
<Typography variant='subtitle2' sx={style1} gutterBottom>Discharge Date</Typography>
<TextField
label="Discharge Date"
variant="outlined"
fullWidth
type="date"
value={formData.discharge_date ? fDateOnly(formData.discharge_date) : '-'}
onChange={(e) => handleChange('discharge_date', e.target.value)}
/>
</Stack>
<Stack direction='row' spacing={2} sx={marginBottom2}>
<Typography variant='subtitle2' sx={style1} gutterBottom>Catatan</Typography>
<TextField
label="Catatan"
variant="outlined"
fullWidth
value={formData.catatan}
onChange={(e) => handleChange('catatan', e.target.value)}
/>
</Stack>
<Stack direction='row' spacing={2} sx={marginBottom2}>
<Typography variant='subtitle2' sx={style1} gutterBottom>Diagnosis ICD - X</Typography>
<Autocomplete
multiple
options={icdOptions}
getOptionLabel={(option) => option.label}
fullWidth
value={formData.icdCodes}
onChange={(e, newValues) => handleChange('icdCodes', newValues)}
inputValue={searchIcd}
onInputChange={(e, newInputValue) => handleSearch(newInputValue)}
renderInput={(params) => (
<TextField
{...params}
label="Diagnosis ICD - X"
variant="outlined"
/>
)}
/>
</Stack>
<Stack direction='row' spacing={2} sx={marginBottom2}>
<Typography variant='subtitle2' sx={style1} gutterBottom>Reason*</Typography>
<Autocomplete
options={reasons}
getOptionLabel={(option) => option.label}
fullWidth
value={reasons.find((r) => r.value == formData.reason) || null} // Use find to match the default value
onChange={(e, newValue) => handleChange('reason', newValue?.value)}
renderInput={(params) => (
<TextField
{...params}
label="Reason"
variant="outlined"
required
error={!isReasonSelected} // Menandai input sebagai salah jika opsi tidak dipilih
helperText={!isReasonSelected ? 'Alasan harus dipilih' : ''}
/>
)}
/>
</Stack>
</Card>
</Grid>
<DialogActions>
<Button variant="outlined" sx={{color: '#212B36', borderColor: '#919EAB52'}} onClick={handleCloseDialog}>Cancel</Button>
<Button color="primary" variant="contained" onClick={() => handleApprove()}>Update</Button>
</DialogActions>
</Stack>
);
return (
<MuiDialog
title={{name: "Update"}}
openDialog={openDialog}
setOpenDialog={setOpenDialog}
content={getContent()}
maxWidth="xl"
/>
);
}

View File

@@ -0,0 +1,171 @@
import * as Yup from 'yup';
import { yupResolver } from '@hookform/resolvers/yup';
import MuiDialog from "@/components/MuiDialog";
import { Button, Autocomplete, Card, Checkbox, DialogActions, Grid, Typography } from "@mui/material";
import { Paper } from "@mui/material";
import { Stack } from '@mui/material';
import React, { useEffect, useState } from 'react';
import { DetailFinalLogType } from "../Model/Types";
import { MedicineType } from "../Model/Types";
import { fDateTimesecond, toTitleCase } from "@/utils/formatTime";
import { useFieldArray, useForm } from 'react-hook-form';
import { FormProvider, RHFDatepicker, RHFSelect, RHFTextField } from '@/components/hook-form';
import axios from "@/utils/axios";
import { enqueueSnackbar } from "notistack";
import { useNavigate } from "react-router";
import { LoadingButton } from '@mui/lab';
import AddIcon from '@mui/icons-material/Add';
import RemoveIcon from '@mui/icons-material/Remove';
import RHFTextFieldMoney from "@/components/hook-form/v2/RHFTextFieldMoney";
import { IconButton } from '@mui/material';
import { postAddMedince } from '../Model/Functions';
type DialogConfirmationType = {
openDialog: boolean;
setOpenDialog: any;
onSubmit?: void;
requestLog: DetailFinalLogType|undefined;
}
export default function DialogMedicine({requestLog, setOpenDialog, openDialog } : DialogConfirmationType ) {
const handleCloseDialogMedicine = () => {
setOpenDialog(false);
}
const requestID = requestLog?.id
const defaultValues: MedicineType = {
medicine : [{
id: 0,
medicine_name: '',
medicine_price: 0,
request_log_id: requestID,
medicine: '', // input to database
price: 0, // input to database
}],
};
const validationSchema = Yup.object().shape({
medicine: Yup.array().of(
Yup.object().shape({
medicine_name : Yup.string().typeError('').required(''),
medicine_price : Yup.number().typeError('').required(''),
request_log_id : Yup.number().typeError('').required(''),
})
)
})
const methods = useForm<any>({
resolver: yupResolver(validationSchema),
defaultValues
});
const {fields, append, remove} = useFieldArray({name: 'medicine',control: methods.control})
useEffect(() => {
let temp = fields.map((item, i) => {
return {
medicine_name: 'test',
medicine_price: 0,
request_log_id: 3,
}
})
reset({medicine: temp})
}, [])
const { handleSubmit, reset, watch, setValue, formState: { isDirty, isSubmitting, errors } } = methods;
// Submit Form
// =====================================
const submitHandler = async (data: MedicineType) => {
const response = await postAddMedince(data);
if (response == true) {
reset();
// navigate('custormer-service/final-log/detail/'+requestLog?.id);
window.location.reload()
}
}
const getContent = () => (
<FormProvider methods={methods} onSubmit={handleSubmit(submitHandler)}>
<Stack spacing={2} sx={{marginTop: 2, padding: 2}}>
<Grid container spacing={2}>
{/* Medicine */}
<Grid item xs={12}>
<Stack direction="row" alignItems="center" sx={{marginBottom: 4}}>
<Typography variant='subtitle1' gutterBottom>Medicine*</Typography>
<Button color="inherit" variant="outlined" startIcon={<AddIcon/>} sx={{marginLeft: 'auto'}} onClick={() => append({medicine_name: '', medicine_price: 0, request_log_id: requestLog?.id })}>
<Typography variant="button" display="block">Medicine</Typography>
</Button>
</Stack>
</Grid>
{fields.map((field, index) => (
<React.Fragment key={index}>
<Grid item xs={6}>
<RHFTextField
id='medicine_name'
key={field.id}
name={`medicine.${index}.medicine_name`}
label="Medicine"
required
placeholder="Medicine"
/>
</Grid>
<Grid item xs={5}>
<RHFTextFieldMoney
id='medicine_price'
key={field.id}
name={`medicine.${index}.medicine_price`}
label="Price"
required
placeholder="Price"
/>
</Grid>
{
index != (fields.length-1) ?
(
<Grid item xs={1} sx={{ textAlign: 'center' }}>
<IconButton size='large' color='error' onClick={() => remove(index)}>
<RemoveIcon />
</IconButton>
</Grid>
) : null
}
</React.Fragment>
))}
</Grid>
</Stack>
<DialogActions>
<Stack direction="row" alignItems="center" justifyContent="space-between" spacing={2}>
<Button color="inherit" variant="outlined" onClick={handleCloseDialogMedicine}><Typography>Cancel</Typography></Button>
<LoadingButton disabled={!isDirty} type="submit" variant="contained" loading={isSubmitting}>
Add
</LoadingButton>
</Stack>
</DialogActions>
</FormProvider>
);
const getAction = () => null;
return (
<MuiDialog
title={{name: "Medicine"}}
openDialog={openDialog}
setOpenDialog={setOpenDialog}
action={getAction()}
content={getContent()}
maxWidth="xl"
/>
);
}

View File

@@ -0,0 +1,185 @@
import { Stack, Typography, Button, Paper, Grid, IconButton, TextField } from "@mui/material";
import MuiDialog from "@/components/MuiDialog";
import { fDate, fDateTimesecond } from '@/utils/formatTime';
import { ContentCopy, WhatsApp, Instagram, Facebook, Telegram } from "@mui/icons-material";
type DialogConfirmationType = {
openDialog: boolean;
setOpenDialog: any;
onSubmit?: void;
requestLog: any;
shareLink: boolean;
};
export default function DialogSendWa({
requestLog,
setOpenDialog,
openDialog,
shareLink = false,
}: DialogConfirmationType) {
const data = {
provider: requestLog?.provider || "LOG",
memberId: requestLog?.member_id || "-",
policyNumber: requestLog?.policy_number || "-",
name: requestLog?.name || "-",
submissionDate: requestLog?.submission_date ? fDateTimesecond(requestLog?.submission_date) : "-",
claimMethod: requestLog?.claim_method || "-",
serviceType: requestLog?.service_type || "-",
linkApproval: requestLog?.url_approval || "https://example.com/approval-link",
};
const getContent = () => (
<Stack spacing={2} sx={{ marginTop: 2, padding: 2 }}>
<Typography>Are you sure want to send this request ?</Typography>
<Paper variant="outlined" sx={{ p: 2 }}>
<Grid container spacing={1}>
<Grid item xs={5}>
<Typography variant="body2" color="textSecondary">
Member ID
</Typography>
</Grid>
<Grid item xs={7}>
<Typography>{data.memberId}</Typography>
</Grid>
<Grid item xs={5}>
<Typography variant="body2" color="textSecondary">
Policy Number
</Typography>
</Grid>
<Grid item xs={7}>
<Typography fontWeight="bold">{data.policyNumber}</Typography>
</Grid>
<Grid item xs={5}>
<Typography variant="body2" color="textSecondary">
Name
</Typography>
</Grid>
<Grid item xs={7}>
<Typography>{data.name}</Typography>
</Grid>
<Grid item xs={5}>
<Typography variant="body2" color="textSecondary">
Submission Date
</Typography>
</Grid>
<Grid item xs={7}>
<Typography>{data.submissionDate}</Typography>
</Grid>
<Grid item xs={5}>
<Typography variant="body2" color="textSecondary">
Claim Method
</Typography>
</Grid>
<Grid item xs={7}>
<Typography>{data.claimMethod}</Typography>
</Grid>
<Grid item xs={5}>
<Typography variant="body2" color="textSecondary">
Service Type
</Typography>
</Grid>
<Grid item xs={7}>
<Typography>{data.serviceType}</Typography>
</Grid>
</Grid>
</Paper>
{shareLink ? (
<>
<Typography>Share this link only with authorized parties!</Typography>
{/* <Stack direction="row" spacing={2}>
<IconButton color="success">
<WhatsApp />
</IconButton>
<IconButton color="primary">
<Instagram />
</IconButton>
<IconButton color="primary">
<Telegram />
</IconButton>
<IconButton color="primary">
<Facebook />
</IconButton>
</Stack> */}
<Typography variant="body2">or copy link</Typography>
<Stack direction="row" spacing={1}>
<TextField
fullWidth
size="small"
value={data.linkApproval}
InputProps={{
readOnly: true,
}}
/>
<Button
variant="outlined"
onClick={() => navigator.clipboard.writeText(data.linkApproval)}
>
Copy
</Button>
</Stack>
</>
): null }
</Stack>
);
const getAction = () => {
if (shareLink) {
return (
<Stack direction="row" justifyContent="flex-end">
<Button variant="outlined" onClick={() => setOpenDialog(false)}>
Cancel
</Button>
</Stack>
);
}
const handleSend = () => {
const message = `*Request Approval*
Yth. Bapak/Ibu, Nama Penerima
Mohon persetujuan atas data berikut:
Provider: *${data.provider}*
Member ID: ${data.memberId}
Nama: ${data.name}
Policy Number: ${data.policyNumber}
Submission Date: ${data.submissionDate}
Claim Method: ${data.claimMethod}
Service Type: ${data.serviceType}
Silakan klik link berikut untuk approval:
${data.linkApproval}`;
const encodedMessage = encodeURIComponent(message);
const waUrl = `https://wa.me/6283807417196?text=${encodedMessage}`;
window.open(waUrl, "_blank");
};
return (
<Stack direction="row" justifyContent="space-between" spacing={2}>
<Button variant="outlined" onClick={() => setOpenDialog(false)}>
Cancel
</Button>
<Button variant="contained" onClick={handleSend}>
Send
</Button>
</Stack>
);
};
return (
<MuiDialog
title={{ name: "Confirmatione", variant: "h4" }}
openDialog={openDialog}
setOpenDialog={setOpenDialog}
content={getContent()}
action={getAction()}
maxWidth="sm"
/>
);
}

View File

@@ -0,0 +1,322 @@
import { styled } from '@mui/material/styles';
import Iconify from '@/components/Iconify';
import { fCurrency } from '@/utils/formatNumber';
import { LoadingButton } from '@mui/lab';
import { Avatar, Button, Divider, LinearProgress, linearProgressClasses, ButtonBase, Box } from '@mui/material';
import { Card } from '@mui/material';
import { Stack, Typography } from '@mui/material';
import { fPostFormat } from '@/utils/formatTime';
import axios from '@/utils/axios';
import { enqueueSnackbar } from 'notistack';
import { useRef, useState, useContext, useEffect } from 'react';
import { makeFormData } from '@/utils/jsonToFormData';
import { format } from 'date-fns';
// import { LanguageContext } from '@/contexts/LanguageContext';
import { DatePicker, LocalizationProvider, MobileDatePicker } from '@mui/x-date-pickers';
import { AdapterDateFns } from '@mui/x-date-pickers/AdapterDateFns';
import TextField from '@mui/material/TextField';
import MuiDialog from '@/components/MuiDialog';
type DialogUploadType = {
openDialog: boolean;
setOpenDialog: any;
onSubmit?: void;
id: number|undefined;
}
export default function DialogUploadFileFinalLog({ id, openDialog, setOpenDialog }: DialogUploadType) {
// ----------------------------------------------------------------------
// Files Diagnosa
const fileDiagnosaInput = useRef<HTMLInputElement>(null);
const [fileDiagnosas, setFileDiagnosas] = useState<any>([]);
const handleDiagnosaInputChange = (event:any) => {
if (event.target.files[0]) {
setFileDiagnosas([...fileDiagnosas, ...event.target.files]);
} else {
console.log('NO FILE');
}
};
const removeDiagnosaFiles = (filesState:any, index:any) => {
setFileDiagnosas(
filesState.filter((file:any, fileIndex:any) => {
return fileIndex != index;
})
);
};
// ----------------------------------------------------------------------
// Files Result Kondisi
const fileKondisiInput = useRef<HTMLInputElement>(null);
const [fileKondisis, setFileKondisis] = useState<any>([]);
const handleKondisiInputChange = (event:any) => {
if (event.target.files[0]) {
setFileKondisis([...fileKondisis, ...event.target.files]);
} else {
console.log('NO FILE');
}
};
const removeKondisiFiles = (filesState:any, index:any) => {
setFileKondisis(
filesState.filter((file:any, fileIndex:any) => {
return fileIndex != index;
})
);
};
// ----------------------------------------------------------------------
// Files Result Hasil Penunjang
const fileHasilPenunjangInput = useRef<HTMLInputElement>(null);
const [fileHasilPenunjangs, setFileHasilPenunjangs] = useState<any>([]);
const handleResultInputChange = (event:any) => {
if (event.target.files[0]) {
setFileHasilPenunjangs([...fileHasilPenunjangs, ...event.target.files]);
} else {
console.log('NO FILE');
}
};
const removeFiles = (filesState:any, index:any) => {
setFileHasilPenunjangs(
filesState.filter((file:any, fileIndex:any) => {
return fileIndex != index;
})
);
};
// --------------------------------------------------------------
// Submit Form
const [submitLoading, setSubmitLoading] = useState(false);
function submitRequestFinalLog() {
setSubmitLoading(true);
const formData = makeFormData({
request_logs_id: id,
result_files: fileHasilPenunjangs,
diagnosa_files: fileDiagnosas,
kondisi_files: fileKondisis,
});
axios
.post(`/customer-service/request/${id}/add_file`, formData)
.then((response) => {
enqueueSnackbar('Berhasil membuat data', { variant: 'success' });
setOpenDialog(false);
window.location.reload()
})
.catch(({ response }) => {
enqueueSnackbar('Something Went Wrong', { variant: 'error' });
})
.then(() => {
setSubmitLoading(false);
});
}
const getContent = () => (
<Stack>
<Stack
divider={<Divider orientation="horizontal" flexItem />}
spacing={4}
sx={{ marginY: 2, marginBottom: 6 }}
>
{/* -------------------------------Upload Dokumen Kondisi------------------------------- */}
<Stack sx={{ marginTop: 2 }}>
<Typography variant="body1" sx={{fontWeight:'bold'}}>
File Billing
</Typography>
{/* <Typography variant="body2">Hasil Lab, </Typography> */}
<Stack
divider={<Divider orientation="horizontal" flexItem />}
spacing={1}
sx={{ marginY: 2 }}
>
{fileKondisis &&
fileKondisis.map((file:any, index:any) => (
<Stack direction="row" justifyContent={'space-between'} key={index}>
<Typography sx={{ color: "text.secondary" }}>{file.name}</Typography>
<Iconify
icon="eva:trash-2-outline"
color={'darkred'}
onClick={() => {
removeKondisiFiles(fileKondisis, index);
}}
></Iconify>
</Stack>
))}
</Stack>
<ButtonBase sx={{ p: 4, border: '2px dashed #F9FAFB',
bgcolor: '#919EAB52',
borderRadius: '8px',
width: '100%', height: '60px'}} onClick={() => fileKondisiInput.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
</Typography>
</Box>
<input
type="file"
id="file"
ref={fileKondisiInput}
style={{ display: 'none' }}
multiple
onChange={handleKondisiInputChange}
accept="application/pdf,image/*"
/>
</ButtonBase>
</Stack>
{/* -------------------------------Upload Dokumen Diagnosa------------------------------- */}
<Stack sx={{ marginTop: 2 }}>
<Typography variant="body1" sx={{fontWeight:'bold'}}>
File Diagnosa
</Typography>
{/* <Typography variant="body2">Hasil Lab, </Typography> */}
<Stack
divider={<Divider orientation="horizontal" flexItem />}
spacing={1}
sx={{ marginY: 2 }}
>
{fileDiagnosas &&
fileDiagnosas.map((file:any, index:any) => (
<Stack direction="row" justifyContent={'space-between'} key={index}>
<Typography sx={{ color: "text.secondary" }}>{file.name}</Typography>
<Iconify
icon="eva:trash-2-outline"
color={'darkred'}
onClick={() => {
removeDiagnosaFiles(fileDiagnosas, index);
}}
></Iconify>
</Stack>
))}
{/* <Stack direction="row" justifyContent={'space-between'}>
<Typography>Nama File .pdf</Typography>
<Iconify icon="eva:trash-2-outline" color={'darkred'}></Iconify>
</Stack> */}
</Stack>
{/* { JSON.stringify(filesResult) } */}
<ButtonBase sx={{ p: 4, border: '2px dashed #F9FAFB',
bgcolor: '#919EAB52',
borderRadius: '8px',
width: '100%', height: '60px'}} onClick={() => fileDiagnosaInput.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
</Typography>
</Box>
<input
type="file"
id="file"
ref={fileDiagnosaInput}
style={{ display: 'none' }}
multiple
onChange={handleDiagnosaInputChange}
accept="application/pdf,image/*"
/>
</ButtonBase>
</Stack>
{/* -------------------------------Upload Dokumen Hasil Penunjang------------------------------- */}
<Stack sx={{ marginTop: 2 }}>
<Typography variant="body1" sx={{fontWeight:'bold'}}>
File Hasil Penunjang Medis
</Typography>
{/* <Typography variant="body2">Hasil Lab, </Typography> */}
<Stack
divider={<Divider orientation="horizontal" flexItem />}
spacing={1}
sx={{ marginY: 2 }}
>
{fileHasilPenunjangs &&
fileHasilPenunjangs.map((file:any, index:any) => (
<Stack direction="row" justifyContent={'space-between'} key={index}>
<Typography sx={{ color: "text.secondary" }}>{file.name}</Typography>
<Iconify
icon="eva:trash-2-outline"
color={'darkred'}
onClick={() => {
removeFiles(fileHasilPenunjangs, index);
}}
></Iconify>
</Stack>
))}
{/* <Stack direction="row" justifyContent={'space-between'}>
<Typography>Nama File .pdf</Typography>
<Iconify icon="eva:trash-2-outline" color={'darkred'}></Iconify>
</Stack> */}
</Stack>
{/* { JSON.stringify(filesResult) } */}
<ButtonBase sx={{ p: 4, border: '2px dashed #F9FAFB',
bgcolor: '#919EAB52',
borderRadius: '8px',
width: '100%', height: '60px'}} onClick={() => fileHasilPenunjangInput.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
</Typography>
</Box>
<input
type="file"
id="file"
ref={fileHasilPenunjangInput}
style={{ display: 'none' }}
multiple
onChange={handleResultInputChange}
accept="application/pdf,image/*"
/>
</ButtonBase>
</Stack>
</Stack>
<LoadingButton
variant="contained"
sx={{ marginTop: 2, p: 2, backgroundColor: '#19BBBB' }}
onClick={() => {
submitRequestFinalLog();
}}
loading={submitLoading}
>
Upload File
</LoadingButton>
</Stack>
)
return (
<MuiDialog
title={{name: "Upload Final LOG"}}
openDialog={openDialog}
setOpenDialog={setOpenDialog}
content={getContent()}
maxWidth="md"
/>
);
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,190 @@
import axios from '@/utils/axios';
import { enqueueSnackbar } from 'notistack';
import { MedicineType, MemberListType } from './Types';
import { BenefitConfigurationListType } from './Types';
import { makeFormData } from '@/utils/jsonToFormData';
/**
* Listing Member
*/
export const getMemberList = async ( page: number, keyword: string ): Promise<MemberListType[]> => {
const response = await axios.get(`/claim-requests/list-member?page=${page}&keyword=${keyword}`)
.then((res) =>{
return res.data.data.member_list;
})
.catch((res) => {
enqueueSnackbar("server error !", {
variant: 'error',
});
return [];
});
return response;
};
/**
* Add Claim Request
*/
export const addClaimRequest = async ( data: MemberListType[] ): Promise<boolean> => {
// Mapping
const formData = new FormData();
data.map((row, index) => {
formData.append(`member_id[${index}]`, row.id.toString());
formData.append(`service_code[${index}]`, row.patien_type??'');
if (row.file_kondisi != undefined) {
row.file_kondisi.forEach((file, file_index) => {
console.log(file);
formData.append(`file_kondisi[member_${row.id}][${file_index}]`, file);
});
}
if (row.file_diagnosa != undefined) {
row.file_diagnosa.forEach((file, file_index) => {
console.log(file);
formData.append(`file_diagnosa[member_${row.id}][${file_index}]`, file);
});
}
if (row.file_penunjang != undefined) {
row.file_penunjang.forEach((file, file_index) => {
console.log(file);
formData.append(`file_penunjang[member_${row.id}][${file_index}]`, file);
});
}
})
// Axios
const response = await axios.post(`/claim-requests`, formData)
.then((res) =>{
enqueueSnackbar("Berhasil membuat data !", {
variant: 'success',
});
return true;
})
.catch((res) => {
enqueueSnackbar("server error !", {
variant: 'error',
});
return false;
});
return response;
};
/**
* Add Benefit
*/
export const postAddBenefit = async (data: BenefitConfigurationListType):Promise<boolean> => {
const response = await axios.post(`customer-service/request/insert-benefit`, {
...data
})
.then((res) =>{
enqueueSnackbar(res.data.message, {
variant: 'success',
});
return true;
})
.catch((res) => {
if (res.response.status == 400) {
let arr_message = res.response.data.message;
// for (const key in arr_message) {
enqueueSnackbar(arr_message, {
variant: 'warning',
});
// }
}
else {
enqueueSnackbar("server error !", {
variant: 'error',
});
}
return false;
});
return response;
}
/**
* Edit Benefit
*/
export const postEditBenefit = async (id:number|undefined, data: BenefitConfigurationListType):Promise<boolean> => {
const response = await axios.put(`customer-service/request/benefit_data/${id}`, {
...data
})
.then((res) =>{
enqueueSnackbar(res.data.message, {
variant: 'success',
});
return true;
})
.catch((res) => {
if (res.response.status == 400) {
let arr_message = res.response.data.message;
// for (const key in arr_message) {
enqueueSnackbar(arr_message, {
variant: 'warning',
});
// }
}
else {
enqueueSnackbar("server error !", {
variant: 'error',
});
}
return false;
});
return response;
}
/**
* Add Medicine
*/
export const postAddMedince = async (data: MedicineType):Promise<boolean> => {
const response = await axios.post(`customer-service/request/medicine-data`, {
...data
})
.then((res) =>{
enqueueSnackbar(res.data.message, {
variant: 'success',
});
return true;
})
.catch((res) => {
if (res.response.status == 400) {
let arr_message = res.response.data.message;
// for (const key in arr_message) {
enqueueSnackbar(arr_message, {
variant: 'warning',
});
// }
}
else {
enqueueSnackbar("server error !", {
variant: 'error',
});
}
return false;
});
return response;
}

View File

@@ -0,0 +1,175 @@
import { Member } from "@/@types/member"
/**
* Search Type
*/
export type SearchType = {
keyword: string,
}
/**
* Member List
*/
export type FinalLogType = {
id : number,
code : string,
member : Member,
member_name : string,
submission_date_fgl : string,
submission_date : string,
admission_date : string,
service_name : string,
payment_type_name : string,
status_final_log : string,
status_approval : string,
nominal : number,
provider : string,
status : string,
files_by_type : files_by_type,
specialities_id : number,
dppj: string
}
export type DetailFinalLogType = {
id : number,
code : string,
member_id : string,
invoice_no : string,
billing_no : string,
provider : string,
policy_number : string,
name : string|any,
date_of_birth : string,
gender : string,
marital_status : string,
admission_date : string,
submission_date : string,
approved_final_log_at : string,
service_type : string,
claim_method : string,
status : string,
status_final_log : string,
status_approval : string,
no_identitas : string,
keterangan : string,
hak_kamar_pasien : string,
penempatan_kamar : string,
catatan : string,
discharge_date : string,
reason : string,
type_of_member : string,
diagnosis : Diagnosis[],
benefit : Benefit[],
benefit_data : BenefitData[],
config_service : ConfigService,
exclusion : Exclusion[],
medicine : Medicine[],
files : file[],
member_usage_benefit : number,
corporate_id : number
nominal : number
}
export type Diagnosis = {
id : number,
value : string,
label : string
}
export type BenefitData = {
amount_incurred : number,
amount_approved : number,
amount_not_approved : number,
excess_paid : number,
keterangan : string,
benefit : Benefit,
request_log_id : number,
benefit_name : string,
description : string,
id : number,
}
export type BenefitConfigurationListType = {
request_log_id: number|undefined,
benefit_name: string,
benefit_id: number,
benefit: {
description: string
},
amount_incurred: number,
amount_approved: number,
amount_not_approved: number,
excess_paid: number,
keterangan: string,
description: string,
reason: {
value:string,
label:string
} | null
}
export type Benefit = {
id: number,
code: string,
description: string
}
export type files_by_type = {
final_log_diagnosis : file[],
final_log_kondisi : file[],
final_log_result : file[],
}
export type file = {
original_name: string,
name: string,
path: string,
url: string,
}
export type ConfigService = {
gp_external_doctor_online: string,
gp_external_doctor_offline: string,
gp_internal_doctor_online: string,
gp_internal_doctor_offline: string,
sp_external_doctor_online: string,
sp_external_doctor_offline: string,
sp_internal_doctor_online: string,
sp_internal_doctor_offline: string,
vitamins: string,
delivery_fee: string,
general_practitioner_fee: string,
specialist_practitioner_fee: string
}
export type Exclusion = {
exclusionable: {
code: string,
name: string
},
rules: Rule[]
}
export type Rule = {
id: number,
exclusion_id: number,
name: string,
values: string,
}
export type MedicineType = {
medicine: Medicine[],
}
export type Medicine = {
id: number,
medicine_name: string,
medicine_price: number,
medicine: string,
price: number,
request_log_id: number|undefined,
}

View File

@@ -325,12 +325,12 @@ export default function TableList() {
isSort: false,
},
];
function handleSearchMember(noPolis:any, birthDate:any) {
setLoadingClaim(false)
axios.post('/search-member', {
no_polis: noPolis,
axios.post('/search-member', {
no_polis: noPolis,
birth_date: birthDate ? fPostFormat(birthDate, 'yyyy-MM-dd') : null,
type: 'view'
})
@@ -346,13 +346,13 @@ export default function TableList() {
});
}
function handleRequestFinalLog(
id:any,
full_name:any,
no_polis:any,
submission_date:any,
id:any,
full_name:any,
no_polis:any,
submission_date:any,
service_code:any,
member_id:any,
specialities_id:any,
@@ -438,20 +438,42 @@ export default function TableList() {
<Iconify icon="eva:download-fill" />
Download LOG
</MenuItem>
):''}
):''}
{obj.final_log === 0 && obj.status === 'approved' ? (
<MenuItem onClick={() => handleRequestFinalLog(
obj.id,
obj.full_name,
obj.no_polis,
obj.submission_date,
obj.service_code,
obj.member_id,
obj.specialities_id,
obj.dppj,
) }>
<Iconify icon="fa:file-text" />
Request Final LOG
//OLD
// <MenuItem onClick={() => handleRequestFinalLog(
// obj.id,
// obj.full_name,
// obj.no_polis,
// obj.submission_date,
// obj.service_code,
// obj.member_id,
// obj.specialities_id,
// obj.dppj,
// ) }>
// <Iconify icon="fa:file-text" />
// Request Final LOG
// </MenuItem>
//NEW
<MenuItem
onClick={() =>
navigate('/detail-request-final-log/'+obj.id, {
state: {
Log_id: obj.id,
full_name: obj.full_name,
no_polis: obj.no_polis,
submission_date: obj.submission_date,
service_code: obj.service_code,
member_id: obj.member_id,
specialities_id: obj.specialities_id,
dppj: obj.dppj,
},
})
}
>
<Iconify icon="fa:file-text" />
Request Final LOG
</MenuItem>
):''}
</>
@@ -484,7 +506,7 @@ export default function TableList() {
// const [noPolis, setNoPolis] = useState('AW001-01');
//const [birthDate, setBirthDate] = useState('1991-01-10');
@@ -527,7 +549,7 @@ export default function TableList() {
DialogMember(currentMember, () => setOpenDialogBenefit(false))
}
maxWidth="sm"
/>
/>
<MuiDialog
title={{name: dataViewFinalDialog?.full_name}}
@@ -547,7 +569,7 @@ export default function TableList() {
/>
}
maxWidth="sm"
/>
/>
</>
);
}