From bf0001ced6f2b3c9deaab549b93182099bfed6ea Mon Sep 17 00:00:00 2001 From: ivan-sim Date: Thu, 26 Oct 2023 11:48:36 +0700 Subject: [PATCH 1/4] Update Logs Claim --- .../Http/Controllers/Api/ClaimRequestController.php | 13 +++++++++++++ .../Http/Controllers/Api/ClaimRequestController.php | 4 +++- .../Http/Controllers/Api/ClaimRequestController.php | 13 +++++++++++++ .../src/pages/ClaimReport/DetailTimeline.tsx | 2 +- .../src/pages/ClaimRequests/DetailTimeline.tsx | 2 +- .../src/sections/dashboard/DetailTimeline.tsx | 2 +- 6 files changed, 32 insertions(+), 4 deletions(-) diff --git a/Modules/Client/Http/Controllers/Api/ClaimRequestController.php b/Modules/Client/Http/Controllers/Api/ClaimRequestController.php index 5d01c090..23dd68f1 100644 --- a/Modules/Client/Http/Controllers/Api/ClaimRequestController.php +++ b/Modules/Client/Http/Controllers/Api/ClaimRequestController.php @@ -68,6 +68,19 @@ class ClaimRequestController extends Controller 'system_origin' => 'client-portal' ]); + // Claim Log + DB::table('claim_logs') + ->insert([ + 'claim_request_id' => $newClaimRequest->id, + 'status' => 'requested', + 'date' => date('Y-m-d H:i:s'), + 'description' => "Claim Requested for Member : {$member->member_id} - ({$member->full_name})", + 'system_origin' => 'hospital-portal', + 'created_by' => auth()->user()->id, + 'created_at' => date('Y-m-d H:i:s'), + 'updated_at'=> date('Y-m-d H:i:s'), + ]); + if ($request->hasFile('laboratorium')) { foreach ($request->laboratorium[$key] as $file) { $pathFile = File::storeFile('claim-result', $newClaimRequest->id, $file); diff --git a/Modules/HospitalPortal/Http/Controllers/Api/ClaimRequestController.php b/Modules/HospitalPortal/Http/Controllers/Api/ClaimRequestController.php index 3bacec67..d0b95cb5 100644 --- a/Modules/HospitalPortal/Http/Controllers/Api/ClaimRequestController.php +++ b/Modules/HospitalPortal/Http/Controllers/Api/ClaimRequestController.php @@ -94,7 +94,9 @@ class ClaimRequestController extends Controller 'date' => date('Y-m-d H:i:s'), 'description' => "Claim Requested for Member : {$member->member_id} - ({$member->full_name})", 'system_origin' => 'hospital-portal', - 'created_by' => auth()->user()->id + 'created_by' => auth()->user()->id, + 'created_at' => date('Y-m-d H:i:s'), + 'updated_at'=> date('Y-m-d H:i:s'), ]); diff --git a/Modules/Internal/Http/Controllers/Api/ClaimRequestController.php b/Modules/Internal/Http/Controllers/Api/ClaimRequestController.php index adf5e3eb..0b7a589a 100644 --- a/Modules/Internal/Http/Controllers/Api/ClaimRequestController.php +++ b/Modules/Internal/Http/Controllers/Api/ClaimRequestController.php @@ -227,6 +227,19 @@ class ClaimRequestController extends Controller 'system_origin' => 'primecenter' ]); + // Claim Log + DB::table('claim_logs') + ->insert([ + 'claim_request_id' => $id, + 'status' => 'reviewed', + 'date' => date('Y-m-d H:i:s'), + 'description' => "Claim Requested Successfully Reviewed", + 'system_origin' => 'prime-center', + 'created_by' => auth()->user()->id, + 'created_at' => date('Y-m-d H:i:s'), + 'updated_at'=> date('Y-m-d H:i:s'), + ]); + } catch (\Exception $e) { return $e->getMessage();; } diff --git a/frontend/client-portal/src/pages/ClaimReport/DetailTimeline.tsx b/frontend/client-portal/src/pages/ClaimReport/DetailTimeline.tsx index b058df06..dd9d682e 100644 --- a/frontend/client-portal/src/pages/ClaimReport/DetailTimeline.tsx +++ b/frontend/client-portal/src/pages/ClaimReport/DetailTimeline.tsx @@ -70,7 +70,7 @@ export default function NoOppositeContent({data}) { - {dataTimeline.date ? format(new Date(dataTimeline.date), "HH : ii") : ''} + {dataTimeline.date ? format(new Date(dataTimeline.date), "HH : mm") : ''} {dataTimeline.txt_status} diff --git a/frontend/dashboard/src/pages/ClaimRequests/DetailTimeline.tsx b/frontend/dashboard/src/pages/ClaimRequests/DetailTimeline.tsx index b058df06..dd9d682e 100644 --- a/frontend/dashboard/src/pages/ClaimRequests/DetailTimeline.tsx +++ b/frontend/dashboard/src/pages/ClaimRequests/DetailTimeline.tsx @@ -70,7 +70,7 @@ export default function NoOppositeContent({data}) { - {dataTimeline.date ? format(new Date(dataTimeline.date), "HH : ii") : ''} + {dataTimeline.date ? format(new Date(dataTimeline.date), "HH : mm") : ''} {dataTimeline.txt_status} diff --git a/frontend/hospital-portal/src/sections/dashboard/DetailTimeline.tsx b/frontend/hospital-portal/src/sections/dashboard/DetailTimeline.tsx index 1e93f302..5e70856b 100644 --- a/frontend/hospital-portal/src/sections/dashboard/DetailTimeline.tsx +++ b/frontend/hospital-portal/src/sections/dashboard/DetailTimeline.tsx @@ -66,7 +66,7 @@ export default function NoOppositeContent({data}) { - {dataTimeline.date ? format(new Date(dataTimeline.date), "HH : ii") : ''} + {dataTimeline.date ? format(new Date(dataTimeline.date), "HH : mm") : ''} {dataTimeline.txt_status} From 1c71edd3ed726e7d60cde64181b3b61597146af9 Mon Sep 17 00:00:00 2001 From: ivan-sim Date: Thu, 26 Oct 2023 17:24:41 +0700 Subject: [PATCH 2/4] Detail Claim Management --- .../Http/Controllers/Api/ClaimController.php | 89 ++++ .../Api/ClaimRequestController.php | 3 +- Modules/Internal/Routes/api.php | 2 + .../src/pages/ClaimReport/Detail.tsx | 2 +- .../src/pages/ClaimRequests/Detail.tsx | 4 +- .../src/pages/ClaimRequests/List.tsx | 2 +- .../dashboard/src/pages/Claims/Detail.tsx | 424 ++++++++++++++++++ frontend/dashboard/src/pages/Claims/List.tsx | 2 +- frontend/dashboard/src/routes/index.tsx | 5 + 9 files changed, 527 insertions(+), 6 deletions(-) create mode 100644 frontend/dashboard/src/pages/Claims/Detail.tsx diff --git a/Modules/Internal/Http/Controllers/Api/ClaimController.php b/Modules/Internal/Http/Controllers/Api/ClaimController.php index 78c739ea..3e220e0b 100644 --- a/Modules/Internal/Http/Controllers/Api/ClaimController.php +++ b/Modules/Internal/Http/Controllers/Api/ClaimController.php @@ -18,6 +18,7 @@ use Modules\Internal\Transformers\ClaimShowResource; use Modules\Internal\Transformers\ClaimEditResource; use Box\Spout\Reader\Common\Creator\ReaderEntityFactory; use Box\Spout\Writer\Common\Creator\WriterEntityFactory; +use Illuminate\Support\Facades\DB; use PDF; @@ -526,4 +527,92 @@ class ClaimController extends Controller "file_url" => url('files/Benefit Usage Report.xlsx') ]); } + + public function getDetailClaims($claim_id) + { + $customer_data = DB::table('claim_requests') + ->leftJoin('claims', 'claim_requests.id', '=', 'claims.claim_request_id') + ->leftJoin('members', 'claim_requests.member_id', '=', 'members.id') + ->leftJoin('corporate_employees', 'members.id', '=', 'corporate_employees.member_id') + ->leftJoin('corporates', 'corporate_employees.corporate_id', '=', 'corporates.id') + ->where('claim_requests.id', '=', $claim_id) + ->select( + 'claim_requests.code', + 'claim_requests.submission_date', + 'claims.status', + 'members.name', + 'members.payor_id', + 'members.member_id', + 'claim_requests.payment_type', + 'corporates.name AS coporate_name', + ) + ->first(); + $results['customer_data'] = $customer_data; + + $documents = DB::table('files') + ->where('fileable_type', 'App\Models\ClaimRequest') + ->where('fileable_id', $claim_id) + ->select('original_name', \DB::raw("CONCAT('" . env('APP_URL') . "/storage/', path) as path"), 'type') + ->orderBy('id', 'desc') + ->get(); + $results['documents'] = $documents; + + $request_documents = DB::table('claim_request_files') + ->where('claim_request_id', $claim_id) + ->get(); + $results['request_documents'] = $request_documents; + + return Helper::responseJson($results); + } + + public function requestDocuments(Request $request) + { + $request->validate([ + 'claim_id' => 'required', + 'note' => 'required', + ]); + + $condition = $request->input('condition'); + $diagnosis = $request->input('diagnosis'); + $result = $request->input('result'); + $note = $request->input('note'); + + $dataToInsert = []; + if ($condition) { + $dataToInsert[] = [ + 'claim_request_id' => $request->claim_id, + 'date' => date('Y-m-d H:i:s'), + 'type' => 'claim-kondisi', + 'description' => $note, + 'created_by' =>auth()->user()->id, + 'created_at' => date('Y-m-d H:i:s'), + 'updated_at' => date('Y-m-d H:i:s'), + ]; + } + if ($diagnosis) { + $dataToInsert[] = [ + 'claim_request_id' => $request->claim_id, + 'date' => date('Y-m-d H:i:s'), + 'type' => 'claim-diagnosis', + 'description' => $note, + 'created_by' =>auth()->user()->id, + 'created_at' => date('Y-m-d H:i:s'), + 'updated_at' => date('Y-m-d H:i:s'), + ]; + } + if ($result) { + $dataToInsert[] = [ + 'claim_request_id' => $request->claim_id, + 'date' => date('Y-m-d H:i:s'), + 'type' => 'claim-result', + 'description' => $note, + 'created_by' =>auth()->user()->id, + 'created_at' => date('Y-m-d H:i:s'), + 'updated_at' => date('Y-m-d H:i:s'), + ]; + } + DB::table('claim_request_files')->insert($dataToInsert); + + return Helper::responseJson([]); + } } diff --git a/Modules/Internal/Http/Controllers/Api/ClaimRequestController.php b/Modules/Internal/Http/Controllers/Api/ClaimRequestController.php index 0b7a589a..1d70f809 100644 --- a/Modules/Internal/Http/Controllers/Api/ClaimRequestController.php +++ b/Modules/Internal/Http/Controllers/Api/ClaimRequestController.php @@ -379,7 +379,8 @@ class ClaimRequestController extends Controller ->leftJoin('corporate_divisions', 'corporate_employees.division_id', '=', 'corporate_divisions.id') ->where('claim_requests.id', '=', $claimRequestId) ->select( - 'claim_requests.submission_date', + 'claim_requests.submission_date', + 'claim_requests.code', DB::raw(' CASE WHEN claim_requests.status = "requested" THEN "requested" diff --git a/Modules/Internal/Routes/api.php b/Modules/Internal/Routes/api.php index a4a57e86..eea89110 100644 --- a/Modules/Internal/Routes/api.php +++ b/Modules/Internal/Routes/api.php @@ -197,6 +197,8 @@ Route::prefix('internal')->group(function () { Route::get('claims/{id}/edit', [ClaimController::class, 'edit']); Route::post('check-limit', [ClaimController::class, 'checkLimit']); Route::get('claims/1/data-claim', [ClaimController::class, 'dataClaimReport']); + Route::get('claims/detail/{id}', [ClaimController::class, 'getDetailClaims']); + Route::post('claims/request-documents', [ClaimController::class, 'requestDocuments']); Route::get('search-organizations', [OrganizationController::class, 'searchOrganization']); Route::get('search-specialities', [SpecialityController::class, 'searchSpeciality']); diff --git a/frontend/client-portal/src/pages/ClaimReport/Detail.tsx b/frontend/client-portal/src/pages/ClaimReport/Detail.tsx index 8fd44714..ec709358 100644 --- a/frontend/client-portal/src/pages/ClaimReport/Detail.tsx +++ b/frontend/client-portal/src/pages/ClaimReport/Detail.tsx @@ -20,7 +20,7 @@ import ArrowBackIosIcon from '@mui/icons-material/ArrowBackIos'; // ---------------------------------------------------------------------- -export default function UserProfile() { +export default function Detail() { const navigate = useNavigate(); const { themeStretch } = useSettings(); const [data, setData] = useState(); diff --git a/frontend/dashboard/src/pages/ClaimRequests/Detail.tsx b/frontend/dashboard/src/pages/ClaimRequests/Detail.tsx index cabc7119..3af03ad6 100644 --- a/frontend/dashboard/src/pages/ClaimRequests/Detail.tsx +++ b/frontend/dashboard/src/pages/ClaimRequests/Detail.tsx @@ -31,7 +31,7 @@ import { enqueueSnackbar } from 'notistack'; // ---------------------------------------------------------------------- -export default function UserProfile() { +export default function Detail() { const location = useLocation(); const queryParams = new URLSearchParams(location.search); const code = queryParams.get('code'); @@ -133,7 +133,7 @@ export default function UserProfile() { navigate(-1)} sx={{cursor:'pointer'}}/> - {code} + {(data && data.data) ? data.data.status.code : ''} {data ? ( Submission Date diff --git a/frontend/dashboard/src/pages/ClaimRequests/List.tsx b/frontend/dashboard/src/pages/ClaimRequests/List.tsx index 00d6057e..c04f8d04 100644 --- a/frontend/dashboard/src/pages/ClaimRequests/List.tsx +++ b/frontend/dashboard/src/pages/ClaimRequests/List.tsx @@ -368,7 +368,7 @@ export default function List() { Edit - navigate ('/claim-requests/detail/'+row.id+'/?code='+row.code)}> + navigate ('/claim-requests/detail/'+row.id+'')}> Detail diff --git a/frontend/dashboard/src/pages/Claims/Detail.tsx b/frontend/dashboard/src/pages/Claims/Detail.tsx new file mode 100644 index 00000000..22ff9ef1 --- /dev/null +++ b/frontend/dashboard/src/pages/Claims/Detail.tsx @@ -0,0 +1,424 @@ +// mui +import { Container, Grid, Stack, Typography, Card, TextField, Divider, ButtonBase, Box, IconButton } from '@mui/material'; +// components +import Page from '../../components/Page'; +// utils +import useSettings from '../../hooks/useSettings'; +// react +import { useNavigate, useParams, useLocation } from 'react-router-dom'; +import { useEffect, useState, useRef } from 'react'; +import axios from '../../utils/axios'; +// pages +import DetailTimeline from '../../pages/ClaimRequests/DetailTimeline'; +import DetailStepper from '../../pages/ClaimRequests/DetailStepper'; +import { format } from 'date-fns'; +import ArrowBackIosIcon from '@mui/icons-material/ArrowBackIos'; +import Button from '@mui/material/Button'; +import AddIcon from '@mui/icons-material/Add'; +import RemoveIcon from '@mui/icons-material/Remove'; +import { DatePicker, LocalizationProvider } from '@mui/x-date-pickers'; +import { AdapterDateFns } from '@mui/x-date-pickers/AdapterDateFns'; +import Iconify from '@/components/Iconify'; +import { fPostFormat } from '@/utils/formatTime'; +import InsertDriveFileIcon from '@mui/icons-material/InsertDriveFile'; +import DownloadIcon from '@mui/icons-material/Download'; +import { Dialog, DialogTitle, DialogContent, DialogActions } from '@mui/material'; +import CloseIcon from '@mui/icons-material/Close'; +import { fDateTimesecond } from '@/utils/formatTime'; +import { makeFormData } from '@/utils/jsonToFormData'; +import FormGroup from '@mui/material/FormGroup'; +import FormControlLabel from '@mui/material/FormControlLabel'; +import Checkbox from '@mui/material/Checkbox'; + +import { enqueueSnackbar } from 'notistack'; + +// ---------------------------------------------------------------------- + +export default function Detail() { + const location = useLocation(); + const queryParams = new URLSearchParams(location.search); + const code = queryParams.get('code'); + + const navigate = useNavigate(); + const { themeStretch } = useSettings(); + const [data, setData] = useState(); + const [dataDialog, setDataDialog] = useState(); + const [customerData, setCustomerData] = useState(null); + const [documentData, setDocumentData] = useState(null); + const [requestDocumentData, setRequestDocumentData] = useState(null); + + const { id } = useParams(); + + useEffect(() => { + axios + .get('/claims/detail/'+id) + .then((response) => { + setCustomerData(response.data.data.customer_data); + setDocumentData(response.data.data.documents); + setRequestDocumentData(response.data.data.request_documents); + }) + .catch((error) => { + console.error(error); + }); + + }, []); + + const [isInvoiceVisible, setInvoiceVisibility] = useState(false); + + const handleInvoice = () => { + setInvoiceVisibility(!isInvoiceVisible); + } + const currentDate = new Date(); + const formattedCurrentDate = format(currentDate, 'dd MMM yyyy'); + const [dateInvoice, setDateInvoice] = useState(currentDate); + + const fileInvoiceInput = useRef(null); + const [fileInvoices, setFileInvoices] = useState([]); + + const handleInvoiceInputChange = (event) => { + if (event.target.files[0]) { + setFileInvoices([...fileInvoices, ...event.target.files]); + } else { + console.log('NO FILE'); + } + }; + const removeInvoiceFiles = (filesState, index) => { + setFileInvoices( + filesState.filter((file, fileIndex) => { + return fileIndex != index; + }) + ); + }; + const date = dateInvoice ? fPostFormat(dateInvoice, 'yyyy-MM-dd') : null; + + const [openDialogSubmit, setOpenDialogSubmit] = useState(false); + const handleCloseDialogSubmit = () => { + setOpenDialogSubmit(false); + } + const handleSubmitData = () => { + if(fileInvoices.length > 0) + { + //submit data + axios + .post('claim-requests/'+id+'/approve') + .then((response) => { + enqueueSnackbar('Success Submit Claim Request', { variant: 'success' }); + setOpenDialogSubmit(false); + }) + .catch(({ response }) => { + enqueueSnackbar(response.data.message ?? 'Something went wrong!', { variant: 'error' }); + }); + //Upload file invoices + const formData = makeFormData({ + date:date, + invoice_files: fileInvoices, + }); + axios + .post('claim-requests/'+id+'/invoice-files', formData) + .then((response) => { + enqueueSnackbar(response.data.message ?? 'Success upload invoice', { variant: 'success' }); + }) + .catch(({ response }) => { + enqueueSnackbar(response.data.message ?? 'Something Went Wrong', { variant: 'error' }); + }); + } + else + { + enqueueSnackbar('Please upload file invoice, before submit', { variant: 'warning' }); + } + + setTimeout(() => + { + window.location.reload(); + }, 5000); + + }; + + function toTitleCase(str) { + return str.replace(/\w\S*/g, function(txt) { + return txt.charAt(0).toUpperCase() + txt.substr(1).toLowerCase(); + }); + } + + const style1 = { + color: '#919EAB', + width: '30%' + } + const style2 = { + width: '70%' + } + const marginBottom1 = { + marginBottom: 1, + } + + const [openDialogRequest, setOpenDialogRequest] = useState(false); + const handleCloseDialogUpdate = () => { + setOpenDialogRequest(false); + } + + const [conditionChecked, setConditionChecked] = useState(true); + const [diagnosisChecked, setDiagnosisChecked] = useState(false); + const [supportingResultChecked, setSupportingResultChecked] = useState(false); + + const handleConditionChange = (event) => { + setConditionChecked(event.target.checked); + }; + + const handleDiagnosisChange = (event) => { + setDiagnosisChecked(event.target.checked); + }; + + const handleSupportingResultChange = (event) => { + setSupportingResultChecked(event.target.checked); + }; + + const [noteField, setNoteField] = useState(''); + const [noteFieldError, setNoteFieldError] = useState(''); + const isRequiredFieldsFilled = () => { + return noteField.trim() !== ''; + }; + + const handelRequestDocument = () => { + const dataForm = { + claim_id: id, + condition: conditionChecked, + diagnosis: diagnosisChecked, + result: supportingResultChecked, + note: noteField, + } + axios + .post('/claims/request-documents', dataForm) + .then((response) => { + enqueueSnackbar('Success Request Document', { variant: 'success' }); + setOpenDialogRequest(false); + window.location.reload(); + }) + .catch((error) => { + enqueueSnackbar('Something Went Wrong', { variant: 'error' }); + }) + } + + return ( + + + + navigate(-1)} sx={{cursor:'pointer'}}/> + {(customerData && customerData.code ? customerData.code : '')} + {customerData ? ( + + + Status + {(customerData && customerData.status) ? toTitleCase(customerData.status) : ''} + + + Submission Date + {(customerData && customerData.submission_date) ? format(new Date(customerData.submission_date), "d MMM yyyy") : ''} + + + ) : ''} + + + {customerData ? ( + + + Summary of Customer Data + + Full Name + {customerData.name} + + + Policy Number + {customerData.payor_id} + + + Member ID + {customerData.member_id} + + + Claim Type + {toTitleCase(customerData.payment_type)} + + + Corporate Name + {toTitleCase(customerData.coporate_name)} + + + + ) : ''} + {documentData ? ( + + + + Additional Documents + + + + {documentData?.map((documentType, index) => ( + + + {documentType.type === 'claim-diagnosis' ? + 'Diagnosis' + : documentType.type === 'claim-kondisi' ? + 'Condition' + : documentType.type === 'claim-result' ? + 'Supporting Result' + : documentType.type === 'claim-invoice' ? + 'Invoice' + : ''} + + + + + {documentType.original_name ? documentType.original_name : '-'} + + + + ))} + + {requestDocumentData && requestDocumentData.length > 0 ? ( + Request Documents + ) : ''} + + {requestDocumentData?.map((documentType, index) => ( + + + + + + {documentType.type === 'claim-diagnosis' ? + 'Diagnosis' + : documentType.type === 'claim-kondisi' ? + 'Condition' + : documentType.type === 'claim-result' ? + 'Supporting Result' + : documentType.type === 'claim-invoice' ? + 'Invoice' + : ''} + + + + ))} + + + + + + Request Document + + + + + + + + + + } + label="Condition Document" + /> + } + label="Diagnosis Document" + /> + } + label="Supporting Result Document" + /> + + { + setNoteField(e.target.value); + setNoteFieldError(e.target.value.trim() === '' ? 'This field is required' : ''); + }} + fullWidth + inputProps={{ maxLength: 50 }} + error={!!noteFieldError} + helperText={noteFieldError} + /> + + + + + + + + + + ): ''} + + + + History of Hospital Care + + + + + + + + + + Diagnostic History + + + + + + + + + Diagnosis Summary + + + + + + + + + + Service + + + + + + + + + + Client Benefit Configuration + + + + + + + + <> + + + + + + + + + ); +} \ No newline at end of file diff --git a/frontend/dashboard/src/pages/Claims/List.tsx b/frontend/dashboard/src/pages/Claims/List.tsx index 91c0d5ae..5e1d01fd 100644 --- a/frontend/dashboard/src/pages/Claims/List.tsx +++ b/frontend/dashboard/src/pages/Claims/List.tsx @@ -208,7 +208,7 @@ export default function List() { Edit - setOpen(!open) }> + navigate('/claims/detail/'+row.id+'') }> Detail diff --git a/frontend/dashboard/src/routes/index.tsx b/frontend/dashboard/src/routes/index.tsx index 2b4a159b..ecb870c0 100644 --- a/frontend/dashboard/src/routes/index.tsx +++ b/frontend/dashboard/src/routes/index.tsx @@ -393,6 +393,10 @@ export default function Router() { path: 'claims/edit/:id', element: , }, + { + path: 'claims/detail/:id', + element: , + }, { path: 'claims/:id', element: , @@ -559,6 +563,7 @@ const Profile = Loadable(lazy(() => import('../pages/Profile/Index'))); const Claims = Loadable(lazy(() => import('../pages/Claims/Index'))); const ClaimsCreate = Loadable(lazy(() => import('../pages/Claims/CreateUpdate'))); +const ClaimsDetail = Loadable(lazy(() => import('../pages/Claims/Detail'))); const ClaimShow = Loadable(lazy(() => import('../pages/Claims/Show'))); const ClaimRequests = Loadable(lazy(() => import('../pages/ClaimRequests/Index'))); From 010e971b69a5dc882ebc5364c68821d73f882868 Mon Sep 17 00:00:00 2001 From: adibwp Date: Thu, 26 Oct 2023 17:43:47 +0700 Subject: [PATCH 3/4] add list master formularium --- .../layouts/dashboard/navbar/NavConfig.tsx | 2 +- .../Corporates/Formularium/New/History.tsx | 2 +- .../Formularium/Master/CreateUpdate.tsx | 1 + .../Master/FormulariumV2/CreateUpdate.tsx | 69 +++++ .../Master/FormulariumV2/CreateUpdateForm.tsx | 143 +++++++++ .../FormulariumV2/Detail/Formularium.tsx | 289 ++++++++++++++++++ .../Master/FormulariumV2/Detail/Index.tsx | 37 +++ .../Master/FormulariumV2/FormulariumRow.tsx | 48 +++ .../pages/Master/FormulariumV2/History.tsx | 211 +++++++++++++ .../src/pages/Master/FormulariumV2/Index.tsx | 33 ++ .../src/pages/Master/FormulariumV2/List.tsx | 172 +++++++++++ .../src/pages/Master/FormulariumV2/Type.ts | 31 ++ frontend/dashboard/src/routes/index.tsx | 25 ++ 13 files changed, 1061 insertions(+), 2 deletions(-) create mode 100644 frontend/dashboard/src/pages/Master/FormulariumV2/CreateUpdate.tsx create mode 100644 frontend/dashboard/src/pages/Master/FormulariumV2/CreateUpdateForm.tsx create mode 100644 frontend/dashboard/src/pages/Master/FormulariumV2/Detail/Formularium.tsx create mode 100644 frontend/dashboard/src/pages/Master/FormulariumV2/Detail/Index.tsx create mode 100644 frontend/dashboard/src/pages/Master/FormulariumV2/FormulariumRow.tsx create mode 100644 frontend/dashboard/src/pages/Master/FormulariumV2/History.tsx create mode 100644 frontend/dashboard/src/pages/Master/FormulariumV2/Index.tsx create mode 100644 frontend/dashboard/src/pages/Master/FormulariumV2/List.tsx create mode 100644 frontend/dashboard/src/pages/Master/FormulariumV2/Type.ts diff --git a/frontend/dashboard/src/layouts/dashboard/navbar/NavConfig.tsx b/frontend/dashboard/src/layouts/dashboard/navbar/NavConfig.tsx index 6ecadc09..70aa3a2b 100644 --- a/frontend/dashboard/src/layouts/dashboard/navbar/NavConfig.tsx +++ b/frontend/dashboard/src/layouts/dashboard/navbar/NavConfig.tsx @@ -53,7 +53,7 @@ const navConfig = [ children: [ { title: 'Corporate', path: '/corporates' }, // { title: 'Corporate Create', path: '/corporates/create' }, - { title: 'Formularium', path: '/master/formularium-template' }, + { title: 'Formularium', path: '/master/formularium-template-v2' }, { title: 'Master ICD-10 Diagnosis', path: '/master/diagnosis-template' }, { title: 'Hospitals', path: '/hospitals' }, ], diff --git a/frontend/dashboard/src/pages/Corporates/Formularium/New/History.tsx b/frontend/dashboard/src/pages/Corporates/Formularium/New/History.tsx index 1a4b4eb2..95f83d2c 100644 --- a/frontend/dashboard/src/pages/Corporates/Formularium/New/History.tsx +++ b/frontend/dashboard/src/pages/Corporates/Formularium/New/History.tsx @@ -200,7 +200,7 @@ import { } else { return ( - {`${field}`} + {`${field}`} {`${value}`} {renderedValue} diff --git a/frontend/dashboard/src/pages/Master/Formularium/Master/CreateUpdate.tsx b/frontend/dashboard/src/pages/Master/Formularium/Master/CreateUpdate.tsx index 5aaaf2eb..29cd5cb4 100644 --- a/frontend/dashboard/src/pages/Master/Formularium/Master/CreateUpdate.tsx +++ b/frontend/dashboard/src/pages/Master/Formularium/Master/CreateUpdate.tsx @@ -21,6 +21,7 @@ export default function PlanCreate() { useEffect(() => { setCorporate(configuredCorporateContext.currentCorporate); + console.log(configuredCorporateContext.currentCorporate); }, [configuredCorporateContext]) const [ currentCorporatePlan, setCurrentCorporatePlan ] = useState(); diff --git a/frontend/dashboard/src/pages/Master/FormulariumV2/CreateUpdate.tsx b/frontend/dashboard/src/pages/Master/FormulariumV2/CreateUpdate.tsx new file mode 100644 index 00000000..2e1aa7f7 --- /dev/null +++ b/frontend/dashboard/src/pages/Master/FormulariumV2/CreateUpdate.tsx @@ -0,0 +1,69 @@ +import { useNavigate, useParams } from "react-router-dom"; +import HeaderBreadcrumbs from "../../../components/HeaderBreadcrumbs"; +import Page from "../../../components/Page"; +import useSettings from "../../../hooks/useSettings"; +import {useContext, useEffect, useMemo, useState } from 'react'; +import axios from '../../../utils/axios'; +import { useSnackbar } from 'notistack'; +import { ConfiguredCorporateContext } from "@/contexts/ConfiguredCorporateContext"; +import { Corporate, CorporatePlan } from "@/@types/corporates"; +import { MasterFormularium } from "./Type"; +import CreateUpdateForm from "./CreateUpdateForm"; +import Typography from "@/theme/overrides/Typography"; + +export default function CreateUpdate() { + const navigate = useNavigate(); + const { corporate_id, id } = useParams(); + const [corporate, setCorporate] = useState(); + const configuredCorporateContext = useContext(ConfiguredCorporateContext) + + useEffect(() => { + setCorporate(configuredCorporateContext.currentCorporate); + }, [ConfiguredCorporateContext]) + + const [ currentCorporatePlan, setCurrentCorporatePlan ] = useState(); + const [ currentMasterForm, setCurrentMasterForm ] = useState(); + const isEdit = !!id; + + useEffect(() => { + if (isEdit) { + axios.get(`/master/formularium-template/${id}/edit`) + .then((res) => { + // setCurrentCorporatePlan(res.data); + setCurrentMasterForm(res.data); + }) + .catch((err) => { + if (err.response.status === 404) { + navigate('/404'); + } + }) + } + }, [corporate_id, id]) + + const pageType = !isEdit ? "Create" : "Edit" + const pageTitle = `Master Formularium ${pageType}` + return ( + + + + + + + ) +} \ No newline at end of file diff --git a/frontend/dashboard/src/pages/Master/FormulariumV2/CreateUpdateForm.tsx b/frontend/dashboard/src/pages/Master/FormulariumV2/CreateUpdateForm.tsx new file mode 100644 index 00000000..b93d3bfd --- /dev/null +++ b/frontend/dashboard/src/pages/Master/FormulariumV2/CreateUpdateForm.tsx @@ -0,0 +1,143 @@ +import * as Yup from 'yup'; +import { LoadingButton } from "@mui/lab"; +import { Button, Card, Grid, Stack, Typography } from "@mui/material"; +import { CorporatePlan } from "../../../@types/corporates"; +import { FormProvider, RHFSwitch, RHFTextField } from "../../../components/hook-form"; +import { useEffect, useMemo } from 'react'; +import { useForm } from 'react-hook-form'; +import { yupResolver } from '@hookform/resolvers/yup'; +import { useSnackbar } from 'notistack'; +import { useNavigate, useParams } from 'react-router-dom'; +import axios from '../../../utils/axios'; +import { MasterFormularium } from "./Type"; + + +type Props = { + isEdit: boolean; + currentMasterForm?: MasterFormularium; +}; + +export default function CreateUpdateForm({ isEdit, currentMasterForm }: Props) { + const navigate = useNavigate(); + const { enqueueSnackbar } = useSnackbar(); + + const NewCorporatePlanSchema = Yup.object().shape({ + name: Yup.string().required('Name is required'), + }); + + const defaultValues = useMemo( + () => ({ + name: currentMasterForm?.name || '', + description: currentMasterForm?.description || '', + }), + [currentMasterForm] + ) + + useEffect(() => { + if (isEdit && currentMasterForm) { + reset(defaultValues); + } + if (!isEdit) { + reset(defaultValues); + } + }, [isEdit, currentMasterForm]) + + const methods = useForm({ + resolver: yupResolver(NewCorporatePlanSchema), + defaultValues, + }) + + const { + reset, + setError, + handleSubmit, + formState: { isSubmitting } + } = methods; + + const onSubmit = async (data: any) => { + if (!isEdit) { + await axios + .post('/master/formularium-template/store', data) + .then((res) => { + enqueueSnackbar('Formularium created succesfully', {variant: 'success'}); + }) + .then((res) => { + navigate('/master/formularium-template-v2', { replace: true }); + }) + .catch(({ response }) => { + if (response.status === 422) { + for (const [key, value] of Object.entries(response.data.errors)) { + setError(key, { message: value[0] }); + enqueueSnackbar(value[0] ?? 'Failed Processing Reques', { variant: 'error' }); + } + } + else { + enqueueSnackbar('Create Failed : ' + response.data.message, {variant: 'error'}); + } + }); + } else { + await axios + .put(`/master/formularium-template/${currentMasterForm?.id}/update`, data) + .then((res) => { + enqueueSnackbar('Formularium updated successfully', { variant: 'success' }); + }) + .then((res) => { + navigate('/master/formularium-template-v2', { replace: true }); + }) + .catch(({ response }) => { + enqueueSnackbar(`Update Failed : ${response.data.message}`, { variant: 'error' }) + }) + } + } + + return ( + + + + + + Detail + Name* + + Description* + + + + + + + + { isEdit? 'Update' : 'Create' } + + + + + + + ) +} \ No newline at end of file diff --git a/frontend/dashboard/src/pages/Master/FormulariumV2/Detail/Formularium.tsx b/frontend/dashboard/src/pages/Master/FormulariumV2/Detail/Formularium.tsx new file mode 100644 index 00000000..d340f412 --- /dev/null +++ b/frontend/dashboard/src/pages/Master/FormulariumV2/Detail/Formularium.tsx @@ -0,0 +1,289 @@ +// @mui +import { Box, Button, Card, Collapse, IconButton, InputLabel, MenuItem, OutlinedInput, Paper, Grid, Select, SelectChangeEvent, Table, TableBody, TableCell, TableContainer, TableHead, TableRow, TextField, Typography, Badge, Tab, Tabs, CardHeader, Stack, Menu, ButtonGroup, Pagination } from '@mui/material'; +import KeyboardArrowDownIcon from '@mui/icons-material/KeyboardArrowDown'; +import KeyboardArrowRightIcon from '@mui/icons-material/KeyboardArrowRight'; +import AddIcon from '@mui/icons-material/Add'; +import UploadIcon from '@mui/icons-material/Upload'; +import CancelIcon from '@mui/icons-material/Cancel'; +// hooks +import React, { ChangeEvent, Component, useEffect, useRef, useState } from 'react'; +import useSettings from '../../../../hooks/useSettings'; +import { useNavigate, useParams, useSearchParams } from 'react-router-dom'; +// components +import axios from '../../../../utils/axios'; +import { LaravelPaginatedData } from '../../../../@types/paginated-data'; +import { Icd } from '../../../../@types/diagnosis'; +import BasePagination from '../../../../components/BasePagination'; +import { enqueueSnackbar } from 'notistack'; + + +export default function List() { + const navigate = useNavigate(); + const { master_formularium_id } = useParams(); + const [searchParams, setSearchParams] = useSearchParams(); + const [importResult, setImportResult] = useState(null); + + function SearchInput(props: any) { + const searchInput = useRef(null); + const [searchText, setSearchText] = useState(""); + + const handleSearchChange = (event: any) => { + const newSearchText = event.target.value ?? '' + setSearchText(newSearchText); + } + + const handleSearchSubmit = (event: any) => { + event.preventDefault(); + props.onSearch(searchText); + } + + useEffect(() => { + setSearchText(searchParams.get('search') ?? ''); + }, [searchParams]) + + return ( +
+ + + ); + } + + function ImportForm( props: any ) { + const [anchorEl, setAnchorEl] = React.useState(null); + const createMenu = Boolean(anchorEl); + const importForm = useRef(null) + const [currentImportFileName, setCurrentImportFileName] = useState(null) + + const handleClick = (event: React.MouseEvent) => { + setAnchorEl(event.currentTarget); + }; + + const handleClose = () => { + setAnchorEl(null); + }; + + const handleImportButton = () => { + if (importForm?.current) { + handleClose(); + importForm.current ? importForm.current.click() : console.log('No File selected'); + } else { + alert('No file selected') + } + } + + const handleCancelImportButton = () => { + importForm.current.value = ''; + importForm.current?.dispatchEvent(new Event('change', { bubbles: true })) + } + + const handleGetTemplate = (type: string) => { + axios.get('corporate/import-document-example/' + type) + .then((response) => { + const link = document.createElement('a'); + link.href = response.data.data.file_url; + link.setAttribute('download', response.data.data.file_name); + document.body.appendChild(link); + link.click(); + handleClose(); + }) + } + + const handleImportChange = (event: any) => { + if (event.target.files[0]) { + setCurrentImportFileName(event.target.files[0].name) + } else { + setCurrentImportFileName(null); + } + } + + const handleFormulariumList = async (appliedFilter = null) => { + axios.get(`master/formulariums/${master_formularium_id}/list`) + .then((response) => { + const link = document.createElement('a'); + link.href = response.data.data.file_url; + link.setAttribute('download', response.data.data.file_name); + document.body.appendChild(link); + link.click(); + handleClose(); + enqueueSnackbar('Download Success', { variant: 'success' }) + }) + .catch(response => { + enqueueSnackbar('Looks like something went wrong. Please check your data and try again. ' + response.message, { variant: 'error' }) + }); + } + + const handleUpload = () => { + if (importForm.current?.files?.length) { + const formData = new FormData(); + formData.append('file', importForm.current?.files[0]) + axios.post(`master/formularium/${master_formularium_id}/import`, formData ) + .then(response => { + handleCancelImportButton(); + loadDataTableData(); + setImportResult(response.data); + }) + .catch(response => { + enqueueSnackbar('Looks like something went wrong. Please check your data and try again. ' + response.message, { variant: 'error' }) + }) + } else { + enqueueSnackbar(`No File Selected`, { variant: 'warning' }) + } + } + + return ( +
+ + {(!currentImportFileName && + + + + handleImportButton}>Import + handleGetTemplate('master-formularium')}>Download Template + handleFormulariumList()}>Download Formularium + + + )} + {( currentImportFileName && + + + + + + + )} + {( importResult && + + Last Import Result Report : {importResult.result_file?.name ?? "-"} + + )} +
+ ); + } + + // Default data + const [dataTableRow, setDataTableRow] = useState<[] | null>(null) + const [dataTableIsLoading, setDataTableLoading] = useState(true); + const [dataTableData, setDataTableData] = useState({ + current_page: 1, + data: [], + path: "", + first_page_url: "", + last_page: 1, + last_page_url: "", + next_page_url: "", + prev_page_url: "", + per_page: 10, + from: 0, + to: 0, + total: 0 + }); + + const loadDataTableData = async (appliedFilter : any | null = null) => { + setDataTableLoading(true); + const filter = appliedFilter ? appliedFilter : Object.fromEntries([...searchParams.entries()]); + const response = await axios.get(`/master/formulariums/${master_formularium_id}`, { params: filter }); + setDataTableLoading(false); + + setDataTableData(response.data) + setDataTableRow(response.data.data) + } + + const applyFilter = async (searchFilter: string) => { + await loadDataTableData({ 'search': searchFilter }); + setSearchParams({ 'search' : searchFilter }); + } + + const handlePageChange = (event : ChangeEvent, value: number) => { + const filter = Object.fromEntries([...searchParams.entries(), ['page', value]]); + loadDataTableData(filter); + setSearchParams(filter); + } + + useEffect(() => { + loadDataTableData(); + }, []) + + const headStyle = { + fontWeight: 'bold', + }; + + return ( + + + + + + + + + Code + ATC Code + Name + Category Name + UOM + + + +
+
+ + +
+
+ ) +} \ No newline at end of file diff --git a/frontend/dashboard/src/pages/Master/FormulariumV2/Detail/Index.tsx b/frontend/dashboard/src/pages/Master/FormulariumV2/Detail/Index.tsx new file mode 100644 index 00000000..17345616 --- /dev/null +++ b/frontend/dashboard/src/pages/Master/FormulariumV2/Detail/Index.tsx @@ -0,0 +1,37 @@ +import { Card, Grid } from "@mui/material"; +import { useParams } from "react-router-dom"; +import HeaderBreadcrumbs from "../../../../components/HeaderBreadcrumbs"; +import Page from "../../../../components/Page"; +import useSettings from "../../../../hooks/useSettings"; +import List from "./Formularium"; + + +export default function Formularium() { + const pageTitle = "Formularium" + const { id } = useParams(); + + return ( + + + + + + + ) +} \ No newline at end of file diff --git a/frontend/dashboard/src/pages/Master/FormulariumV2/FormulariumRow.tsx b/frontend/dashboard/src/pages/Master/FormulariumV2/FormulariumRow.tsx new file mode 100644 index 00000000..24225cfd --- /dev/null +++ b/frontend/dashboard/src/pages/Master/FormulariumV2/FormulariumRow.tsx @@ -0,0 +1,48 @@ +import TableMoreMenu from "@/components/table/TableMoreMenu" +import EditOutlinedIcon from '@mui/icons-material/EditOutlined'; +import CachedOutlinedIcon from '@mui/icons-material/CachedOutlined'; +import HistoryIcon from '@mui/icons-material/History'; +import FindInPageOutlinedIcon from '@mui/icons-material/FindInPageOutlined'; +import { Collapse, Grid, MenuItem, Paper, Table, TableCell, TableContainer, TableHead, TableRow } from "@mui/material" +import React, { useEffect } from "react"; +import axios from "@/utils/axios"; +import { useNavigate, useParams } from "react-router-dom"; +import { MasterFormularium } from "./Type"; + +type Props = { + props: MasterFormularium +} + +export default function FormulariumRow({props} : Props) { + const navigate = useNavigate(); + + return ( + + + {props.name} + {props.description} + + + navigate(`/master/formularium-template-v2/${props.id}/detail`)}> + + Detail + + navigate(`/master/formularium-template-v2/${props.id}/edit`)}> + + Edit + + + + Update Status + + navigate(`/master/formularium-template-v2/${props.id}/history`)}> + + History + + + } /> + + + ) +} \ No newline at end of file diff --git a/frontend/dashboard/src/pages/Master/FormulariumV2/History.tsx b/frontend/dashboard/src/pages/Master/FormulariumV2/History.tsx new file mode 100644 index 00000000..ca991be6 --- /dev/null +++ b/frontend/dashboard/src/pages/Master/FormulariumV2/History.tsx @@ -0,0 +1,211 @@ +// @mui +import { + Box, + Button, + Card, + Collapse, + Container, + FormControl, + Grid, + IconButton, + InputLabel, + MenuItem, + OutlinedInput, + Paper, + Select, + SelectChangeEvent, + Table, + TableBody, + TableCell, + TableContainer, + TableHead, + TableRow, + TextField, + Typography, + Badge, + Stack, + } from '@mui/material'; + import * as React from 'react'; +import { useParams } from 'react-router-dom'; +import { styled } from '@mui/material/styles'; +import ArrowForwardIosSharpIcon from '@mui/icons-material/ArrowForwardIosSharp'; +import MuiAccordion, { AccordionProps } from '@mui/material/Accordion'; +import { useContext, useEffect, useState } from 'react'; +import MuiAccordionSummary, { + AccordionSummaryProps, +} from '@mui/material/AccordionSummary'; +import useSettings from '../../../hooks/useSettings'; +import axios from '../../../utils/axios'; +import { ConfiguredCorporateContext } from '@/contexts/ConfiguredCorporateContext'; +import MuiAccordionDetails from '@mui/material/AccordionDetails'; +import HeaderBreadcrumbs from '../../../components/HeaderBreadcrumbs'; +import { Corporate } from '@/@types/corporates'; +import { fDate, fDateTime } from '@/utils/formatTime'; + + +const Accordion = styled((props: AccordionProps) => ( + +))(({ theme }) => ({ + border: `1px solid ${theme.palette.divider}`, + "&:not(:last-child)": { + borderBottom: 0, + }, + "&:before": { + display: 'none' + }, +})); + +const AccordionSummary = styled((props: AccordionSummaryProps) => ( + } + {...props} + /> +))(({ theme }) => ({ + backgroundColor: theme.palette.mode === 'dark' + ? 'rgba(255,255,255,0.5)' + : 'rgba(0,0,0,.03)', + flexDirection: 'row-reverse', + "& .MuiAccordionSummary-expandIconWrapper.Mui-expanded": { + transform: 'rotate(90dg)', + }, + "& .MuiAccordionSummary=content": { + marginLeft: theme.spacing(1), + }, +})); + +const AccordionDetails = styled(MuiAccordionDetails)(({ theme }) => ({ + padding: theme.spacing(2), + borderTop: '1px solid rgba(0,0,0,.125)', +})); + +export default function MasterFormulariumHistory() { + const [expanded, setExpanded] = React.useState('panel1'); + + const handleChange = (panel: string) => (event: React.SyntheticEvent, newExpanded: boolean) => { + setExpanded(newExpanded ? panel : false); + }; + const pageTitle = 'Master Formularium History' + const { id } = useParams(); + const { corporate_id } = useParams(); + const [corporate, setCorporate] = useState(); + const [currentCorporate, setCurrentCorporate] = useState(); + const configuredCorporateContext = useContext(ConfiguredCorporateContext); + + useEffect(() => { + setCorporate(configuredCorporateContext.currentCorporate); + const model = 'App\\Models\\FormulariumTemplate'; + const url = `/audittrail/${id}?model=${model}`; + axios.get(url) + .then((res) => { + setCurrentCorporate(res.data); + }) + .catch((error) => { + console.error('Terjadi kesalahan: ', error); + }); + }, [configuredCorporateContext]) + + return ( +
+ + {currentCorporate?.data.map((item, index) => ( + + + {`Data has ${item.action} by ${item.user_id} on ${fDateTime(item.updated_at)}`} + + + + + + + Field + Old Value + New Values + + + + {Object.entries(item.old_values).map(([key, value]) => { + let renderedValue; + if (key === 'deleted_by' || + key === 'deleted_at' || + key === 'created_by' || + key === 'created_at' || + key === 'updated_by' || + key === 'description' + ) { + return null; // Melewati iterasi saat key adalah 'deleted_by' + } + switch (key) { + case 'welcome_message': + renderedValue = item.new_values[key].replace(/<[^>]*>/g, ''); + value = value.replace(/<[^>]*>/g, ''); + break; + case 'help_text': + renderedValue = item.new_values[key].replace(/<[^>]*>/g, ''); + value = value.replace(/<[^>]*>/g, ''); + break; + case 'active': + renderedValue = item.new_values[key] == 1 ? 'Active' : 'Inactive'; + value = value == 1 ? 'Active' : 'Inactive'; + break; + case 'created_at': + renderedValue = fDateTime(item.new_values[key]); + value = fDateTime(value); + break; + case 'updated_at': + renderedValue = fDateTime(item.new_values[key]); + value = fDateTime(value); + break; + case 'delete_at': + renderedValue = fDateTime(item.new_values[key]); + value = fDateTime(value); + break; + default: + renderedValue = item.new_values[key]; + break; + } + + const field = key.charAt(0).toUpperCase() + key.slice(1); + if (value == renderedValue) { + return null + } else { + return ( + + {`${field}`} + {`${value}`} + {renderedValue} + + ); + } + })} + +
+
+
+
+ ))} +
+ ) +} \ No newline at end of file diff --git a/frontend/dashboard/src/pages/Master/FormulariumV2/Index.tsx b/frontend/dashboard/src/pages/Master/FormulariumV2/Index.tsx new file mode 100644 index 00000000..370d2f9e --- /dev/null +++ b/frontend/dashboard/src/pages/Master/FormulariumV2/Index.tsx @@ -0,0 +1,33 @@ +import { Card, Grid } from "@mui/material"; +import { useParams } from "react-router-dom"; +import HeaderBreadcrumbs from "../../../components/HeaderBreadcrumbs"; +import Page from "../../../components/Page"; +import useSettings from "../../../hooks/useSettings"; +import List from "./List"; + +export default function MasterFormularium() { + const pageTitle = "Master Formularium" + + return ( + + + + + + + + + ) +} \ No newline at end of file diff --git a/frontend/dashboard/src/pages/Master/FormulariumV2/List.tsx b/frontend/dashboard/src/pages/Master/FormulariumV2/List.tsx new file mode 100644 index 00000000..dda9ab94 --- /dev/null +++ b/frontend/dashboard/src/pages/Master/FormulariumV2/List.tsx @@ -0,0 +1,172 @@ +// @mui +import { Box, Button, Card, Collapse, IconButton, InputLabel, MenuItem, OutlinedInput, Paper, Grid, Select, SelectChangeEvent, Table, TableBody, TableCell, TableContainer, TableHead, TableRow, TextField, Typography, Badge, Tab, Tabs, CardHeader, Stack, Menu, ButtonGroup, Pagination } from '@mui/material'; +import AddIcon from '@mui/icons-material/Add'; +// hooks +import React, { ChangeEvent, Component, useEffect, useRef, useState } from 'react'; +import useSettings from '../../../hooks/useSettings'; +import { Link, useNavigate, useParams, useSearchParams } from 'react-router-dom'; +// components +import axios from '../../../utils/axios'; +import { LaravelPaginatedData } from '../../../@types/paginated-data'; +import BasePagination from '../../../components/BasePagination'; +import FormulariumRow from "./FormulariumRow"; +import { MasterFormularium } from "./Type"; + +export default function List() { + const navigate = useNavigate(); + const [searchParams, setSearchParams] = useSearchParams(); + + // Default data + const [dataTableRow, setDataTableRow] = useState(null) + const [dataTableIsLoading, setDataTableLoading] = useState(true); + const [dataTableData, setDataTableData] = useState({ + current_page: 1, + data: [], + path: "", + first_page_url: "", + last_page: 1, + last_page_url: "", + next_page_url: "", + prev_page_url: "", + per_page: 10, + from: 0, + to: 0, + total: 0 + }); + + const loadDataTableData =async (appliedFilter: any | null = null) => { + setDataTableLoading(true); + const filter = appliedFilter ? appliedFilter : Object.fromEntries([...searchParams.entries()]); + const response = await axios.get('/master/formularium-template', { params: filter }); + console.log(response.data); + console.log(response.data.data) + setDataTableLoading(false); + + setDataTableData(response.data); + setDataTableRow(response.data.data); + } + + const applyFilter = async (searchFilter: string) => { + await loadDataTableData({'search' : searchFilter }); + setSearchParams({ 'search' : searchFilter }) + } + + const handlePageChange = (event : ChangeEvent, value: number) => { + const filter = Object.fromEntries([...searchParams.entries(), ['page', value]]); + loadDataTableData(filter); + setSearchParams(filter); + } + + useEffect(() => { + loadDataTableData(); + }, []) + + function SearchInput(props: any) { + const searchInput = useRef(null); + const [searchText, setSearchText] = useState(""); + + const handleSearchChange = (event: any) => { + const newSearchText = event.target.value ?? "" + setSearchText(newSearchText) + } + + const handleSearchSubmit = (event: any) => { + event.preventDefault(); + props.onSearch(searchText); + } + + useEffect(() => { + setSearchText(searchParams.get('search') ?? ''); + }, [searchParams]) + + return ( +
+ + + ) + } + + function SearchCreate(props: any) { + return ( +
+ + + + +
+ ) + } + + const headStyle = { + fontWeight: 'bold' + } + + return ( + + + + + + + + + + Name + Description + + + + {dataTableIsLoading ? ( + + + + Loading + + + + ) : dataTableData.data.length == 0 ? ( + + + + No Data + + + + ) : ( + + {dataTableRow?.map(item => ( + + ))} + + )} +
+
+ +
+
+
+ ) +} \ No newline at end of file diff --git a/frontend/dashboard/src/pages/Master/FormulariumV2/Type.ts b/frontend/dashboard/src/pages/Master/FormulariumV2/Type.ts new file mode 100644 index 00000000..0421b24c --- /dev/null +++ b/frontend/dashboard/src/pages/Master/FormulariumV2/Type.ts @@ -0,0 +1,31 @@ +export type MasterFormularium = { + id: number + name: string + description: string +} + + +export type FormulariumData = { + id: number + code: string + name: string + description: string + manufacturer: string + category_name: string + kategori_obat: string + uom: string + general_indication: string + composition: string + atc_code: string + class: string + bpom_registration: string + classifications: string + cat_for: string + created_at: string + updated_at: string + deleted_at: any + created_by: number + updated_by: number + deleted_by: any + formularium_template_id: number + } \ No newline at end of file diff --git a/frontend/dashboard/src/routes/index.tsx b/frontend/dashboard/src/routes/index.tsx index 75a4c793..5755645a 100644 --- a/frontend/dashboard/src/routes/index.tsx +++ b/frontend/dashboard/src/routes/index.tsx @@ -323,6 +323,26 @@ export default function Router() { path: 'master/formularium-template/:id/edit', element: , }, + { + path: 'master/formularium-template-v2', + element: + }, + { + path: 'master/formularium-template-v2/create', + element: + }, + { + path: 'master/formularium-template-v2/:id/edit', + element: + }, + { + path: 'master/formularium-template-v2/:id/history', + element: + }, + { + path: 'master/formularium-template-v2/:id/detail', + element: + }, { path: 'report/appointments', @@ -536,6 +556,11 @@ const MasterFormulariumTemplate = Loadable(lazy(() => import('../pages/Master/Fo const MasterFormulariumTemplateCreate = Loadable(lazy(() => import('../pages/Master/Formularium/Master/CreateUpdate'))); const MasterFormulariumTemplateHistories = Loadable(lazy(() => import('../pages/Master/Formularium/Master/History'))); +const MasterFormulariumTemplateV2 = Loadable(lazy(() => import('../pages/Master/FormulariumV2/Index'))); +const MasterFormulariumTemplateCreateV2 = Loadable(lazy(() => import('../pages/Master/FormulariumV2/CreateUpdate'))); +const MasterFormulariumTemplateHistoriesV2 = Loadable(lazy(() => import('../pages/Master/FormulariumV2/History'))); +const MasterFormulariumTemplateDetailV2 = Loadable(lazy(() => import('../pages/Master/FormulariumV2/Detail/Index'))) + const CorporateServices = Loadable(lazy(() => import('../pages/Corporates/Services/Index'))); const CorporateServicesCreate = Loadable(lazy(() => import('../pages/Corporates/Services/Create'))); const CorporateServicesHistory = Loadable(lazy(() => import('../pages/Corporates/Services/sections/History'))); From 0c5960275c5034ad895050ab7e6aa31b98908c88 Mon Sep 17 00:00:00 2001 From: ivan-sim Date: Fri, 27 Oct 2023 09:07:29 +0700 Subject: [PATCH 4/4] Update --- .../dashboard/src/pages/Claims/Detail.tsx | 85 +------------------ 1 file changed, 1 insertion(+), 84 deletions(-) diff --git a/frontend/dashboard/src/pages/Claims/Detail.tsx b/frontend/dashboard/src/pages/Claims/Detail.tsx index 22ff9ef1..546e0984 100644 --- a/frontend/dashboard/src/pages/Claims/Detail.tsx +++ b/frontend/dashboard/src/pages/Claims/Detail.tsx @@ -9,23 +9,13 @@ import { useNavigate, useParams, useLocation } from 'react-router-dom'; import { useEffect, useState, useRef } from 'react'; import axios from '../../utils/axios'; // pages -import DetailTimeline from '../../pages/ClaimRequests/DetailTimeline'; -import DetailStepper from '../../pages/ClaimRequests/DetailStepper'; import { format } from 'date-fns'; import ArrowBackIosIcon from '@mui/icons-material/ArrowBackIos'; import Button from '@mui/material/Button'; import AddIcon from '@mui/icons-material/Add'; -import RemoveIcon from '@mui/icons-material/Remove'; -import { DatePicker, LocalizationProvider } from '@mui/x-date-pickers'; -import { AdapterDateFns } from '@mui/x-date-pickers/AdapterDateFns'; -import Iconify from '@/components/Iconify'; -import { fPostFormat } from '@/utils/formatTime'; import InsertDriveFileIcon from '@mui/icons-material/InsertDriveFile'; -import DownloadIcon from '@mui/icons-material/Download'; import { Dialog, DialogTitle, DialogContent, DialogActions } from '@mui/material'; import CloseIcon from '@mui/icons-material/Close'; -import { fDateTimesecond } from '@/utils/formatTime'; -import { makeFormData } from '@/utils/jsonToFormData'; import FormGroup from '@mui/material/FormGroup'; import FormControlLabel from '@mui/material/FormControlLabel'; import Checkbox from '@mui/material/Checkbox'; @@ -41,8 +31,6 @@ export default function Detail() { const navigate = useNavigate(); const { themeStretch } = useSettings(); - const [data, setData] = useState(); - const [dataDialog, setDataDialog] = useState(); const [customerData, setCustomerData] = useState(null); const [documentData, setDocumentData] = useState(null); const [requestDocumentData, setRequestDocumentData] = useState(null); @@ -61,78 +49,7 @@ export default function Detail() { console.error(error); }); - }, []); - - const [isInvoiceVisible, setInvoiceVisibility] = useState(false); - - const handleInvoice = () => { - setInvoiceVisibility(!isInvoiceVisible); - } - const currentDate = new Date(); - const formattedCurrentDate = format(currentDate, 'dd MMM yyyy'); - const [dateInvoice, setDateInvoice] = useState(currentDate); - - const fileInvoiceInput = useRef(null); - const [fileInvoices, setFileInvoices] = useState([]); - - const handleInvoiceInputChange = (event) => { - if (event.target.files[0]) { - setFileInvoices([...fileInvoices, ...event.target.files]); - } else { - console.log('NO FILE'); - } - }; - const removeInvoiceFiles = (filesState, index) => { - setFileInvoices( - filesState.filter((file, fileIndex) => { - return fileIndex != index; - }) - ); - }; - const date = dateInvoice ? fPostFormat(dateInvoice, 'yyyy-MM-dd') : null; - - const [openDialogSubmit, setOpenDialogSubmit] = useState(false); - const handleCloseDialogSubmit = () => { - setOpenDialogSubmit(false); - } - const handleSubmitData = () => { - if(fileInvoices.length > 0) - { - //submit data - axios - .post('claim-requests/'+id+'/approve') - .then((response) => { - enqueueSnackbar('Success Submit Claim Request', { variant: 'success' }); - setOpenDialogSubmit(false); - }) - .catch(({ response }) => { - enqueueSnackbar(response.data.message ?? 'Something went wrong!', { variant: 'error' }); - }); - //Upload file invoices - const formData = makeFormData({ - date:date, - invoice_files: fileInvoices, - }); - axios - .post('claim-requests/'+id+'/invoice-files', formData) - .then((response) => { - enqueueSnackbar(response.data.message ?? 'Success upload invoice', { variant: 'success' }); - }) - .catch(({ response }) => { - enqueueSnackbar(response.data.message ?? 'Something Went Wrong', { variant: 'error' }); - }); - } - else - { - enqueueSnackbar('Please upload file invoice, before submit', { variant: 'warning' }); - } - - setTimeout(() => - { - window.location.reload(); - }, 5000); - - }; + }, []); function toTitleCase(str) { return str.replace(/\w\S*/g, function(txt) {