From 54019e998da4a2abc0e583aecb47e60a5db861af Mon Sep 17 00:00:00 2001 From: Tb Fajri Date: Fri, 13 Oct 2023 10:47:22 +0700 Subject: [PATCH] update fitur alarm center --- .../Api/CorporateMemberController.php | 32 +- Modules/Client/Routes/api.php | 2 + .../DataListClaimMemberResource.php | 37 ++ .../AlarmCenter/DataServiceMonitoring.php | 126 ++++ app/Models/Claim.php | 1 + app/Models/ClaimEncounter.php | 12 + app/Models/ClaimItem.php | 5 + app/Models/Member.php | 6 + app/Services/CorporateMemberService.php | 12 + frontend/client-portal/src/@types/table.ts | 40 ++ .../client-portal/src/components/Table.tsx | 157 ++++- .../src/pages/AlarmCenter/Index.tsx | 16 +- .../src/pages/AlarmCenter/List.tsx | 228 +++++-- .../src/pages/AlarmCenter/ListMember.tsx | 520 +++++++++++++++ .../pages/AlarmCenter/ServiceMonitoring.tsx | 622 +++++++++++++----- frontend/client-portal/src/routes/index.tsx | 9 +- .../client-portal/src/utils/formatTime.ts | 3 +- 17 files changed, 1563 insertions(+), 265 deletions(-) create mode 100644 Modules/Client/Transformers/AlarmCenter/DataListClaimMemberResource.php create mode 100644 Modules/Client/Transformers/AlarmCenter/DataServiceMonitoring.php create mode 100644 app/Models/ClaimEncounter.php create mode 100644 frontend/client-portal/src/pages/AlarmCenter/ListMember.tsx diff --git a/Modules/Client/Http/Controllers/Api/CorporateMemberController.php b/Modules/Client/Http/Controllers/Api/CorporateMemberController.php index 05032d18..23a17981 100644 --- a/Modules/Client/Http/Controllers/Api/CorporateMemberController.php +++ b/Modules/Client/Http/Controllers/Api/CorporateMemberController.php @@ -4,11 +4,15 @@ namespace Modules\Client\Http\Controllers\Api; use App\Helpers\Helper; use App\Models\Member; +use App\Models\Claim; +use App\Models\ClaimRequest; use App\Services\CorporateMemberService; use Illuminate\Contracts\Support\Renderable; use Illuminate\Http\Request; use Illuminate\Routing\Controller; use Modules\Client\Transformers\ClaimReport\MemberResources as ClaimReportMemberResources; +use Modules\Client\Transformers\AlarmCenter\DataListClaimMemberResource; +use Modules\Client\Transformers\AlarmCenter\DataServiceMonitoring; use Modules\Client\Transformers\Dashboard\MemberResources as ClaimSubmitMemberResources; use Modules\Client\Transformers\Dashboard\MemberResources as DashboardMemberResources; use Modules\Client\Transformers\Dashboard\MemberAlarmCenterResources as DashboardMemberAlarmResources; @@ -52,12 +56,13 @@ class CorporateMemberController extends Controller public function show($corporate_id, $person_id) { $data = Member::with(['claims', 'person', 'employeds', 'currentPlan.benefits', 'person.currentAddress']) - ->where('person_id', $person_id) - ->whereHas('employeds', function ($query) use ($corporate_id) { - $query->where('corporate_id', $corporate_id); - }) - ->first(); + ->where('person_id', $person_id) + ->whereHas('employeds', function ($query) use ($corporate_id) { + $query->where('corporate_id', $corporate_id); + }) + ->first(); + $totalClaims = $data->claims->sum('total_claim'); $data->total_claims = $totalClaims; @@ -95,5 +100,22 @@ class CorporateMemberController extends Controller $data->claim_history = $data_claim_history; return response()->json(DataMemberResource::make($data)); + + + } + + public function showPerMember($corporate_id, $member_id){ + $data = ClaimRequest::where(['member_id' => $member_id]) + ->whereNotNull('claim_id') + ->paginate(10); + return response()->json(Helper::paginateResources(DataListClaimMemberResource::collection($data))); + } + + public function serviceMonitoring($corporate_id, $claim_id) + { + $data = Claim::where('id', $claim_id)->first(); + + + return Helper::responseJson(DataServiceMonitoring::make($data)); } } diff --git a/Modules/Client/Routes/api.php b/Modules/Client/Routes/api.php index cd3acf81..1dbb8497 100644 --- a/Modules/Client/Routes/api.php +++ b/Modules/Client/Routes/api.php @@ -48,6 +48,8 @@ Route::prefix('client')->group(function () { Route::get('division', [CorporateDivisionController::class, 'index']); Route::get('members', [CorporateMemberController::class, 'index']); Route::get('members/{id}', [CorporateMemberController::class, 'show']); + Route::get('alarm-center-members/{id}', [CorporateMemberController::class, 'showPerMember']); + Route::get('service-monitoring/{id}', [CorporateMemberController::class, 'serviceMonitoring']); Route::get('claims/status', [ClaimController::class, 'status']); Route::get('claims', [ClaimController::class, 'index']); Route::get('claims/{claim_id}/encounters', [ClaimEncounterController::class, 'getEncounterData']); diff --git a/Modules/Client/Transformers/AlarmCenter/DataListClaimMemberResource.php b/Modules/Client/Transformers/AlarmCenter/DataListClaimMemberResource.php new file mode 100644 index 00000000..988ebb55 --- /dev/null +++ b/Modules/Client/Transformers/AlarmCenter/DataListClaimMemberResource.php @@ -0,0 +1,37 @@ +member_id); + + return [ + 'id' => $this->id, + 'admission_date' => $this->submission_date, + 'discharge_date' => $this->submission_date, + 'code' => $this->code, + 'service_type' => $this->service_code == 'IP' ? 'Inpatient' : 'Outpatient', + 'status' => $this->service_code == 'approved' ? 'Done' : 'OnGoing', + 'claim_id' => $this->claim_id, + // 'memberId' => $this->member_id, + 'fullName' => $member->name, + // 'division' => $this->division_name ?? '', + // 'status' => $this->status, + // 'claimRequestId' => $this->claim_request_id, + // 'submissionDate' => $this->submission_date, + ]; + } +} diff --git a/Modules/Client/Transformers/AlarmCenter/DataServiceMonitoring.php b/Modules/Client/Transformers/AlarmCenter/DataServiceMonitoring.php new file mode 100644 index 00000000..22ec05c6 --- /dev/null +++ b/Modules/Client/Transformers/AlarmCenter/DataServiceMonitoring.php @@ -0,0 +1,126 @@ +claim_request_id); + $member = Member::findOrFail($this->member_id); + + $encounter = ClaimEncounter::where('claim_id', $this->id)->first(); + if ($encounter) { + $final_encounter = Encounter::findOrFail($this->final_encounter_id); + $data = Organization::findOrFail($final_encounter->healthcare_id); + $hospital = $data->name; + } else { + $hospital = '-'; + } + $data = [ + "id" => $this->id, + "company_name" => $member->currentCorporate->name, + "member_name" => $member->name, + "member_code" => $member->member_id, + "member_id" => $member->id, + "phone" => $member->person->phone, + "email" => $member->email, + "birth_date" => $member->birth_date, + "symptoms" => "Nyeri dada", + "sign" => "Sesak Nafas", + "main_diagnose" => "Chest pain on breathing", + "main_diagnose_code" => "R07.1", + "comparative_diagnosis" => "Abnormalities of breathing", + "comparative_diagnosis_code" => "R06", + "medical_evacuation" => "Land Transportation", + "benefit_name" => "Konsultasi Dokter", + "hospital" => $hospital, + "admission_date" => $claim_request->submission_date, + "discharge_date" => $claim_request->submission_date, + "dialy_monitoring" => [ + "0" => [ + "date" => "2023-10-05", + "time" => "09:10", + "status" => "Done", + "subject_title" => "Pasien mengalami sesak napas dan nyeri dada", + "body_temperature" => "36.5", + "sistole" => "110 mm[Hg]", + "diastole" => "110 mm[Hg]", + "respiration_rate" => "20/min", + "analisis_title" => "Asthma bronkial dengan perbaikan", + "Perencanaan" => [ + "O2 4L/min", "IVDL RL 2 kolf/6 jam", "Rencana tes sputum" + ] + ], + "1" => [ + "date" => "2023-10-04", + "time" => "09:10", + "status" => "Done", + "subject_title" => "Pasien mengalami sesak napas dan nyeri dada", + "body_temperature" => "36.5", + "sistole" => "110 mm[Hg]", + "diastole" => "110 mm[Hg]", + "respiration_rate" => "20/min", + "analisis_title" => "Asthma bronkial dengan perbaikan", + "Perencanaan" => [ + "O2 4L/min", "IVDL RL 2 kolf/6 jam", "Rencana tes sputum" + ] + ] + ], + "laboratorium_result" => [ + "0" => [ + [ + "datetime" => "2023-10-05 10:00", + "reimbursement_code" => "RE-011", + "examination" => "SGOT", + "location" => "Pramita Jakarta Ragunan", + "files" => "https:://test.com" + ], + [ + "datetime" => "2023-10-05 09:00", + "reimbursement_code" => "RE-010", + "examination" => "SGOT", + "location" => "Pramita Jakarta Ragunan", + "files" => "https:://test.com" + ], + ], + "1" => [ + [ + "datetime" => "2023-10-04 10:00", + "reimbursement_code" => "RE-09", + "examination" => "Hematologi Lengkap", + "location" => "Pramita Jakarta Ragunan", + "files" => "https:://test.com" + ], + [ + "datetime" => "2023-10-04 09:00", + "reimbursement_code" => "RE-08", + "examination" => "Hematologi Lengkap", + "location" => "Pramita Jakarta Ragunan", + "files" => "https:://test.com" + ] + ] + + ] + + ]; + + + return $data; + } +} diff --git a/app/Models/Claim.php b/app/Models/Claim.php index 88b7b11f..84161e59 100644 --- a/app/Models/Claim.php +++ b/app/Models/Claim.php @@ -30,6 +30,7 @@ class Claim extends Model 'plan_id', 'benefit_id', 'status', + 'service_code' ]; protected $hidden = [ diff --git a/app/Models/ClaimEncounter.php b/app/Models/ClaimEncounter.php new file mode 100644 index 00000000..d4eea577 --- /dev/null +++ b/app/Models/ClaimEncounter.php @@ -0,0 +1,12 @@ +belongsTo(Claim::class, 'claim_id'); } + public function benefit() + { + return $this->belongsTo(Benefit::class, 'claim_itemable_id'); + } + public function claim_itemable() { return $this->morphTo(); diff --git a/app/Models/Member.php b/app/Models/Member.php index 25d2eb60..cb0caa13 100644 --- a/app/Models/Member.php +++ b/app/Models/Member.php @@ -98,6 +98,12 @@ class Member extends Model return $this->hasMany(Claim::class, 'member_id', 'id'); } + public function claimRequest() + { + return $this->hasMany(ClaimRequest::class, 'member_id', 'id')->where('claim_id', '!=', null); + } + + public function postponedClaims() { return $this->hasMany(Claim::class, 'member_id', 'id')->where('status', 'postpone'); diff --git a/app/Services/CorporateMemberService.php b/app/Services/CorporateMemberService.php index 8eb40c0a..09314cb5 100644 --- a/app/Services/CorporateMemberService.php +++ b/app/Services/CorporateMemberService.php @@ -130,7 +130,10 @@ class CorporateMemberService public function getAllMemberAlarmCenter(int $corporateId, Request $request) { $limit = $request->has('perPage') ? $request->input('perPage') : 10; + $start_date = date('Y-m-d', strtotime($request->input('start_date') . ' +1 day')); + $end_date = date('Y-m-d', strtotime($request->input('end_date') . ' +1 day')); + // dd($request); return Member::query() ->joinCorporateEmployees('left') ->joinMemberPlans('left') @@ -143,9 +146,18 @@ class CorporateMemberService ->orWhere('members.name', 'like', "%" . $search . "%"); }); }) + ->when($request->input('start_date'), function (Builder $query, $start) { + $query->where('member_plans.start', '>=', $start); + }) + ->when($request->input('end_date'), function (Builder $query, $end) { + $query->where('member_plans.end', '<', $end); + }) ->when($request->input('division'), function (Builder $query, $value) { $query->where('corporate_employees.division_id', $value); }) + ->when($request->input('status'), function (Builder $query, $value) { + $query->where('plans.active', $value); + }) ->when($request->has('orderBy'), function (Builder $query) use ($request) { $orderBy = match ($request->input('orderBy')) { 'memberId' => 'member_id', diff --git a/frontend/client-portal/src/@types/table.ts b/frontend/client-portal/src/@types/table.ts index 2f95319e..2e71163b 100644 --- a/frontend/client-portal/src/@types/table.ts +++ b/frontend/client-portal/src/@types/table.ts @@ -23,6 +23,11 @@ export type DivisionDataProps = { id: number; name: string; }; + +export type StatusDataProps = { + id: number; + name: string; +}; /* -------------------------------------------------------------------------- */ /* -------------------------------- headcell -------------------------------- */ @@ -42,6 +47,13 @@ export type DivisionData = { }; /* -------------------------------------------------------------------------- */ +/* ----------------------------- status filter ---------------------------- */ +export type Status = { + id: number; + name: string; +}; +/* -------------------------------------------------------------------------- */ + /* ----------------------------------- row ---------------------------------- */ export type TableListProps = { headCells?: HeadCell[]; @@ -85,5 +97,33 @@ export type TableListProps = { handleDivisionChange: (event: SelectChangeEvent) => void; }; }; + filterStatus?: { + useFilter: boolean; + config: { + label: string; + statusValue: string; + statusData: Status[]; + handleStatusChange: (event: SelectChangeEvent) => void; + }; + }; + filterStartDate: { + useFilter: boolean; + startDate: string; + setStartDate: Dispatch>; + handleStartDateChange: (event: FormEvent) => void; + }; + filterEndDate: { + useFilter: boolean; + endDate: string; + setEndDate: Dispatch>; + handleEndDateChange: (event: FormEvent) => void; + }; + exportReport: { + useExport: boolean; + startDate: string; + endDate: string; + status: string; + handleExportReport: (event: FormEvent) => void; + }; }; /* -------------------------------------------------------------------------- */ diff --git a/frontend/client-portal/src/components/Table.tsx b/frontend/client-portal/src/components/Table.tsx index 3d082c1a..b38aa559 100644 --- a/frontend/client-portal/src/components/Table.tsx +++ b/frontend/client-portal/src/components/Table.tsx @@ -37,9 +37,11 @@ import palette from '../theme/palette'; /* ---------------------------------- utils --------------------------------- */ import { UserCurrentCorporateContext } from '../contexts/UserCurrentCorporate'; import { fSplit } from '../utils/formatNumber'; +import { Download, Search as SearchIcon, Upload } from '@mui/icons-material'; /* ---------------------------------- types --------------------------------- */ import { DivisionDataProps, Order, PaginationTableProps, TableListProps } from '../@types/table'; - +import { InputAdornment } from '@mui/material'; +import GetAppIcon from '@mui/icons-material/GetApp'; /* --------------------------------- styled --------------------------------- */ const BorderLinearProgress = styled(LinearProgress)(({ theme }) => ({ height: 10, @@ -62,7 +64,11 @@ export default function Table({ loadings, params, filters, + filterStatus, + filterStartDate, + filterEndDate, searchs, + exportReport, }: TableListProps) { /* ------------------------------- handle sort ------------------------------ */ const handleRequestSort = async (event: React.MouseEvent, property: string) => { @@ -192,39 +198,132 @@ export default function Table({ - ) : null - // ( - // - //
- // searchs.setSearchText(event.target.value)} - // value={searchs.searchText} - // fullWidth - // /> - // - //
- // ) - } + ) : null } {searchs && searchs.useSearchs ? ( - -
- searchs.setSearchText(event.target.value)} - value={searchs.searchText} - fullWidth - /> - + {filterStatus && filterStatus.useFilter ? ( + +
+ searchs.setSearchText(event.target.value)} + value={searchs.searchText} + fullWidth + InputProps={{ + startAdornment: ( + + + + ), + }} + placeholder="Search Name or Member ID... " + /> +
+ ) : + +
+ searchs.setSearchText(event.target.value)} + value={searchs.searchText} + fullWidth + InputProps={{ + startAdornment: ( + + + + ), + }} + placeholder="Search Name or Member ID... " + /> + +
+ } +
) : null } + + {/* Start date */} + {filterStartDate && filterStartDate.useFilter ? ( + +
+ filterStartDate.setStartDate(event.target.value)} + fullWidth + label="Start Date" + InputLabelProps={{ + shrink: true, + }} + /> + +
+ ) : null } + + {/* End Date */} + + {filterEndDate && filterEndDate.useFilter ? ( + +
+ filterEndDate.setEndDate(event.target.value)} + fullWidth + label="End Date" + InputLabelProps={{ + shrink: true, + }} + /> + +
+ ) : null } + + {/* Filter status */} + {filterStatus && filterStatus.useFilter ? ( + + + Status + + + + ) : null } + + {/* Export Report */} + + {exportReport && exportReport.useExport ? ( + + + + + + ) : null } + {/* End Field 1 */} @@ -238,7 +337,7 @@ export default function Table({ {/* End Table Header */} {/* Table Body */} - {loadings.isLoading ? ( + {loadings.isLoading && rows.length >= 1 ? ( Loading . . . diff --git a/frontend/client-portal/src/pages/AlarmCenter/Index.tsx b/frontend/client-portal/src/pages/AlarmCenter/Index.tsx index 1566fcfe..be37af34 100644 --- a/frontend/client-portal/src/pages/AlarmCenter/Index.tsx +++ b/frontend/client-portal/src/pages/AlarmCenter/Index.tsx @@ -10,6 +10,7 @@ import useSettings from '../../hooks/useSettings'; import List from './List'; import ServiceMonitoring from './ServiceMonitoring'; import UserProfile from './UserProfile'; +import HeaderBreadcrumbs from '../../components/HeaderBreadcrumbs'; /* ------------------------------ tabs setting ------------------------------ */ @@ -102,16 +103,23 @@ export default function Drugs() { return ( + - - + {/* */} + {/* - + */} @@ -121,7 +129,7 @@ export default function Drugs() { */} - + {/* */} diff --git a/frontend/client-portal/src/pages/AlarmCenter/List.tsx b/frontend/client-portal/src/pages/AlarmCenter/List.tsx index d0375d7d..d67fb19f 100644 --- a/frontend/client-portal/src/pages/AlarmCenter/List.tsx +++ b/frontend/client-portal/src/pages/AlarmCenter/List.tsx @@ -12,6 +12,9 @@ import { Button, TableSortLabel, Box, + SelectChangeEvent, + Typography, + MenuItem } from '@mui/material'; import { visuallyHidden } from '@mui/utils'; /* ---------------------------------- axios --------------------------------- */ @@ -32,6 +35,11 @@ import palette from '../../theme/palette'; import { UserCurrentCorporateContext } from '../../contexts/UserCurrentCorporate'; import { HeadCell, Order, PaginationTableProps } from '../../@types/table'; import { useSearchParams, useNavigate, Link } from 'react-router-dom'; +import { fDateSuffix } from '../../utils/formatTime'; +import TableMoreMenu from '../../components/table/TableMoreMenu'; +import VisibilityOutlinedIcon from '@mui/icons-material/VisibilityOutlined'; + +import DetailDataMember from './ListMember'; /* ---------------------------------- types --------------------------------- */ @@ -227,6 +235,94 @@ export default function List() { handleSearchSubmit: handleSearchSubmit, }; + /* ------------------------------ handle filter ----------------------------- */ + const [statusValue, setStatusValue] = useState('all'); + const [filterData, setStatusData] = useState([]); + + // handle status + const handleStatusChanges = (event: SelectChangeEvent) => { + setStatusValue(event.target.value as string); + + if (event.target.value === 'all') { + searchParams.delete('status'); + const params = Object.fromEntries([...searchParams.entries()]); + setAppliedParams(params); + } else { + const params = Object.fromEntries([ + ...searchParams.entries(), + ['status', event.target.value as string], + ]); + setAppliedParams(params); + } + }; + + const filterStatus = { + useFilter: false, + config: { + label: 'Status', + statusValue: statusValue, + filterData: filterData, + handleStatusChange: handleStatusChanges, + }, + }; + + // handle start date + const [startDateValue, setStartDateValue] = useState(''); + + const handleStartDateChanges = async (event: React.FormEvent) => { + event.preventDefault(); + console.log(startDateValue) + if (startDateValue === '') { + searchParams.delete('start_date'); + const params = Object.fromEntries([...searchParams.entries()]); + setAppliedParams(params); + } else { + const params = Object.fromEntries([...searchParams.entries(), ['start_date', startDateValue]]); + setAppliedParams(params); + } + }; + + const filterStartDate = { + useFilter: true, + startDate: startDateValue, + setStartDate: setStartDateValue, + handleStartDateChange: handleStartDateChanges, + }; + + // handle end date + const [endDateValue, setEndDateValue] = useState(''); + + const handleEndDateChanges = async (event: React.FormEvent) => { + event.preventDefault(); + if (endDateValue === '') { + searchParams.delete('end_date'); + const params = Object.fromEntries([...searchParams.entries()]); + setAppliedParams(params); + } else { + const params = Object.fromEntries([...searchParams.entries(), ['end_date', endDateValue]]); + setAppliedParams(params); + } + }; + + const filterEndDate = { + useFilter: true, + endDate: endDateValue, + setEndDate: setEndDateValue, + handleEndDateChange: handleEndDateChanges, + }; + + /* -------------------------------- handle export --------------------------- */ + const handleExportReport = { + + } + const exportReport = { + useExport: true, + startDate: startDateValue, + endDate: endDateValue, + status: statusValue, + handleExportReport: handleExportReport + } + /* -------------------------------- headCell -------------------------------- */ const headCells: HeadCell[] = [ { @@ -252,14 +348,20 @@ export default function List() { id: 'end_date', align: 'center', label: 'End Date', - isSort: false, - }, - { - id: 'status', - align: 'center', - label: 'Status', isSort: true, }, + // { + // id: 'status', + // align: 'center', + // label: 'Status', + // isSort: false, + // }, + { + id: 'action', + align: 'center', + label: '', + isSort: false, + }, ]; /* -------------------------------------------------------------------------- */ @@ -278,50 +380,82 @@ export default function List() { params: { ...parameters }, }); + const status = [ + {"id": 1, "name": "Done" }, + {"id": 0, "name": "On Going" }, + + ] + setStatusData(status) + setData( response.data.data.map((obj: any) => { return { ...obj, - memberId: - // - + // memberId: + // // + // + // , + start_date: + { fDateSuffix(obj.start_date) } + , - status: - obj.status === 1 ? ( - - ) : ( - - ), + end_date: + { fDateSuffix(obj.end_date) } + + , + // status: + // obj.status === 1 ? ( + // + // Done + // + // ) : ( + // + // Ongoing + // + // ), + action: + + navigate('member/'+obj.id )}> + + View + + + } /> }; }) ); @@ -354,6 +488,10 @@ export default function List() { params={params} searchs={searchs} // filters={filters} + filterStatus={filterStatus} + filterStartDate={filterStartDate} + filterEndDate={filterEndDate} + exportReport={exportReport} /> ); diff --git a/frontend/client-portal/src/pages/AlarmCenter/ListMember.tsx b/frontend/client-portal/src/pages/AlarmCenter/ListMember.tsx new file mode 100644 index 00000000..9eb8aaf9 --- /dev/null +++ b/frontend/client-portal/src/pages/AlarmCenter/ListMember.tsx @@ -0,0 +1,520 @@ +/* ---------------------------------- @mui ---------------------------------- */ +import { + Paper, + Table, + TableBody, + TableCell, + TableContainer, + TableHead, + TableRow, + TextField, + Stack, + Button, + TableSortLabel, + Box, + SelectChangeEvent, + Typography, + MenuItem, + Grid +} from '@mui/material'; +import { visuallyHidden } from '@mui/utils'; +/* ---------------------------------- axios --------------------------------- */ +// import axios from 'axios'; +import axios from '../../utils/axios'; +/* ---------------------------------- react --------------------------------- */ +import { useContext, useEffect, useState } from 'react'; + +/* -------------------------------- component ------------------------------- */ +import Iconify from '../../components/Iconify'; +import BaseTablePagination from '../../components/BaseTablePagination'; +import TableComponent from '../../components/Table'; +import ArrowBackIosIcon from '@mui/icons-material/ArrowBackIos'; + +/* ---------------------------------- hooks --------------------------------- */ +import useMap from '../../hooks/useMap'; +/* ---------------------------------- theme --------------------------------- */ +import palette from '../../theme/palette'; +import { UserCurrentCorporateContext } from '../../contexts/UserCurrentCorporate'; +import { HeadCell, Order, PaginationTableProps } from '../../@types/table'; +import { useSearchParams, useNavigate, Link, useParams } from 'react-router-dom'; +import { fDateSuffix, fPostFormat } from '../../utils/formatTime'; +import TableMoreMenu from '../../components/table/TableMoreMenu'; +import VisibilityOutlinedIcon from '@mui/icons-material/VisibilityOutlined'; + + +/* ---------------------------------- types --------------------------------- */ + +type DataList = { + name: string; +}; + +// type PaginationTableProps = { +// current_page: number; +// from: number; +// last_page: number; +// links: []; +// path: string; +// per_page: number; +// to: number; +// total: number; +// }; + +// type DataTableProps = { +// fullName: string; +// memberId: string; +// service: string; +// start_date: string; +// end_date: string; +// status: boolean | number; +// }; + +// /* -------------------------------------------------------------------------- */ + +// /* -------------------------- enchanced table head -------------------------- */ + +// type Order = 'asc' | 'desc'; + +// interface HeadCell { +// id: string; +// label: string; +// } + +// const headCells: readonly HeadCell[] = [ +// { +// id: 'name', +// label: 'Name', +// }, +// { +// id: 'member_id', +// label: 'Member ID', +// }, +// { +// id: 'service', +// label: 'Service', +// }, +// { +// id: 'start_date', +// label: 'Start Date', +// }, +// { +// id: 'end_date', +// label: 'End Date', +// }, +// { +// id: 'status', +// label: 'Status', +// }, +// ]; + +// interface EnhancedTableProps { +// onRequestSort: (event: React.MouseEvent, property: string) => void; +// order: Order; +// orderBy: string; +// } + +// function EnhancedTableHead(props: EnhancedTableProps) { +// const { order, orderBy, onRequestSort } = props; +// const createSortHandler = (property: string) => (event: React.MouseEvent) => { +// onRequestSort(event, property); +// }; + +// return ( +// +// +// No +// {headCells.map((headCell) => ( +// +// +// {headCell.label} +// {orderBy === headCell.id ? ( +// +// {order === 'desc' ? 'sorted descending' : 'sorted ascending'} +// +// ) : null} +// +// +// ))} +// +// +// ); +// } + +/* -------------------------------------------------------------------------- */ + +export default function List() { + const navigate = useNavigate(); + + const { corporateValue } = useContext(UserCurrentCorporateContext); + + const [data, setData] = useState([]); + const { id } = useParams(); + + /* -------------------------------------------------------------------------- */ + /* setting up for the table */ + /* -------------------------------------------------------------------------- */ + const [isLoading, setIsLoading] = useState(true); + + const loadings = { + isLoading: isLoading, + setIsLoading: setIsLoading, + }; + + /* ------------------------------ handle params ----------------------------- */ + const [searchParams, setSearchParams] = useSearchParams(); + const [appliedParams, setAppliedParams] = useState({}); + + const params = { + searchParams: searchParams, + setSearchParams: setSearchParams, + appliedParams: appliedParams, + setAppliedParams: setAppliedParams, + }; + /* -------------------------------------------------------------------------- */ + + /* ------------------------------ handle order ------------------------------ */ + const [order, setOrder] = useState('asc'); + const [orderBy, setOrderBy] = useState('fullName'); + + const orders = { + order: order, + setOrder: setOrder, + orderBy: orderBy, + setOrderBy: setOrderBy, + }; + /* -------------------------------------------------------------------------- */ + + /* ---------------------------- handle pagination --------------------------- */ + const [page, setPage] = useState(0); + const [rowsPerPage, setRowsPerPage] = useState(10); + + const [paginationTable, setPaginationTable] = useState({ + current_page: 0, + from: 0, + last_page: 0, + links: [], + path: '', + per_page: 0, + to: 0, + total: 0, + }); + + const paginations = { + page: page, + setPage: setPage, + rowsPerPage: rowsPerPage, + setRowsPerPage: setRowsPerPage, + paginationTable: paginationTable, + setPaginationTable: setPaginationTable, + }; + + /* -------------------------------------------------------------------------- */ + + /* ------------------------------ handle search ----------------------------- */ + const [searchText, setSearchText] = useState(''); + const [name, setName] = useState(''); + + const handleSearchSubmit = async (event: React.FormEvent) => { + event.preventDefault(); + + if (searchText === '') { + searchParams.delete('search'); + const params = Object.fromEntries([...searchParams.entries()]); + setAppliedParams(params); + } else { + const params = Object.fromEntries([...searchParams.entries(), ['search', searchText]]); + setAppliedParams(params); + } + }; + + const searchs = { + useSearchs: false, + searchText: searchText, + setSearchText: setSearchText, + handleSearchSubmit: handleSearchSubmit, + }; + + /* ------------------------------ handle filter ----------------------------- */ + const [statusValue, setStatusValue] = useState('all'); + const [filterData, setStatusData] = useState([]); + + // handle status + const handleStatusChanges = (event: SelectChangeEvent) => { + setStatusValue(event.target.value as string); + + if (event.target.value === 'all') { + searchParams.delete('status'); + const params = Object.fromEntries([...searchParams.entries()]); + setAppliedParams(params); + } else { + const params = Object.fromEntries([ + ...searchParams.entries(), + ['status', event.target.value as string], + ]); + setAppliedParams(params); + } + }; + + const filterStatus = { + useFilter: false, + config: { + label: 'Status', + statusValue: statusValue, + filterData: filterData, + handleStatusChange: handleStatusChanges, + }, + }; + + // handle start date + const [startDateValue, setStartDateValue] = useState(''); + + const handleStartDateChanges = async (event: React.FormEvent) => { + event.preventDefault(); + console.log(startDateValue) + if (startDateValue === '') { + searchParams.delete('start_date'); + const params = Object.fromEntries([...searchParams.entries()]); + setAppliedParams(params); + } else { + const params = Object.fromEntries([...searchParams.entries(), ['start_date', startDateValue]]); + setAppliedParams(params); + } + }; + + const filterStartDate = { + useFilter: false, + startDate: startDateValue, + setStartDate: setStartDateValue, + handleStartDateChange: handleStartDateChanges, + }; + + // handle end date + const [endDateValue, setEndDateValue] = useState(''); + + const handleEndDateChanges = async (event: React.FormEvent) => { + event.preventDefault(); + if (endDateValue === '') { + searchParams.delete('end_date'); + const params = Object.fromEntries([...searchParams.entries()]); + setAppliedParams(params); + } else { + const params = Object.fromEntries([...searchParams.entries(), ['end_date', endDateValue]]); + setAppliedParams(params); + } + }; + + const filterEndDate = { + useFilter: false, + endDate: endDateValue, + setEndDate: setEndDateValue, + handleEndDateChange: handleEndDateChanges, + }; + + /* -------------------------------- handle export --------------------------- */ + const handleExportReport = { + + } + const exportReport = { + useExport: false, + startDate: startDateValue, + endDate: endDateValue, + status: statusValue, + handleExportReport: handleExportReport + } + + /* -------------------------------- headCell -------------------------------- */ + const headCells: HeadCell[] = [ + { + id: 'admission_date', + align: 'center', + label: 'Admission Date', + isSort: true, + }, + { + id: 'discharge_date', + align: 'center', + label: 'Discharge Date', + isSort: true, + }, + { + id: 'code', + align: 'left', + label: 'Code', + isSort: true, + }, + { + id: 'status', + align: 'center', + label: 'Status', + isSort: false, + }, + { + id: 'action', + align: 'center', + label: '', + isSort: false, + }, + ]; + /* -------------------------------------------------------------------------- */ + + useEffect(() => { + (async () => { + setIsLoading(true); + + await new Promise((resolve) => setTimeout(resolve, 250)); + + const parameters = + Object.keys(appliedParams).length !== 0 + ? appliedParams + : Object.fromEntries([...searchParams.entries(), ['order', order], ['orderBy', orderBy]]); + + const response = await axios.get(`${corporateValue}/alarm-center-members/${id}`, { + params: { ...parameters }, + }); + + const status = [ + {"id": 1, "name": "Done" }, + {"id": 0, "name": "On Going" }, + + ] + setStatusData(status) + const datatable = response.data.data; + + // if (response.data.data.length > 0){ + // setIsLoading(true); + // } else { + // setIsLoading(false); + // } + + const dataName = response.data.data[0].fullName + setName(dataName) + setData( + datatable.map((obj: any) => { + return { + ...obj, + admission_date: + { fDateSuffix(obj.admission_date) } + + , + discharge_date: + { fDateSuffix(obj.discharge_date) } + + , + status: + obj.status === 'Done' ? ( + + Done + + ) : ( + + Ongoing + + ), + action: + + navigate('service-monitoring/'+obj.claim_id )}> + + View + + + } /> + }; + }) + ); + + setPaginationTable(response.data); + setRowsPerPage(response.data.per_page); + + + + if (searchParams.get('page')) { + //@ts-ignore + const currentPage = parseInt(searchParams.get('page')) - 1; + + paginationTable.current_page = currentPage; + setPage(currentPage); + } + + setIsLoading(false); + })(); + }, [appliedParams, searchParams, order, orderBy, setSearchParams, corporateValue]); + console.log(loadings); + return ( + + + + navigate(`/alarm-center`)} + sx={{ cursor: 'pointer' }} + /> + + {name} + + + + + + + + + + + + + + ); +} diff --git a/frontend/client-portal/src/pages/AlarmCenter/ServiceMonitoring.tsx b/frontend/client-portal/src/pages/AlarmCenter/ServiceMonitoring.tsx index 5fd6e12c..3f0bf095 100644 --- a/frontend/client-portal/src/pages/AlarmCenter/ServiceMonitoring.tsx +++ b/frontend/client-portal/src/pages/AlarmCenter/ServiceMonitoring.tsx @@ -9,9 +9,14 @@ import { Card, Stack, Typography, + TableHead, + TableCell, + TableBody, + Table, + TableRow, } from '@mui/material'; import { styled } from '@mui/material/styles'; -import { Favorite } from '@mui/icons-material'; +import DownloadIcon from '@mui/icons-material/Download'; // components import Page from '../../components/Page'; import Iconify from '../../components/Iconify'; @@ -21,8 +26,15 @@ import { useState, SyntheticEvent, useContext, useEffect } from 'react'; import { UserCurrentCorporateContext } from '../../contexts/UserCurrentCorporate'; import { useNavigate, useParams } from 'react-router-dom'; import axios from '../../utils/axios'; -import { fDate } from '../../utils/formatTime'; +import { fDate, fDateSuffix, fDateTime, fDateTimeSuffix } from '../../utils/formatTime'; + +import ArrowBackIosIcon from '@mui/icons-material/ArrowBackIos'; +import TimelineItem, { timelineItemClasses } from '@mui/lab/TimelineItem'; +import { Timeline, TimelineConnector, TimelineContent, TimelineDot, TimelineSeparator } from '@mui/lab'; +import Select from '../../theme/overrides/Select'; +import TableMoreMenu from '../../components/table/TableMoreMenu'; +import { MenuItem } from '@mui/material'; // sections // import ListTable from '../../sections/claimreports/ListTable'; // import ClaimStatusCard from '../../sections/claimreports/ClaimStatusCard'; @@ -42,7 +54,7 @@ function TabPanel(props: TabPanelProps) { hidden={value !== index} id={`simple-tabpanel-${index}`} aria-labelledby={`simple-tab-${index}`} - style={{ backgroundColor: '#F9FAFB' }} + // style={{ backgroundColor: '#F9FAFB' }} {...other} > {value === index && ( @@ -61,6 +73,8 @@ function a11yProps(index: number) { }; } + + interface StyledTabsProps { children?: React.ReactNode; value: number; @@ -71,7 +85,7 @@ const StyledTabs = styled((props: StyledTabsProps) => )({ '& .MuiTabs-indicator': { display: 'flex', justifyContent: 'center', - backgroundColor: 'transparent', + backgroundColor: '19BBBB', }, '& .MuiTabs-indicatorSpan': { maxWidth: 40, @@ -85,27 +99,73 @@ interface StyledTabProps { icon?: string | React.ReactElement; } + const StyledTab = styled((props: StyledTabProps) => )( ({ theme }) => ({ textTransform: 'none', fontWeight: 500, fontSize: theme.typography.pxToRem(20), - color: theme.palette.primary.main, - maxWidth: '100%', + color: '#637381', + maxWidth: '15%', flex: 1, margin: '0 !important', '&.Mui-selected': { - color: '#FFF', - backgroundColor: theme.palette.primary.main, + color: '#212B36', }, '&:hover': { - backgroundColor: theme.palette.primary.dark, - color: '#FFF', + color: '#212B36', opacity: 1, }, }) ); +type Data = { + id: number, + company_name: string, + member_name: string, + member_code: string, + member_id: number, + phone: string, + email: string, + birth_date: string, + symptoms: string, + sign: string, + main_diagnose: string, + main_diagnose_code: string, + comparative_diagnosis: string, + comparative_diagnosis_code: string, + medical_evacuation: string, + benefit_name: string, + hospital: string, + admission_date: string, + discharge_date: string, + dialy_monitoring: DailyMonitoring[], + laboratorium_result: LaboratoriumResult[], + +} + +type DailyMonitoring = { + date: string, + time: string, + status: string, + subject_title: string, + body_temperature: string, + sistole: string, + diastole: string, + respiration_rate: string, + analisis_title: string, + Perencanaan: string, + +} + +type LaboratoriumResult = { + datetime: string, + reimbursement_code: string, + examination: string, + location: string, + files: string, +} + export default function ServiceMonitoring() { const { themeStretch } = useSettings(); const navigate = useNavigate(); @@ -115,234 +175,436 @@ export default function ServiceMonitoring() { setValue(newValue); }; - const [data, setData] = useState({}); + const [data, setData] = useState(null); const [corporate, setCorporate] = useState(); const { corporateValue } = useContext(UserCurrentCorporateContext); const { id } = useParams(); - const claimId = '2'; -// console.log('id', id); + useEffect(() => { - console.log('fetching data...'); - axios - .get('/data/' + id) - .then((response) => { -// console.log('data fetched...', response.data); - setData(response.data); - }) - .catch((error) => { - console.error('error fetching data...', error); - }); + (async () => { - axios - .get('/corporate-manage/' + corporateValue) - .then((response) => { -// console.log('corporate fetched...', response.data); - setCorporate(response.data); - }) - .catch((error) => { - console.error('error fetching corporate...', error); - }); - }, []); - -// console.log('Data:', data); - const [encounterData, setEncounterData] = useState({}); - - useEffect(() => { -// console.log('fetching encounter data...'); - axios - .get('/claims/${claim_id}/encounters') - .then((response) => { -// console.log('encounter data fetched...', response.data); - setEncounterData(response.data); - }) - .catch((error) => { - console.error('error fetching encounter data...', error); - }); - }, []); + await new Promise((resolve) => setTimeout(resolve, 250)); + const response = await axios.get(`${corporateValue}/service-monitoring/${id}`); + setData(response.data.data); + })(); + }, [corporateValue]); + + console.log(data?.laboratorium_result) return ( - - - - navigate('/alarm-center')} - sx={{ marginRight: '10px', color: '#424242' }} - > - - - Service Monitoring - - - Done - - - + + + + + navigate(`/alarm-center/member/${data.member_id}}`)} + sx={{ cursor: 'pointer' }} + /> + + Service Monitoring + + + + {/* Item 1 */} - + - - Employee Profiles + Employee Profiles + + + + + Company Name + {data?.company_name} + + + + + Member ID + {data?.member_code || 'Loading...'} + + - + - Nama perusahaan - {corporate?.name} + Full Name + {data?.member_name} + + - Nama Lengkap - {data?.name || 'Loading...'} + Date of Birth + {data?.birth_date || 'Loading...'} + + + + - Tanggal lahir - - {data?.birth_date ? fDate(data?.birth_date) : ''} - + Phone Number + {data?.phone} + + - Email - {data?.email} + Email + {data?.email || 'Loading...'} - - No telepon - {data?.phone} - - - - ID Karyawan - 12345678 - + {/* Item 2 */} - - + + - - Diagnose Summary + Diagnose Summary - - - Gejala - Nyeri dada - - - Tanda - Sesak Napas - - - Main Diagnose - - J46 Status asthmaticus, Acute severe asthma - - - - Diagnosis pembanding - K21 Gastro-oesophageal reflux disease - + + + + Symptoms + {data?.symptoms} + + + + + Sign + {data?.sign || 'Loading...'} + + + + + Main Diagnosis + + {data?.main_diagnose} + {data?.main_diagnose_code} + + + + + + Comparative Diagnosis + + {data?.comparative_diagnosis} + {data?.comparative_diagnosis_code} + + + + + + + + + {/* Item 3 */} - - + + - - Services + Services - - - - Evakuasi medis - Land Transportation + + + + Medical Evacuation + {data?.medical_evacuation} - - Rumah sakit - Primaya Hospital + + + + Benefit Name + {data?.benefit_name || 'Loading...'} - - - Tanggal mulai - 17 Aug 2022 - - - Selesai - 18 Aug 2022 - + + + + Hospital + {data?.hospital} - - Daftar layanan - - Inpatient, Medivac (Medical Evacuation) - + + + + Admission Date + {data?.admission_date ? fDateSuffix(data?.admission_date) : '-'} - + + + + Discharge Date + { data?.discharge_date ? fDateSuffix(data?.discharge_date) : '-'} + + - - - - } label="Daily Monitoring" {...a11yProps(0)} /> - } - label="Laboratorium Result" - {...a11yProps(1)} - /> - - - - Item One - - - Item Two - + + + + + + + + + + + + + {data?.dialy_monitoring.length > 0 ? data?.dialy_monitoring.map((row, index) => ( + + + + + + + { fDateSuffix(row.date)} + + + {row.time} + {row.status} + + +
+ + + + Subject + {row.subject_title} + + + + + Objektif + + + + + Body Temperature + + + + + {row.body_temperature} + + + + + + + Sistole + + + + + {row.sistole} + + + + + + + Diastole + + + + + {row.diastole} + + + + + + + Respiration Rate + + + + + {row.respiration_rate} + + + + + Analysis + + + + + {row.analisis_title} + + + + + Perencanaan + + + + +
    + {/* {data.} */} +
  • test
  • +
  • test
  • +
+
+
+
+
+ +
+
+
+
+ )) : + + No Data Found + + } +
+
+
+ +
+ + + + {data?.laboratorium_result.length > 0 ? data?.laboratorium_result.map((row, index) => ( + + + + {fDateSuffix(row[index].datetime)} + + {row.length > 0 ? row.map((list, i) => ( + + {list.reimbursement_code} + + + + + Date + Examination + Location + + + + + + + {fDateTime(list.datetime)} + + + {list.examination} + {list.location} + + navigate(`${list.files}` )}> + + Download + + + } /> + + +
+
+ )) : Data Not Found} +
+
+ )) : + + Data Not Found + + } +
+
+
+
-
); } diff --git a/frontend/client-portal/src/routes/index.tsx b/frontend/client-portal/src/routes/index.tsx index 4db6bd16..7e346267 100644 --- a/frontend/client-portal/src/routes/index.tsx +++ b/frontend/client-portal/src/routes/index.tsx @@ -108,11 +108,17 @@ export default function Router() { index: true, }, { - path: 'service-monitoring/:id', + path: 'member/:id', + element: , + }, + { + path: 'member/:id/service-monitoring/:id', element: , }, ], }, + + { path: '/claim-submit', element: ( @@ -242,6 +248,7 @@ const EmployeeDataUserProfile = Loadable(lazy(() => import('../pages/EmployeeDat // Alarm Center const AlarmCenter = Loadable(lazy(() => import('../pages/AlarmCenter/Index'))); +const AlarmCenterMemberPerList = Loadable(lazy(() => import('../pages/AlarmCenter/ListMember'))); const AlarmCenterServiceMonitoring = Loadable( lazy(() => import('../pages/AlarmCenter/ServiceMonitoring')) ); diff --git a/frontend/client-portal/src/utils/formatTime.ts b/frontend/client-portal/src/utils/formatTime.ts index a8ecb956..ed88dcae 100644 --- a/frontend/client-portal/src/utils/formatTime.ts +++ b/frontend/client-portal/src/utils/formatTime.ts @@ -8,7 +8,7 @@ export function fDate(date: Date | string | number) { } export function fDateTime(date: Date | string | number) { - return format(new Date(date), 'dd MMM yyyy p'); + return format(new Date(date), 'dd MMM yyyy hh:mm'); } export function fTimestamp(date: Date | string | number) { @@ -19,6 +19,7 @@ export function fDateTimeSuffix(date: Date | string | number) { return format(new Date(date), 'dd/MM/yyyy hh:mm p'); } + export function fDateSuffix(date: Date | string | number) { return format(new Date(date), 'dd MMM yyyy'); }