diff --git a/Modules/HospitalPortal/Http/Controllers/Api/RequestLogController.php b/Modules/HospitalPortal/Http/Controllers/Api/RequestLogController.php index 3f6328c9..7bc347e7 100644 --- a/Modules/HospitalPortal/Http/Controllers/Api/RequestLogController.php +++ b/Modules/HospitalPortal/Http/Controllers/Api/RequestLogController.php @@ -339,6 +339,8 @@ class RequestLogController extends Controller 'status_final_log' => 'requested', 'final_log' => 1, 'discharge_date' => $request->discharge_date, + 'created_final_by'=> date('Y-m-d H:i:s'), + 'created_final_at'=> auth()->user()->id, ]); if ($request->hasFile('result_files')) { foreach ($request->result_files as $file) { diff --git a/Modules/Internal/Http/Controllers/Api/ReportLogController.php b/Modules/Internal/Http/Controllers/Api/ReportLogController.php new file mode 100644 index 00000000..4407cdc0 --- /dev/null +++ b/Modules/Internal/Http/Controllers/Api/ReportLogController.php @@ -0,0 +1,192 @@ +where('deleted_at', null) + ->when($request->final_log, function($q, $final_log) { + $q->where('final_log', $final_log); + }) + ->when($request->search, function ($q, $search) { + $q->where('code', 'LIKE', "%".$search."%"); + $q->orWhereHas('member', function ($subQuery) use ($search) { + $subQuery->where('name', 'LIKE', "%".$search."%"); + }); + }) + ->when($request->orderBy, function ($q, $orderBy) use ($request) { + if (in_array($orderBy, ['submission_date', 'code', 'service_code', 'status'])) { + $q->orderBy($orderBy, $request->order); + } + }) + ->when(empty($request->orderBy), function ($q) { + $q->orderBy('submission_date', 'desc'); + }) + ->when($request->service_code, function($q, $service_code) { + if ($service_code == 'IP'){ // Penjagaan sementara agar ini hanya muncul di inpatient monitoring + $q->where('service_code', $service_code); + } else { + $q->where('service_code', '!=', 'IP'); // Dan selain IP muncul di final LOG + } + }) + // ->where('status', $request->status) + ->with(['member', 'files', 'service', 'member.currentPolicy']) + ->paginate(); + + return Helper::paginateResources(ReportLogResource::collection($requestLog)); + } + + /** + * Show the form for creating a new resource. + * @return Renderable + */ + public function create() + { + return view('internal::create'); + } + + /** + * Show the specified resource. + * @param int $id + * @return Renderable + */ + public function show($id) + { + $claimRequest = RequestLog::findOrFail($id); + $claimRequest->load([ + 'histories' => function ($history) { + $history->latest(); + }, + 'files', + 'member', + 'member.currentPlan' => function($memberPlan) { + $memberPlan->join('request_logs', 'request_logs.service_code', '=', 'plans.service_code'); + }, + // 'member.current_policy', + 'claim', + 'organization', + + ]); + + return Helper::responseJson(data: RequestLogShowResource::make($claimRequest)); + } + + /** + * Show the form for editing the specified resource. + * @param int $id + * @return Renderable + */ + public function edit($id) + { + return view('internal::edit'); + } + + /** + * Update the specified resource in storage. + * @param Request $request + * @param int $id + * @return Renderable + */ + public function update(Request $request, $id) + { + + } + + /** + * Remove the specified resource from storage. + * @param int $id + * @return Renderable + */ + public function destroy(Request $request, $id) + { + + } + + + /** + * Generate Export Excel Request LOG + */ + + public function generateDataRequestLogExcel(){ + $file_name = 'Data Request LOG'; + // Membuat penulis entitas Spout + $writer = WriterEntityFactory::createXLSXWriter(); + // Membuka penulis untuk menulis ke file + $writer->openToFile(public_path('files/Data Request LOG.xlsx')); + + // Sheet 1 + $writer->getCurrentSheet()->setName('Data'); + $headers_map_to_table_fields = RequestLog::$listing_data_doc_headers; + $headerRow = WriterEntityFactory::createRowFromArray($headers_map_to_table_fields); + $writer->addRow($headerRow); + + $dataRequestLog = RequestLog::query() + // ->whereHas('corporatePlan', function ($corporatePlan) use ($corporate_id) { + // $corporatePlan->where('corporate_id', $corporate_id); + // }) + ->with('member') + ->orderBy('id', 'desc') + ->get()->toArray(); + + // dd($dataRequestLog); + foreach ($dataRequestLog as $index => $row){ + $serviceType = $this->getServiceName($row['service_code']); + + $rowData = [ + $row['id'], // id + $row['code'], // code + $row['member']['name'], // name + $row['submission_date'], // submission date + $serviceType, // service type + $row['payment_type_name'], // service type + $row['status'], // service type + ]; + $row = WriterEntityFactory::createRowFromArray($rowData); + $writer->addRow($row); + } + $writer->close(); + + return Helper::responseJson([ + 'file_name' => "Data Request Log " . date('Y-m-d h:i:s'), + "file_url" => url('files/Data Request LOG.xlsx') + ]); + } + +} diff --git a/Modules/Internal/Http/Controllers/Api/RequestLogController.php b/Modules/Internal/Http/Controllers/Api/RequestLogController.php index 1a7875f4..a4479d40 100644 --- a/Modules/Internal/Http/Controllers/Api/RequestLogController.php +++ b/Modules/Internal/Http/Controllers/Api/RequestLogController.php @@ -63,8 +63,8 @@ class RequestLogController extends Controller }); }) ->when($request->orderBy, function ($q, $orderBy) use ($request) { - if (in_array($orderBy, ['submission_date', 'code'])) { - $q->orderBy($orderBy, $request->orderBy); + if (in_array($orderBy, ['submission_date', 'code', 'service_code', 'status'])) { + $q->orderBy($orderBy, $request->order); } }) ->when(empty($request->orderBy), function ($q) { diff --git a/Modules/Internal/Routes/api.php b/Modules/Internal/Routes/api.php index b7800eb2..5126ef8c 100644 --- a/Modules/Internal/Routes/api.php +++ b/Modules/Internal/Routes/api.php @@ -45,6 +45,9 @@ use Modules\Internal\Http\Controllers\Api\LaboratoriumResultController; use Modules\Internal\Http\Controllers\Api\CorporateManageController; use Modules\Internal\Http\Controllers\ClaimEncounterController; +// Report +use Modules\Internal\Http\Controllers\Api\ReportLogController; + /* |-------------------------------------------------------------------------- @@ -315,6 +318,12 @@ Route::prefix('internal')->group(function () { Route::get('claim-requests/service/{id}', [ClaimRequestController::class, 'getServiceMember']); + // Report API + Route::prefix('report')->group(function () { + Route::prefix('/logs')->group(function () { + Route::get('/', [ReportLogController::class, 'index']); + }); + }); }); diff --git a/Modules/Internal/Transformers/ReportLogResource.php b/Modules/Internal/Transformers/ReportLogResource.php new file mode 100644 index 00000000..5db086dd --- /dev/null +++ b/Modules/Internal/Transformers/ReportLogResource.php @@ -0,0 +1,58 @@ +files->mapToGroups(function($file) { + return [Str::slug($file->type, '_') => $file]; + }); + $provider = Organization::where('id', $this->organization_id)->first(); + $documentQty = File::where(['fileable_type' => 'App\Models\RequestLog', 'fileable_id' => $this->id])->get()->toArray(); + $parsedDateTime = Carbon::parse($this->created_at); + $formattedDateTime = $parsedDateTime->format('Y-m-d H:i:s'); + + $durationGl = Helper::differenceTime($formattedDateTime, $this->submission_date); + $durationFinalGl = Helper::differenceTime($this->created_final_at, $this->approved_by); + + $data = [ + 'id' => $this->id, + 'code' => $this->code, + 'created_at' => $formattedDateTime, + 'created_final_at' => $this->created_final_at, + 'submission_date' => $this->submission_date, + 'approved_by' => Helper::userName($this->approved_by), + 'approved_final_log_at' => $this->approved_final_log_at, + 'approved_final_log_by' => Helper::userName($this->approved_final_log_by), + 'service_name' => $this->service ? $this->service->name : '', + 'provider' => $provider ? $provider->name : '-', + 'document_qty' => count($documentQty), + 'status' => $this->status ?? '-', + 'status_final_log' => $this->status_final_log ?? '-', + 'member_name' => $this->member->name, + 'payment_type' => $this->payment_type, + 'payment_type_name' => $this->payment_type_name, + 'duration_gl' => $durationGl, + 'duration_final_gl' => $this->final_log == 1 ? $durationFinalGl : '-', + 'files_by_type' => $filesGroupByType + ]; + + return $data; + } +} diff --git a/app/Helpers/Helper.php b/app/Helpers/Helper.php index e41efe7a..b9b1a09b 100644 --- a/app/Helpers/Helper.php +++ b/app/Helpers/Helper.php @@ -9,6 +9,7 @@ use Symfony\Component\HttpFoundation\Response; use PHPMailer\PHPMailer\PHPMailer; use Illuminate\Support\Facades\DB; use App\Models\Member; +use App\Models\User; use App\Models\Service; class Helper @@ -89,6 +90,22 @@ class Helper return $principalName->name; } + public static function userName($id) + { + $user = User::find($id); + if ($user) { + $person = $user->person; + if ($person) { + return $person->name; + } else { + return 'Person not found for this user.'; + } + } else { + return 'User not found.'; + } + + } + public static function serviceName($code) { $serviceName = Service::where('code', $code)->get()->first(); @@ -138,6 +155,14 @@ class Helper return $datesAvailabilities; } + public static function differenceTime($startDate, $endDate){ + $startTime = Carbon::parse($startDate); + $endTime = Carbon::parse($endDate); + + $interval = $endTime->diff($startTime); + return $interval->format('%d days, %h hours and %i minutes'); + } + public static function dailyAvailabilities($availabilities) { $hours = [ diff --git a/app/Models/RequestLog.php b/app/Models/RequestLog.php index ce7fb29b..8f7f9a20 100644 --- a/app/Models/RequestLog.php +++ b/app/Models/RequestLog.php @@ -47,6 +47,8 @@ class RequestLog extends Model 'approved_at', 'approved_final_log_by', 'approved_final_log_at', + 'created_final_at', + 'created_final_by', ]; protected $hidden = [ diff --git a/database/migrations/2024_01_30_102516_add_coloum_to_request_logs.php b/database/migrations/2024_01_30_102516_add_coloum_to_request_logs.php new file mode 100644 index 00000000..65f73135 --- /dev/null +++ b/database/migrations/2024_01_30_102516_add_coloum_to_request_logs.php @@ -0,0 +1,34 @@ +dateTime('created_final_at'); + $table->bigInteger('created_final_by'); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::table('request_logs', function (Blueprint $table) { + $table->dropColumn('created_final_at'); + $table->dropColumn('created_final_by'); + }); + } +}; diff --git a/frontend/dashboard/src/layouts/dashboard/navbar/NavConfig.tsx b/frontend/dashboard/src/layouts/dashboard/navbar/NavConfig.tsx index 687e7a3a..be279ee1 100644 --- a/frontend/dashboard/src/layouts/dashboard/navbar/NavConfig.tsx +++ b/frontend/dashboard/src/layouts/dashboard/navbar/NavConfig.tsx @@ -91,6 +91,7 @@ const navConfig = [ { title: 'REPORT', children: [ + { title: 'Letter of Guarantee', path: '/report/logs' }, { title: 'Appointment', path: '/report/appointments' }, { title: 'Live Chat', path: '/report/live-chat' }, { title: 'Linksehat Payment', path: '/report/linksehat-payments' }, diff --git a/frontend/dashboard/src/pages/CustomerService/Request/List.tsx b/frontend/dashboard/src/pages/CustomerService/Request/List.tsx index 44cef222..ecf25789 100644 --- a/frontend/dashboard/src/pages/CustomerService/Request/List.tsx +++ b/frontend/dashboard/src/pages/CustomerService/Request/List.tsx @@ -9,6 +9,7 @@ import { Table, TableBody, TableCell, + TableSortLabel, TableRow, TextField, Typography, @@ -26,6 +27,7 @@ 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'; +import { visuallyHidden } from '@mui/utils'; import FindInPageOutlinedIcon from '@mui/icons-material/FindInPageOutlined'; import ApprovalIcon from '../../../../build/icons/ic_approval.svg'; @@ -57,6 +59,7 @@ import { RequestLogType } from '../Request/Model/Types'; import SvgIconStyle from '../../../components/SvgIconStyle'; import { Delete } from '@mui/icons-material'; import DialogDeleteRequestLOG from '../Request/Components/DialogDeleteRequestLOG'; +import { HeadCell, Order } from '@/@types/table'; // import LoadingButton from '@/theme/overrides/LoadingButton'; export default function List() { @@ -298,8 +301,15 @@ export default function List() { const loadDataTableData = async (appliedFilter: any | null = null) => { setDataTableLoading(true); - const filter = appliedFilter ? appliedFilter : Object.fromEntries([...searchParams.entries()]); - const response = await axios.get('/customer-service/request', { params: filter }); + const parameters = + Object.keys(appliedParams).length !== 0 + ? appliedParams + : Object.fromEntries([...searchParams.entries(), ['order', order], ['orderBy', orderBy]]); + + const response = await axios.get('/customer-service/request', { + params: { ...parameters }, + }); + setDataTableLoading(false); setDataTableData(response.data); }; @@ -319,10 +329,6 @@ export default function List() { const [idRequestLog, setidRequestLog] = useState(); const [openDialogDeleteRequestLog, setDialogDeleteRequestLog] = useState(false) - useEffect(() => { - loadDataTableData(); - }, []); - const headStyle = { fontWeight: 'bold', }; @@ -484,6 +490,104 @@ export default function List() { /* ------------------ END TABLE ROW ------------------ */ } + /* -------------------------------- headCell -------------------------------- */ + const headCells: HeadCell[] = [ + { + id: 'code', + align: 'left', + label: 'Code', + isSort: true, + }, + { + id: 'provider', + align: 'left', + label: 'Provider', + isSort: false, + }, + + { + id: 'name', + align: 'left', + label: 'Name', + isSort: false, + }, + { + id: 'submission_date', + align: 'left', + label: 'Submision Date', + isSort: true, + }, + { + id: 'service_code', + align: 'left', + label: 'Service Type', + isSort: true, + }, + { + id: 'claim_method', + align: 'left', + label: 'Claim Method', + isSort: false, + }, + { + id: 'status', + align: 'left', + label: 'Status', + isSort: true, + }, + { + id: '', + align: 'left', + label: 'Action', + isSort: false, + }, + ]; + /* -------------------------------------------------------------------------- */ + + const createSortHandler = (property: string) => (event: React.MouseEvent) => { + handleRequestSort(event, property); + }; + + /* ------------------------------ handle params ----------------------------- */ + const [appliedParams, setAppliedParams] = useState({}); + + const params = { + searchParams: searchParams, + setSearchParams: setSearchParams, + appliedParams: appliedParams, + setAppliedParams: setAppliedParams, + }; + + /* ------------------------------ handle order ------------------------------ */ + const [order, setOrder] = useState('desc'); + const [orderBy, setOrderBy] = useState('submission_date'); + + const orders = { + order: order, + setOrder: setOrder, + orderBy: orderBy, + setOrderBy: setOrderBy, + }; + + /* ------------------------------- handle sort ------------------------------ */ + const handleRequestSort = async (event: React.MouseEvent, property: string) => { + const isAsc = orders?.orderBy === property && orders?.order === 'asc'; + + orders?.setOrder(isAsc ? 'desc' : 'asc'); + orders?.setOrderBy(property); + const parameters = Object.fromEntries([ + ...(params?.searchParams.entries() as IterableIterator<[string, string]>), + ['order', isAsc ? 'desc' : 'asc'], + ['orderBy', property], + ]); + params?.setAppliedParams(parameters); + }; + + useEffect(() => { + loadDataTableData(); + }, [appliedParams, searchParams, order, orderBy, setSearchParams]); + + function TableContent() { return ( @@ -494,7 +598,7 @@ export default function List() { {/* ID Request LOG */} - + {/* Code @@ -504,7 +608,17 @@ export default function List() { Name - Date of Submission + {}} + > + Submision Date + + + sorted ascending + + Service Type @@ -515,7 +629,37 @@ export default function List() { Status - + */} + + {headCells && + headCells.map((headCell, index) => ( + + {headCell.isSort ? ( + + {headCell.label} + {orders?.orderBy === headCell.id ? ( + + {orders.order === 'desc' ? 'sorted descending' : 'sorted ascending'} + + ) : null} + + ) : ( + headCell.label + )} + + ))} + {/* ------------------ END TABLE HEADER ------------------ */} diff --git a/frontend/dashboard/src/pages/Report/Log/Index.tsx b/frontend/dashboard/src/pages/Report/Log/Index.tsx new file mode 100644 index 00000000..9f5b1cbe --- /dev/null +++ b/frontend/dashboard/src/pages/Report/Log/Index.tsx @@ -0,0 +1,35 @@ +import { Card, Grid, Container } 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 Doctors() { + const { themeStretch } = useSettings(); + + const { id } = useParams(); + + const pageTitle = 'Letter of Guarantee'; + return ( + + + + + + + + ); +} diff --git a/frontend/dashboard/src/pages/Report/Log/List.tsx b/frontend/dashboard/src/pages/Report/Log/List.tsx new file mode 100644 index 00000000..6ea09c9d --- /dev/null +++ b/frontend/dashboard/src/pages/Report/Log/List.tsx @@ -0,0 +1,605 @@ +// @mui +import { + Box, + Button, + Card, + Collapse, + IconButton, + MenuItem, + Table, + TableBody, + TableCell, + TableSortLabel, + TableRow, + TextField, + Typography, + Stack, + Menu, + ButtonGroup, + Link, + Chip, + TableHead, + Grid, + SvgIcon, +} from '@mui/material'; +import UploadIcon from '@mui/icons-material/Upload'; +import CancelIcon from '@mui/icons-material/Cancel'; +import { visuallyHidden } from '@mui/utils'; + +import FindInPageOutlinedIcon from '@mui/icons-material/FindInPageOutlined'; + + +// hooks +import React, { ChangeEvent, useEffect, useRef, useState } from 'react'; +import { Navigate, useNavigate, useSearchParams } from 'react-router-dom'; +import useSettings from '@/hooks/useSettings'; +// components +import axios from '../../../utils/axios'; +import { LaravelPaginatedData, LaravelPaginatedDataDefault } from '../../../@types/paginated-data'; +import DataTable from '../../../components/LaravelTable'; +import { LoadingButton } from '@mui/lab'; +import { enqueueSnackbar } from 'notistack'; +import { fDateTimesecond } from '@/utils/formatTime'; +import { capitalizeFirstLetter } from '@/utils/formatString'; +import Label from '@/components/Label'; +import TableMoreMenu from '@/components/table/TableMoreMenu'; +import { Import } from '@/@types/claims'; +// import DialogDeleteRequestLOG from '../Request/Components/DialogDeleteRequestLOG'; +import { HeadCell, Order } from '@/@types/table'; +// import LoadingButton from '@/theme/overrides/LoadingButton'; + +export default function List() { + const { themeColorPresets } = useSettings(); + const [searchParams, setSearchParams] = useSearchParams(); + const [importResult, setImportResult] = useState(null); + + const navigate = useNavigate() + + function SearchInput(props: any) { + // SEARCH + 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({ search: searchText }); // Trigger to Parent + }; + + useEffect(() => { + // Trigger First Search + setSearchText(searchParams.get('search') ?? ''); + }, []); + + return ( +
+ + + ); + } + + function ImportForm(props: any) { + // IMPORT + // Create Button Menu + const [anchorEl, setAnchorEl] = React.useState(null); + const createMenu = Boolean(anchorEl); + const importForm = useRef(null); + const [currentImportFileName, setCurrentImportFileName] = useState(null); + const [importLoading, setImportLoading] = useState(false); + + 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 handleImportChange = (event: any) => { + if (event.target.files[0]) { + setCurrentImportFileName(event.target.files[0].name); + } else { + setCurrentImportFileName(null); + } + }; + + const handleUpload = () => { + if (importForm.current?.files.length) { + const formData = new FormData(); + formData.append('file', importForm.current?.files[0]); + + setImportLoading(true); + axios + .post(`customer-service/request/import`, formData) + .then((response) => { + handleCancelImportButton(); + loadDataTableData(); + setImportResult(response.data); + // alert('Succesfully read '+ response.data.total_successed_row + ' with ' + response.data.total_failed_row + ' failed rows'); + setImportLoading(false); + }) + .catch((response) => { + enqueueSnackbar( + 'Looks like something went wrong. Please check your data and try again. ' + + response.message, + { variant: 'error' } + ); + setImportLoading(false); + }); + } else { + enqueueSnackbar('No File Selected', { variant: 'warning' }); + } + }; + + const handleGetTemplate = (type :string) => { + axios.get('corporates/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 handleGetData = (type :string) => { + axios.get(`customer-service/request/data`) + .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(); + }) + } + + return ( +
+ + {!currentImportFileName && ( + + + + + Import + {handleGetTemplate('template-request-log')}}>Download Template + {handleGetData('data-request-log')}}>Download Request LOG + + + )} + + {currentImportFileName && ( + + + + + + + } + sx={{ p: 1.8 }} + onClick={handleUpload} + loading={importLoading} + > + Upload + + + )} + + {importResult && ( + + + Last Import Result :{' '} + + {importResult.total_success_row ?? 0} + {' '} + Row Processed,{' '} + + {importResult.total_failed_row} + {' '} + Failed, Report :{' '} + + {importResult.result_file?.name ?? '-'} + + + + )} +
+ ); + } + + // Dummy Default Data + const [dataTableIsLoading, setDataTableLoading] = useState(true); + const [dataTableData, setDataTableData] = useState( + LaravelPaginatedDataDefault + ); + + const loadDataTableData = async (appliedFilter: any | null = null) => { + setDataTableLoading(true); + const parameters = + Object.keys(appliedParams).length !== 0 + ? appliedParams + : Object.fromEntries([...searchParams.entries(), ['order', order], ['orderBy', orderBy]]); + + const response = await axios.get('/report/logs', { + params: { ...parameters }, + }); + + setDataTableLoading(false); + setDataTableData(response.data); + }; + + const applyFilter = async (searchFilter: { search: string }) => { + await loadDataTableData(searchFilter); + setSearchParams(searchFilter); + }; + + const handlePageChange = (event: ChangeEvent, value: number): void => { + const filter = Object.fromEntries([...searchParams.entries(), ['page', value]]); + loadDataTableData(filter); + setSearchParams(filter); + }; + + // Called on every row to map the data to the columns + function createData(data: any): any { + return { + ...data, + }; + } + + { + /* ------------------ TABLE ROW ------------------ */ + } + function Row(props: { row: ReturnType }) { + const { row } = props; + const [open, setOpen] = React.useState(false); + const [loadingApprove, setLoadingApprove] = React.useState(false); + + return ( + + *': { borderBottom: 'unset' } }}> + {row.code} + {row.member_name} + + + {row.approved_by} + + + {row.approved_final_log_by} + {row.service_name} + {row.provider} + {row.document_qty} + {row.duration_gl} + {row.duration_final_gl} + + { row.status == "requested" ? + () : + row.status == "declined" ? + () + : + row.status == "canceled" ? + () + : + () + } + + + { row.status_final_log == "requested" ? + () : + row.status_final_log == "declined" ? + () + : + row.status_final_log == "canceled" ? + () + : + row.status_final_log == "unknown" ? + () + : + () + } + + {/* + + navigate ('/custormer-service/request/detail/'+row.id+'')}> + + Detail + + + } /> + */} + + + ); + } + { + /* ------------------ END TABLE ROW ------------------ */ + } + + /* -------------------------------- headCell -------------------------------- */ + const headCells: HeadCell[] = [ + { + id: 'code', + align: 'left', + label: 'Code', + isSort: true, + }, + { + id: 'name', + align: 'left', + label: 'Member', + isSort: false, + }, + { + id: 'created_at', + align: 'left', + label: 'GL Create Time', + isSort: true, + }, + { + id: 'submission_date', + align: 'left', + label: 'GL Submit Time', + isSort: true, + }, + { + id: 'approved_by', + align: 'left', + label: 'GL Created by', + isSort: false, + }, + { + id: 'name', + align: 'left', + label: 'FGL Create Time', + isSort: false, + }, + { + id: 'submission_date', + align: 'left', + label: 'FGL Submit Time', + isSort: true, + }, + { + id: 'service_code', + align: 'left', + label: 'FGL Created by', + isSort: true, + }, + { + id: 'claim_method', + align: 'left', + label: 'Service', + isSort: false, + }, + { + id: 'status', + align: 'left', + label: 'Provider', + isSort: true, + }, + { + id: '', + align: 'left', + label: 'Document Qty ', + isSort: false, + }, + { + id: '', + align: 'left', + label: 'Duration GL ', + isSort: false, + }, + { + id: '', + align: 'left', + label: 'DurationĀ FGL ', + isSort: false, + }, + { + id: '', + align: 'left', + label: 'Status GL ', + isSort: false, + }, + { + id: '', + align: 'left', + label: 'Status Final GL ', + isSort: false, + }, + ]; + /* -------------------------------------------------------------------------- */ + + const createSortHandler = (property: string) => (event: React.MouseEvent) => { + handleRequestSort(event, property); + }; + + /* ------------------------------ handle params ----------------------------- */ + const [appliedParams, setAppliedParams] = useState({}); + + const params = { + searchParams: searchParams, + setSearchParams: setSearchParams, + appliedParams: appliedParams, + setAppliedParams: setAppliedParams, + }; + + /* ------------------------------ handle order ------------------------------ */ + const [order, setOrder] = useState('desc'); + const [orderBy, setOrderBy] = useState('submission_date'); + + const orders = { + order: order, + setOrder: setOrder, + orderBy: orderBy, + setOrderBy: setOrderBy, + }; + + /* ------------------------------- handle sort ------------------------------ */ + const handleRequestSort = async (event: React.MouseEvent, property: string) => { + const isAsc = orders?.orderBy === property && orders?.order === 'asc'; + + orders?.setOrder(isAsc ? 'desc' : 'asc'); + orders?.setOrderBy(property); + const parameters = Object.fromEntries([ + ...(params?.searchParams.entries() as IterableIterator<[string, string]>), + ['order', isAsc ? 'desc' : 'asc'], + ['orderBy', property], + ]); + params?.setAppliedParams(parameters); + }; + + useEffect(() => { + loadDataTableData(); + }, [appliedParams, searchParams, order, orderBy, setSearchParams]); + + + function TableContent() { + return ( +
+ {/* ------------------ TABLE HEADER ------------------ */} + + + {headCells && + headCells.map((headCell, index) => ( + + {headCell.isSort ? ( + + {headCell.label} + {orders?.orderBy === headCell.id ? ( + + {orders.order === 'desc' ? 'sorted descending' : 'sorted ascending'} + + ) : null} + + ) : ( + headCell.label + )} + + ))} + + + + {/* ------------------ END TABLE HEADER ------------------ */} + + {/* ------------------ TABLE ROW ------------------ */} + {dataTableIsLoading ? ( + + + + Loading + + + + ) : dataTableData.data.length === 0 ? ( + + + + No Data + + + + ) : ( + + {dataTableData.data.map((row) => ( + + ))} + + )} + {/* ------------------ END TABLE ROW ------------------ */} +
+ ); + } + + // --------------------------------------------------------- + return ( + + + + + + + } + /> + + + ); +} diff --git a/frontend/dashboard/src/routes/index.tsx b/frontend/dashboard/src/routes/index.tsx index 3d0a249c..92c0f5ad 100644 --- a/frontend/dashboard/src/routes/index.tsx +++ b/frontend/dashboard/src/routes/index.tsx @@ -385,6 +385,19 @@ export default function Router() { element: }, + { + path: 'report/logs', + element: , + }, + { + path: 'report/logs/:id', + element: , + }, + { + path: 'report/logs/:id/show', + element: , + }, + { path: 'report/appointments', element: , @@ -637,6 +650,10 @@ const MasterDoctorsCreate = Loadable(lazy(() => import('../pages/Master/Doctors/ const MasterHospitals = Loadable(lazy(() => import('../pages/Master/Hospitals/Index'))); const MasterHospitalsCreate = Loadable(lazy(() => import('../pages/Master/Hospitals/Create'))); +const Log = Loadable(lazy(() => import('../pages/Report/Log/Index'))); +const LogCreate = Loadable(lazy(() => import('../pages/Report/Log/Create'))); +const LogShow = Loadable(lazy(() => import('../pages/Report/Log/Show'))); + const Appointment = Loadable(lazy(() => import('../pages/Report/Appointments/Index'))); const AppointmentCreate = Loadable(lazy(() => import('../pages/Report/Appointments/Create'))); const AppointmentShow = Loadable(lazy(() => import('../pages/Report/Appointments/Show')));