diff --git a/Modules/HospitalPortal/Http/Controllers/Api/ClaimRequestController.php b/Modules/HospitalPortal/Http/Controllers/Api/ClaimRequestController.php
index 27bd30e3..ccee7ce5 100644
--- a/Modules/HospitalPortal/Http/Controllers/Api/ClaimRequestController.php
+++ b/Modules/HospitalPortal/Http/Controllers/Api/ClaimRequestController.php
@@ -16,6 +16,7 @@ use Illuminate\Routing\Controller;
use Modules\HospitalPortal\Transformers\ClaimRequestResource;
use Modules\HospitalPortal\Transformers\ClaimRequestShowResource;
use PDF;
+use Illuminate\Support\Facades\DB;
class ClaimRequestController extends Controller
{
@@ -208,4 +209,114 @@ class ClaimRequestController extends Controller
// Menghasilkan kode dengan format yang diinginkan
return self::$code_prefix . '-' . str_pad($next_number, 5, '0', STR_PAD_LEFT);
}
+
+ public function get_claim_requests(Request $request)
+ {
+
+ $limit = $request->has('per_page') ? $request->input('per_page') : 10;
+
+ $results = 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')
+ ->when($request->input('search'), function ($query, $search) {
+ $query->where(function ($query) use ($search) {
+ $query->orWhere('claim_requests.code', 'like', "%" . $search . "%")
+ ->orWhere('members.member_id', 'like', "%" . $search . "%")
+ ->orWhere('members.name', 'like', "%" . $search . "%")
+ ->orWhere('corporate_divisions.name', 'like', "%" . $search . "%")
+ ->orWhere('claim_requests.status', 'like', "%" . $search . "%")
+ ->orWhere('claim_requests.submission_date', 'like', "%" . $search . "%");
+ });
+ })
+ ->when($request->has('orderBy'), function ($query) use ($request) {
+ $orderBy = $request->orderBy;
+ $direction = $request->order ?? 'asc';
+
+ $query->orderBy($orderBy, $direction);
+ })
+ ->select('members.id', 'claim_requests.code','members.member_id', 'members.name as full_name', 'corporate_divisions.name AS division_name',
+ 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
+ '),
+ 'claim_requests.id AS claim_request_id', 'claim_requests.submission_date')
+ ->paginate($limit);
+ return response()->json(Helper::paginateResources($results));
+ }
+
+ public function detail_claim_requests($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;
+
+ return Helper::responseJson($results);
+ }
}
diff --git a/Modules/HospitalPortal/Routes/api.php b/Modules/HospitalPortal/Routes/api.php
index 3ff6dc32..ffe1e1bf 100644
--- a/Modules/HospitalPortal/Routes/api.php
+++ b/Modules/HospitalPortal/Routes/api.php
@@ -51,6 +51,8 @@ Route::prefix('v1')->group(function() {
Route::post('claim-requests', [ClaimRequestController::class, 'store'])->name('claim-requests.store');
Route::get('claim-requests/{claim_request_id}/log', [ClaimRequestController::class, 'generateLog'])->name('claim-requests.generate-log');
Route::get('claim-requests/{id}', [ClaimRequestController::class, 'show'])->name('claim-requests.show');
+ Route::get('get-claim-requests', [ClaimRequestController::class, 'get_claim_requests'])->name('claim-requests.get_claim_requests');
+ Route::get('detail-claim-requests/{id}', [ClaimRequestController::class, 'detail_claim_requests'])->name('claim-requests.detail_claim_requests');
});
});
});
diff --git a/frontend/hospital-portal/src/components/Label.tsx b/frontend/hospital-portal/src/components/Label.tsx
new file mode 100644
index 00000000..c633ec4f
--- /dev/null
+++ b/frontend/hospital-portal/src/components/Label.tsx
@@ -0,0 +1,98 @@
+// @mui
+import { alpha, Theme, useTheme, styled } from '@mui/material/styles';
+import { BoxProps } from '@mui/material';
+// theme
+import { ColorSchema } from '../theme/palette';
+
+// ----------------------------------------------------------------------
+
+type LabelColor = 'default' | 'primary' | 'secondary' | 'info' | 'success' | 'warning' | 'error';
+
+type LabelVariant = 'filled' | 'outlined' | 'ghost';
+
+const RootStyle = styled('span')(
+ ({
+ theme,
+ ownerState,
+ }: {
+ theme: Theme;
+ ownerState: {
+ color: LabelColor;
+ variant: LabelVariant;
+ };
+ }) => {
+ const isLight = theme.palette.mode === 'light';
+ const { color, variant } = ownerState;
+
+ const styleFilled = (color: ColorSchema) => ({
+ color: theme.palette[color].contrastText,
+ backgroundColor: theme.palette[color].main,
+ });
+
+ const styleOutlined = (color: ColorSchema) => ({
+ color: theme.palette[color].main,
+ backgroundColor: 'transparent',
+ border: `1px solid ${theme.palette[color].main}`,
+ });
+
+ const styleGhost = (color: ColorSchema) => ({
+ color: theme.palette[color][isLight ? 'dark' : 'light'],
+ backgroundColor: alpha(theme.palette[color].main, 0.16),
+ });
+
+ return {
+ height: 22,
+ minWidth: 22,
+ lineHeight: 0,
+ borderRadius: 6,
+ // cursor: 'default',
+ alignItems: 'center',
+ whiteSpace: 'nowrap',
+ display: 'inline-flex',
+ justifyContent: 'center',
+ padding: theme.spacing(0, 1),
+ color: theme.palette.grey[800],
+ fontSize: theme.typography.pxToRem(12),
+ fontFamily: theme.typography.fontFamily,
+ backgroundColor: theme.palette.grey[300],
+ fontWeight: theme.typography.fontWeightBold,
+
+ ...(color !== 'default'
+ ? {
+ ...(variant === 'filled' && { ...styleFilled(color) }),
+ ...(variant === 'outlined' && { ...styleOutlined(color) }),
+ ...(variant === 'ghost' && { ...styleGhost(color) }),
+ }
+ : {
+ ...(variant === 'outlined' && {
+ backgroundColor: 'transparent',
+ color: theme.palette.text.primary,
+ border: `1px solid ${theme.palette.grey[500_32]}`,
+ }),
+ ...(variant === 'ghost' && {
+ color: isLight ? theme.palette.text.secondary : theme.palette.common.white,
+ backgroundColor: theme.palette.grey[500_16],
+ }),
+ }),
+ };
+ }
+);
+
+// ----------------------------------------------------------------------
+
+interface Props extends BoxProps {
+ color?: LabelColor;
+ variant?: LabelVariant;
+}
+
+export default function Label({ color = 'default', variant = 'ghost', children, sx }: Props) {
+ const theme = useTheme();
+
+ return (
+
+ {children}
+
+ );
+}
+
+
diff --git a/frontend/hospital-portal/src/components/Table.tsx b/frontend/hospital-portal/src/components/Table.tsx
new file mode 100644
index 00000000..5a9ac040
--- /dev/null
+++ b/frontend/hospital-portal/src/components/Table.tsx
@@ -0,0 +1,387 @@
+/* ---------------------------------- @mui ---------------------------------- */
+import { styled } from '@mui/material/styles';
+import {
+ Paper,
+ Table as TableContent,
+ TableBody,
+ TableCell,
+ TableContainer,
+ TableHead,
+ TableRow,
+ TextField,
+ Button,
+ TableSortLabel,
+ Box,
+ Card,
+ Grid,
+ FormControl,
+ InputLabel,
+ Select,
+ MenuItem,
+ SelectChangeEvent,
+ Stack,
+ Typography,
+ LinearProgress,
+ linearProgressClasses,
+} from '@mui/material';
+import { visuallyHidden } from '@mui/utils';
+/* ---------------------------------- axios --------------------------------- */
+import axios from '../utils/axios';
+/* ---------------------------------- react --------------------------------- */
+import { Fragment, useContext, useEffect, useState } from 'react';
+import { useSearchParams } from 'react-router-dom';
+/* -------------------------------- component ------------------------------- */
+import BaseTablePagination from './BaseTablePagination';
+/* ---------------------------------- theme --------------------------------- */
+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,
+ borderRadius: 6,
+ [`&.${linearProgressClasses.colorPrimary}`]: {
+ backgroundColor: '#D1F1F1',
+ },
+ [`& .${linearProgressClasses.bar}`]: {
+ borderRadius: 6,
+ backgroundColor: theme.palette.primary.main,
+ },
+}));
+/* -------------------------------------------------------------------------- */
+
+export default function Table({
+ headCells,
+ rows,
+ paginations,
+ orders,
+ loadings,
+ params,
+ filters,
+ filterStatus,
+ filterStartDate,
+ filterEndDate,
+ searchs,
+ exportReport,
+}: TableListProps) {
+ /* ------------------------------- 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(),
+ ['order', isAsc ? 'desc' : 'asc'],
+ ['orderBy', property],
+ ]);
+ params.setAppliedParams(parameters);
+ };
+ /* -------------------------------------------------------------------------- */
+
+ /* -------------------------- enchanced table head -------------------------- */
+ const EnhancedTableHead = () => {
+ const createSortHandler = (property: string) => (event: React.MouseEvent) => {
+ handleRequestSort(event, property);
+ };
+
+ return (
+
+
+ {headCells &&
+ headCells.map((headCell, index) => (
+
+ {headCell.isSort ? (
+
+ {headCell.label}
+ {orders?.orderBy === headCell.id ? (
+
+ {orders.order === 'desc' ? 'sorted descending' : 'sorted ascending'}
+
+ ) : null}
+
+ ) : (
+ headCell.label
+ )}
+
+ ))}
+
+
+ );
+ };
+ /* -------------------------------------------------------------------------- */
+
+ /* ------------------------ button change pagination ------------------------ */
+ const onPageChangeHandle = async (
+ event: React.MouseEvent | null,
+ newPage: number
+ ) => {
+ const parameters = Object.fromEntries([
+ ...params.searchParams.entries(),
+ ['page', newPage + 1],
+ ['per_page', paginations.rowsPerPage]
+ ]);
+ paginations.setPage(newPage);
+ await new Promise((resolve) => setTimeout(resolve, 500));
+ params.setAppliedParams(parameters);
+ };
+ /* -------------------------------------------------------------------------- */
+
+ /* --------------------------- row page per limit --------------------------- */
+ const onRowsPerPageChangeHandle = async (event: React.ChangeEvent) => {
+ params.searchParams.delete('page');
+ const parameters = Object.fromEntries([
+ ...params.searchParams.entries(),
+ ['per_page', parseInt(event.target.value, 10)],
+ ]);
+
+ paginations.setPage(0);
+ paginations.setRowsPerPage(parseInt(event.target.value, 10));
+ await new Promise((resolve) => setTimeout(resolve, 500));
+ params.setAppliedParams(parameters);
+ };
+ /* -------------------------------------------------------------------------- */
+
+ return (
+ //
+
+ {/* Field 1 */}
+
+
+ {filters && filters.useFilter ? (
+
+
+
+ Division
+
+
+
+
+
+
+
+ ) : null }
+
+ {searchs && searchs.useSearchs ? (
+
+ {filterStatus && filterStatus.useFilter ? (
+
+
+
+ ) :
+
+
+
+ }
+
+
+ ) : null }
+
+ {/* Start date */}
+ {filterStartDate && filterStartDate.useFilter ? (
+
+
+
+ ) : null }
+
+ {/* End Date */}
+
+ {filterEndDate && filterEndDate.useFilter ? (
+
+
+
+ ) : null }
+
+ {/* Filter status */}
+ {filterStatus && filterStatus.useFilter ? (
+
+
+ Status
+
+
+
+ ) : null }
+
+ {/* Export Report */}
+
+ {exportReport && exportReport.useExport ? (
+
+
+
+
+
+ ) : null }
+
+
+
+ {/* End Field 1 */}
+ {/* Field 2 */}
+
+ {/* Table */}
+
+
+ {/* Table Header */}
+
+ {/* End Table Header */}
+ {/* Table Body */}
+
+ {loadings.isLoading && rows.length >= 1 ? (
+
+
+ Loading . . .
+
+
+ ) : rows && rows.length >= 1 ? (
+ rows.map((row, rowIndex) => (
+
+ {headCells &&
+ //@ts-ignore
+ headCells.map((head, headIndex) => (
+ //@ts-ignore
+
+ {row[head.id]}
+
+ ))}
+
+ ))
+ ) : (
+
+
+ No Data Found
+
+
+ )}
+
+ {/* End Table Body */}
+
+
+ {/* End Table */}
+
+ {/* Pagination */}
+
+ {/* End Pagination */}
+
+ {/* End Field 2 */}
+
+ //
+ );
+}
diff --git a/frontend/hospital-portal/src/pages/Dashboard.tsx b/frontend/hospital-portal/src/pages/Dashboard.tsx
index ab6274f6..6ff99da1 100644
--- a/frontend/hospital-portal/src/pages/Dashboard.tsx
+++ b/frontend/hospital-portal/src/pages/Dashboard.tsx
@@ -13,6 +13,7 @@ import { Stack } from '@mui/system';
import { Input } from '@mui/material';
//sections
import TableList from '@/sections/dashboard/TableList';
+import TableList2 from '@/sections/dashboard/TableList2';
import { fDate } from '@/utils/formatTime';
import DialogDetailClaim from '@/components/dialogs/DialogDetailClaim';
@@ -93,7 +94,7 @@ export default function Dashboard() {
*/}
-
+
diff --git a/frontend/hospital-portal/src/routes/index.tsx b/frontend/hospital-portal/src/routes/index.tsx
index 26fcfbdc..4815a322 100644
--- a/frontend/hospital-portal/src/routes/index.tsx
+++ b/frontend/hospital-portal/src/routes/index.tsx
@@ -76,6 +76,10 @@ export default function Router() {
path: 'dashboard',
element: ,
},
+ {
+ path: '/detail/:id',
+ element: ,
+ },
],
},
@@ -98,3 +102,5 @@ const ForgetPassword = Loadable(lazy(() => import('@/pages/auth/ForgetPassword')
// Dashboard
const Dashboard = Loadable(lazy(() => import('@/pages/Dashboard')));
const NotFound = Loadable(lazy(() => import('@/pages/Page404')));
+
+const DetailClaimReport = Loadable(lazy(()=> import('@/sections/dashboard/Detail')));
diff --git a/frontend/hospital-portal/src/sections/dashboard/Detail.tsx b/frontend/hospital-portal/src/sections/dashboard/Detail.tsx
new file mode 100644
index 00000000..46405438
--- /dev/null
+++ b/frontend/hospital-portal/src/sections/dashboard/Detail.tsx
@@ -0,0 +1,67 @@
+// mui
+import { Container, Grid, Stack, Typography } from '@mui/material';
+// components
+import Page from '../../components/Page';
+// utils
+import useSettings from '../../hooks/useSettings';
+// section
+import CardFamilyInformation from '../../sections/alarm-center/user-profile/CardFamilyInformation';
+// react
+import { useNavigate, useParams } from 'react-router-dom';
+import ButtonBack from '../../components/ButtonBack';
+import { useEffect, useState, useContext } from 'react';
+import axios from '../../utils/axios';
+// pages
+import DetailTimeline from '../../sections/dashboard/DetailTimeline';
+import DetailStepper from '../../sections/dashboard/DetailStepper';
+import { format } from 'date-fns';
+import ArrowBackIosIcon from '@mui/icons-material/ArrowBackIos';
+
+// ----------------------------------------------------------------------
+
+export default function Detail() {
+ const navigate = useNavigate();
+ const { themeStretch } = useSettings();
+ const [data, setData] = useState();
+
+ const { id } = useParams();
+
+ useEffect(() => {
+ axios
+ .get('/detail-claim-requests/' + id)
+ .then((response) => {
+ setData(response.data);
+ })
+ .catch((error) => {
+ console.error(error);
+ });
+
+ }, []);
+
+ return (
+
+
+
+ navigate(-1)} sx={{cursor:'pointer'}}/>
+ Detail
+ {data ? (
+
+ Submission Date
+ {(data && data.data) ? format(new Date(data.data.status.submission_date), "d MMM yyyy") : ''}
+
+ ) : ''}
+
+ {data ? (
+
+
+
+
+
+
+
+
+ ) : ''}
+
+
+ );
+}
\ No newline at end of file
diff --git a/frontend/hospital-portal/src/sections/dashboard/DetailStepper.tsx b/frontend/hospital-portal/src/sections/dashboard/DetailStepper.tsx
new file mode 100644
index 00000000..18dc959a
--- /dev/null
+++ b/frontend/hospital-portal/src/sections/dashboard/DetailStepper.tsx
@@ -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 (
+
+
+ {status?.map((label) => (
+
+ : ''}>{label}
+
+ ))}
+
+
+ );
+}
diff --git a/frontend/hospital-portal/src/sections/dashboard/DetailTimeline.tsx b/frontend/hospital-portal/src/sections/dashboard/DetailTimeline.tsx
new file mode 100644
index 00000000..1e93f302
--- /dev/null
+++ b/frontend/hospital-portal/src/sections/dashboard/DetailTimeline.tsx
@@ -0,0 +1,104 @@
+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';
+
+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);
+ useEffect(() => {
+ if (data && data.data) {
+ setTimeline(data.data.timeline);
+ setRequestFile(data.data.request_files);
+ }
+
+ }, [data]);
+ return (
+ <>
+ {timeline?.map((dataTimeline, index) => (
+
+ {dataTimeline.date ? format(new Date(dataTimeline.date), "d MMM yyyy") : ''}
+
+
+
+
+
+
+
+
+
+ {dataTimeline.date ? format(new Date(dataTimeline.date), "HH : ii") : ''}
+ {dataTimeline.txt_status}
+
+
+ Detail:
+ {dataTimeline.description}
+
+ {dataTimeline.status === 'reviewed' && requestFile ? (
+ <>
+ {requestFile?.map((dataRequestFile, index) => (
+
+ {dataRequestFile.description}
+ }>
+
+ {dataRequestFile.type === 'claim-diagnosis' ?
+ 'Dokumen Diagnosa'
+ : dataRequestFile.type === 'claim-kondisi' ?
+ 'Dokumen Kondisi'
+ : dataRequestFile.type === 'claim-result' ?
+ 'Dokumen Hasil Penunjang'
+ : ''}
+
+
+
+ ))}
+ >
+ ) : ''}
+
+
+
+
+
+ ))}
+ >
+ );
+}
diff --git a/frontend/hospital-portal/src/sections/dashboard/TableList2.tsx b/frontend/hospital-portal/src/sections/dashboard/TableList2.tsx
new file mode 100644
index 00000000..22c895eb
--- /dev/null
+++ b/frontend/hospital-portal/src/sections/dashboard/TableList2.tsx
@@ -0,0 +1,284 @@
+/* ---------------------------------- @mui ---------------------------------- */
+import { Stack, Button, MenuItem } from '@mui/material';
+/* ---------------------------------- axios --------------------------------- */
+// import axios from 'axios';
+import axios from '../../utils/axios';
+/* ---------------------------------- react --------------------------------- */
+import { useContext, useEffect, useState } from 'react';
+
+/* -------------------------------- component ------------------------------- */
+import Iconify from '../../components/Iconify';
+import TableComponent from '../../components/Table';
+/* ---------------------------------- theme --------------------------------- */
+import palette from '../../theme/palette';
+//import { UserCurrentCorporateContext } from '../../contexts/UserCurrentCorporate';
+import { HeadCell, Order, PaginationTableProps } from '../../@types/table';
+import { useSearchParams, useNavigate } from 'react-router-dom';
+import { fDate, fDateSuffix } from '../../utils/formatTime';
+import Typography from '@mui/material/Typography';
+import { format } from 'date-fns';
+import TableMoreMenu from '../../components/table/TableMoreMenu';
+import VisibilityOutlinedIcon from '@mui/icons-material/VisibilityOutlined';
+import HistoryIcon from '@mui/icons-material/History';
+import SearchIcon from '@mui/icons-material/Search';
+import Label from '../../components/Label';
+import { enqueueSnackbar } from 'notistack';
+
+export default function TableList2() {
+ const navigate = useNavigate();
+
+ //const { corporateValue } = useContext(UserCurrentCorporateContext);
+ //const { corporateValue } = useContext(null);
+
+ const [data, setData] = useState([]);
+
+ // Download LOG
+ async function handleDownloadLog(claimRequest) {
+ return axios
+ .get(`claim-requests/${claimRequest}/log`, {
+ responseType: 'blob',
+ })
+ .then((response) => {
+ window.open(URL.createObjectURL(response.data));
+ // setLoadingLog(false);
+ })
+ // .then((blobFile) => {
+ // new File([blobFile], 'asdads.pdf', { type: blobFile.type })
+ // setLoadingLog(false);
+ // })
+ .catch((response) => {
+ console.log(response);
+ enqueueSnackbar(response.message, { variant: 'error' });
+ // setLoadingLog(false);
+ });
+ }
+
+ /* -------------------------------------------------------------------------- */
+ /* 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('desc');
+ const [orderBy, setOrderBy] = useState('member_id');
+
+ 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 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: true,
+ searchText: searchText,
+ setSearchText: setSearchText,
+ handleSearchSubmit: handleSearchSubmit,
+ };
+
+ /* -------------------------------- headCell -------------------------------- */
+ const headCells: HeadCell[] = [
+ {
+ id: 'submission_date',
+ align: 'center',
+ label: 'Request Date',
+ isSort: true,
+ },
+ {
+ id: 'member_id',
+ align: 'left',
+ label: 'Member ID',
+ isSort: true,
+ },
+ {
+ id: 'code',
+ align: 'left',
+ label: 'Claim Code',
+ isSort: true,
+ },
+ {
+ id: 'full_name',
+ align: 'left',
+ label: 'Name',
+ isSort: true,
+ },
+ {
+ id: 'status',
+ align: 'center',
+ label: 'Status',
+ isSort: true,
+ },
+ {
+ id: 'action',
+ align: 'right',
+ 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(`/get-claim-requests`, {
+ params: { ...parameters, type: 'claim-report' },
+ });
+
+ setData(
+ response.data.data.map((obj: any) => ({
+ ...obj,
+ status:
+ obj.status === 'requested' ? (
+
+ ) : obj.status === 'approved' ? (
+
+ ) : obj.status === 'declined' ? (
+
+ ) : obj.status === 'pending' ? (
+
+ ) : obj.status === 'reviewed' ? (
+
+ ) : (
+ }
+ sx={{
+ backgroundColor: '#CD7B2E',
+ color: '#FFFF',
+ padding: '1px, 8px',
+ paddingY: 1,
+ '&:hover': {
+ backgroundColor: '#BF6919',
+ color: '#FFFF',
+ },
+ }}
+ >
+ Ongoing
+
+ ),
+ submission_date:
+
+ ,
+ action:
+
+
+
+ >
+ } />
+ }))
+ );
+
+ 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]);
+
+ return (
+
+
+
+ );
+}
diff --git a/frontend/hospital-portal/src/utils/formatTime.ts b/frontend/hospital-portal/src/utils/formatTime.ts
index b2656c01..ed88dcae 100644
--- a/frontend/hospital-portal/src/utils/formatTime.ts
+++ b/frontend/hospital-portal/src/utils/formatTime.ts
@@ -1,13 +1,14 @@
-import { format, getTime, formatDistanceToNow } from 'date-fns';
+import { format, parseISO, getTime, setHours, setMinutes, formatDistanceToNow } from 'date-fns';
// ----------------------------------------------------------------------
-export function fDate(date: Date | string | number, dateFormat = 'dd MMMM yyyy' ) {
- return format(new Date(date), dateFormat);
+export function fDate(date: Date | string | number) {
+ //console.log(date);
+ return format(new Date(date), 'dd MMMM yyyy');
}
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) {
@@ -18,13 +19,30 @@ 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');
+}
+
export function fToNow(date: Date | string | number) {
return formatDistanceToNow(new Date(date), {
- addSuffix: true
+ addSuffix: true,
});
}
-
-export function fPostFormat(date: Date | string | number, dateFormat = 'yyyy-MM-dd HH:mm:ss' ) {
+export function fPostFormat(date: Date | string | number, dateFormat = 'yyyy-MM-dd HH:mm:ss') {
return format(new Date(date), dateFormat);
}
+
+// export function fDateString(date) {
+// const dateObj = parseISO(date);
+// const formattedDate = format(dateObj, 'dd MMMM yyyy');
+// return formattedDate;
+// }
+
+// export function fFormattedDateString(date : String) {
+// console.log(date);
+// const datePart = date.split(' ')[0]; // Memisahkan bagian tanggal
+// const formattedDate = fDateString(datePart); // Menggunakan fungsi sebelumnya untuk memformat tanggal
+// return formattedDate;
+// }