Update Add Input Hospital Portal
This commit is contained in:
@@ -7,6 +7,10 @@ use Modules\HospitalPortal\Http\Controllers\Api\MemberController;
|
||||
use Modules\HospitalPortal\Http\Controllers\ClaimController;
|
||||
use Modules\HospitalPortal\Http\Controllers\Api\NotificationController;
|
||||
use Modules\HospitalPortal\Http\Controllers\Api\RequestLogController;
|
||||
use Modules\Internal\Http\Controllers\Api\RequestLogController as RequestLogControllerInternal;
|
||||
use Modules\Internal\Http\Controllers\Api\RequestLogBenefitController;
|
||||
use Modules\Internal\Http\Controllers\Api\RequestLogMedicineController;
|
||||
|
||||
use Modules\HospitalPortal\Http\Controllers\ApotekController;
|
||||
use Modules\HospitalPortal\Http\Middleware\Authentication;
|
||||
use Modules\HospitalPortal\Http\Middleware\Authorization;
|
||||
@@ -35,12 +39,42 @@ Route::prefix('v1')->group(function() {
|
||||
Route::post('forget-password', [AuthController::class, 'forgetPassword']);
|
||||
Route::post('verify-email', [AuthController::class, 'verifyEmail'])->name('verify-email');
|
||||
Route::post('verify-code', [AuthController::class, 'verifCode']);
|
||||
|
||||
|
||||
Route::get('service-member/{id}', [AutocompleteController::class, 'serviceCode']);
|
||||
Route::get('specialis', [AutocompleteController::class, 'specialisList']);
|
||||
Route::get('diagnosis', [RequestLogControllerInternal::class, 'diagnosis']);
|
||||
|
||||
Route::middleware('auth:sanctum')->group(function () {
|
||||
|
||||
//dari Internal Prime center
|
||||
Route::get('customer-service/request', [RequestLogControllerInternal::class, 'index']);
|
||||
Route::post('customer-service/request', [RequestLogControllerInternal::class, 'createNew']);
|
||||
Route::put('customer-service/request/{id}', [RequestLogControllerInternal::class, 'update']);
|
||||
Route::get('customer-service/request/{id}', [RequestLogControllerInternal::class, 'show']);
|
||||
Route::put('customer-service/request/delete/{id}', [RequestLogControllerInternal::class, 'destroy']);
|
||||
Route::put('customer-service/request/final_log/{id}', [RequestLogControllerInternal::class, 'deleteFinalLog']);
|
||||
Route::get('customer-service/request/{id}/download', [RequestLogControllerInternal::class, 'generateRequestLog']);
|
||||
Route::post('customer-service/request/import', [RequestLogControllerInternal::class, 'importRequestLog']);
|
||||
Route::post('customer-service/request/import-invoice', [RequestLogControllerInternal::class, 'importInvoice']);
|
||||
Route::post('customer-service/request/exportFiledInvoice', [RequestLogControllerInternal::class, 'exportFiledInvoice']);
|
||||
Route::get('customer-service/request/data', [RequestLogControllerInternal::class, 'generateDataRequestLogExcel']);
|
||||
Route::post('customer-service/request/{id}/add_file', [RequestLogControllerInternal::class, 'requestFiles']);
|
||||
Route::post('customer-service/request/{id}/approval_files', [RequestLogControllerInternal::class, 'approvalFiles']);
|
||||
Route::post('customer-service/request/{id}/delete_file', [RequestLogControllerInternal::class, 'deleteFiles']);
|
||||
|
||||
Route::post('customer-service/request/final-log', [RequestLogControllerInternal::class, 'updateFinalLog']);
|
||||
|
||||
// insert benefit
|
||||
Route::post('customer-service/request/insert-benefit', [RequestLogBenefitController::class, 'store']);
|
||||
Route::post('customer-service/request/benefit_data/{id}', [RequestLogBenefitController::class, 'destroy']);
|
||||
Route::put('customer-service/request/benefit_data/{id}', [RequestLogBenefitController::class, 'update']);
|
||||
|
||||
// insert medicine
|
||||
Route::post('customer-service/request/medicine-data', [RequestLogMedicineController::class, 'store']);
|
||||
Route::delete('customer-service/request/medicine-data/{id}', [RequestLogMedicineController::class, 'destroy']);
|
||||
Route::put('customer-service/request/medicine-data/{id}', [RequestLogMedicineController::class, 'update']);
|
||||
// end prime center
|
||||
|
||||
// Navigation
|
||||
Route::get('navigations', [NavigationController::class, 'index']);
|
||||
|
||||
@@ -96,6 +130,6 @@ Route::prefix('v1')->group(function() {
|
||||
Route::post('claim-requests/{id}/request-files', [ClaimRequestController::class, 'requestFiles']);
|
||||
});
|
||||
|
||||
|
||||
|
||||
});
|
||||
});
|
||||
|
||||
@@ -54,6 +54,10 @@ use Modules\Internal\Http\Controllers\Api\CorporateManageController;
|
||||
use Modules\Internal\Http\Controllers\Api\UserManagementController;
|
||||
use Modules\Internal\Http\Controllers\ClaimEncounterController;
|
||||
use Modules\Linksehat\Http\Controllers\Api\AutocompleteController;
|
||||
use Modules\HospitalPortal\Http\Controllers\Api\MemberController as MemberControllerHospitalPortal;
|
||||
use Modules\HospitalPortal\Http\Controllers\Api\RequestLogController as RequestLogControllerHospitalPortal;
|
||||
|
||||
|
||||
|
||||
// Report
|
||||
use Modules\Internal\Http\Controllers\Api\ReportLogController;
|
||||
@@ -311,6 +315,49 @@ Route::prefix('internal')->group(function () {
|
||||
Route::get('claims/{id}/benefit-configuration', [ClaimController::class, 'getBenefitConfiguration']); // Bagaskoro, BSD 03 November 2023
|
||||
Route::put('claims/benefit-configuration/edit/{id}', [ClaimController::class, 'editBenefitConfiguration']); // Bagaskoro, BSD 03 November 2023
|
||||
|
||||
//dari hospital-portal
|
||||
//Search Member
|
||||
Route::post(
|
||||
'search-member',
|
||||
[MemberControllerHospitalPortal::class, 'search']
|
||||
);
|
||||
// Request LOG
|
||||
Route::post(
|
||||
'request-log',
|
||||
[RequestLogControllerHospitalPortal::class, 'requestLog']
|
||||
);
|
||||
|
||||
Route::get(
|
||||
'get-request-log',
|
||||
[RequestLogControllerHospitalPortal::class, 'getRequestLog']
|
||||
);
|
||||
|
||||
Route::get(
|
||||
'get-final-log',
|
||||
[RequestLogControllerHospitalPortal::class, 'getFinalLog']
|
||||
);
|
||||
|
||||
Route::post(
|
||||
'request-final-log',
|
||||
[RequestLogControllerHospitalPortal::class, 'requestFinalLog']
|
||||
);
|
||||
|
||||
Route::get(
|
||||
'download-log/{request_log_id}',
|
||||
[RequestLogControllerHospitalPortal::class, 'downlodLog']
|
||||
);
|
||||
|
||||
Route::get(
|
||||
'download-final-log/{request_log_id}',
|
||||
[RequestLogControllerHospitalPortal::class, 'downlodFinalLog']
|
||||
);
|
||||
|
||||
Route::post(
|
||||
'submit-claims',
|
||||
[RequestLogControllerHospitalPortal::class, 'submitClaims']
|
||||
);
|
||||
//end dari hospital-portal
|
||||
|
||||
Route::get('customer-service/request', [RequestLogController::class, 'index']);
|
||||
Route::post('customer-service/request', [RequestLogController::class, 'createNew']);
|
||||
Route::put('customer-service/request/{id}', [RequestLogController::class, 'update']);
|
||||
|
||||
@@ -30,13 +30,15 @@ class RequestLogShowResource extends JsonResource
|
||||
{
|
||||
|
||||
$requestLog = parent::toArray($request);
|
||||
|
||||
$corporateId = $requestLog['member']['current_plan']['corporate_id'] ?? 0;
|
||||
$member_id = $requestLog['member_id'];
|
||||
$planMember = MemberPlan::where('member_id', $member_id)->get('plan_id');
|
||||
|
||||
|
||||
$planId = Plan::whereIn('id', $planMember)->where('service_code', $requestLog['service_code'])->first();
|
||||
$benefit = CorporateBenefit::with(['benefit', 'plan'])->where('plan_id', $planId->id)->get()->toArray();
|
||||
$benefitDetailLog = RequestLogBenefit::with('benefit')->where('request_log_id', $requestLog['id'])->get()->toArray();
|
||||
|
||||
$medicineDetailLog = RequestLogMedicine::where('request_log_id', $requestLog['id'])->get()->toArray();
|
||||
$provider = Organization::where('id', $requestLog['organization_id'])->first();
|
||||
$claimRequest = ClaimRequest::where('request_log_id', $requestLog['id'])->first();
|
||||
@@ -139,8 +141,8 @@ class RequestLogShowResource extends JsonResource
|
||||
'invoice_no' => $requestLog['invoice_no'],
|
||||
'billing_no' => $requestLog['billing_no'],
|
||||
'specialities_id' => $name,
|
||||
'specialitiesID' => $requestLog['specialities_id'],
|
||||
'dppj' => $dppj,
|
||||
'code' => $requestLog['code'],
|
||||
'code_claim' => $claimCode,
|
||||
'member_id' => $requestLog['member']['member_id'],
|
||||
'type_of_member' => $requestLog['type_of_member'],
|
||||
@@ -160,6 +162,7 @@ class RequestLogShowResource extends JsonResource
|
||||
'approved_final_log_at' => $requestLog['approved_final_log_at'], // submission final log
|
||||
'discharge_date' => $requestLog['discharge_date'],
|
||||
'service_type' => Helper::serviceName($requestLog['service_code']),
|
||||
'service_code' => $requestLog['service_code'],
|
||||
'claim_method' => $requestLog['payment_type'],
|
||||
'status' => $requestLog['status'],
|
||||
'status_final_log' => $requestLog['status_final_log'],
|
||||
|
||||
@@ -205,7 +205,7 @@ class NavigationSeeder extends Seeder
|
||||
'permission' => 'report-livechat-payment'
|
||||
],
|
||||
[
|
||||
'title' => 'Prescription',
|
||||
'title' => 'Prescription',
|
||||
'path' => '/report/prescription',
|
||||
'permission' => 'report-prescription'
|
||||
],
|
||||
@@ -346,6 +346,12 @@ class NavigationSeeder extends Seeder
|
||||
'icon' => 'ic_booking',
|
||||
'permission' => 'dashboard-claim-hospital-portal'
|
||||
],
|
||||
[
|
||||
'title' => 'Request LOG',
|
||||
'path' => '',
|
||||
'icon' => '',
|
||||
'permission' => 'request-log-hospital-portal'
|
||||
],
|
||||
####################### CS LMS & APOTEK PORTAL #########################
|
||||
[
|
||||
'title' => 'Dashboard',
|
||||
|
||||
@@ -111,6 +111,7 @@ class PermissionTableSeeder extends Seeder
|
||||
'datas' => [
|
||||
'dashboard-hospital-portal',
|
||||
'dashboard-claim-hospital-portal',
|
||||
'request-log-hospital-portal',
|
||||
'dashboard-apotek-portal',
|
||||
]
|
||||
],
|
||||
|
||||
@@ -23,6 +23,8 @@ import Page from '../../../components/Page';
|
||||
import Iconify from '@/components/Iconify';
|
||||
import { FormProvider, RHFDatepicker, RHFSelect, RHFTextField } from '@/components/hook-form';
|
||||
import RHFTextFieldMoney from '@/components/hook-form/v2/RHFTextFieldMoney';
|
||||
import { DatePicker, LocalizationProvider, MobileDatePicker } from '@mui/x-date-pickers';
|
||||
import { AdapterDateFns } from '@mui/x-date-pickers/AdapterDateFns';
|
||||
// utils
|
||||
import useSettings from '../../../hooks/useSettings';
|
||||
import { useFieldArray, useForm } from 'react-hook-form';
|
||||
@@ -35,7 +37,7 @@ import { enqueueSnackbar } from 'notistack';
|
||||
import ArrowBackIosIcon from '@mui/icons-material/ArrowBackIos';
|
||||
import { DetailFinalLogType } from './Model/Types';
|
||||
import { fDate, fDateTimesecond } from '@/utils/formatTime';
|
||||
import { Button } from '@mui/material';
|
||||
import { Button, Autocomplete, FormHelperText} from '@mui/material';
|
||||
import DialogConfirmation from '../FinalLog/Components/DialogConfirmation';
|
||||
import Label from '@/components/Label';
|
||||
import { Box } from '@mui/system';
|
||||
@@ -45,6 +47,11 @@ import {BenefitData } from '../FinalLog/Model/Types'
|
||||
import AddIcon from '@mui/icons-material/Add';
|
||||
import { LoadingButton } from '@mui/lab';
|
||||
import { makeFormData } from '@/utils/jsonToFormData';
|
||||
import TextField from '@mui/material/TextField';
|
||||
import { fPostFormat } from '@/utils/formatTime';
|
||||
|
||||
|
||||
|
||||
|
||||
// Import Card Detail Final LOG
|
||||
import CardDetail from '../Components/CardDetail';
|
||||
@@ -71,11 +78,86 @@ import DialogDeleteFileLog from './Components/DialogDeleteFileLog';
|
||||
import DialogUploadFileFinalLog from './Components/DialogUploadFileFinalLog';
|
||||
import DialogSendWa from './Components/DialogSendWa';
|
||||
import { set } from 'nprogress';
|
||||
import { format } from 'date-fns';
|
||||
|
||||
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
export default function Detail() {
|
||||
//dari hospital portal
|
||||
const [dischargeDate, setDischargeDate] = useState<string>(format(new Date(), "yyyy MMM d HH:mm:ss"));
|
||||
const [serviceOptions, setServiceOptions] = useState([
|
||||
{ value: '-', label: '-' }
|
||||
]);
|
||||
const [specialisOptions, setSpecialisOptions] = useState([
|
||||
{ value: '-', label: '-' }
|
||||
]);
|
||||
useEffect(() => {
|
||||
axios.get('service-member/'+1)
|
||||
.then((response) => {
|
||||
setServiceOptions(response.data);
|
||||
}).catch((error) => {
|
||||
console.error('Error fetching ICD options:', error);
|
||||
});
|
||||
|
||||
axios.get('specialis')
|
||||
.then((response) => {
|
||||
setSpecialisOptions(response.data);
|
||||
}).catch((error) => {
|
||||
console.error('Error fetching ICD options:', error);
|
||||
});
|
||||
|
||||
}, []);
|
||||
const [serviceCode, setServiceCode] = useState<string>("");
|
||||
const [idSpecialities, setIdSpecialities] = useState("");
|
||||
const [inputDppj, setInputDppj] = useState("");
|
||||
function submitRequestFinalLog() {
|
||||
if(dischargeDate == '')
|
||||
{
|
||||
enqueueSnackbar('Tanggal Keluar', { variant: 'warning' });
|
||||
return false;
|
||||
}
|
||||
//cek spesialis
|
||||
if(!idSpecialities)
|
||||
{
|
||||
enqueueSnackbar('Spesialis', { variant: 'warning' });
|
||||
return false;
|
||||
}
|
||||
//cek dpjp
|
||||
if(!inputDppj)
|
||||
{
|
||||
enqueueSnackbar('DPPJ', { variant: 'warning' });
|
||||
return false;
|
||||
}
|
||||
setSubmitLoading(true);
|
||||
const formData = makeFormData({
|
||||
// request_logs_id: member.id,
|
||||
// result_files: fileHasilPenunjangs,
|
||||
// diagnosa_files: fileDiagnosas,
|
||||
// kondisi_files: fileKondisis,
|
||||
discharge_date: fPostFormat(dischargeDate, 'yyyy-MM-dd HH:mm:ss'),
|
||||
service_code: serviceCode,
|
||||
spescialis_id: idSpecialities,
|
||||
dppj: inputDppj,
|
||||
});
|
||||
axios
|
||||
.post('/request-final-log', formData)
|
||||
.then((response) => {
|
||||
enqueueSnackbar(response.data.meta.message ?? 'Berhasil membuat data', { variant: 'success' });
|
||||
// handleSubmitSuccess();
|
||||
// onClose({ someData: 'example data' }, getData);
|
||||
})
|
||||
.catch(({ response }) => {
|
||||
enqueueSnackbar(response.data.meta.message ?? 'Something Went Wrong', { variant: 'error' });
|
||||
})
|
||||
.then(() => {
|
||||
setSubmitLoading(false);
|
||||
});
|
||||
}
|
||||
//end dari hospital portal
|
||||
|
||||
|
||||
const location = useLocation();
|
||||
const queryParams = new URLSearchParams(location.search);
|
||||
|
||||
@@ -106,7 +188,7 @@ export default function Detail() {
|
||||
.post(`/customer-service/request/${id}/approval_files`, formData)
|
||||
.then((response) => {
|
||||
enqueueSnackbar('Berhasil membuat data', { variant: 'success' });
|
||||
|
||||
|
||||
window.location.reload()
|
||||
})
|
||||
.catch(({ response }) => {
|
||||
@@ -231,10 +313,10 @@ export default function Detail() {
|
||||
// Handle Delete File LOG
|
||||
const [pathFile, setPathFile] = useState('')
|
||||
const [dialogDeleteFIleLog, setDialogDeleteFileLog] = useState(false)
|
||||
|
||||
|
||||
// Handle Upload File LOG
|
||||
const [dialogUploadFileLog, setDialogUploadFileLog] = useState(false)
|
||||
|
||||
|
||||
|
||||
const fileDiagnosaInput = useRef<HTMLInputElement>(null);
|
||||
const [fileApprovals, setFileApproval] = useState<any>([]);
|
||||
@@ -425,6 +507,91 @@ export default function Detail() {
|
||||
>
|
||||
</DialogHospitalCare>
|
||||
</Grid> */}
|
||||
<Grid item xs={12}>
|
||||
<Card sx={{p:3}}>
|
||||
<Stack direction="row" spacing={2} sx={{ width: '100%' }}>
|
||||
{/* Kolom Tanggal Discharge */}
|
||||
<Stack spacing={2} sx={{ flex: 1 }}>
|
||||
<Typography variant="subtitle1">Tanggal Keluar </Typography>
|
||||
<LocalizationProvider dateAdapter={AdapterDateFns}>
|
||||
<DatePicker
|
||||
label="Tanggal Keluar"
|
||||
value={dischargeDate}
|
||||
onChange={(newValue: any) => {
|
||||
setDischargeDate(newValue);
|
||||
}}
|
||||
inputFormat="dd-MM-yyyy HH:mm"
|
||||
renderInput={(params) => <TextField {...params} fullWidth required />}
|
||||
/>
|
||||
</LocalizationProvider>
|
||||
</Stack>
|
||||
|
||||
{/* Kolom Service Type */}
|
||||
<Stack spacing={2} sx={{ flex: 1 }}>
|
||||
<Typography variant="subtitle1">Tipe Service </Typography>
|
||||
<Autocomplete
|
||||
id="service_type"
|
||||
options={serviceOptions}
|
||||
getOptionLabel={(option) => option.label || ""}
|
||||
value={serviceOptions.find((opt) => opt.value == serviceCode) || null}
|
||||
onChange={(event, newValue) => {
|
||||
setServiceCode(newValue?.value || "");
|
||||
}}
|
||||
renderInput={(params) => (
|
||||
<TextField {...params} label='Tipe Service' fullWidth />
|
||||
)}
|
||||
/>
|
||||
<FormHelperText style={{ color: "red" }}></FormHelperText>
|
||||
</Stack>
|
||||
</Stack>
|
||||
|
||||
{/* Specialist */}
|
||||
<Stack direction="row" spacing={2}>
|
||||
<Stack spacing={2} sx={{ width: '100%' }}>
|
||||
<Typography variant='subtitle1'>Spesialis </Typography>
|
||||
<Autocomplete
|
||||
id='specialities'
|
||||
options={specialisOptions}
|
||||
getOptionLabel={(option) => option.label || ''}
|
||||
value={specialisOptions.find((opt) => opt.value === idSpecialities) || null}
|
||||
onChange={(event, newValue) => {
|
||||
setIdSpecialities(newValue?.value || 0);
|
||||
}}
|
||||
renderInput={(params) => (
|
||||
<TextField {...params} label="Spesialis" fullWidth />
|
||||
)}
|
||||
/>
|
||||
<FormHelperText style={{ color: 'red' }}></FormHelperText>
|
||||
</Stack>
|
||||
</Stack>
|
||||
|
||||
<Stack direction="row" spacing={2}>
|
||||
<Stack spacing={2} sx={{ width: '100%' }}>
|
||||
<Typography variant='subtitle1'>DPPJ </Typography>
|
||||
<TextField
|
||||
id='dppj'
|
||||
variant='outlined'
|
||||
value={inputDppj}
|
||||
placeholder="DPPJ"
|
||||
onChange={(event) => {
|
||||
setInputDppj(event.target.value);
|
||||
}}
|
||||
fullWidth
|
||||
/>
|
||||
</Stack>
|
||||
</Stack>
|
||||
<LoadingButton
|
||||
variant="contained"
|
||||
sx={{ marginTop: 2, p: 2, backgroundColor: '#19BBBB' }}
|
||||
onClick={() => {
|
||||
submitRequestFinalLog();
|
||||
}}
|
||||
loading={submitLoading}
|
||||
>
|
||||
Simpan
|
||||
</LoadingButton>
|
||||
</Card>
|
||||
</Grid>
|
||||
|
||||
{/* Surat persetujuan Tindakan */}
|
||||
<Grid item xs={12}>
|
||||
@@ -592,7 +759,7 @@ export default function Detail() {
|
||||
|
||||
{/* FILE YANG SUDAH TERUPLOAD */}
|
||||
{requestLog?.files
|
||||
?.filter((document) => document.type === 'approval')
|
||||
?.filter((document) => document.type === 'approval')
|
||||
?.map((documentType, index) => (
|
||||
<Stack
|
||||
key={index}
|
||||
@@ -640,7 +807,7 @@ export default function Detail() {
|
||||
openDialog={dialogUploadFileLog}
|
||||
/>
|
||||
</Card>
|
||||
</Grid>
|
||||
</Grid>
|
||||
|
||||
|
||||
{/* Benefit */}
|
||||
@@ -993,7 +1160,7 @@ export default function Detail() {
|
||||
|
||||
</Stack>
|
||||
{requestLog?.files
|
||||
?.filter((document) => document.type !== 'approval')
|
||||
?.filter((document) => document.type !== 'approval')
|
||||
?.map((documentType, index) => (
|
||||
<Stack direction="row" alignItems="center" justifyContent="space-between" sx={{marginBottom: 2}} key={index}>
|
||||
<Stack direction="column" spacing={2} >
|
||||
@@ -1043,7 +1210,7 @@ export default function Detail() {
|
||||
variant="outlined"
|
||||
sx={{ color: '#FF4842', borderColor: '#FF4842' }}
|
||||
onClick={() => {
|
||||
|
||||
|
||||
}}
|
||||
>
|
||||
Decline
|
||||
|
||||
@@ -0,0 +1,149 @@
|
||||
// @mui
|
||||
import { styled } from '@mui/material/styles';
|
||||
import {
|
||||
Button,
|
||||
Card,
|
||||
Typography,
|
||||
Link,
|
||||
Divider,
|
||||
Stack,
|
||||
TextField,
|
||||
Grid,
|
||||
InputAdornment,
|
||||
} from '@mui/material';
|
||||
import { ChevronRight } from '@mui/icons-material';
|
||||
// React
|
||||
import React, { useContext, useState } from 'react';
|
||||
import { LoadingButton } from '@mui/lab';
|
||||
import Iconify from '@/components/Iconify';
|
||||
import { DatePicker, LocalizationProvider, MobileDatePicker } from '@mui/x-date-pickers';
|
||||
import { AdapterDateFns } from '@mui/x-date-pickers/AdapterDateFns';
|
||||
import { fDateOnly } from '@/utils/formatTime';
|
||||
import MuiDialog from '@/components/MuiDialog';
|
||||
import axios from '@/utils/axios';
|
||||
import { useSnackbar } from 'notistack';
|
||||
import DialogMember from './DialogMember';
|
||||
// import { LanguageContext } from '@/contexts/LanguageContext';
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
const RootNotificationStyle = styled(Card)(({ theme }) => ({
|
||||
boxShadow: 'none',
|
||||
padding: '1rem 0.5rem',
|
||||
color: 'black',
|
||||
backgroundColor: theme.palette.grey[200],
|
||||
// maxHeight: '240px',
|
||||
}));
|
||||
|
||||
const ItemNotificationStyle = styled(Card)(({ theme }) => ({
|
||||
boxShadow: 'none',
|
||||
padding: theme.spacing(1),
|
||||
borderRadius: 0.5,
|
||||
color: 'black',
|
||||
}));
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
export default function CardSearchMember(handleSubmitSuccess:()=> void) {
|
||||
// const { localeData }: any = useContext(LanguageContext);
|
||||
const {enqueueSnackbar} = useSnackbar();
|
||||
|
||||
const [noPolis, setNoPolis] = useState('');
|
||||
const [birthDate, setBirthDate] = useState(null);
|
||||
const [loadingBenefit, setLoadingBenefit] = useState(false);
|
||||
const [loadingClaim, setLoadingClaim] = useState(false);
|
||||
const [openDialogBenefit, setOpenDialogBenefit] = useState(false);
|
||||
const [openDialogClaim, setOpenDialogClaim] = useState(false);
|
||||
const [currentMember, setCurrentMember] = useState(null);
|
||||
const [nameMember, setNameMember] = useState('');
|
||||
|
||||
function handleSearchMember() {
|
||||
setLoadingBenefit(true)
|
||||
|
||||
axios.post('/search-member', {
|
||||
no_polis: noPolis,
|
||||
birth_date: birthDate ? fDateOnly(birthDate, 'yyyy-MM-dd') : null
|
||||
})
|
||||
.then((response) => {
|
||||
setOpenDialogBenefit(true)
|
||||
setCurrentMember(response.data.data)
|
||||
setNameMember(response.data.data.members.name);
|
||||
})
|
||||
.catch(({response}) => {
|
||||
enqueueSnackbar(response.data.errors ? response.data.errors[0] : (response.data ? response.data.meta.message : 'Opps, Something went Wrong!'), {variant : "error"})
|
||||
})
|
||||
.then(() => {
|
||||
setLoadingBenefit(false)
|
||||
});
|
||||
}
|
||||
|
||||
return (
|
||||
<div>
|
||||
<RootNotificationStyle sx={{ p: 2, height: 'auto' }}>
|
||||
<Stack
|
||||
direction="row"
|
||||
justifyContent="space-between"
|
||||
alignItems="center"
|
||||
sx={{ paddingBottom: 2, paddingTop: 1 }}
|
||||
>
|
||||
<Typography
|
||||
variant="body2"
|
||||
component="span"
|
||||
sx={{ display: 'flex', alignItems: 'center' }}
|
||||
>
|
||||
Pengajuan Jaminan
|
||||
</Typography>
|
||||
</Stack>
|
||||
<Stack spacing={2} direction="row" justifyContent="space-between">
|
||||
<TextField
|
||||
variant="outlined"
|
||||
label="Member ID"
|
||||
value={noPolis}
|
||||
onChange={(event) => {
|
||||
setNoPolis(event.target.value)
|
||||
}}
|
||||
sx={{width:'40%'}}
|
||||
required
|
||||
/>
|
||||
|
||||
<LocalizationProvider dateAdapter={AdapterDateFns}>
|
||||
<DatePicker
|
||||
label="Tanggal Lahir"
|
||||
value={birthDate}
|
||||
onChange={(newValue:any) => {
|
||||
setBirthDate( (newValue));
|
||||
}}
|
||||
inputFormat="dd-MM-yyyy"
|
||||
renderInput={(params) => <TextField sx={{width:'40%'}} {...params} required/>}
|
||||
/>
|
||||
</LocalizationProvider>
|
||||
|
||||
<LoadingButton
|
||||
sx={{
|
||||
backgroundColor: '#19BBBB',
|
||||
p: 1,
|
||||
width: '20%',
|
||||
color: '#FFFF'
|
||||
}}
|
||||
loading={loadingBenefit}
|
||||
onClick={() => {
|
||||
handleSearchMember()
|
||||
}}
|
||||
>
|
||||
<Iconify icon="eva:search-fill" marginRight={0.75} sx={{width: '24px', height: '24px'}} />
|
||||
Cari Anggota
|
||||
</LoadingButton>
|
||||
</Stack>
|
||||
</RootNotificationStyle>
|
||||
{/*
|
||||
<DialogBenefit open={openDialogBenefit} setOpen={setOpenDialogBenefit}></DialogBenefit> */}
|
||||
<MuiDialog
|
||||
title={{name: nameMember}}
|
||||
openDialog={openDialogBenefit}
|
||||
setOpenDialog={setOpenDialogBenefit}
|
||||
content={DialogMember(currentMember, () => {setOpenDialogBenefit(false); handleSubmitSuccess()})}
|
||||
maxWidth="sm"
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,204 @@
|
||||
// mui
|
||||
import { styled } from '@mui/material/styles';
|
||||
import { LoadingButton, TabPanel } from "@mui/lab";
|
||||
import {
|
||||
Button,
|
||||
Card,
|
||||
Divider,
|
||||
Grid,
|
||||
LinearProgress,
|
||||
linearProgressClasses,
|
||||
Typography,
|
||||
Paper,
|
||||
Table,
|
||||
TableBody,
|
||||
TableCell,
|
||||
TableContainer,
|
||||
TableHead,
|
||||
TableRow,
|
||||
Collapse, } from "@mui/material";
|
||||
import { Tab, Tabs } from "@mui/material";
|
||||
import { Box, Stack } from "@mui/material";
|
||||
import React, { useEffect, useState, useContext } from "react";
|
||||
import { fCurrency } from '@/utils/formatNumber';
|
||||
import { fPostFormat } from '@/utils/formatTime';
|
||||
import { Avatar } from '@mui/material';
|
||||
import Iconify from '@/components/Iconify';
|
||||
import FormRequestLog from './FormRequestLog';
|
||||
// import { LanguageContext } from '@/contexts/LanguageContext';
|
||||
import { format } from 'date-fns';
|
||||
import KeyboardArrowDownIcon from '@mui/icons-material/KeyboardArrowDown';
|
||||
import KeyboardArrowRightIcon from '@mui/icons-material/KeyboardArrowRight';
|
||||
|
||||
export default function DialogMember(member:any, handleSubmitSuccess:() => void) {
|
||||
// const { localeData }: any = useContext(LanguageContext);
|
||||
const [currentTab, setCurrentTab] = useState('request');
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
useEffect(() => {
|
||||
setCurrentTab('detail')
|
||||
}, [member])
|
||||
|
||||
function handleChangeTab(event: React.SyntheticEvent, newValue: string) {
|
||||
setCurrentTab(newValue)
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
const BorderLinearProgress = styled(LinearProgress)(({ theme }) => ({
|
||||
height: 10,
|
||||
borderRadius: 6,
|
||||
[`&.${linearProgressClasses.colorPrimary}`]: {
|
||||
backgroundColor: theme.palette.grey[theme.palette.mode === 'light' ? 300 : 800],
|
||||
},
|
||||
[`& .${linearProgressClasses.bar}`]: {
|
||||
borderRadius: 6,
|
||||
background: 'linear-gradient(270deg, #19BBBB 38.42%, #FF9565 76.21%, #FE7253 104.02%)',
|
||||
},
|
||||
}));
|
||||
|
||||
function TabPanel(props:any) {
|
||||
const { children, value, index, ...other } = props;
|
||||
return (
|
||||
<div
|
||||
role="tabpanel"
|
||||
hidden={value !== index}
|
||||
id={`simple-tabpanel-${index}`}
|
||||
aria-labelledby={`simple-tab-${index}`}
|
||||
{...other}
|
||||
>
|
||||
{value === index && (
|
||||
<Box sx={{ p: 3 }}>
|
||||
<div>{children}</div>
|
||||
</Box>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
const [openRows, setOpenRows] = useState<any>({});
|
||||
|
||||
const handleRowToggle = (index:number) => {
|
||||
setOpenRows((prevOpenRows:any) => ({
|
||||
...prevOpenRows,
|
||||
[index]: !prevOpenRows[index],
|
||||
}));
|
||||
};
|
||||
|
||||
return (
|
||||
<div>
|
||||
<Box sx={{ borderBottom: 1, borderColor: 'divider' }}>
|
||||
<Tabs
|
||||
value={currentTab}
|
||||
onChange={handleChangeTab}
|
||||
aria-label="wrapped label tabs example"
|
||||
>
|
||||
<Tab value="detail" label="Detail" />
|
||||
<Tab value="service" label="Layanan" />
|
||||
{member?.type !== 'view' ? (
|
||||
<Tab value="request" label="Request LOG" />
|
||||
) : ''}
|
||||
</Tabs>
|
||||
|
||||
<TabPanel value={currentTab} index={'detail'}>
|
||||
<Stack direction="column" spacing={2}>
|
||||
<Stack direction="row" justifyContent="space-between">
|
||||
<Typography sx={{width:'50%'}} variant="body2">Member ID</Typography>
|
||||
<Typography sx={{width:'50%', fontWeight: 'bold'}} variant="body2">{ member?.members.member_id ?? '-'}</Typography>
|
||||
</Stack>
|
||||
<Stack direction="row" justifyContent="space-between">
|
||||
<Typography sx={{width:'50%'}} variant="body2">Policy Number</Typography>
|
||||
<Typography sx={{width:'50%', fontWeight: 'bold'}} variant="body2">{ member?.members.policy_id ?? '-'}</Typography>
|
||||
</Stack>
|
||||
<Stack direction="row" justifyContent="space-between">
|
||||
<Typography sx={{width:'50%'}} variant="body2">Deposit Corporate</Typography>
|
||||
<Typography sx={{width:'50%', fontWeight: 'bold'}} variant="body2">{ member?.total_premi ? fCurrency(member?.total_premi) : '-'}</Typography>
|
||||
</Stack>
|
||||
<Stack direction="row" justifyContent="space-between">
|
||||
<Typography sx={{width:'50%'}} variant="body2">Limit Peserta</Typography>
|
||||
<Typography sx={{width:'50%', fontWeight: 'bold'}} variant="body2">{ member?.limit_rules ? fCurrency(member?.limit_rules) : '-'}</Typography>
|
||||
</Stack>
|
||||
<Stack direction="row" justifyContent="space-between">
|
||||
<Typography sx={{width:'50%'}} variant="body2">NRIC</Typography>
|
||||
<Typography sx={{width:'50%', fontWeight: 'bold'}} variant="body2">{member?.members.nik ?? '-'}</Typography>
|
||||
</Stack>
|
||||
<Stack direction="row" justifyContent="space-between">
|
||||
<Typography sx={{width:'50%'}} variant="body2">NIK</Typography>
|
||||
<Typography sx={{width:'50%', fontWeight: 'bold'}} variant="body2">{member?.members.nik ?? '-'}</Typography>
|
||||
</Stack>
|
||||
<Stack direction="row" justifyContent="space-between">
|
||||
<Typography sx={{width:'50%'}} variant="body2">Email</Typography>
|
||||
<Typography sx={{width:'50%', fontWeight: 'bold'}} variant="body2">{member?.members.email ?? '-'}</Typography>
|
||||
</Stack>
|
||||
<Stack direction="row" justifyContent="space-between">
|
||||
<Typography sx={{width:'50%'}} variant="body2">Tanggal Lahir</Typography>
|
||||
<Typography sx={{width:'50%', fontWeight: 'bold'}} variant="body2">{member?.members.birth_date ? format(new Date(member.members.birth_date), "d MMM yyyy") : '-'}</Typography>
|
||||
</Stack>
|
||||
<Stack direction="row" justifyContent="space-between">
|
||||
<Typography sx={{width:'50%'}} variant="body2">Jenis Kelamin</Typography>
|
||||
<Typography sx={{width:'50%', fontWeight: 'bold'}} variant="body2">{member?.members.gender ?? '-'}</Typography>
|
||||
</Stack>
|
||||
<Stack direction="row" justifyContent="space-between">
|
||||
<Typography sx={{width:'50%'}} variant="body2">Status Perkawinan</Typography>
|
||||
<Typography sx={{width:'50%', fontWeight: 'bold'}} variant="body2">{member?.members.marital_status ?? '-'}</Typography>
|
||||
</Stack>
|
||||
<Stack direction="row" justifyContent="space-between">
|
||||
<Typography sx={{width:'50%'}} variant="body2">Bahasa</Typography>
|
||||
<Typography sx={{width:'50%', fontWeight: 'bold'}} variant="body2">{member?.members.language ?? '-'}</Typography>
|
||||
</Stack>
|
||||
<Stack direction="row" justifyContent="space-between">
|
||||
<Typography sx={{width:'50%'}} variant="body2">Race</Typography>
|
||||
<Typography sx={{width:'50%', fontWeight: 'bold'}} variant="body2">{member?.members.race ?? '-'}</Typography>
|
||||
</Stack>
|
||||
<Stack direction="row" justifyContent="space-between">
|
||||
<Typography sx={{width:'50%'}} variant="body2">Hubungan</Typography>
|
||||
<Typography sx={{width:'50%', fontWeight: 'bold'}} variant="body2">{member?.members.relation_with_principal != '' ? member?.members.relation_with_principal : '-'}</Typography>
|
||||
</Stack>
|
||||
</Stack>
|
||||
</TabPanel>
|
||||
<TabPanel value={currentTab} index={'service'}>
|
||||
<TableContainer component={Paper}>
|
||||
<Table aria-label="collapsible table">
|
||||
{member && member.groupServices && Object.keys(member.groupServices).map((serviceCode, index) => (
|
||||
<TableBody key={index}>
|
||||
<TableRow sx={{backgroundColor: '#FFFFFF', borderBottom: openRows[index] ? '' : '1px solid #e0e0e0'}}>
|
||||
<TableCell align="left" sx={{fontWeight: 'bold', width: '95%'}}><Typography variant="subtitle1">{serviceCode}</Typography></TableCell>
|
||||
<TableCell align="left" sx={{width: '5%'}}>
|
||||
{openRows[index] ? (
|
||||
<KeyboardArrowDownIcon sx={{ cursor: 'pointer' }} onClick={() => handleRowToggle(index)} />
|
||||
) : (
|
||||
<KeyboardArrowRightIcon sx={{ cursor: 'pointer' }} onClick={() => handleRowToggle(index)} />
|
||||
)}
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
<TableRow sx={{display: openRows[index] ? '' : 'none', borderBottom: openRows[index] ? '1px solid #e0e0e0' : ''}}>
|
||||
<TableCell colSpan={2}>
|
||||
{/* COLLAPSIBLE ROW */}
|
||||
<Collapse in={openRows[index]} timeout="auto" unmountOnExit>
|
||||
<Grid container spacing={2}>
|
||||
{/* Loop through the array for the current serviceCode */}
|
||||
{member.groupServices[serviceCode].map((item:any, innerIndex:number) => (
|
||||
<Grid item sm={6} key={innerIndex}>
|
||||
<Card sx={{ p: 2 }}>
|
||||
<Typography variant="body2" sx={{ fontWeight: 'bold' }}>{item.description}</Typography>
|
||||
<Typography variant="body2" sx={{ color: '#919EAB' }}>{item.code}</Typography>
|
||||
</Card>
|
||||
</Grid>
|
||||
))}
|
||||
</Grid>
|
||||
</Collapse>
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
</TableBody>
|
||||
))}
|
||||
</Table>
|
||||
</TableContainer>
|
||||
</TabPanel>
|
||||
<TabPanel value={currentTab} index={'request'}>
|
||||
<FormRequestLog member={member} handleSubmitSuccess={handleSubmitSuccess} />
|
||||
</TabPanel>
|
||||
</Box>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,322 @@
|
||||
import { LoadingButton } from '@mui/lab';
|
||||
import
|
||||
{
|
||||
Avatar,
|
||||
FormControl,
|
||||
InputLabel,
|
||||
Select,
|
||||
FormHelperText,
|
||||
MenuItem
|
||||
} from '@mui/material';
|
||||
import { Card } from '@mui/material';
|
||||
import { Stack, Typography } from '@mui/material';
|
||||
import axios from '@/utils/axios';
|
||||
import { enqueueSnackbar } from 'notistack';
|
||||
import React, { useRef, useState, useContext, useEffect } from 'react';
|
||||
import { makeFormData } from '@/utils/jsonToFormData';
|
||||
import { format } from 'date-fns';
|
||||
// import { LanguageContext } from '@/contexts/LanguageContext';
|
||||
import Autocomplete from '@mui/material/Autocomplete';
|
||||
import TextField from '@mui/material/TextField';
|
||||
import Button from '@mui/material/Button';
|
||||
import { DatePicker, LocalizationProvider, MobileDatePicker } from '@mui/x-date-pickers';
|
||||
import { AdapterDateFns } from '@mui/x-date-pickers/AdapterDateFns';
|
||||
import { fPostFormat } from '@/utils/formatTime';
|
||||
|
||||
interface MemberType {
|
||||
members: any;
|
||||
services: any;
|
||||
providers:any;
|
||||
companies:any;
|
||||
specialities:any;
|
||||
}
|
||||
interface FormRequestClaimProps {
|
||||
member: MemberType;
|
||||
handleSubmitSuccess: () => void;
|
||||
}
|
||||
export default function FormRequestClaim({ member, handleSubmitSuccess }: FormRequestClaimProps) {
|
||||
// const { localeData }: any = useContext(LanguageContext);
|
||||
const [serviceCode, setServiceCode] = useState<string>('');
|
||||
const [idProvider, setIdProvider] = useState<number>(0);
|
||||
const [idSpecialities, setIdSpecialities] = useState<number>(0);
|
||||
const [inputDppj, setInputDppj] = useState<string>('');
|
||||
//Submission date
|
||||
const [submissionDate, setSubmissionDate] = useState<string>(format(new Date(), "yyyy MMM d HH:mm:ss"));
|
||||
|
||||
const [submitLoading, setSubmitLoading] = useState<boolean>(false);
|
||||
|
||||
const [corporate_id_partner, setCorporateIdPartner] = useState<any>([]);
|
||||
useEffect(() => {
|
||||
setCorporateIdPartner(member?.companies?.map((item: { id: any; name: any; }) => ({ value: item.id, label: item.name })));
|
||||
}, []);
|
||||
const [selectedCorporatID, setSelectedCorporateID] = useState<any>([]);
|
||||
|
||||
const handleSelectChangePatner = (event:any, selectedOptions:any) => {
|
||||
const selectedValues = selectedOptions.map((option: { value: any; }) => option.value);
|
||||
setSelectedCorporateID(selectedValues);
|
||||
};
|
||||
|
||||
function submitRequest() {
|
||||
if(!idProvider&& (name == '' || alamat == ''))
|
||||
{
|
||||
enqueueSnackbar("Mohon masukan provider", { variant: 'warning' });
|
||||
return false;
|
||||
}
|
||||
if(serviceCode == '')
|
||||
{
|
||||
enqueueSnackbar("Mohon pilih layanan", { variant: 'warning' });
|
||||
return false;
|
||||
}
|
||||
if(submissionDate == '')
|
||||
{
|
||||
enqueueSnackbar("Mohon pilih tanggal masuk", { variant: 'warning' });
|
||||
return false;
|
||||
}
|
||||
//cek spesialis
|
||||
if(!idSpecialities)
|
||||
{
|
||||
enqueueSnackbar("Mohon pilih Spesialis", { variant: 'warning' });
|
||||
return false;
|
||||
}
|
||||
//cek dpjp
|
||||
if(!inputDppj)
|
||||
{
|
||||
enqueueSnackbar("Mohon isi DPJP", { variant: 'warning' });
|
||||
return false;
|
||||
}
|
||||
setSubmitLoading(true);
|
||||
const formData = {
|
||||
member_id: member.members.id,
|
||||
service_code: serviceCode,
|
||||
organization_id: idProvider,
|
||||
organization_name : name,
|
||||
address_provider: alamat,
|
||||
submission_date: fPostFormat(submissionDate, 'yyyy-MM-dd HH:mm:ss'),
|
||||
corporate_id_partner: selectedCorporatID,
|
||||
specialities_id: idSpecialities,
|
||||
dppj: inputDppj
|
||||
};
|
||||
axios
|
||||
.post('/request-log', formData)
|
||||
.then((response) => {
|
||||
if (response && response.data && response.data.meta) {
|
||||
setTimeout(() => {
|
||||
window.location.reload();
|
||||
}, 1500);
|
||||
enqueueSnackbar(response.data.meta.message, { variant: 'success' });
|
||||
handleSubmitSuccess();
|
||||
|
||||
}
|
||||
})
|
||||
.catch(({ response }) => {
|
||||
if (response && response.data && response.data.meta) {
|
||||
enqueueSnackbar(response.data.meta.message, { variant: 'error' });
|
||||
}
|
||||
})
|
||||
.then(() => {
|
||||
setSubmitLoading(false);
|
||||
});
|
||||
}
|
||||
|
||||
interface MemberService {
|
||||
service_code: string;
|
||||
name: string;
|
||||
}
|
||||
|
||||
interface Providers {
|
||||
id: number;
|
||||
name: string;
|
||||
}
|
||||
|
||||
interface Specialities {
|
||||
id: number;
|
||||
name: string;
|
||||
}
|
||||
|
||||
const [showAddNewForm, setShowAddNewForm] = useState(false);
|
||||
const [name, setName] = useState('');
|
||||
const [alamat, setAlamat] = useState('');
|
||||
|
||||
const handleAddNewData = () => {
|
||||
// Logika untuk menambahkan data baru ke database
|
||||
// Pastikan untuk menyesuaikan logika ini sesuai dengan kebutuhan aplikasi Anda
|
||||
console.log('Adding new data:', { name, alamat });
|
||||
|
||||
// Setelah menambahkan data baru, Anda mungkin ingin melakukan sesuatu seperti menutup formulir tambahan atau melakukan pengaturan lainnya
|
||||
setShowAddNewForm(false);
|
||||
};
|
||||
|
||||
return (
|
||||
<Stack direction="column" spacing={2}>
|
||||
<Stack direction="row" justifyContent={'end'} sx={{ marginBottom: 2 }} spacing={2}>
|
||||
<Typography variant='body2' sx={{color: '#757575'}}>
|
||||
Tanggal Buat
|
||||
</Typography>
|
||||
<Typography variant='body2' sx={{fontWeight:'bold'}}>{format(new Date(), "d MMM yyyy")}</Typography>
|
||||
</Stack>
|
||||
|
||||
<Stack direction="row" spacing={2}>
|
||||
<Stack spacing={2} sx={{ width: '100%' }}>
|
||||
<Typography variant='subtitle1'>Provider <span style={{ color: 'red' }}>*</span></Typography>
|
||||
<Autocomplete
|
||||
id="provider"
|
||||
options={[{ name: "Tambah Baru", id: 0 }, ...member?.providers || []]}
|
||||
getOptionLabel={(option: Providers) => option.name || ''}
|
||||
value={member?.providers.find((item: Providers) => item.id === idProvider) || null}
|
||||
onChange={(event: React.ChangeEvent<{}>, newValue: Providers | null) => {
|
||||
if (newValue?.id === 0) {
|
||||
// Pengguna memilih opsi "Tambahkan Data Baru"
|
||||
setIdProvider(0); // Reset nilai
|
||||
setShowAddNewForm(true); // Menampilkan formulir tambahan
|
||||
} else {
|
||||
// Pengguna memilih opsi dari hasil pencarian
|
||||
setIdProvider(newValue?.id || 0);
|
||||
setShowAddNewForm(false); // Menyembunyikan formulir tambahan
|
||||
}
|
||||
}}
|
||||
renderInput={(params) => (
|
||||
<TextField
|
||||
{...params}
|
||||
label="Provider"
|
||||
fullWidth
|
||||
/>
|
||||
)}
|
||||
/>
|
||||
{showAddNewForm && (
|
||||
<Stack direction="column" spacing={1} padding={1}>
|
||||
<Typography variant='body2'>Tambah Baru <span style={{ color: 'red' }}>*</span></Typography>
|
||||
<TextField
|
||||
required={true}
|
||||
label="Nama"
|
||||
fullWidth
|
||||
onChange={(e) => setName(e.target.value)}
|
||||
/>
|
||||
<TextField
|
||||
required={true}
|
||||
label="Alamat"
|
||||
fullWidth
|
||||
onChange={(e) => setAlamat(e.target.value)}
|
||||
/>
|
||||
<Autocomplete
|
||||
id="corporate_id_partner"
|
||||
options={corporate_id_partner}
|
||||
getOptionLabel={(option:any) => option.label}
|
||||
value={corporate_id_partner.filter((option: { value: any; }) => selectedCorporatID.includes(option.value))}
|
||||
onChange={handleSelectChangePatner}
|
||||
multiple
|
||||
renderInput={(params) => (
|
||||
<TextField {...params} label="Rekanan" fullWidth />
|
||||
)}
|
||||
/>
|
||||
</Stack>
|
||||
)}
|
||||
<FormHelperText style={{ color: 'red' }}></FormHelperText>
|
||||
</Stack>
|
||||
</Stack>
|
||||
|
||||
<Stack direction="row" spacing={2}>
|
||||
<Stack spacing={2} sx={{ width: '100%' }}>
|
||||
<Typography variant='subtitle1'>Layanan <span style={{ color: 'red' }}>*</span></Typography>
|
||||
<Autocomplete
|
||||
id="service_type"
|
||||
options={member?.services || []}
|
||||
getOptionLabel={(option: MemberService) => option.name || ''}
|
||||
value={member?.services.find((item: MemberService) => item.service_code === serviceCode) || null}
|
||||
onChange={(event: React.ChangeEvent<{}>, newValue: MemberService | null) => {
|
||||
setServiceCode(newValue?.service_code || '');
|
||||
}}
|
||||
renderInput={(params) => (
|
||||
<TextField
|
||||
{...params}
|
||||
label="Layanan"
|
||||
fullWidth
|
||||
/>
|
||||
)}
|
||||
/>
|
||||
<FormHelperText style={{ color: 'red' }}></FormHelperText>
|
||||
</Stack>
|
||||
</Stack>
|
||||
|
||||
{/* Specialist */}
|
||||
<Stack direction="row" spacing={2}>
|
||||
<Stack spacing={2} sx={{ width: '100%' }}>
|
||||
<Typography variant='subtitle1'>Spesialis <span style={{ color: 'red' }}>*</span></Typography>
|
||||
<Autocomplete
|
||||
id='specialities'
|
||||
options={member?.specialities || []}
|
||||
getOptionLabel={(option: Specialities) => option.name || ''}
|
||||
value={member?.specialities.find((item: Specialities) => item.id === idSpecialities) || null}
|
||||
onChange={(event: React.ChangeEvent<{}>, newValue : Specialities | null) => {
|
||||
setIdSpecialities(newValue?.id || 0);
|
||||
}}
|
||||
renderInput={(params) => (
|
||||
<TextField
|
||||
{...params}
|
||||
label="Spesialis"
|
||||
fullWidth
|
||||
/>
|
||||
)}
|
||||
/>
|
||||
<FormHelperText style={{ color: 'red' }}></FormHelperText>
|
||||
</Stack>
|
||||
</Stack>
|
||||
|
||||
<Stack direction="row" spacing={2}>
|
||||
<Stack spacing={2} sx={{ width: '100%' }}>
|
||||
<Typography variant='subtitle1'>DPJP <span style={{ color: 'red' }}>*</span></Typography>
|
||||
<TextField
|
||||
id='dppj'
|
||||
variant='outlined'
|
||||
placeholder="DPJP"
|
||||
onChange={(event) => {
|
||||
setInputDppj(event.target.value);
|
||||
}}
|
||||
fullWidth
|
||||
/>
|
||||
</Stack>
|
||||
</Stack>
|
||||
|
||||
<Stack direction="row" spacing={2}>
|
||||
<Stack spacing={2} sx={{ width: '100%' }}>
|
||||
<Typography variant='subtitle1'>Tanggal Masuk <span style={{ color: 'red' }}>*</span></Typography>
|
||||
<LocalizationProvider dateAdapter={AdapterDateFns}>
|
||||
<DatePicker
|
||||
label="Tanggal Masuk"
|
||||
value={submissionDate}
|
||||
onChange={(newValue:any) => {
|
||||
setSubmissionDate( (newValue));
|
||||
}}
|
||||
inputFormat="dd-MM-yyyy HH:mm"
|
||||
renderInput={(params) => <TextField sx={{width:'45%'}} {...params} required/>}
|
||||
/>
|
||||
</LocalizationProvider>
|
||||
</Stack>
|
||||
</Stack>
|
||||
|
||||
<Card sx={{ p: 1, background: '#f4f6f8'}}>
|
||||
<Stack direction="row">
|
||||
<Avatar
|
||||
src=""
|
||||
alt={member?.members.name ?? ''}
|
||||
sx={{ marginTop: 1, width: 48, height: 48 }}
|
||||
/>
|
||||
<Stack sx={{ p: 1 }}>
|
||||
<Typography variant="body2">{member?.members.name ?? ''}</Typography>
|
||||
<Typography variant="body2" sx={{color:'#637381'}}>{member?.members.member_id ?? ''}</Typography>
|
||||
</Stack>
|
||||
</Stack>
|
||||
</Card>
|
||||
|
||||
<LoadingButton
|
||||
variant="contained"
|
||||
sx={{ marginTop: 2, p: 2, backgroundColor: '#19BBBB' }}
|
||||
onClick={() => {
|
||||
submitRequest();
|
||||
}}
|
||||
loading={submitLoading}
|
||||
>
|
||||
Request LOG
|
||||
</LoadingButton>
|
||||
</Stack>
|
||||
);
|
||||
}
|
||||
@@ -1,7 +1,8 @@
|
||||
import { Card, Stack } from "@mui/material";
|
||||
import { Card, Stack,Grid,Typography,Divider } from "@mui/material";
|
||||
import HeaderBreadcrumbs from "../../../components/HeaderBreadcrumbs";
|
||||
import Page from "../../../components/Page";
|
||||
import List from "./List";
|
||||
import CardSearchMember from "./Components/CardSearchMember";
|
||||
|
||||
|
||||
|
||||
@@ -9,22 +10,32 @@ export default function RequestLog() {
|
||||
|
||||
const pageTitle = 'Request LOG';
|
||||
return (
|
||||
<Page title={ pageTitle } sx={{ mx: 2}}>
|
||||
<Page title={pageTitle} sx={{ mx: 2 }}>
|
||||
<HeaderBreadcrumbs
|
||||
heading={pageTitle}
|
||||
links={[
|
||||
{ name: 'Dashboard', href: '/dashboard' },
|
||||
{ name: 'Request LOG', href: '/customer-service/requests' },
|
||||
]}
|
||||
/>
|
||||
|
||||
<HeaderBreadcrumbs
|
||||
heading={ pageTitle }
|
||||
links={[
|
||||
{ name: 'Dashboard', href: '/dashboard' },
|
||||
{
|
||||
name: 'Request LOG',
|
||||
href: '/customer-service/requests',
|
||||
},
|
||||
]}
|
||||
/>
|
||||
|
||||
{/* <Stack> */}
|
||||
<Stack spacing={3}>
|
||||
<Card sx={{ p: 2 }}>
|
||||
<Typography variant="subtitle1" gutterBottom>
|
||||
Pengajuan Jaminan
|
||||
</Typography>
|
||||
<CardSearchMember />
|
||||
</Card>
|
||||
|
||||
<Card sx={{ p: 2 }}>
|
||||
<Typography variant="subtitle1" gutterBottom>
|
||||
Daftar Request LOG
|
||||
</Typography>
|
||||
<List />
|
||||
{/* </Stack> */}
|
||||
</Page>
|
||||
</Card>
|
||||
</Stack>
|
||||
</Page>
|
||||
|
||||
|
||||
);
|
||||
}
|
||||
|
||||
58
frontend/hospital-portal/src/components/MoreMenu.tsx
Normal file
58
frontend/hospital-portal/src/components/MoreMenu.tsx
Normal file
@@ -0,0 +1,58 @@
|
||||
import Iconify from '@/components/Iconify';
|
||||
import MenuPopover from './MenuPopover';
|
||||
import { IconButton, MenuItem } from '@mui/material';
|
||||
import { useEffect, useState } from 'react';
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
type Props = {
|
||||
actions: React.ReactNode;
|
||||
};
|
||||
|
||||
export default function MoreMenu({ actions }: Props) {
|
||||
const [open, setOpen] = useState<HTMLElement | null>(null);
|
||||
|
||||
// Close menu popover
|
||||
useEffect(() => {
|
||||
setOpen(null);
|
||||
}, [actions])
|
||||
|
||||
const handleOpen = (event: React.MouseEvent<HTMLElement>) => {
|
||||
setOpen(event.currentTarget);
|
||||
};
|
||||
|
||||
const handleClose = () => {
|
||||
setOpen(null);
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
<IconButton onClick={handleOpen}>
|
||||
<Iconify icon={'eva:more-vertical-fill'} width={20} height={20} />
|
||||
</IconButton>
|
||||
|
||||
<MenuPopover
|
||||
open={Boolean(open)}
|
||||
anchorEl={open}
|
||||
onClose={handleClose}
|
||||
anchorOrigin={{ vertical: 'top', horizontal: 'left' }}
|
||||
transformOrigin={{ vertical: 'top', horizontal: 'right' }}
|
||||
arrow="right-top"
|
||||
sx={{
|
||||
mt: -1,
|
||||
width: 'auto',
|
||||
minWidth: 160,
|
||||
'& .MuiMenuItem-root': {
|
||||
px: 1,
|
||||
typography: 'body2',
|
||||
borderRadius: 0.75,
|
||||
'& svg': { mr: 2, width: 20, height: 20 },
|
||||
},
|
||||
}}
|
||||
>
|
||||
{actions}
|
||||
</MenuPopover>
|
||||
|
||||
</>
|
||||
);
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
import { Dialog, DialogTitle, DialogContent, Stack, Typography, IconButton } from '@mui/material';
|
||||
import { Dialog, DialogTitle, DialogContent, Stack, Typography, IconButton, DialogActions } from '@mui/material';
|
||||
import CloseIcon from '@mui/icons-material/Close';
|
||||
import { ReactElement } from 'react';
|
||||
import Iconify from './Iconify';
|
||||
@@ -13,12 +13,13 @@ type MuiDialogProps = {
|
||||
openDialog: boolean;
|
||||
setOpenDialog: Function;
|
||||
content?: ReactElement;
|
||||
action?: ReactElement|null;
|
||||
maxWidth?: string;
|
||||
};
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
const MuiDialog = ({ title, openDialog, setOpenDialog, content, maxWidth }: MuiDialogProps) => {
|
||||
const MuiDialog = ({ title, openDialog, setOpenDialog, content, action, maxWidth }: MuiDialogProps) => {
|
||||
const handleClose = () => {
|
||||
setOpenDialog(false);
|
||||
};
|
||||
@@ -46,9 +47,15 @@ const MuiDialog = ({ title, openDialog, setOpenDialog, content, maxWidth }: MuiD
|
||||
</IconButton>
|
||||
</Stack>
|
||||
</DialogTitle>
|
||||
|
||||
<DialogContent sx={{ backgroundColor: '#F9FAFB' }}>
|
||||
{content ? content : 'Testing Content Dialog'}
|
||||
</DialogContent>
|
||||
|
||||
{action ? (
|
||||
<DialogActions> {action} </DialogActions>
|
||||
) : ''}
|
||||
|
||||
</Dialog>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -80,7 +80,7 @@ export default function NavbarVertical({ isOpenSidebar, onCloseSidebar }: Props)
|
||||
// console.log(data);
|
||||
|
||||
// Pastikan user dan user.permissions terdefinisi dan merupakan array
|
||||
const userPermissions = user?.permissions?.map(permission => permission.name) || [];
|
||||
// const userPermissions = user?.permissions?.map(permission => permission.name) || [];
|
||||
|
||||
// Fungsi untuk memeriksa apakah pengguna memiliki izin untuk item tertentu
|
||||
const hasPermission = (permission) => {
|
||||
@@ -88,37 +88,26 @@ export default function NavbarVertical({ isOpenSidebar, onCloseSidebar }: Props)
|
||||
};
|
||||
|
||||
// Filter data berdasarkan izin pengguna
|
||||
const filteredNavConfig = data.map(section => {
|
||||
if (section.children && section.children.length > 0) {
|
||||
// Cek apakah ada satu atau lebih children yang memiliki izin
|
||||
const filteredChildren = section.children.filter(child => hasPermission(child.permission));
|
||||
const userPermissions =
|
||||
user?.permissions?.map(permission => permission.name) || [];
|
||||
|
||||
if (filteredChildren.length > 0) {
|
||||
return {
|
||||
...section,
|
||||
children: filteredChildren
|
||||
};
|
||||
} else {
|
||||
return null; // Lewati bagian yang tidak memiliki children dengan izin
|
||||
}
|
||||
}
|
||||
// Jika tidak ada children, cek izin untuk section itu sendiri
|
||||
// console.log(section.permission);
|
||||
return hasPermission(section.permission) ? section : null;
|
||||
}).filter(section => section !== null);
|
||||
const filteredNavConfig = data
|
||||
.filter(item =>
|
||||
userPermissions.includes(item.permission) &&
|
||||
item.path && item.path.trim() !== ''
|
||||
)
|
||||
.map(item => ({
|
||||
items: [
|
||||
{
|
||||
title: item.title,
|
||||
path: item.path,
|
||||
icon: ICONS[item.icon],
|
||||
},
|
||||
],
|
||||
}));
|
||||
|
||||
// console.log(filteredNavConfig);
|
||||
setNavConfig(filteredNavConfig);
|
||||
|
||||
const formattedNavConfig = filteredNavConfig.map(item => ({
|
||||
|
||||
items: [{
|
||||
title: item.title,
|
||||
path: item.path,
|
||||
icon: ICONS[item.icon]
|
||||
}]
|
||||
}));
|
||||
|
||||
setNavConfig(formattedNavConfig);
|
||||
|
||||
} catch (error) {
|
||||
console.error('Gagal mengambil konfigurasi navigasi:', error);
|
||||
@@ -127,7 +116,7 @@ export default function NavbarVertical({ isOpenSidebar, onCloseSidebar }: Props)
|
||||
|
||||
fetchNavConfig();
|
||||
}, [user]);
|
||||
console.log(navConfig);
|
||||
// console.log(navConfig);
|
||||
|
||||
useEffect(() => {
|
||||
if (isOpenSidebar) {
|
||||
|
||||
@@ -7,6 +7,7 @@ import Page from '@/components/Page';
|
||||
// theme
|
||||
import CardNotification from '@/sections/dashboard/CardNotification';
|
||||
import CardSearchMember from '@/sections/dashboard/CardSearchMember'
|
||||
import HeaderBreadcrumbs from '@/components/HeaderBreadcrumbs';
|
||||
import { useContext, useEffect, useState } from 'react';
|
||||
import axios from '@/utils/axios';
|
||||
import { Stack } from '@mui/system';
|
||||
@@ -15,6 +16,7 @@ import { Input } from '@mui/material';
|
||||
import TableList from '@/sections/dashboard/TableList';
|
||||
import { fDate } from '@/utils/formatTime';
|
||||
import DialogDetailClaim from '@/components/dialogs/DialogDetailClaim';
|
||||
import useAuth from '@/hooks/useAuth';
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
@@ -60,6 +62,15 @@ const defaultPolicyData = {
|
||||
/* -------------------------------------------------------------------------- */
|
||||
|
||||
export default function Dashboard() {
|
||||
const { user } = useAuth();
|
||||
|
||||
const userPermissions =
|
||||
user?.permissions?.map(permission => permission.name) || [];
|
||||
|
||||
const canSearchMember =
|
||||
userPermissions.includes('request-log-hospital-portal');
|
||||
|
||||
|
||||
const { themeStretch } = useSettings();
|
||||
|
||||
// const [tableData, setTableData] = useState([]);
|
||||
@@ -87,7 +98,24 @@ export default function Dashboard() {
|
||||
<Container maxWidth={themeStretch ? false : 'xl'}>
|
||||
<Grid container spacing={2}>
|
||||
<Grid item xs={12} lg={12} md={12}>
|
||||
<CardSearchMember/>
|
||||
{canSearchMember ? (
|
||||
<CardSearchMember />
|
||||
) : (
|
||||
<HeaderBreadcrumbs
|
||||
heading={'Dashboard'}
|
||||
links={[
|
||||
{
|
||||
name: 'Dashboard',
|
||||
href: '/dashboard',
|
||||
},
|
||||
{
|
||||
name: 'Hospital Portal',
|
||||
href: '/dashboard',
|
||||
},
|
||||
]}
|
||||
/>
|
||||
)}
|
||||
|
||||
</Grid>
|
||||
{/*<Grid item xs={12} lg={6} md={6}>
|
||||
<CardNotification data={itemList} />
|
||||
|
||||
@@ -13,6 +13,7 @@ import { AuthProvider } from '@/contexts/LaravelAuthContext';
|
||||
import AuthGuard from '@/guards/AuthGuard';
|
||||
import useAuth from '@/hooks/useAuth';
|
||||
import RoleBasedGuard from '@/guards/RoleBasedGuard';
|
||||
import DetailRequestFinalLog from '@/sections/dashboard/DetailRequestFinalLog';
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
@@ -116,6 +117,14 @@ export default function Router() {
|
||||
</RoleBasedGuard>
|
||||
),
|
||||
},
|
||||
{
|
||||
path: '/detail-request-final-log/:id',
|
||||
element: (
|
||||
<RoleBasedGuard accessibleRoles={['hospital-admin']}>
|
||||
<DetailRequestFinalLog />
|
||||
</RoleBasedGuard>
|
||||
),
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
|
||||
@@ -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>
|
||||
)
|
||||
|
||||
}
|
||||
@@ -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"
|
||||
/>
|
||||
);
|
||||
}
|
||||
@@ -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"
|
||||
/>
|
||||
);
|
||||
}
|
||||
@@ -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"
|
||||
/>
|
||||
);
|
||||
}
|
||||
@@ -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"
|
||||
/>
|
||||
);
|
||||
}
|
||||
@@ -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"
|
||||
/>
|
||||
);
|
||||
}
|
||||
@@ -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"
|
||||
/>
|
||||
);
|
||||
}
|
||||
@@ -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"
|
||||
/>
|
||||
);
|
||||
}
|
||||
@@ -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"
|
||||
/>
|
||||
);
|
||||
}
|
||||
@@ -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"
|
||||
/>
|
||||
);
|
||||
}
|
||||
@@ -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
@@ -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;
|
||||
}
|
||||
175
frontend/hospital-portal/src/sections/dashboard/Model/Types.ts
Normal file
175
frontend/hospital-portal/src/sections/dashboard/Model/Types.ts
Normal 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,
|
||||
}
|
||||
|
||||
|
||||
@@ -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"
|
||||
/>
|
||||
/>
|
||||
</>
|
||||
);
|
||||
}
|
||||
@@ -68,6 +68,20 @@ export function fPostFormat(date: Date | string | number, dateFormat = 'yyyy-MM-
|
||||
return format(new Date(date), dateFormat);
|
||||
}
|
||||
|
||||
export function fDateTimesecond(date: Date | string | number) {
|
||||
return format(new Date(date), 'dd MMM yyyy HH:mm:ss');
|
||||
}
|
||||
|
||||
export function toTitleCase(str: string | null) {
|
||||
return str.replace(/\w\S*/g, function(txt) {
|
||||
return txt.charAt(0).toUpperCase() + txt.substr(1).toLowerCase();
|
||||
});
|
||||
}
|
||||
|
||||
export function fDateOnly(date: Date | string | number) {
|
||||
return format(new Date(date), 'yyyy-MM-dd');
|
||||
}
|
||||
|
||||
// export function fDateString(date) {
|
||||
// const dateObj = parseISO(date);
|
||||
// const formattedDate = format(dateObj, 'dd MMMM yyyy');
|
||||
|
||||
Reference in New Issue
Block a user