Merge branch 'staging' of itcorp.primaya.id:rajif/aso into staging
This commit is contained in:
@@ -124,6 +124,13 @@ class ClaimReportController extends Controller
|
||||
->where('claim_request_files.claim_request_id', '=', $claimRequestId)
|
||||
->get();
|
||||
$results['request_files'] = $request_files;
|
||||
$documents = DB::table('files')
|
||||
->where('fileable_type', 'App\Models\ClaimRequest')
|
||||
->where('fileable_id', $claimRequestId)
|
||||
->select('original_name', \DB::raw("CONCAT('" . env('APP_URL') . "/storage/', path) as path"), 'type')
|
||||
->orderBy('id', 'desc')
|
||||
->get();
|
||||
$results['documents'] = $documents;
|
||||
|
||||
return Helper::responseJson($results);
|
||||
}
|
||||
|
||||
@@ -20,6 +20,8 @@ use App\Events\ClaimRequested;
|
||||
|
||||
use App\Models\File;
|
||||
use App\Models\FilesMcu;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use App\Models\Member;
|
||||
|
||||
class ClaimRequestController extends Controller
|
||||
{
|
||||
@@ -354,4 +356,111 @@ class ClaimRequestController extends Controller
|
||||
]
|
||||
];
|
||||
}
|
||||
|
||||
public function claimRequestDetail($claimRequestId)
|
||||
{
|
||||
$status = 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('corporate_divisions', 'corporate_employees.division_id', '=', 'corporate_divisions.id')
|
||||
->where('claim_requests.id', '=', $claimRequestId)
|
||||
->select(
|
||||
'claim_requests.submission_date',
|
||||
DB::raw('
|
||||
CASE
|
||||
WHEN claim_requests.status = "requested" THEN "requested"
|
||||
WHEN claim_requests.status = "approved" AND claims.status = "approved" THEN "approved"
|
||||
WHEN claim_requests.status = "approved" AND claims.status = "declined" THEN "declined"
|
||||
WHEN claim_requests.status = "approved" AND claims.status = "disbrusmented" THEN "disbrusmented"
|
||||
/*WHEN claim_requests.status = "approved" AND claims.status = "received" THEN "pending"*/
|
||||
WHEN claim_requests.status = "approved" AND claims.status = "received" THEN "reviewed"
|
||||
ELSE ""
|
||||
END AS status
|
||||
')
|
||||
)
|
||||
->first();
|
||||
$results['status'] = $status;
|
||||
$timeline = DB::table('claim_logs')
|
||||
->where('claim_logs.claim_request_id', '=', $claimRequestId)
|
||||
->select(
|
||||
DB::raw('
|
||||
CASE
|
||||
WHEN claim_logs.status = "requested" THEN "Request"
|
||||
WHEN claim_logs.status = "reviewed" THEN "Review"
|
||||
WHEN claim_logs.status = "approved" THEN "Approval"
|
||||
ELSE "-"
|
||||
END AS txt_status
|
||||
'),
|
||||
DB::raw('
|
||||
CASE
|
||||
WHEN claim_logs.status = "requested" THEN "#159C9C"
|
||||
WHEN claim_logs.status = "reviewed" THEN "#0C53B7"
|
||||
WHEN claim_logs.status = "approved" THEN "#229A16"
|
||||
ELSE "-"
|
||||
END AS txt_status_color
|
||||
'),
|
||||
DB::raw('
|
||||
CASE
|
||||
WHEN claim_logs.status = "requested" THEN "#00AB5529"
|
||||
WHEN claim_logs.status = "reviewed" THEN "#1890FF29"
|
||||
WHEN claim_logs.status = "approved" THEN "#54D62C29"
|
||||
ELSE "-"
|
||||
END AS txt_status_backgroundColor
|
||||
'),
|
||||
'claim_logs.date',
|
||||
'claim_logs.description',
|
||||
'claim_logs.status'
|
||||
)
|
||||
->orderBy('claim_logs.id', 'desc')
|
||||
->get();
|
||||
$results['timeline'] = $timeline;
|
||||
$request_files = DB::table('claim_request_files')
|
||||
->where('claim_request_files.claim_request_id', '=', $claimRequestId)
|
||||
->get();
|
||||
$results['request_files'] = $request_files;
|
||||
$documents = DB::table('files')
|
||||
->where('fileable_type', 'App\Models\ClaimRequest')
|
||||
->where('fileable_id', $claimRequestId)
|
||||
->select('original_name', \DB::raw("CONCAT('" . env('APP_URL') . "/storage/', path) as path"), 'type')
|
||||
->orderBy('id', 'desc')
|
||||
->get();
|
||||
$results['documents'] = $documents;
|
||||
$dialog_submits = DB::table('claim_requests')
|
||||
->leftJoin('members', 'claim_requests.member_id','=', 'members.id')
|
||||
->where('claim_requests.id', $claimRequestId)
|
||||
->select('claim_requests.code', 'members.name', 'claim_requests.submission_date', 'claim_requests.service_code','claim_requests.status')
|
||||
->first();
|
||||
$results['dialog_submits'] = $dialog_submits;
|
||||
|
||||
return Helper::responseJson($results);
|
||||
}
|
||||
|
||||
public function invoiceFiles(Request $request, $claim_id)
|
||||
{
|
||||
if ($request->hasFile('invoice_files')) {
|
||||
foreach ($request->invoice_files as $file) {
|
||||
$pathFile = File::storeFile('claim-invoice', $claim_id, $file);
|
||||
File::updateOrCreate([
|
||||
'fileable_type'=>'App\Models\ClaimRequest',
|
||||
'fileable_id' => $claim_id,
|
||||
'type' => 'claim-invoice',
|
||||
'name' => File::getFileName('claim-invoice', $claim_id, $file),
|
||||
'original_name' => $file->getClientOriginalName(),
|
||||
'extension' => $file->getClientOriginalExtension(),
|
||||
'path' => $pathFile,
|
||||
'created_by' => auth()->user()->id,
|
||||
'updated_by' => auth()->user()->id,
|
||||
]);
|
||||
}
|
||||
}
|
||||
if($request->date)
|
||||
{
|
||||
DB::table('claim_requests')
|
||||
->where('id', $claim_id)
|
||||
->update(['invoice_date' => $request->date]);
|
||||
|
||||
}
|
||||
return Helper::responseJson(data: $request->toArray(), message: 'Invoice Success Uploaded');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -220,6 +220,8 @@ Route::prefix('internal')->group(function () {
|
||||
Route::get('claim-requests/{id}', [ClaimRequestController::class, 'show'])->name('claim-requests.show');
|
||||
Route::put('claim-requests/{id}', [ClaimRequestController::class, 'update'])->name('claim-requests.update');
|
||||
Route::post('claim-requests/import', [ClaimRequestController::class, 'importClaim'])->name('claim-requests.importClaim');
|
||||
Route::get('claim-requests/detail/{id}', [ClaimRequestController::class, 'claimRequestDetail']);
|
||||
Route::post('claim-requests/{id}/invoice-files', [ClaimRequestController::class, 'invoiceFiles']);
|
||||
});
|
||||
|
||||
Route::get('province', [ProvinceController::class, 'index']);
|
||||
|
||||
@@ -43,6 +43,7 @@ class File extends Model
|
||||
'claim-result' => 'claim/',
|
||||
'claim-diagnosis' => 'claim/',
|
||||
'claim-kondisi' => 'claim/',
|
||||
'claim-invoice' => 'claim/',
|
||||
'docs' => 'docs/',
|
||||
];
|
||||
|
||||
|
||||
@@ -0,0 +1,32 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function up()
|
||||
{
|
||||
Schema::table('claim_requests', function (Blueprint $table) {
|
||||
$table->dateTime('invoice_date')->nullable()->after('claim_id');
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function down()
|
||||
{
|
||||
Schema::table('claim_requests', function (Blueprint $table) {
|
||||
$table->dropColumn('invoice_date');
|
||||
});
|
||||
}
|
||||
};
|
||||
@@ -13,6 +13,8 @@ import AddIcon from '@mui/icons-material/Add';
|
||||
import Iconify from '../../components/Iconify';
|
||||
import { useEffect, useState } from 'react';
|
||||
import { format } from 'date-fns';
|
||||
import InsertDriveFileIcon from '@mui/icons-material/InsertDriveFile';
|
||||
import DescriptionIcon from '@mui/icons-material/Description';
|
||||
|
||||
const Item1 = styled(Paper)(({ theme }) => ({
|
||||
...theme.typography.body2,
|
||||
@@ -37,10 +39,12 @@ const Item2 = styled(Paper)(({ theme }) => ({
|
||||
export default function NoOppositeContent({data}) {
|
||||
const [timeline, setTimeline] = useState(null);
|
||||
const [requestFile, setRequestFile] = useState(null);
|
||||
const [document, setDocument] = useState(null);
|
||||
useEffect(() => {
|
||||
if (data && data.data) {
|
||||
setTimeline(data.data.timeline);
|
||||
setRequestFile(data.data.request_files);
|
||||
setDocument(data.data.documents);
|
||||
}
|
||||
|
||||
}, [data]);
|
||||
@@ -65,7 +69,7 @@ export default function NoOppositeContent({data}) {
|
||||
<TimelineContent spacing={3}>
|
||||
<Card sx={{ borderRadius: '6px', paddingY: 2 }}>
|
||||
<Stack sx={{marginLeft: 2, marginRight: 2, marginTop: 2 }}>
|
||||
<Stack direction="row" spacing={2} sx={{marginBottom: 2, paddingBottom: 2, borderBottom: '1px solid #919EAB52' }}>
|
||||
<Stack direction="row" sx={{marginBottom: 2, paddingBottom: 2, borderBottom: '1px solid #919EAB52' }}>
|
||||
<Item1>{dataTimeline.date ? format(new Date(dataTimeline.date), "HH : ii") : ''}</Item1>
|
||||
<Item2 sx={{backgroundColor: dataTimeline.txt_status_backgroundColor, color: dataTimeline.txt_status_color}}>{dataTimeline.txt_status}</Item2>
|
||||
</Stack>
|
||||
@@ -81,11 +85,13 @@ export default function NoOppositeContent({data}) {
|
||||
<Button variant="outlined" color="primary" startIcon={< AddIcon/>}>
|
||||
<Typography variant="button" display="block">
|
||||
{dataRequestFile.type === 'claim-diagnosis' ?
|
||||
'Dokumen Diagnosa'
|
||||
'Diagnosis'
|
||||
: dataRequestFile.type === 'claim-kondisi' ?
|
||||
'Dokumen Kondisi'
|
||||
'Condition'
|
||||
: dataRequestFile.type === 'claim-result' ?
|
||||
'Dokumen Hasil Penunjang'
|
||||
'Supporting Result'
|
||||
: dataRequestFile.type === 'claim-invoice' ?
|
||||
'Invoice'
|
||||
: ''}
|
||||
</Typography>
|
||||
</Button>
|
||||
@@ -95,6 +101,43 @@ export default function NoOppositeContent({data}) {
|
||||
) : ''}
|
||||
</Stack>
|
||||
</Card>
|
||||
{dataTimeline.status === 'requested' ? (
|
||||
<Card sx={{marginTop: 2 }}>
|
||||
<Stack sx={{marginLeft: 2, marginRight: 2, marginTop: 2 }}>
|
||||
<Stack direction="row" spacing={2} sx={{marginBottom: 2, paddingBottom: 2, borderBottom: '1px solid #919EAB52' }} alignItems="center">
|
||||
<DescriptionIcon />
|
||||
<Typography variant="Subtitle2" sx={{fontWeight: 'bold'}}>Documents</Typography>
|
||||
</Stack>
|
||||
<Stack direction="column" spacing={2} sx={{marginBottom: 2}}>
|
||||
{document?.map((dataDocument, index) => (
|
||||
<Stack direction="column" spacing={2} key={index}>
|
||||
<Typography variant="Subtitle2" gutterBottom>
|
||||
{dataDocument.type === 'claim-diagnosis' ?
|
||||
'Diagnosis'
|
||||
: dataDocument.type === 'claim-kondisi' ?
|
||||
'Condition'
|
||||
: dataDocument.type === 'claim-result' ?
|
||||
'Supporting Result'
|
||||
: dataDocument.type === 'claim-invoice' ?
|
||||
'Invoice'
|
||||
: ''}
|
||||
</Typography>
|
||||
<Stack direction="row" spacing={1} sx={{color: '#19BBBB'}}>
|
||||
<InsertDriveFileIcon />
|
||||
<a
|
||||
href={dataDocument.path}
|
||||
style={{ cursor: 'pointer', textDecoration: 'underline', color: '#19BBBB' }}
|
||||
target="_blank"
|
||||
>
|
||||
<Typography variant="body2" gutterBottom>{dataDocument.original_name ? dataDocument.original_name : '-'}</Typography>
|
||||
</a>
|
||||
</Stack>
|
||||
</Stack>
|
||||
))}
|
||||
</Stack>
|
||||
</Stack>
|
||||
</Card>
|
||||
) : ''}
|
||||
</TimelineContent>
|
||||
</TimelineItem>
|
||||
</Timeline>
|
||||
|
||||
@@ -90,6 +90,13 @@ const navConfig = [
|
||||
|
||||
],
|
||||
},
|
||||
{
|
||||
title: 'MASTER',
|
||||
children: [
|
||||
{ title: 'Diagnosis', path: '/master/diagnosis' },
|
||||
|
||||
],
|
||||
},
|
||||
{
|
||||
title: 'USER MANAGEMENT',
|
||||
path: '/users',
|
||||
|
||||
300
frontend/dashboard/src/pages/ClaimRequests/Detail.tsx
Normal file
300
frontend/dashboard/src/pages/ClaimRequests/Detail.tsx
Normal file
@@ -0,0 +1,300 @@
|
||||
// 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 { enqueueSnackbar } from 'notistack';
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
export default function UserProfile() {
|
||||
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 { id } = useParams();
|
||||
|
||||
useEffect(() => {
|
||||
axios
|
||||
.get('/claim-requests/detail/'+id)
|
||||
.then((response) => {
|
||||
setData(response.data);
|
||||
setDataDialog(response.data.data.dialog_submits);
|
||||
|
||||
})
|
||||
.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<HTMLInputElement>(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);
|
||||
|
||||
};
|
||||
|
||||
return (
|
||||
<Page title='Detail'>
|
||||
<Container maxWidth={themeStretch ? false : 'xl'}>
|
||||
<Stack direction="row" alignItems="center" sx={{ marginBottom: 3 }}>
|
||||
<ArrowBackIosIcon onClick={() => navigate(-1)} sx={{cursor:'pointer'}}/>
|
||||
<Typography variant="h5" sx={{marginLeft:2}}>{code}</Typography>
|
||||
{data ? (
|
||||
<Stack direction="row" spacing={2} ml="auto">
|
||||
<Typography variant="body2" sx={{color: '#757575'}}>Submission Date</Typography>
|
||||
<Typography variant="body2" fontWeight="bold">{(data && data.data) ? format(new Date(data.data.status.submission_date), "d MMM yyyy") : ''}</Typography>
|
||||
</Stack>
|
||||
) : ''}
|
||||
</Stack>
|
||||
{data ? (
|
||||
<Grid container spacing={2}>
|
||||
<Grid item xs={12} md={12}>
|
||||
<DetailStepper data={data}/>
|
||||
</Grid>
|
||||
<Grid item xs={12} md={12}>
|
||||
<Stack direction="row" alignItems="center">
|
||||
<Typography variant="subtitle1">Format Claim</Typography>
|
||||
<Button variant="outlined" color="primary" startIcon={< DownloadIcon/>} sx={{marginLeft: 'auto'}}>
|
||||
<Typography variant="button" display="block">Import</Typography>
|
||||
</Button>
|
||||
</Stack>
|
||||
</Grid>
|
||||
<Grid item xs={12} md={12}>
|
||||
<Stack direction="row" alignItems="center">
|
||||
<Typography variant="subtitle1">Request Claim</Typography>
|
||||
<Button variant="outlined" color="primary" startIcon={ isInvoiceVisible ? < RemoveIcon/> : < AddIcon/>} sx={{marginLeft: 'auto'}} onClick={() => handleInvoice()}>
|
||||
<Typography variant="button" display="block">Invoice</Typography>
|
||||
</Button>
|
||||
</Stack>
|
||||
</Grid>
|
||||
<Grid item xs={12} md={12} sx={{display : isInvoiceVisible ? '' : 'none',}}>
|
||||
<Card sx={{padding: 2}}>
|
||||
<Stack direction="column" spacing={2}>
|
||||
<LocalizationProvider dateAdapter={AdapterDateFns}>
|
||||
<DatePicker
|
||||
label="Invoice Date"
|
||||
value={dateInvoice}
|
||||
onChange={(newValue) => {
|
||||
setDateInvoice(newValue);
|
||||
}}
|
||||
inputFormat="dd MMM yyyy"
|
||||
renderInput={(params) => <TextField sx={{width:'40%'}} {...params} defaultValue={formattedCurrentDate} required/>}
|
||||
/>
|
||||
</LocalizationProvider>
|
||||
<Stack
|
||||
divider={<Divider orientation="horizontal" flexItem />}
|
||||
spacing={1}
|
||||
sx={{ marginY: 2 }}
|
||||
>
|
||||
{fileInvoices &&
|
||||
fileInvoices.map((file, index) => (
|
||||
<Stack direction="row" justifyContent={'space-between'} key={index}>
|
||||
<Stack direction="row" spacing={1} sx={{color: '#19BBBB'}}>
|
||||
<InsertDriveFileIcon />
|
||||
<Typography variant="body2" gutterBottom>{file.name ? file.name : '-'}</Typography>
|
||||
</Stack>
|
||||
<Iconify
|
||||
icon="eva:trash-2-outline"
|
||||
color={'darkred'}
|
||||
onClick={() => {
|
||||
removeInvoiceFiles(fileInvoices, index);
|
||||
}}
|
||||
sx={{cursor: 'pointer'}}
|
||||
></Iconify>
|
||||
</Stack>
|
||||
))}
|
||||
</Stack>
|
||||
<ButtonBase sx={{ p: 4, border: '2px dashed #F9FAFB',
|
||||
bgcolor: '#919EAB52',
|
||||
borderRadius: '8px',
|
||||
width: '100%', height: '60px'}} onClick={() => fileInvoiceInput.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 Invoice
|
||||
</Typography>
|
||||
</Box>
|
||||
<input
|
||||
type="file"
|
||||
id="file"
|
||||
ref={fileInvoiceInput}
|
||||
style={{ display: 'none' }}
|
||||
multiple
|
||||
onChange={handleInvoiceInputChange}
|
||||
accept=".csv, application/vnd.openxmlformats-officedocument.spreadsheetml.sheet, application/vnd.ms-excel, text/plain, application/pdf"
|
||||
/>
|
||||
</ButtonBase>
|
||||
</Stack>
|
||||
</Card>
|
||||
</Grid>
|
||||
<Grid item xs={12} md={12}>
|
||||
<DetailTimeline data={data}/>
|
||||
</Grid>
|
||||
<Grid item xs={12} md={12}>
|
||||
<Stack direction="row" padding={4}>
|
||||
{dataDialog && dataDialog.status === 'requested' ? (
|
||||
<>
|
||||
<Button variant="outlined" sx={{color: '#212B36', marginLeft: 'auto'}} >Cancel</Button>
|
||||
<Button sx={{backgroundColor: '#19BBBB', marginLeft: 1}} variant="contained" onClick={()=> setOpenDialogSubmit(true)}>Submit</Button>
|
||||
</>
|
||||
) : ''}
|
||||
{/* Dialog Submits */}
|
||||
<Dialog open={openDialogSubmit} onClose={handleCloseDialogSubmit} fullWidth={true}>
|
||||
<DialogTitle sx={{ backgroundColor: '#19BBBB', color: '#FFF', padding: 2 }}>
|
||||
<Stack direction="row" alignItems="center" justifyContent="space-between">
|
||||
<Stack direction="row" alignItems='center' spacing={1}>
|
||||
<Typography variant="h6">Confirmation</Typography>
|
||||
</Stack>
|
||||
<IconButton sx={{ color: '#FFF' }} onClick={handleCloseDialogSubmit}>
|
||||
<CloseIcon />
|
||||
</IconButton>
|
||||
</Stack>
|
||||
</DialogTitle>
|
||||
<DialogContent>
|
||||
{dataDialog ? (
|
||||
<Stack spacing={2} padding={2}>
|
||||
<Typography variant='body1'>Are you sure to submit this claim ?</Typography>
|
||||
<Card sx={{padding:2}} >
|
||||
<Stack direction='row' spacing={2}>
|
||||
<Typography variant='subtitle2' sx={{color: '#919EAB', width: '30%'}}>Code</Typography>
|
||||
<Typography variant='subtitle2' sx={{width: '70%'}}>{dataDialog.code}</Typography>
|
||||
</Stack>
|
||||
<Stack direction='row' spacing={2}>
|
||||
<Typography variant='subtitle2' sx={{color: '#919EAB', width: '30%'}}>Name</Typography>
|
||||
<Typography variant='subtitle2' sx={{width: '70%'}}>{dataDialog.name}</Typography>
|
||||
</Stack>
|
||||
<Stack direction='row' spacing={2}>
|
||||
<Typography variant='subtitle2' sx={{color: '#919EAB', width: '30%'}}>Date Submission</Typography>
|
||||
<Typography variant='subtitle2' sx={{width: '70%'}}>{fDateTimesecond(dataDialog.submission_date)}</Typography>
|
||||
</Stack>
|
||||
<Stack direction='row' spacing={2}>
|
||||
<Typography variant='subtitle2' sx={{color: '#919EAB', width: '30%'}}>Claim Method</Typography>
|
||||
<Typography variant='subtitle2' sx={{width: '70%'}}>Service Type</Typography>
|
||||
</Stack>
|
||||
<Stack direction='row' spacing={2}>
|
||||
<Typography variant='subtitle2' sx={{color: '#919EAB', width: '30%'}}>Service Type</Typography>
|
||||
<Typography variant='subtitle2' sx={{width: '70%'}}>
|
||||
{dataDialog.service_code === 'IP' ? 'Inpatient' : 'Outpatient'}
|
||||
</Typography>
|
||||
</Stack>
|
||||
</Card>
|
||||
</Stack>
|
||||
) : ''}
|
||||
</DialogContent>
|
||||
<DialogActions>
|
||||
<Button variant="outlined" sx={{color: '#212B36'}} onClick={handleCloseDialogSubmit}>Cancel</Button>
|
||||
<Button sx={{backgroundColor: '#19BBBB'}} onClick={handleSubmitData} variant="contained">Submit</Button>
|
||||
</DialogActions>
|
||||
</Dialog>
|
||||
</Stack>
|
||||
</Grid>
|
||||
</Grid>
|
||||
) : ''}
|
||||
</Container>
|
||||
</Page>
|
||||
);
|
||||
}
|
||||
58
frontend/dashboard/src/pages/ClaimRequests/DetailStepper.tsx
Normal file
58
frontend/dashboard/src/pages/ClaimRequests/DetailStepper.tsx
Normal file
@@ -0,0 +1,58 @@
|
||||
import * as React from 'react';
|
||||
import Box from '@mui/material/Box';
|
||||
import Stepper from '@mui/material/Stepper';
|
||||
import Step from '@mui/material/Step';
|
||||
import StepLabel from '@mui/material/StepLabel';
|
||||
import { useEffect, useState } from 'react';
|
||||
import ClearIcon from '@mui/icons-material/Clear';
|
||||
|
||||
const steps = [
|
||||
'Request',
|
||||
'Review',
|
||||
'Approval',
|
||||
'Decline',
|
||||
];
|
||||
|
||||
export default function HorizontalLinearAlternativeLabelStepper({data}) {
|
||||
const [active, setActive] = useState(0);
|
||||
const [status, SetStatus] = useState(null);
|
||||
let updatedSteps = [...steps];
|
||||
useEffect(() => {
|
||||
if (data && data.data) {
|
||||
if (data.data.status.status === 'requested') {
|
||||
setActive(1);
|
||||
updatedSteps = updatedSteps.filter(step => step !== 'Decline');
|
||||
}
|
||||
else if (data.data.status.status === 'reviewed') {
|
||||
setActive(2);
|
||||
updatedSteps = updatedSteps.filter(step => step !== 'Decline');
|
||||
}
|
||||
else if (data.data.status.status === 'approved')
|
||||
{
|
||||
setActive(3);
|
||||
updatedSteps = updatedSteps.filter(step => step !== 'Decline');
|
||||
}
|
||||
else if(data.data.status.status === 'declined')
|
||||
{
|
||||
setActive(4)
|
||||
updatedSteps = updatedSteps.filter(step => step !== 'Approval');
|
||||
}
|
||||
}
|
||||
SetStatus(updatedSteps);
|
||||
}, [data]);
|
||||
|
||||
|
||||
|
||||
|
||||
return (
|
||||
<Box sx={{ width: '100%', marginBottom: 2 }}>
|
||||
<Stepper activeStep={active} alternativeLabel>
|
||||
{status?.map((label) => (
|
||||
<Step key={label}>
|
||||
<StepLabel icon={label==='Decline' ? <ClearIcon sx={{ color: 'white', backgroundColor: 'red', borderRadius: '50%' }} /> : ''}>{label}</StepLabel>
|
||||
</Step>
|
||||
))}
|
||||
</Stepper>
|
||||
</Box>
|
||||
);
|
||||
}
|
||||
147
frontend/dashboard/src/pages/ClaimRequests/DetailTimeline.tsx
Normal file
147
frontend/dashboard/src/pages/ClaimRequests/DetailTimeline.tsx
Normal file
@@ -0,0 +1,147 @@
|
||||
import * as React from 'react';
|
||||
import Timeline from '@mui/lab/Timeline';
|
||||
import TimelineItem, { timelineItemClasses } from '@mui/lab/TimelineItem';
|
||||
import TimelineSeparator from '@mui/lab/TimelineSeparator';
|
||||
import TimelineConnector from '@mui/lab/TimelineConnector';
|
||||
import TimelineContent from '@mui/lab/TimelineContent';
|
||||
import TimelineDot from '@mui/lab/TimelineDot';
|
||||
import {Typography, Card, Stack} from '@mui/material';
|
||||
import { styled } from '@mui/material/styles';
|
||||
import Paper from '@mui/material/Paper';
|
||||
import Button from '@mui/material/Button';
|
||||
import AddIcon from '@mui/icons-material/Add';
|
||||
import Iconify from '../../components/Iconify';
|
||||
import { useEffect, useState } from 'react';
|
||||
import { format } from 'date-fns';
|
||||
import InsertDriveFileIcon from '@mui/icons-material/InsertDriveFile';
|
||||
import DescriptionIcon from '@mui/icons-material/Description';
|
||||
|
||||
const Item1 = styled(Paper)(({ theme }) => ({
|
||||
...theme.typography.body2,
|
||||
padding: theme.spacing(1),
|
||||
textAlign: 'center',
|
||||
backgroundColor: '#919EAB29',
|
||||
color: '#637381',
|
||||
width: 'fit-content',
|
||||
marginRight: 'auto',
|
||||
}));
|
||||
|
||||
const Item2 = styled(Paper)(({ theme }) => ({
|
||||
backgroundColor: theme.palette.mode === 'dark' ? '#1A2027' : '#fff',
|
||||
...theme.typography.body2,
|
||||
padding: theme.spacing(1),
|
||||
textAlign: 'center',
|
||||
color: theme.palette.text.secondary,
|
||||
width: 'fit-content',
|
||||
marginLeft: 'auto',
|
||||
}));
|
||||
|
||||
export default function NoOppositeContent({data}) {
|
||||
const [timeline, setTimeline] = useState(null);
|
||||
const [requestFile, setRequestFile] = useState(null);
|
||||
const [document, setDocument] = useState(null);
|
||||
useEffect(() => {
|
||||
if (data && data.data) {
|
||||
setTimeline(data.data.timeline);
|
||||
setRequestFile(data.data.request_files);
|
||||
setDocument(data.data.documents);
|
||||
}
|
||||
|
||||
}, [data]);
|
||||
return (
|
||||
<>
|
||||
{timeline?.map((dataTimeline, index) => (
|
||||
<Timeline
|
||||
sx={{
|
||||
[`& .${timelineItemClasses.root}:before`]: {
|
||||
flex: 0,
|
||||
padding: 0,
|
||||
},
|
||||
}}
|
||||
key={index}
|
||||
>
|
||||
<Typography variant="body2" gutterBottom fontWeight="bold">{dataTimeline.date ? format(new Date(dataTimeline.date), "d MMM yyyy") : ''}</Typography>
|
||||
<TimelineItem>
|
||||
<TimelineSeparator>
|
||||
<TimelineDot />
|
||||
<TimelineConnector />
|
||||
</TimelineSeparator>
|
||||
<TimelineContent spacing={3}>
|
||||
<Card sx={{ borderRadius: '6px', paddingY: 2 }}>
|
||||
<Stack sx={{marginLeft: 2, marginRight: 2, marginTop: 2 }}>
|
||||
<Stack direction="row" sx={{marginBottom: 2, paddingBottom: 2, borderBottom: '1px solid #919EAB52' }}>
|
||||
<Item1>{dataTimeline.date ? format(new Date(dataTimeline.date), "HH : ii") : ''}</Item1>
|
||||
<Item2 sx={{backgroundColor: dataTimeline.txt_status_backgroundColor, color: dataTimeline.txt_status_color}}>{dataTimeline.txt_status}</Item2>
|
||||
</Stack>
|
||||
<Stack direction="row" spacing={2} sx={{marginBottom: 2}}>
|
||||
<Typography variant="body2" gutterBottom>Detail:</Typography>
|
||||
<Typography variant="body2" gutterBottom>{dataTimeline.description}</Typography>
|
||||
</Stack>
|
||||
{dataTimeline.status === 'reviewed' && requestFile ? (
|
||||
<>
|
||||
{requestFile?.map((dataRequestFile, index) => (
|
||||
<Stack spacing={2} sx={{marginBottom: 2}} key={index}>
|
||||
<Typography variant="body2" gutterBottom fontWeight="bold">{dataRequestFile.description}</Typography>
|
||||
<Button variant="outlined" color="primary" startIcon={< AddIcon/>}>
|
||||
<Typography variant="button" display="block">
|
||||
{dataRequestFile.type === 'claim-diagnosis' ?
|
||||
'Diagnosis'
|
||||
: dataRequestFile.type === 'claim-kondisi' ?
|
||||
'Condition'
|
||||
: dataRequestFile.type === 'claim-result' ?
|
||||
'Supporting Result'
|
||||
: dataRequestFile.type === 'claim-invoice' ?
|
||||
'Invoice'
|
||||
: ''}
|
||||
</Typography>
|
||||
</Button>
|
||||
</Stack>
|
||||
))}
|
||||
</>
|
||||
) : ''}
|
||||
</Stack>
|
||||
</Card>
|
||||
{dataTimeline.status === 'requested' ? (
|
||||
<Card sx={{marginTop: 2 }}>
|
||||
<Stack sx={{marginLeft: 2, marginRight: 2, marginTop: 2 }}>
|
||||
<Stack direction="row" spacing={2} sx={{marginBottom: 2, paddingBottom: 2, borderBottom: '1px solid #919EAB52' }} alignItems="center">
|
||||
<DescriptionIcon />
|
||||
<Typography variant="Subtitle2" sx={{fontWeight: 'bold'}}>Documents</Typography>
|
||||
</Stack>
|
||||
<Stack direction="column" spacing={2} sx={{marginBottom: 2}}>
|
||||
{document?.map((dataDocument, index) => (
|
||||
<Stack direction="column" spacing={2} key={index}>
|
||||
<Typography variant="Subtitle2" gutterBottom>
|
||||
{dataDocument.type === 'claim-diagnosis' ?
|
||||
'Diagnosis'
|
||||
: dataDocument.type === 'claim-kondisi' ?
|
||||
'Condition'
|
||||
: dataDocument.type === 'claim-result' ?
|
||||
'Supporting Result'
|
||||
: dataDocument.type === 'claim-invoice' ?
|
||||
'Invoice'
|
||||
: ''}
|
||||
</Typography>
|
||||
<Stack direction="row" spacing={1} sx={{color: '#19BBBB'}}>
|
||||
<InsertDriveFileIcon />
|
||||
<a
|
||||
href={dataDocument.path}
|
||||
style={{ cursor: 'pointer', textDecoration: 'underline', color: '#19BBBB' }}
|
||||
target="_blank"
|
||||
>
|
||||
<Typography variant="body2" gutterBottom>{dataDocument.original_name ? dataDocument.original_name : '-'}</Typography>
|
||||
</a>
|
||||
</Stack>
|
||||
</Stack>
|
||||
))}
|
||||
</Stack>
|
||||
</Stack>
|
||||
</Card>
|
||||
) : ''}
|
||||
</TimelineContent>
|
||||
</TimelineItem>
|
||||
</Timeline>
|
||||
))}
|
||||
</>
|
||||
);
|
||||
}
|
||||
@@ -368,7 +368,7 @@ export default function List() {
|
||||
<EditOutlinedIcon />
|
||||
Edit
|
||||
</MenuItem>
|
||||
<MenuItem onClick={() => ''}>
|
||||
<MenuItem onClick={() => navigate ('/claim-requests/detail/'+row.id+'/?code='+row.code)}>
|
||||
<FindInPageOutlinedIcon />
|
||||
Detail
|
||||
</MenuItem>
|
||||
|
||||
@@ -283,8 +283,8 @@ export default function List(props: any) {
|
||||
id: number;
|
||||
status: number;
|
||||
code: string,
|
||||
name: string,
|
||||
rules: string,
|
||||
name: string,
|
||||
rules: string,
|
||||
};
|
||||
const plans = props?.data.map((plan: any) => {
|
||||
return {
|
||||
@@ -576,32 +576,32 @@ export default function List(props: any) {
|
||||
)}
|
||||
</TableCell>
|
||||
|
||||
<TableCell align="left">
|
||||
<TableMoreMenu actions={
|
||||
<>
|
||||
<MenuItem onClick={() => setOpen(!open)}>
|
||||
<FindInPageOutlined />
|
||||
Detail
|
||||
</MenuItem>
|
||||
<MenuItem onClick={() => navigate(`/corporates/${corporate_id}/diagnosis-exclusions/${row.id}/edit`)} >
|
||||
<EditOutlined />
|
||||
Edit
|
||||
</MenuItem>
|
||||
<MenuItem onClick={() => handleActivate(true, {
|
||||
code: row.code,
|
||||
name: row.name,
|
||||
rules: Object.keys(row.rules).length ? 'With Rules' : 'All',
|
||||
id:row.id,
|
||||
status: row.active,
|
||||
service: row.service_code
|
||||
})
|
||||
} >
|
||||
<CachedIcon />
|
||||
Update Status
|
||||
</MenuItem>
|
||||
</>
|
||||
} />
|
||||
</TableCell>
|
||||
<TableCell align="left">
|
||||
<TableMoreMenu actions={
|
||||
<>
|
||||
<MenuItem onClick={() => setOpen(!open)}>
|
||||
<FindInPageOutlined />
|
||||
Detail
|
||||
</MenuItem>
|
||||
<MenuItem onClick={() => navigate(`/corporates/${corporate_id}/diagnosis-exclusions/${row.id}/edit`)} >
|
||||
<EditOutlined />
|
||||
Edit
|
||||
</MenuItem>
|
||||
<MenuItem onClick={() => handleActivate(true, {
|
||||
code: row.code,
|
||||
name: row.name,
|
||||
rules: Object.keys(row.rules).length ? 'With Rules' : 'All',
|
||||
id:row.id,
|
||||
status: row.active,
|
||||
service: row.service_code
|
||||
})
|
||||
} >
|
||||
<CachedIcon />
|
||||
Update Status
|
||||
</MenuItem>
|
||||
</>
|
||||
} />
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
{/* COLLAPSIBLE ROW */}
|
||||
<TableRow>
|
||||
@@ -801,7 +801,7 @@ export default function List(props: any) {
|
||||
|
||||
const onSubmit = async (row : any) => {
|
||||
try {
|
||||
handleUpdate(dataValue.status, dataValue.id, row.reason)
|
||||
handleUpdate(dataValue.status, dataValue.id, row.reason)
|
||||
} catch (error: any) {
|
||||
console.log('data gagal');
|
||||
}
|
||||
@@ -836,7 +836,7 @@ export default function List(props: any) {
|
||||
resolver: yupResolver(NewCorporateSchema),
|
||||
});
|
||||
|
||||
|
||||
|
||||
const {
|
||||
reset,
|
||||
handleSubmit,
|
||||
@@ -924,7 +924,7 @@ export default function List(props: any) {
|
||||
Cancel
|
||||
</Button>
|
||||
|
||||
{dataValue?.status == 1?
|
||||
{dataValue?.status == 1?
|
||||
<LoadingButton
|
||||
sx={{ boxShadow: '0px 2px 4px rgba(0, 0, 0, 0.1)'}}
|
||||
type="submit"
|
||||
@@ -936,7 +936,7 @@ export default function List(props: any) {
|
||||
>
|
||||
Inactive
|
||||
</LoadingButton>
|
||||
:
|
||||
:
|
||||
<LoadingButton
|
||||
sx={{ boxShadow: '0px 2px 4px rgba(0, 0, 0, 0.1)'}}
|
||||
type="submit"
|
||||
@@ -948,12 +948,12 @@ export default function List(props: any) {
|
||||
>
|
||||
Active
|
||||
</LoadingButton>
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
</Stack>
|
||||
</Stack>
|
||||
|
||||
|
||||
</FormProvider>
|
||||
</>
|
||||
);
|
||||
@@ -1031,9 +1031,9 @@ export default function List(props: any) {
|
||||
<BasePagination paginationData={dataTableData} onPageChange={handlePageChange} />
|
||||
</Card>
|
||||
|
||||
<DialogUpdateStatus
|
||||
<DialogUpdateStatus
|
||||
openDialog={isDialogOpen}
|
||||
setOpenDialog={setDialogOpen}
|
||||
setOpenDialog={setDialogOpen}
|
||||
title={titles}
|
||||
data={dataValue}
|
||||
description={dataDescription}
|
||||
|
||||
@@ -350,11 +350,11 @@ export default function HospitalList() {
|
||||
<Card sx={{padding:2}} >
|
||||
<Stack direction='row' spacing={2}>
|
||||
<Typography variant='subtitle2' sx={{color: '#919EAB', width: '30%'}}>Code</Typography>
|
||||
<Typography variant='subtitle2' sx={{width: '70%'}}>{nameField}</Typography>
|
||||
<Typography variant='subtitle2' sx={{width: '70%'}}>{codeField}</Typography>
|
||||
</Stack>
|
||||
<Stack direction='row' spacing={2}>
|
||||
<Typography variant='subtitle2' sx={{color: '#919EAB', width: '30%'}}>Hospital Name</Typography>
|
||||
<Typography variant='subtitle2' sx={{width: '70%'}}>{codeField}</Typography>
|
||||
<Typography variant='subtitle2' sx={{width: '70%'}}>{nameField}</Typography>
|
||||
</Stack>
|
||||
</Card>
|
||||
</Stack>
|
||||
|
||||
@@ -16,27 +16,26 @@ export default function Divisions() {
|
||||
return (
|
||||
<Page title={ pageTitle }>
|
||||
|
||||
<HeaderBreadcrumbs
|
||||
heading={ pageTitle }
|
||||
links={[
|
||||
{
|
||||
name: 'Master',
|
||||
href: '/master/diagnosis-template',
|
||||
},
|
||||
{
|
||||
name: 'Diagnosis Template',
|
||||
href: '/master/diagnosis-template',
|
||||
},
|
||||
{
|
||||
name: 'Diagnosis',
|
||||
href: '/master/diagnosis-template',
|
||||
},
|
||||
]}
|
||||
/>
|
||||
|
||||
<Card>
|
||||
<HeaderBreadcrumbs
|
||||
heading={ pageTitle }
|
||||
sx={{ px: 2 }}
|
||||
links={[
|
||||
{
|
||||
name: 'Master',
|
||||
href: '/master/diagnosis',
|
||||
},
|
||||
{
|
||||
name: 'Diagnosis',
|
||||
href: '/master/diagnosis',
|
||||
},
|
||||
{
|
||||
name: 'Diagnosis',
|
||||
href: '/master/diagnosis',
|
||||
},
|
||||
]}
|
||||
/>
|
||||
|
||||
<List />
|
||||
</Card>
|
||||
</Page>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -7,7 +7,7 @@ import UploadIcon from '@mui/icons-material/Upload';
|
||||
import CancelIcon from '@mui/icons-material/Cancel';
|
||||
import HistoryIcon from '@mui/icons-material/History';
|
||||
// hooks
|
||||
import { Link, NavLink as RouterLink } from 'react-router-dom';
|
||||
import { Link, NavLink as RouterLink, useNavigate } from 'react-router-dom';
|
||||
import React, { ChangeEvent, Component, useEffect, useRef, useState } from 'react';
|
||||
import useSettings from '../../../hooks/useSettings';
|
||||
import { useParams, useSearchParams } from 'react-router-dom';
|
||||
@@ -17,13 +17,15 @@ import { LaravelPaginatedData } from '../../../@types/paginated-data';
|
||||
import { Icd } from '../../../@types/diagnosis';
|
||||
import BasePagination from '../../../components/BasePagination';
|
||||
import { enqueueSnackbar } from 'notistack';
|
||||
import TableMoreMenu from '@/components/table/TableMoreMenu';
|
||||
|
||||
export default function List() {
|
||||
const { themeStretch } = useSettings();
|
||||
const { diagnosis_template_id } = useParams();
|
||||
const [searchParams, setSearchParams] = useSearchParams();
|
||||
const [importResult, setImportResult] = useState(null);
|
||||
|
||||
const navigate = useNavigate();
|
||||
const { themeStretch } = useSettings();
|
||||
const { diagnosis_template_id } = useParams();
|
||||
const [searchParams, setSearchParams] = useSearchParams();
|
||||
const [importResult, setImportResult] = useState(null);
|
||||
|
||||
function SearchInput(props: any) {
|
||||
// SEARCH
|
||||
const searchInput = useRef<HTMLInputElement>(null);
|
||||
@@ -44,7 +46,7 @@ export default function List() {
|
||||
}, [searchParams])
|
||||
|
||||
return (
|
||||
<form onSubmit={handleSearchSubmit} style={{ width: '100%' }}>
|
||||
<form onSubmit={handleSearchSubmit} style={{ width: '90%' }}>
|
||||
<TextField id="search-input" ref={searchInput} label="Search" variant="outlined" fullWidth onChange={handleSearchChange} value={searchText}/>
|
||||
</form>
|
||||
);
|
||||
@@ -55,7 +57,7 @@ export default function List() {
|
||||
// Create Button Menu
|
||||
const [anchorEl, setAnchorEl] = React.useState<null | HTMLElement>(null);
|
||||
const createMenu = Boolean(anchorEl);
|
||||
const importForm = useRef<HTMLInputElement>(null)
|
||||
const importForm = useRef<HTMLInputElement>(null)
|
||||
const [currentImportFileName, setCurrentImportFileName] = useState(null)
|
||||
|
||||
const handleClick = (event: React.MouseEvent<HTMLButtonElement>) => {
|
||||
@@ -135,8 +137,8 @@ export default function List() {
|
||||
handleClose();
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
return (
|
||||
<div>
|
||||
<input type='file' id='file' ref={importForm} style={{ display: 'none' }} onChange={handleImportChange} accept=".csv, application/vnd.openxmlformats-officedocument.spreadsheetml.sheet, application/vnd.ms-excel, text/plain" />
|
||||
@@ -145,8 +147,8 @@ export default function List() {
|
||||
{/* <h1>kjasndkjandskjasndkjansdkjansd</h1> */}
|
||||
<Button
|
||||
id="import-button"
|
||||
variant='outlined'
|
||||
startIcon={<AddIcon />} sx={{ p: 1.8 }}
|
||||
variant='contained'
|
||||
startIcon={<AddIcon />} sx={{ p: 1.8, width: '200px' }}
|
||||
aria-controls={createMenu ? 'basic-menu' : undefined}
|
||||
aria-haspopup="true"
|
||||
aria-expanded={createMenu ? 'true' : undefined}
|
||||
@@ -186,7 +188,7 @@ export default function List() {
|
||||
</Button>
|
||||
</Stack>
|
||||
)}
|
||||
{( importResult &&
|
||||
{( importResult &&
|
||||
<Stack direction={'row'} sx={{ px: 2, pb: 2 }}>
|
||||
<Box sx={{ color: "text.secondary" }}>Last Import Result Report : <a href={importResult.result_file?.url ?? "#"}>{importResult.result_file?.name ?? "-"}</a></Box>
|
||||
</Stack>
|
||||
@@ -220,7 +222,7 @@ export default function List() {
|
||||
let updatedModel = model;
|
||||
if (row.id == model.id) {
|
||||
updatedModel.active = res.data.icd.active;
|
||||
}
|
||||
}
|
||||
return updatedModel;
|
||||
}),
|
||||
});
|
||||
@@ -240,15 +242,22 @@ export default function List() {
|
||||
|
||||
return (
|
||||
<React.Fragment>
|
||||
<TableRow sx={{ '& > *': { borderBottom: 'unset' } }}>
|
||||
<TableCell align="left">{row.code}</TableCell>
|
||||
<TableCell align="left">{row.name}</TableCell>
|
||||
<TableCell align="right">
|
||||
{/* <Button variant="outlined" color="error" size="small">Disable</Button> */}
|
||||
<Link to={`/master/diagnosis/${row.id}/diagnosis-history`}>
|
||||
<HistoryIcon />
|
||||
</Link>
|
||||
</TableCell>
|
||||
<TableRow sx={{ '& > *': { borderBottom: '1' } }}>
|
||||
<TableCell align="left"/>
|
||||
<TableCell align="left">{row.code}</TableCell>
|
||||
<TableCell align="left">{row.name}</TableCell>
|
||||
<TableCell align="right">
|
||||
<Stack direction="row" justifyContent="flex-end" spacing={1}>
|
||||
<TableMoreMenu actions={
|
||||
<>
|
||||
<MenuItem onClick={() => navigate(`/master/diagnosis/${row.id}/diagnosis-history`)}>
|
||||
<HistoryIcon />
|
||||
History
|
||||
</MenuItem>
|
||||
</>
|
||||
} />
|
||||
</Stack>
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
</React.Fragment>
|
||||
);
|
||||
@@ -301,22 +310,29 @@ export default function List() {
|
||||
useEffect(() => {
|
||||
loadDataTableData();
|
||||
}, [])
|
||||
|
||||
|
||||
return (
|
||||
<Stack>
|
||||
<ImportForm />
|
||||
|
||||
<Card>
|
||||
{/* The Main Table */}
|
||||
<TableContainer component={Paper}>
|
||||
<TableContainer component={Paper} sx={{ px: 1, mt: 3 }}>
|
||||
<Table aria-label="collapsible table">
|
||||
<TableBody>
|
||||
<colgroup>
|
||||
<col width="20" />
|
||||
<col width="250" />
|
||||
<col width="*" />
|
||||
<col width="50" />
|
||||
</colgroup>
|
||||
|
||||
<TableHead>
|
||||
<TableRow>
|
||||
<TableCell align="left" />
|
||||
<TableCell style={headStyle} align="left">Code</TableCell>
|
||||
<TableCell style={headStyle} align="left">Description</TableCell>
|
||||
<TableCell style={headStyle} align="right">Action</TableCell>
|
||||
<TableCell style={headStyle} align="right"></TableCell>
|
||||
</TableRow>
|
||||
</TableBody>
|
||||
</TableHead>
|
||||
{dataTableIsLoading ?
|
||||
(
|
||||
<TableBody>
|
||||
@@ -325,7 +341,7 @@ export default function List() {
|
||||
</TableRow>
|
||||
</TableBody>
|
||||
) : (
|
||||
dataTableData.data.length == 0 ?
|
||||
dataTableData.data.length == 0 ?
|
||||
(
|
||||
<TableBody>
|
||||
<TableRow>
|
||||
@@ -342,9 +358,8 @@ export default function List() {
|
||||
)}
|
||||
</Table>
|
||||
</TableContainer>
|
||||
|
||||
|
||||
<BasePagination paginationData={dataTableData} onPageChange={handlePageChange}/>
|
||||
</Card>
|
||||
</Stack>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -24,8 +24,8 @@ export default function PlanCreate() {
|
||||
}, [configuredCorporateContext])
|
||||
|
||||
const [ currentCorporatePlan, setCurrentCorporatePlan ] = useState<CorporatePlan>();
|
||||
|
||||
|
||||
|
||||
|
||||
const navigate = useNavigate();
|
||||
|
||||
const isEdit = !!id;
|
||||
@@ -48,6 +48,7 @@ export default function PlanCreate() {
|
||||
return (
|
||||
<Page title= "Master ICD - 10">
|
||||
<HeaderBreadcrumbs
|
||||
sx={{ px: 2 }}
|
||||
heading={'Master ICD - 10'}
|
||||
links={[
|
||||
{
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import * as Yup from 'yup';
|
||||
import { LoadingButton } from "@mui/lab";
|
||||
import { Card, Grid, Stack, Typography } from "@mui/material";
|
||||
import { Box, 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';
|
||||
@@ -9,6 +9,7 @@ import { yupResolver } from '@hookform/resolvers/yup';
|
||||
import { useSnackbar } from 'notistack';
|
||||
import { useNavigate, useParams } from 'react-router-dom';
|
||||
import axios from '../../../../utils/axios';
|
||||
import palette from '@/theme/palette';
|
||||
|
||||
type Props = {
|
||||
isEdit: boolean;
|
||||
@@ -68,11 +69,11 @@ export default function CorporatePlanForm({ isEdit, currentCorporatePlan }: Prop
|
||||
enqueueSnackbar('Division created successfully', { variant: 'success' });
|
||||
})
|
||||
.then((res) => {
|
||||
navigate('/master/diagnosis-template', { replace: true });
|
||||
navigate('/master/diagnosis', { replace: true });
|
||||
})
|
||||
.catch(({ response }) => {
|
||||
if (response.status === 422) {
|
||||
for (const [key, value] of Object.entries(response.data.errors)) {
|
||||
for (const [key, value] of Object.entries(response.data.errors)) {
|
||||
setError(key, { message: value[0] });
|
||||
enqueueSnackbar(value[0] ?? 'Failed Processing Request', { variant: 'error' });
|
||||
}
|
||||
@@ -88,7 +89,7 @@ export default function CorporatePlanForm({ isEdit, currentCorporatePlan }: Prop
|
||||
enqueueSnackbar('Division updated successfully', { variant: 'success' });
|
||||
})
|
||||
.then((res) => {
|
||||
navigate('/master/diagnosis-template' , { replace: true });
|
||||
navigate('/master/diagnosis' , { replace: true });
|
||||
})
|
||||
.catch(({ response }) => {
|
||||
enqueueSnackbar('Update Failed : '+ response.data.message, { variant: 'error' });
|
||||
@@ -98,31 +99,27 @@ export default function CorporatePlanForm({ isEdit, currentCorporatePlan }: Prop
|
||||
|
||||
return (
|
||||
<FormProvider methods={methods} onSubmit={handleSubmit(onSubmit)}>
|
||||
<Grid container spacing={2}>
|
||||
<Grid item xs={8}>
|
||||
<Card sx={{ p: 2 }}>
|
||||
<Stack spacing={3}>
|
||||
<Box sx={{ px: 2 }}>
|
||||
<Grid container spacing={2}>
|
||||
<Grid item xs={8}>
|
||||
<Card sx={{ px: 3, py: 4 }}>
|
||||
<Stack spacing={6}>
|
||||
|
||||
<Typography variant="h6">Detail</Typography>
|
||||
<Typography variant="h6" color={palette.light.primary.main}>Detail</Typography>
|
||||
|
||||
|
||||
<RHFTextField name="name" label="Name" />
|
||||
<RHFTextField name="description" label="Description" />
|
||||
<RHFTextField name="name" label="Name" />
|
||||
<RHFTextField name="description" label="Description" />
|
||||
|
||||
<LoadingButton type="submit" variant="contained" size="large" fullWidth={true} loading={isSubmitting}>
|
||||
{ isEdit? 'Update' : 'Create' }
|
||||
</LoadingButton>
|
||||
<LoadingButton type="submit" variant="contained" size="large" fullWidth={true} loading={isSubmitting}>
|
||||
{ isEdit? 'Update' : 'Create' }
|
||||
</LoadingButton>
|
||||
|
||||
</Stack>
|
||||
</Card>
|
||||
</Grid>
|
||||
{/* <Grid item xs={4}>
|
||||
<Card sx={{ p:2 }}>
|
||||
|
||||
<RHFSwitch name="active" label="Active" />
|
||||
</Card>
|
||||
</Grid> */}
|
||||
</Grid>
|
||||
</Stack>
|
||||
</Card>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</Box>
|
||||
</FormProvider>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -12,27 +12,26 @@ export default function Divisions() {
|
||||
|
||||
const { corporate_id } = useParams();
|
||||
|
||||
const pageTitle = 'Diagnosis Template';
|
||||
const pageTitle = 'Diagnosis';
|
||||
return (
|
||||
<Page title={ pageTitle }>
|
||||
|
||||
<HeaderBreadcrumbs
|
||||
sx={{ px: 2 }}
|
||||
heading={ pageTitle }
|
||||
links={[
|
||||
{
|
||||
name: 'Master',
|
||||
href: '/master/diagnosis-template',
|
||||
href: '/master/diagnosis',
|
||||
},
|
||||
{
|
||||
name: 'Diagnosis Template',
|
||||
href: '/master/diagnosis-template',
|
||||
name: 'Diagnosis',
|
||||
href: '/master/diagnosis',
|
||||
},
|
||||
]}
|
||||
/>
|
||||
|
||||
<Card>
|
||||
|
||||
<List />
|
||||
</Card>
|
||||
</Page>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -7,7 +7,7 @@ import UploadIcon from '@mui/icons-material/Upload';
|
||||
import CancelIcon from '@mui/icons-material/Cancel';
|
||||
import HistoryIcon from '@mui/icons-material/History';
|
||||
// hooks
|
||||
import { Link, NavLink as RouterLink } from 'react-router-dom';
|
||||
import { Link, NavLink as RouterLink, useNavigate } from 'react-router-dom';
|
||||
import React, { ChangeEvent, Component, useEffect, useRef, useState } from 'react';
|
||||
import useSettings from '../../../../hooks/useSettings';
|
||||
import { useParams, useSearchParams } from 'react-router-dom';
|
||||
@@ -17,13 +17,16 @@ import { LaravelPaginatedData } from '../../../../@types/paginated-data';
|
||||
import { Icd } from '../../../../@types/diagnosis';
|
||||
import BasePagination from '../../../../components/BasePagination';
|
||||
import { enqueueSnackbar } from 'notistack';
|
||||
import TableMoreMenu from '@/components/table/TableMoreMenu';
|
||||
import { EditOutlined, FindInPageOutlined } from '@mui/icons-material';
|
||||
|
||||
export default function List() {
|
||||
const { themeStretch } = useSettings();
|
||||
const { corporate_id } = useParams();
|
||||
const [searchParams, setSearchParams] = useSearchParams();
|
||||
const [importResult, setImportResult] = useState(null);
|
||||
|
||||
const navigate = useNavigate();
|
||||
const { themeStretch } = useSettings();
|
||||
const { corporate_id } = useParams();
|
||||
const [searchParams, setSearchParams] = useSearchParams();
|
||||
const [importResult, setImportResult] = useState(null);
|
||||
|
||||
function SearchInput(props: any) {
|
||||
// SEARCH
|
||||
const searchInput = useRef<HTMLInputElement>(null);
|
||||
@@ -44,7 +47,7 @@ export default function List() {
|
||||
}, [searchParams])
|
||||
|
||||
return (
|
||||
<form onSubmit={handleSearchSubmit} style={{ width: '100%' }}>
|
||||
<form onSubmit={handleSearchSubmit} style={{ width: '90%' }}>
|
||||
<TextField id="search-input" ref={searchInput} label="Search" variant="outlined" fullWidth onChange={handleSearchChange} value={searchText}/>
|
||||
</form>
|
||||
);
|
||||
@@ -55,7 +58,7 @@ export default function List() {
|
||||
// Create Button Menu
|
||||
const [anchorEl, setAnchorEl] = React.useState<null | HTMLElement>(null);
|
||||
const createMenu = Boolean(anchorEl);
|
||||
const importForm = useRef<HTMLInputElement>(null)
|
||||
const importForm = useRef<HTMLInputElement>(null)
|
||||
const [currentImportFileName, setCurrentImportFileName] = useState(null)
|
||||
|
||||
const handleClick = (event: React.MouseEvent<HTMLButtonElement>) => {
|
||||
@@ -130,8 +133,8 @@ export default function List() {
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
return (
|
||||
<div>
|
||||
<input type='file' id='file' ref={importForm} style={{ display: 'none' }} onChange={handleImportChange} accept=".csv, application/vnd.openxmlformats-officedocument.spreadsheetml.sheet, application/vnd.ms-excel, text/plain" />
|
||||
@@ -139,17 +142,15 @@ export default function List() {
|
||||
<SearchInput onSearch={applyFilter}/>
|
||||
{/* <h1>kjasndkjandskjasndkjansdkjansd</h1> */}
|
||||
<Button
|
||||
id="import-button"
|
||||
variant='outlined'
|
||||
startIcon={<AddIcon />} sx={{ p: 1.8 }}
|
||||
aria-controls={createMenu ? 'basic-menu' : undefined}
|
||||
aria-haspopup="true"
|
||||
aria-expanded={createMenu ? 'true' : undefined}
|
||||
|
||||
id="import-button"
|
||||
variant='contained'
|
||||
startIcon={<AddIcon />} sx={{ p: 1.8, width: '200px' }}
|
||||
aria-controls={createMenu ? 'basic-menu' : undefined}
|
||||
aria-haspopup="true"
|
||||
aria-expanded={createMenu ? 'true' : undefined}
|
||||
onClick={() => navigate(`/master/diagnosis/create`)}
|
||||
>
|
||||
<Link to={`/master/diagnosis-template/create`} style={{ textDecoration: 'none', color: 'blue'}}>
|
||||
Create
|
||||
</Link>
|
||||
Create
|
||||
</Button>
|
||||
<Menu
|
||||
id="import-button"
|
||||
@@ -161,7 +162,7 @@ export default function List() {
|
||||
}}
|
||||
>
|
||||
<MenuItem>
|
||||
|
||||
|
||||
</MenuItem>
|
||||
</Menu>
|
||||
</Stack>
|
||||
@@ -195,7 +196,7 @@ export default function List() {
|
||||
let updatedModel = model;
|
||||
if (row.id == model.id) {
|
||||
updatedModel.active = res.data.icd.active;
|
||||
}
|
||||
}
|
||||
return updatedModel;
|
||||
}),
|
||||
});
|
||||
@@ -211,27 +212,30 @@ export default function List() {
|
||||
|
||||
return (
|
||||
<React.Fragment>
|
||||
<TableRow sx={{ '& > *': { borderBottom: 'unset' } }}>
|
||||
<TableCell align="left">{row.name}</TableCell>
|
||||
<TableCell align="left">{row.description ?? '-'}</TableCell>
|
||||
<TableCell align="center">
|
||||
{/* <Button variant="outlined" color="error" size="small">Disable</Button> */}
|
||||
<Stack direction="row" justifyContent="flex-end" spacing={1}>
|
||||
<Link to={`/master/diagnosis/${row.id}`}>
|
||||
<Button variant="outlined" color="primary" size="small">
|
||||
Detail
|
||||
</Button>
|
||||
</Link>
|
||||
<Link to={`/master/diagnosis-template/${row.id}/edit`}>
|
||||
<Button variant="outlined" color="primary" size="small">
|
||||
Edit
|
||||
</Button>
|
||||
</Link>
|
||||
<Link to={`/master/diagnosis-template/${row.id}/diagnosis-template-history`}>
|
||||
<HistoryIcon />
|
||||
</Link>
|
||||
</Stack>
|
||||
</TableCell>
|
||||
<TableRow sx={{ '& > *': { borderBottom: '1' } }}>
|
||||
<TableCell align="left"/>
|
||||
<TableCell align="left">{row.name}</TableCell>
|
||||
<TableCell align="left">{row.description ?? '-'}</TableCell>
|
||||
<TableCell align="center">
|
||||
<Stack direction="row" justifyContent="flex-end" spacing={1}>
|
||||
<TableMoreMenu actions={
|
||||
<>
|
||||
<MenuItem onClick={() => navigate(`/master/diagnosis/${row.id}`)}>
|
||||
<FindInPageOutlined />
|
||||
Detail
|
||||
</MenuItem>
|
||||
<MenuItem onClick={() => navigate(`/master/diagnosis-template/${row.id}/edit`)} >
|
||||
<EditOutlined />
|
||||
Edit
|
||||
</MenuItem>
|
||||
<MenuItem onClick={() => navigate(`/master/diagnosis-template/${row.id}/diagnosis-template-history`)}>
|
||||
<HistoryIcon />
|
||||
History
|
||||
</MenuItem>
|
||||
</>
|
||||
} />
|
||||
</Stack>
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
</React.Fragment>
|
||||
);
|
||||
@@ -285,22 +289,29 @@ export default function List() {
|
||||
useEffect(() => {
|
||||
loadDataTableData();
|
||||
}, [])
|
||||
|
||||
|
||||
return (
|
||||
<Stack>
|
||||
<ImportForm />
|
||||
<ImportForm />
|
||||
|
||||
<Card>
|
||||
{/* The Main Table */}
|
||||
<TableContainer component={Paper}>
|
||||
<TableContainer component={Paper} sx={{ px: 1, mt: 3 }}>
|
||||
<Table aria-label="collapsible table">
|
||||
<TableBody>
|
||||
<colgroup>
|
||||
<col width="20" />
|
||||
<col width="250" />
|
||||
<col width="*" />
|
||||
<col width="50" />
|
||||
</colgroup>
|
||||
|
||||
<TableHead>
|
||||
<TableRow>
|
||||
<TableCell align="left" />
|
||||
<TableCell style={headStyle} align="left">Name</TableCell>
|
||||
<TableCell style={headStyle} align="left">Description</TableCell>
|
||||
<TableCell style={headStyle} align="right">Action</TableCell>
|
||||
<TableCell style={headStyle} align="right"></TableCell>
|
||||
</TableRow>
|
||||
</TableBody>
|
||||
</TableHead>
|
||||
{dataTableIsLoading ?
|
||||
(
|
||||
<TableBody>
|
||||
@@ -309,7 +320,7 @@ export default function List() {
|
||||
</TableRow>
|
||||
</TableBody>
|
||||
) : (
|
||||
dataTableData.data.length == 0 ?
|
||||
dataTableData.data.length == 0 ?
|
||||
(
|
||||
<TableBody>
|
||||
<TableRow>
|
||||
@@ -326,9 +337,8 @@ export default function List() {
|
||||
)}
|
||||
</Table>
|
||||
</TableContainer>
|
||||
|
||||
|
||||
<BasePagination paginationData={dataTableData} onPageChange={handlePageChange}/>
|
||||
</Card>
|
||||
</Stack>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -148,8 +148,8 @@ import {
|
||||
handleCancelImportButton();
|
||||
loadDataTableData();
|
||||
setImportResult(response.data);
|
||||
console.log(response.data);
|
||||
setImportLoading(false);
|
||||
enqueueSnackbar('Success Import Drugs', { variant: 'success' });
|
||||
})
|
||||
.catch((response) => {
|
||||
enqueueSnackbar(
|
||||
|
||||
@@ -268,12 +268,12 @@ export default function Router() {
|
||||
element: <MasterHospitalsCreate />,
|
||||
},
|
||||
{
|
||||
path: 'master/diagnosis-template/create',
|
||||
element: <MasterDiagnosisTemplateCreate />,
|
||||
path: 'master/diagnosis',
|
||||
element: <MasterDiagnosisTemplate />,
|
||||
},
|
||||
{
|
||||
path: 'master/diagnosis-template',
|
||||
element: <MasterDiagnosisTemplate />,
|
||||
path: 'master/diagnosis/create',
|
||||
element: <MasterDiagnosisTemplateCreate />,
|
||||
},
|
||||
{
|
||||
path: 'master/diagnosis-template/:id/diagnosis-template-history',
|
||||
@@ -381,6 +381,10 @@ export default function Router() {
|
||||
path: 'claim-requests/edit/:id',
|
||||
element: <ClaimRequestsCreate />,
|
||||
},
|
||||
{
|
||||
path: 'claim-requests/detail/:id',
|
||||
element: <ClaimRequestsDetail />,
|
||||
},
|
||||
{
|
||||
path: 'claims/create',
|
||||
element: <ClaimsCreate />,
|
||||
@@ -559,6 +563,7 @@ const ClaimShow = Loadable(lazy(() => import('../pages/Claims/Show')));
|
||||
|
||||
const ClaimRequests = Loadable(lazy(() => import('../pages/ClaimRequests/Index')));
|
||||
const ClaimRequestsCreate = Loadable(lazy(() => import('../pages/ClaimRequests/CreateUpdate')));
|
||||
const ClaimRequestsDetail = Loadable(lazy(() => import('../pages/ClaimRequests/Detail')));
|
||||
|
||||
|
||||
const Membership = Loadable(lazy(() => import('../pages/Service/Membership/index')));
|
||||
|
||||
@@ -234,7 +234,7 @@ export default function FormRequestClaim({ member, handleSubmitSuccess }) {
|
||||
{/* -------------------------------Upload Dokumen Diagnosa------------------------------- */}
|
||||
<Stack sx={{ marginTop: 2 }}>
|
||||
<Typography variant="body1" sx={{fontWeight:'bold'}}>
|
||||
Diagnosis Dokumen
|
||||
Diagnosis Dokument
|
||||
</Typography>
|
||||
{/* <Typography variant="body2">Hasil Lab, </Typography> */}
|
||||
<Stack
|
||||
|
||||
Reference in New Issue
Block a user