diff --git a/database/seeders/NavigationSeeder.php b/database/seeders/NavigationSeeder.php index 55cb5d42..6f7e7b42 100644 --- a/database/seeders/NavigationSeeder.php +++ b/database/seeders/NavigationSeeder.php @@ -16,9 +16,10 @@ class NavigationSeeder extends Seeder public function run() { $menuItems = [ - // DOCTORS & HOSPITALS + // Dashboard [ 'title' => 'Dashboard', + 'urutan' => 1, 'children' => [ [ 'title' => 'Dashboard', @@ -31,6 +32,7 @@ class NavigationSeeder extends Seeder // DOCTORS & HOSPITALS [ 'title' => 'DOCTORS & HOSPITALS', + 'urutan' => 2, 'children' => [ [ 'title' => 'Doctors', @@ -48,6 +50,7 @@ class NavigationSeeder extends Seeder // PHARMACY & DELIVERY MANAGEMENT [ 'title' => 'PHARMACY & DELIVERY MANAGEMENT', + 'urutan' => 3, 'children' => [ [ 'title' => 'Drug', @@ -70,6 +73,7 @@ class NavigationSeeder extends Seeder // STATION BENEFIT & MEMBERSHIP [ 'title' => 'STATION BENEFIT & MEMBERSHIP', + 'urutan' => 4, 'openWhen' => ['/corporates', '/formularium', '/diagnosis', '/hospitals'], 'children' => [ [ @@ -77,7 +81,6 @@ class NavigationSeeder extends Seeder 'path' => '/corporates', 'permission' => 'corporate-list', ], - // ['title' => 'Corporate Create', 'path' => '/corporates/create'], [ 'title' => 'Formularium', 'path' => '/master/formularium-template-v2', @@ -96,28 +99,33 @@ class NavigationSeeder extends Seeder ], 'permission' => null ], - // CLAIM REQUEST + // MASTER [ - 'title' => 'CLAIM REQUEST', - 'path' => '/claim-requests', + 'title' => 'MASTER', + 'urutan' => 5, 'children' => [ [ - 'title' => 'CLAIM REQUEST', - 'path' => '/claim-requests', - 'permission' => 'claim-request-list' + 'title' => 'Diagnosis', + 'path' => '/master/diagnosis', + 'permission' => 'diagnosis-list' ], ], 'permission' => null ], - // CLAIM MANAGEMENT + // CUSTOMER SERVICES [ - 'title' => 'CLAIM MANAGEMENT', - 'path' => '/claims', + 'title' => 'CUSTOMER SERVICES', + 'urutan' => 6, 'children' => [ [ - 'title' => 'CLAIM MANAGEMENT', - 'path' => '/claims', - 'permission' => 'claim-management-list' + 'title' => 'Request', + 'path' => '/custormer-service/request', + 'permission' => 'request-log-list' + ], + [ + 'title' => 'Final LOG', + 'path' => '/custormer-service/final-log', + 'permission' => 'final-log-list' ], ], 'permission' => null @@ -125,13 +133,13 @@ class NavigationSeeder extends Seeder // CASE MANAGEMENT [ 'title' => 'CASE MANAGEMENT', + 'urutan' => 7, 'children' => [ [ 'title' => 'Daily Monitoring', 'path' => '/case_management/daily_monitoring', 'permission' => 'daily-monitoring-list' ], - // ['title' => 'Laboratorium Result', 'path' => '/case_management/laboratorium_result'], [ 'title' => 'Inpatient Monitoring', 'path' => '/case_management/inpatient_monitoring', @@ -145,9 +153,56 @@ class NavigationSeeder extends Seeder ], 'permission' => null ], - // Invoice + // CLAIM REQUEST + [ + 'title' => 'CLAIM REQUEST', + 'urutan' => 8, + 'path' => '/claim-requests', + 'children' => [ + [ + 'title' => 'CLAIM REQUEST', + 'path' => '/claim-requests', + 'permission' => 'claim-request-list' + ], + ], + 'permission' => null + ], + // CLAIM MANAGEMENT + [ + 'title' => 'CLAIM MANAGEMENT', + 'urutan' => 9, + 'path' => '/claims', + 'children' => [ + [ + 'title' => 'CLAIM MANAGEMENT', + 'path' => '/claims', + 'permission' => 'claim-management-list' + ], + ], + 'permission' => null + ], + // USER MANAGEMENT + [ + 'title' => 'USER MANAGEMENT', + 'urutan' => 10, + 'children' => [ + [ + 'title' => 'User Role', + 'path' => '/user-role', + 'permission' => 'user-role-list' + ], + [ + 'title' => 'User Access', + 'path' => '/user-access', + 'permission' => 'user-access-list' + ], + ], + 'permission' => null + ], + // INVOICE [ 'title' => 'INVOICE', + 'urutan' => 11, 'children' => [ [ 'title' => 'Invoice', @@ -157,79 +212,78 @@ class NavigationSeeder extends Seeder ], 'permission' => null ], - // CUSTOMER SERVICES - [ - 'title' => 'CUSTOMER SERVICES', - 'children' => [ - [ - 'title' => 'Request', - 'path' => '/custormer-service/request', - 'permission' => 'request-log-list' - ], - // ['title' => 'Membership', 'path' => '/cs-membership'], - [ - 'title' => 'Final LOG', - 'path' => '/custormer-service/final-log', - 'permission' => 'final-log-list' - ], - ], - 'permission' => null - ], // REPORT [ 'title' => 'REPORT', + 'urutan' => 12, 'children' => [ [ 'title' => 'Files Provider', 'path' => 'report/files-provider', - 'permission' => 'report-files-provider-list' + 'permission' => 'report-files-provider-list', + 'urutan' => 1, ], [ 'title' => 'Letter of Guarantee', 'path' => '/report/logs', - 'permission' => 'report-log-list' + 'permission' => 'report-log-list', + 'urutan' => 2, ], [ 'title' => 'Appointment', 'path' => '/report/appointments', - 'permission' => 'report-appointment-list' + 'permission' => 'report-appointment-list', + 'urutan' => 3, ], [ 'title' => 'Live Chat', 'path' => '/report/live-chat', - 'permission' => 'report-livechat-list' + 'permission' => 'report-livechat-list', + 'urutan' => 4, ], [ 'title' => 'Linksehat Payment', 'path' => '/report/linksehat-payments', - 'permission' => 'report-livechat-payment' + 'permission' => 'report-livechat-payment', + 'urutan' => 5, ], [ 'title' => 'Prescription', 'path' => '/report/prescription', - 'permission' => 'report-prescription' + 'permission' => 'report-prescription', + 'urutan' => 6, ], [ 'title' => 'Doctor Rating', 'path' => '/report/doctor-rating', - 'permission' => 'report-doctor-rating' + 'permission' => 'report-doctor-rating', + 'urutan' => 7, ], [ 'title' => 'Doctor Online', 'path' => '/report/doctor-online', - 'permission' => 'report-doctor-online' + 'permission' => 'report-doctor-online', + 'urutan' => 8, ], [ 'title' => 'Katalog Dokter', 'path' => '/report/katalog-dokter', - 'permission' => 'report-katalog-dokter' - ] + 'permission' => 'report-katalog-dokter', + 'urutan' => 9, + ], + [ + 'title' => 'Primayan Medicare', + 'path' => '/report/primayan-medicare', + 'permission' => 'report-primayan-medicare', + 'urutan' => 10, + ], ], 'permission' => null ], // MASTER [ 'title' => 'MASTER', + 'urutan' => 11, 'children' => [ [ 'title' => 'Diagnosis', @@ -242,6 +296,7 @@ class NavigationSeeder extends Seeder // USER MANAGEMENT [ 'title' => 'USER MANAGEMENT', + 'urutan' => 9, 'children' => [ [ 'title' => 'User Role', @@ -259,12 +314,14 @@ class NavigationSeeder extends Seeder // LINKING TOOLS [ 'title' => 'LINKING TOOLS', + 'urutan' => 13, 'path' => '/linking', 'permission' => 'linkking-list' ], // E-PRESCRIPTION [ 'title' => 'E-PRESCRIPTION', + 'urutan' => 14, 'path' => '/e-prescription/live-chat', 'permission' => 'prescription-list' ], @@ -370,7 +427,8 @@ class NavigationSeeder extends Seeder 'title' => $menuItemData['title'], 'path' => $menuItemData['path'] ?? null, 'icon' => $menuItemData['icon'] ?? null, - 'permission' => $menuItemData['permission'] ?? null + 'permission' => $menuItemData['permission'] ?? null, + 'urutan' => $menuItemData['urutan'] ?? null ]); if (isset($menuItemData['children'])) { @@ -384,7 +442,8 @@ class NavigationSeeder extends Seeder 'path' => $childData['path'] ?? null, 'icon' => $childData['icon'] ?? null, 'parent_id' => $menuItem->id, - 'permission' => $childData['permission'] ?? null + 'permission' => $childData['permission'] ?? null, + 'urutan' => $childData['urutan'] ?? null ]); } } diff --git a/database/seeders/PermissionTableSeeder.php b/database/seeders/PermissionTableSeeder.php index 75da78fd..4f317935 100644 --- a/database/seeders/PermissionTableSeeder.php +++ b/database/seeders/PermissionTableSeeder.php @@ -70,6 +70,7 @@ class PermissionTableSeeder extends Seeder 'report-livechat-list', 'report-livechat-payment', 'report-doctor-rating', + 'report-primayan-medicare', 'report-doctor-online', 'report-prescription', 'user-role-list', diff --git a/frontend/dashboard/src/layouts/dashboard/navbar/NavConfig.tsx b/frontend/dashboard/src/layouts/dashboard/navbar/NavConfig.tsx index 5add5536..1dae1e2f 100644 --- a/frontend/dashboard/src/layouts/dashboard/navbar/NavConfig.tsx +++ b/frontend/dashboard/src/layouts/dashboard/navbar/NavConfig.tsx @@ -106,6 +106,7 @@ const navConfig = [ { title: 'Linksehat Payment', path: '/report/linksehat-payments' }, // { title: 'Prescription', path: '/report/prescription' }, { title: 'Doctor Rating', path: '/report/doctor-rating' }, + { title: 'Primayan Medicare', path: '/report/primayan-medicare' }, ], }, diff --git a/frontend/dashboard/src/pages/Report/PrimayanMedicare/Index.tsx b/frontend/dashboard/src/pages/Report/PrimayanMedicare/Index.tsx new file mode 100644 index 00000000..c888da30 --- /dev/null +++ b/frontend/dashboard/src/pages/Report/PrimayanMedicare/Index.tsx @@ -0,0 +1,32 @@ +import { Container } from '@mui/material'; +import HeaderBreadcrumbs from '../../../components/HeaderBreadcrumbs'; +import Page from '../../../components/Page'; +import useSettings from '../../../hooks/useSettings'; +import List from './List'; + +export default function PrimayanMedicare() { + const { themeStretch } = useSettings(); + + const pageTitle = 'Primayan Medicare'; + return ( + + + + + + + + ); +} diff --git a/frontend/dashboard/src/pages/Report/PrimayanMedicare/List.tsx b/frontend/dashboard/src/pages/Report/PrimayanMedicare/List.tsx new file mode 100644 index 00000000..de95bd07 --- /dev/null +++ b/frontend/dashboard/src/pages/Report/PrimayanMedicare/List.tsx @@ -0,0 +1,402 @@ +import { + Card, + Grid, + Paper, + Table, + TableBody, + TableCell, + TableContainer, + TableRow, + TextField, + Stack, + Chip, + FormControl, + InputLabel, + Select, + MenuItem, + Menu, +} from '@mui/material'; + +import { useSearchParams } from 'react-router-dom'; +import React, { ChangeEvent, useEffect, useRef, useState } from 'react'; +import axios from '../../../utils/axios'; +import { LaravelPaginatedData } from '../../../@types/paginated-data'; +import BasePagination from '../../../components/BasePagination'; +import { fNumber } from '@/utils/formatNumber'; +import { fDateOnly } from '@/utils/formatTime'; +import { DesktopDatePicker, LocalizationProvider } from '@mui/x-date-pickers'; +import { AdapterDateFns } from '@mui/x-date-pickers/AdapterDateFns'; +import { LoadingButton } from '@mui/lab'; +import UploadIcon from '@mui/icons-material/Upload'; + +// ---------------------------------------------------------------------- + +const statusColors: Record = { + draft: 'default', + requested: 'info', + received: 'primary', + approved: 'success', + postpone: 'warning', + paid: 'success', + declined: 'error', +}; + +export default function List() { + const [searchParams, setSearchParams] = useSearchParams(); + const [providers, setProviders] = useState([]); + + function Filter() { + const searchInput = useRef(null); + const [searchText, setSearchText] = useState(''); + const [exportLoading, setExportLoading] = useState(false); + const [anchorEl, setAnchorEl] = React.useState(null); + const exportMenuOpen = Boolean(anchorEl); + + const handleExportClick = (event: React.MouseEvent) => { + setAnchorEl(event.currentTarget); + }; + const handleExportClose = () => { + setAnchorEl(null); + }; + + const handleExport = (exportType: string) => { + const parameters = Object.fromEntries([...searchParams.entries()]); + setExportLoading(true); + axios + .get('/primayan-medicare/export', { + params: { ...parameters, export_type: exportType }, + }) + .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(); + handleExportClose(); + setExportLoading(false); + }) + .catch(() => { + setExportLoading(false); + }); + }; + + const handleSearchChange = (event: any) => { + setSearchText(event.target.value ?? ''); + }; + + useEffect(() => { + setSearchText(searchParams.get('search') ?? ''); + }, []); + + return ( +
+ + + { + if (event.key === 'Enter') { + event.preventDefault(); + const filter = Object.fromEntries([ + ...searchParams.entries(), + ['search', searchText], + ['page', '1'], + ]); + setSearchParams(filter); + loadDataTableData(filter); + } + }} + label="Search" + value={searchText} + InputProps={{ + placeholder: 'Nama, Member ID', + }} + /> + + + + + Status + + + + + + + Provider + + + + + + + { + try { + if (value && !!Date.parse(value)) { + const date = fDateOnly(value); + let entries = [...searchParams.entries(), ['start_date', date ?? '']]; + if (!searchParams.get('end_date')) { + entries = [...entries, ['end_date', date ?? '']]; + } + const filter = Object.fromEntries([...entries, ['page', '1']]); + setSearchParams(filter); + loadDataTableData(filter); + } + } catch (e) {} + }} + renderInput={(params) => } + /> + + + + + + { + try { + if (value && !!Date.parse(value)) { + const date = fDateOnly(value); + let entries = [...searchParams.entries(), ['end_date', date ?? '']]; + if (!searchParams.get('start_date')) { + entries = [...entries, ['start_date', date ?? '']]; + } + const filter = Object.fromEntries([...entries, ['page', '1']]); + setSearchParams(filter); + loadDataTableData(filter); + } + } catch (e) {} + }} + renderInput={(params) => } + /> + + + + + } + sx={{ p: 1.8 }} + onClick={handleExportClick} + loading={exportLoading} + > + Export + + + handleExport('list')}>Download List Excel + handleExport('summary')}>Download Summary Excel + + + +
+ ); + } + + function FilterForm() { + return ( + + + + + + ); + } + + function Row(props: { row: any }) { + const { row } = props; + + const serviceCodeMap: Record = { + 'OP': 'Outpatient', + 'IP': 'Inpatient', + 'DE': 'Dental', + 'MA': 'Maternal', + 'GL': 'Optical', + 'MCU': 'Medical Check Up', + 'MEDIVAC': 'Medical Emergency Evacuation', + }; + + const serviceName = serviceCodeMap[row.service_code] || row.service_code || '-'; + + return ( + + + {(row.claim_code || row.request_code) && row.log_code + ? `${row.claim_code ?? row.request_code} / ${row.log_code}` + : row.claim_code ?? row.request_code ?? row.log_code ?? '-'} + + {row.member_name ?? '-'} + {row.member_number ?? '-'} + {serviceName} + {row.provider_name ?? '-'} + {row.request_date ?? '-'} + {fNumber(parseInt(row.amount_incurred ?? 0))} + {fNumber(parseInt(row.amount_approved ?? 0))} + {fNumber(parseInt(row.excess_paid ?? 0))} + + + + + ); + } + + const headStyle = { + fontWeight: 'bold', + }; + + const [dataTableIsLoading, setDataTableLoading] = useState(true); + const [dataTableData, setDataTableData] = useState({ + current_page: 1, + data: [], + path: '', + first_page_url: '', + last_page: 1, + last_page_url: '', + next_page_url: '', + prev_page_url: '', + per_page: 10, + from: 0, + to: 0, + total: 0, + }); + + const loadDataTableData = async (appliedFilter: any | null = null) => { + setDataTableLoading(true); + const filter = appliedFilter ? appliedFilter : Object.fromEntries([...searchParams.entries()]); + try { + const response = await axios.get('/primayan-medicare', { + params: filter, + }); + setDataTableData(response.data.data.results); + setProviders(response.data.data.providers); + } catch (error) { + console.error('Failed to load Primayan Medicare data:', error); + } + setDataTableLoading(false); + }; + + const handlePageChange = (event: ChangeEvent, value: number) => { + const filter = Object.fromEntries([...searchParams.entries(), ['page', value]]); + loadDataTableData(filter); + setSearchParams(filter); + }; + + useEffect(() => { + loadDataTableData(); + }, []); + + return ( + + + + + + + + + Code Claim / Code LOG + Nama Member + Member ID + Service + Provider + Tanggal Request + Amount Incurred + Amount Approved + Excess Paid + Status + + + {dataTableIsLoading ? ( + + + + Loading + + + + ) : dataTableData.data.length === 0 ? ( + + + + No Data + + + + ) : ( + + {dataTableData.data.map((row, index) => ( + + ))} + + )} +
+
+ + +
+
+ ); +} diff --git a/frontend/dashboard/src/routes/index.tsx b/frontend/dashboard/src/routes/index.tsx index 9082b104..fa0b42e6 100644 --- a/frontend/dashboard/src/routes/index.tsx +++ b/frontend/dashboard/src/routes/index.tsx @@ -471,6 +471,10 @@ export default function Router() { path: 'report/linksehat-payments', element: , }, + { + path: 'report/primayan-medicare', + element: , + }, { path: 'report/phr', @@ -770,6 +774,8 @@ const EPrescriptionShow = Loadable(lazy(() => import('../pages/EPrescription/Liv const LinksehatPayment = Loadable(lazy(() => import('../pages/Report/LinksehatPayments/Index'))); +const PrimayanMedicare = Loadable(lazy(() => import('../pages/Report/PrimayanMedicare/Index'))); + const RiwayatMedisPeserta = Loadable(lazy(() => import('../pages/Report/RiwayatMedisPeserta/Index'))); const RujukanPasien = Loadable(lazy(() => import('../pages/Report/Rujukan/Index'))); const Prescription = Loadable(lazy(() => import('../pages/Report/Prescription/Index')));