1037 lines
35 KiB
TypeScript
Executable File
1037 lines
35 KiB
TypeScript
Executable File
// @mui
|
|
import {
|
|
Box,
|
|
Grid,
|
|
Button,
|
|
Card,
|
|
Collapse,
|
|
IconButton,
|
|
MenuItem,
|
|
Table,
|
|
TableBody,
|
|
TableCell,
|
|
TableRow,
|
|
TextField,
|
|
Typography,
|
|
Stack,
|
|
Menu,
|
|
ButtonGroup,
|
|
Tooltip,
|
|
TableHead,
|
|
Checkbox,
|
|
InputAdornment,
|
|
TableSortLabel,
|
|
FormControl
|
|
} from '@mui/material';
|
|
import { visuallyHidden } from '@mui/utils';
|
|
|
|
import { DesktopDatePicker, LocalizationProvider } from '@mui/x-date-pickers';
|
|
import { fDateOnly } from '@/utils/formatTime';
|
|
|
|
import { AdapterDateFns } from '@mui/x-date-pickers/AdapterDateFns';
|
|
import FindInPageOutlinedIcon from '@mui/icons-material/FindInPageOutlined';
|
|
import AssessmentIcon from '@mui/icons-material/Assessment';
|
|
// hooks
|
|
import React, { ChangeEvent, useEffect, useRef, useState } from 'react';
|
|
import { Link, Navigate, useNavigate, useSearchParams } from 'react-router-dom';
|
|
|
|
import { LoadingButton } from '@mui/lab';
|
|
// components
|
|
import axios from '../../utils/axios';
|
|
import { LaravelPaginatedData, LaravelPaginatedDataDefault } from '../../@types/paginated-data';
|
|
import DataTable from '../../components/LaravelTable';
|
|
import { fCurrency } from '../../utils/formatNumber';
|
|
import EditRoundedIcon from '@mui/icons-material/EditRounded';
|
|
import { Chip } from '@mui/material';
|
|
import Iconify from '@/components/Iconify';
|
|
import { enqueueSnackbar } from 'notistack';
|
|
import { fDate, fDateTime } from '../../utils/formatTime';
|
|
import { Claims } from '@/@types/claims';
|
|
import Label from '@/components/Label';
|
|
import { capitalizeFirstLetter } from '@/utils/formatString';
|
|
import TableMoreMenu from '@/components/table/TableMoreMenu';
|
|
import Edit from '@mui/icons-material/Edit';
|
|
import { Download } from '@mui/icons-material';
|
|
import { Add, Search } from '@mui/icons-material';
|
|
import Autocomplete from '@mui/material/Autocomplete';
|
|
|
|
import DownloadIcon from '@mui/icons-material/Download';
|
|
|
|
import UploadIcon from '@mui/icons-material/Upload';
|
|
import CancelIcon from '@mui/icons-material/Cancel';
|
|
import CheckCircleIcon from '@mui/icons-material/CheckCircle';
|
|
|
|
import { Dialog, DialogTitle, DialogContent, DialogActions } from '@mui/material';
|
|
import CloseIcon from '@mui/icons-material/Close';
|
|
|
|
|
|
export default function List() {
|
|
const [selectAll, setSelectAll] = useState(false);
|
|
const [selectedRows, setSelectedRows] = useState([]);
|
|
const [providers, setProviders] = useState(null);
|
|
// const [searchText, setSearchText] = useState('');
|
|
const [order, setOrder] = useState<Order>('desc');
|
|
const [orderBy, setOrderBy] = useState('created_at');
|
|
const [perPage, setPerPage] = useState<number>(0);
|
|
|
|
const handleChange = (event, newValue) => {
|
|
// Jika newValue tidak undefined, atur nilai dataProvider
|
|
if (newValue !== undefined) {
|
|
setDataProvider(newValue.service_code);
|
|
} else {
|
|
// Jika tidak ada yang dipilih, set dataProvider menjadi string kosong
|
|
setDataProvider(null);
|
|
}
|
|
};
|
|
// Dummy data
|
|
const dummyServices = [
|
|
{ service_code: '1', name: 'Service 1' },
|
|
{ service_code: '2', name: 'Service 2' },
|
|
{ service_code: '3', name: 'Service 3' },
|
|
// tambahkan data lain sesuai kebutuhan
|
|
];
|
|
|
|
|
|
|
|
const handleSelectAll = () => {
|
|
setSelectAll(!selectAll);
|
|
if (!selectAll) {
|
|
const requestedIds = dataTableData.data
|
|
.filter(row => row.status === 'received') // Memfilter baris dengan status 'requested'
|
|
.map(row => row.id); // Mengambil hanya ID dari baris-baris yang memenuhi kondisi
|
|
setSelectedRows(requestedIds);
|
|
} else {
|
|
setSelectedRows([]);
|
|
}
|
|
};
|
|
|
|
const handleRowSelect = (id) => {
|
|
if (selectedRows.includes(id)) {
|
|
setSelectedRows(selectedRows.filter(rowId => rowId !== id));
|
|
} else {
|
|
setSelectedRows([...selectedRows, id]);
|
|
}
|
|
};
|
|
|
|
const [searchParams, setSearchParams] = useSearchParams();
|
|
const [startDate, setStartDate] = useState(null);
|
|
const [searchText, setSearchText] = useState('');
|
|
const [endDate, setEndDate] = useState(null);
|
|
const navigate = useNavigate();
|
|
const [dataProvider, setDataProvider] = useState(null);
|
|
|
|
useEffect(() => {
|
|
if (startDate !== null || endDate !== null || dataProvider !== null
|
|
|| order !== null || orderBy !== null || perPage !== 0) {
|
|
loadDataTableData();
|
|
getProvider();
|
|
}
|
|
}, [startDate, endDate, dataProvider, order, orderBy, perPage]);
|
|
|
|
const [isLoading, setIsLoading] = useState(false);
|
|
const [isLoadingImport, setIsLoadingImport] = useState(false);
|
|
const handleExportReport = async () => {
|
|
|
|
|
|
const year = startDate?.getFullYear();
|
|
const month = (startDate?.getMonth() + 1).toString().padStart(2, '0'); // Tambahkan 1 karena bulan dimulai dari 0, dan padStart untuk memastikan 2 digit
|
|
const day = startDate?.getDate().toString().padStart(2, '0'); // padStart untuk memastikan 2 digit
|
|
|
|
const formattedDate = year && month && day ? `${year}-${month}-${day}` : '';
|
|
|
|
const year1 = endDate?.getFullYear();
|
|
const month1 = (endDate?.getMonth() + 1).toString().padStart(2, '0'); // Tambahkan 1 karena bulan dimulai dari 0, dan padStart untuk memastikan 2 digit
|
|
const day1 = endDate?.getDate().toString().padStart(2, '0'); // padStart untuk memastikan 2 digit
|
|
|
|
const formattedDate1 = year1 && month1 && day1 ? `${year1}-${month1}-${day1}` : '';
|
|
|
|
|
|
|
|
var filter = Object.fromEntries([...searchParams.entries()]);
|
|
setIsLoading(true)
|
|
await axios
|
|
.get('/claims/export-claim-management',{
|
|
params: {
|
|
search: searchText,
|
|
start_date: formattedDate ? formattedDate : null,
|
|
end_date:formattedDate1,
|
|
provider: dataProvider,
|
|
order: order,
|
|
orderBy: orderBy,
|
|
page: perPage,
|
|
}
|
|
})
|
|
.then((res) => {
|
|
enqueueSnackbar('Data berhasil di Export', {
|
|
variant: 'success',
|
|
anchorOrigin: { horizontal: 'right', vertical: 'top' },
|
|
});
|
|
setIsLoading(false)
|
|
|
|
document.location.href = res.data.data.file_url;
|
|
})
|
|
.catch((err) =>
|
|
enqueueSnackbar('Data Gagal di Export', {
|
|
variant: 'error',
|
|
anchorOrigin: { horizontal: 'right', vertical: 'top' },
|
|
})
|
|
|
|
);
|
|
};
|
|
|
|
|
|
function SearchInput(props: any) {
|
|
// SEARCH
|
|
const searchInput = useRef<HTMLInputElement>(null);
|
|
|
|
const handleSearchChange = (event: any) => {
|
|
const newSearchText = event.target.value ?? '';
|
|
setSearchText(newSearchText);
|
|
};
|
|
|
|
const handleSearchSubmit = (event: any) => {
|
|
event.preventDefault();
|
|
props.onSearch({ search: searchText }); // Trigger to Parent
|
|
};
|
|
|
|
const handleGetData = (type :string) => {
|
|
axios.get(`claims/1/data-claim`)
|
|
.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();
|
|
})
|
|
}
|
|
|
|
useEffect(() => {
|
|
// Trigger First Search
|
|
// setSearchText(searchParams.get('search') ?? '');
|
|
}, []);
|
|
|
|
return (
|
|
<form onSubmit={handleSearchSubmit} style={{ width: '100%' }}>
|
|
<Stack direction={'row'} spacing={2} sx={{ mb: 2 }}>
|
|
<TextField
|
|
id="search-input"
|
|
ref={searchInput}
|
|
label="Search"
|
|
variant="outlined"
|
|
fullWidth
|
|
onChange={handleSearchChange}
|
|
value={searchText}
|
|
placeholder='Search Code or Member ID...'
|
|
/>
|
|
<Button
|
|
variant="contained"
|
|
startIcon={<Download />}
|
|
onClick={() => handleGetData('DO')}
|
|
sx={{ p: 1.8 }}
|
|
>
|
|
Export
|
|
</Button>
|
|
</Stack>
|
|
</form>
|
|
);
|
|
}
|
|
|
|
function ImportForm(props: any) {
|
|
// IMPORT
|
|
// Create Button Menu
|
|
const [anchorEl, setAnchorEl] = React.useState<null | HTMLElement>(null);
|
|
|
|
return (
|
|
<div>
|
|
<Stack direction={'row'} spacing={2} sx={{ p: 2 }}>
|
|
<SearchInput onSearch={applyFilter} />
|
|
{/* <Button
|
|
variant="outlined"
|
|
startIcon={<AddIcon />}
|
|
sx={{ p: 1.8 }}
|
|
onClick={() => {
|
|
navigate('/claims/create');
|
|
}}
|
|
>
|
|
Create
|
|
</Button> */}
|
|
</Stack>
|
|
</div>
|
|
);
|
|
}
|
|
|
|
const searchInput = useRef<HTMLInputElement>(null);
|
|
|
|
|
|
//handle search
|
|
const handleSearchChange = (event: any) => {
|
|
const newSearchText = event.target.value ?? '';
|
|
setSearchText(newSearchText);
|
|
};
|
|
|
|
const handleSearchSubmit = (event: any) => {
|
|
event.preventDefault();
|
|
loadDataTableData();
|
|
};
|
|
|
|
|
|
|
|
useEffect(() => {
|
|
// Trigger First Search
|
|
//setSearchText(searchText);
|
|
}, []);
|
|
|
|
const item = [
|
|
{
|
|
id: '',
|
|
value: '',
|
|
name: 'Semua',
|
|
},
|
|
];
|
|
|
|
// const handleClick = () => {
|
|
|
|
// }
|
|
|
|
|
|
|
|
// Dummy Default Data
|
|
const [dataTableIsLoading, setDataTableLoading] = useState(true);
|
|
const [dataTableData, setDataTableData] = useState<LaravelPaginatedData>(
|
|
LaravelPaginatedDataDefault
|
|
);
|
|
|
|
|
|
|
|
const loadDataTableData = async (appliedFilter: any | null = null) => {
|
|
setDataTableLoading(true);
|
|
const year = startDate?.getFullYear();
|
|
const month = (startDate?.getMonth() + 1).toString().padStart(2, '0'); // Tambahkan 1 karena bulan dimulai dari 0, dan padStart untuk memastikan 2 digit
|
|
const day = startDate?.getDate().toString().padStart(2, '0'); // padStart untuk memastikan 2 digit
|
|
|
|
const formattedDate = year && month && day ? `${year}-${month}-${day}` : '';
|
|
|
|
const year1 = endDate?.getFullYear();
|
|
const month1 = (endDate?.getMonth() + 1).toString().padStart(2, '0'); // Tambahkan 1 karena bulan dimulai dari 0, dan padStart untuk memastikan 2 digit
|
|
const day1 = endDate?.getDate().toString().padStart(2, '0'); // padStart untuk memastikan 2 digit
|
|
|
|
const formattedDate1 = year1 && month1 && day1 ? `${year1}-${month1}-${day1}` : '';
|
|
|
|
const filter = appliedFilter ? appliedFilter : Object.fromEntries([...searchParams.entries()]);
|
|
const response = await axios.get('/claims', {
|
|
params: {
|
|
search: searchText,
|
|
start_date: formattedDate ? formattedDate : null,
|
|
end_date:formattedDate1,
|
|
provider: dataProvider,
|
|
order: order,
|
|
orderBy: orderBy,
|
|
page: perPage,
|
|
}
|
|
});
|
|
|
|
setDataTableLoading(false);
|
|
|
|
setDataTableData(response.data);
|
|
};
|
|
|
|
const getProvider = async () => {
|
|
const response = await axios.get('/claims/get-provider');
|
|
setProviders(response.data)
|
|
}
|
|
|
|
const applyFilter = async (searchFilter: { search: string }) => {
|
|
await loadDataTableData(searchFilter);
|
|
setSearchParams(searchFilter);
|
|
};
|
|
|
|
const handlePageChange = (event: ChangeEvent, value: number): void => {
|
|
setPerPage(value);
|
|
};
|
|
|
|
const [openDialogSubmit, setOpenDialogSubmit] = useState(false);
|
|
const handleCloseDialogSubmit = () => {
|
|
setOpenDialogSubmit(false);
|
|
}
|
|
|
|
function toTitleCase(str: string | null) {
|
|
return str.replace(/\w\S*/g, function(txt) {
|
|
return txt.charAt(0).toUpperCase() + txt.substr(1).toLowerCase();
|
|
});
|
|
}
|
|
|
|
const [approve, setApprove] = useState('');
|
|
|
|
const [reasonDecline, setReasonDecline] = useState('');
|
|
|
|
const handleReasonDeclineChange = (event) => {
|
|
setReasonDecline(event.target.value);
|
|
// Tambahkan logika yang diperlukan di sini
|
|
};
|
|
|
|
const handleSubmitData = () => {
|
|
//approve or decline
|
|
if (!reasonDecline && approve == 'decline') {
|
|
enqueueSnackbar('Mohon isi alasan', { variant: 'warning' });
|
|
return false;
|
|
}
|
|
Promise.all(selectedRows.map(send_bulk))
|
|
.then(() => {
|
|
enqueueSnackbar('All requests processed successfully', { variant: 'success' });
|
|
setOpenDialogSubmit(false);
|
|
setTimeout(() => {
|
|
window.location.reload();
|
|
}, 5000); // Reload the page after 5 seconds
|
|
})
|
|
.catch((error) => {
|
|
enqueueSnackbar(error.response?.data?.message ?? 'Something went wrong!', { variant: 'error' });
|
|
});
|
|
};
|
|
|
|
function send_bulk(id) {
|
|
return axios.post(`claims/${id}/${approve}`, { reasonDecline: reasonDecline });
|
|
}
|
|
|
|
|
|
const [anchorEl, setAnchorEl] = React.useState<null | HTMLElement>(null);
|
|
const createMenu = Boolean(anchorEl);
|
|
const importClaimManagement = useRef<HTMLInputElement>(null);
|
|
const [currentImportFileName, setCurrentImportFileName] = useState(null);
|
|
const [importLoading, setImportLoading] = useState(false);
|
|
const [importResult, setImportResult] = useState(null);
|
|
const handleClick = (event: React.MouseEvent<HTMLButtonElement>) => {
|
|
setAnchorEl(event.currentTarget);
|
|
};
|
|
const handleClose = () => {
|
|
setAnchorEl(null);
|
|
};
|
|
const handleImportButton = () => {
|
|
if (importClaimManagement?.current) {
|
|
handleClose();
|
|
importClaimManagement.current ? importClaimManagement.current.click() : console.log('No File selected');
|
|
} else {
|
|
alert('No file selected');
|
|
}
|
|
};
|
|
const handleCancelImportButton = () => {
|
|
if(importClaimManagement.current)
|
|
{
|
|
importClaimManagement.current.value = '';
|
|
importClaimManagement.current.dispatchEvent(new Event('change', { bubbles: true }));
|
|
}
|
|
};
|
|
const handleImportChange = (event: any) => {
|
|
if (event.target.files[0]) {
|
|
setCurrentImportFileName(event.target.files[0].name);
|
|
} else {
|
|
setCurrentImportFileName(null);
|
|
}
|
|
};
|
|
const handleUpload = () => {
|
|
if(importClaimManagement.current && importClaimManagement.current.files)
|
|
{
|
|
if (importClaimManagement.current?.files.length) {
|
|
const formData = new FormData();
|
|
formData.append('file', importClaimManagement.current?.files[0]);
|
|
setImportLoading(true);
|
|
axios
|
|
.post('claims/import', formData)
|
|
.then((response) => {
|
|
handleCancelImportButton();
|
|
loadDataTableData();
|
|
setImportResult(response.data);
|
|
setImportLoading(false);
|
|
enqueueSnackbar('Success Import Claim Managemenet', { variant: 'success' });
|
|
})
|
|
.catch((response) => {
|
|
enqueueSnackbar(
|
|
'Looks like something went wrong. Please check your data and try again. ' +
|
|
response.message,
|
|
{ variant: 'error' }
|
|
);
|
|
setImportLoading(false);
|
|
});
|
|
} else {
|
|
enqueueSnackbar('No File Selected', { variant: 'warning' });
|
|
}
|
|
}
|
|
};
|
|
const handleGetTemplate = () => {
|
|
axios.get('claims/download-template').then((response) => {
|
|
const link = document.createElement('a');
|
|
link.href = response.data.data.file_url;
|
|
link.setAttribute('download', response.data.data.file_name);
|
|
document.body.appendChild(link);
|
|
link.click();
|
|
handleClose();
|
|
});
|
|
|
|
|
|
};
|
|
|
|
const handleExportReportFiled = async () => {
|
|
|
|
await axios
|
|
.post('claims/exportFiled', { params: importResult?.data.result_rows })
|
|
.then((res) => {
|
|
enqueueSnackbar('Data berhasil di Export', {
|
|
variant: 'success',
|
|
anchorOrigin: { horizontal: 'right', vertical: 'top' },
|
|
});
|
|
setIsLoading(false)
|
|
|
|
document.location.href = res.data.data.file_url;
|
|
})
|
|
.catch((err) =>
|
|
enqueueSnackbar('Data Gagal di Export', {
|
|
variant: 'error',
|
|
anchorOrigin: { horizontal: 'right', vertical: 'top' },
|
|
})
|
|
|
|
);
|
|
};
|
|
|
|
|
|
// useEffect(() => {
|
|
// loadDataTableData();
|
|
// getProvider();
|
|
// }, []);
|
|
|
|
const headStyle = {
|
|
fontWeight: 'bold',
|
|
};
|
|
const headCells = [
|
|
{
|
|
id: 'code',
|
|
align: 'left',
|
|
label: 'Code / Code LOG',
|
|
isSort: true,
|
|
},
|
|
{
|
|
id: 'name',
|
|
align: 'left',
|
|
label: 'Name',
|
|
isSort: false,
|
|
},
|
|
|
|
{
|
|
id: 'member_id',
|
|
align: 'left',
|
|
label: 'Member ID',
|
|
isSort: false,
|
|
},
|
|
{
|
|
id: 'created_at',
|
|
align: 'left',
|
|
label: 'Date Submission',
|
|
isSort: true,
|
|
},
|
|
{
|
|
id: 'plan_code',
|
|
align: 'left',
|
|
label: 'Plan ID',
|
|
isSort: true,
|
|
},
|
|
{
|
|
id: 'service_code',
|
|
align: 'left',
|
|
label: 'Service',
|
|
isSort: false,
|
|
},
|
|
{
|
|
id: 'corporate_policies',
|
|
align: 'left',
|
|
label: 'Policy Number',
|
|
isSort: true,
|
|
},
|
|
{
|
|
id: 'provider',
|
|
align: 'left',
|
|
label: 'Provider',
|
|
isSort: false,
|
|
},
|
|
{
|
|
id: 'tot_bill',
|
|
align: 'left',
|
|
label: 'Total Billing',
|
|
isSort: false,
|
|
},
|
|
{
|
|
id: 'status',
|
|
align: 'left',
|
|
label: 'Status',
|
|
isSort: false,
|
|
},
|
|
{
|
|
id: 'action',
|
|
align: 'left',
|
|
label: '',
|
|
isSort: false,
|
|
},
|
|
];
|
|
|
|
const orders = {
|
|
order: order,
|
|
setOrder: setOrder,
|
|
orderBy: orderBy,
|
|
setOrderBy: setOrderBy,
|
|
};
|
|
const createSortHandler = (property: string) => (event: React.MouseEvent<unknown>) => {
|
|
handleRequestSort(event, property);
|
|
};
|
|
const handleRequestSort = async (event: React.MouseEvent<unknown>, property: string) => {
|
|
const isAsc = orders?.orderBy === property && orders?.order === 'asc';
|
|
|
|
orders?.setOrder(isAsc ? 'desc' : 'asc');
|
|
orders?.setOrderBy(property);
|
|
};
|
|
// Called on every row to map the data to the columns
|
|
function createData(data: Claims): Claims {
|
|
return {
|
|
...data,
|
|
};
|
|
}
|
|
|
|
{
|
|
/* ------------------ TABLE ROW ------------------ */
|
|
}
|
|
function Row(props: { row: ReturnType<typeof createData>, isSelected: boolean, onSelect: (id: string) => void }) {
|
|
const { row, isSelected, onSelect } = props;
|
|
// Memperbaiki destrukturisasi props
|
|
|
|
const handleRowCheckboxChange = () => {
|
|
onSelect(row.id); // Panggil fungsi onSelect dari komponen induk dengan id baris saat checkbox di baris diklik
|
|
};
|
|
|
|
const [open, setOpen] = React.useState(false);
|
|
|
|
const test = 1000;
|
|
|
|
return (
|
|
<React.Fragment>
|
|
<TableRow sx={{ '& > *': { borderBottom: 'unset' } }}>
|
|
{/* <TableCell>
|
|
<IconButton aria-label="expand row" size="small" onClick={() => setOpen(!open)}>
|
|
{open ? <KeyboardArrowDownIcon /> : <KeyboardArrowRightIcon />}
|
|
</IconButton>
|
|
</TableCell> */}
|
|
<TableCell align="left">
|
|
{row?.status == 'received' ? (
|
|
<Checkbox checked={isSelected} onChange={handleRowCheckboxChange} />
|
|
):''}
|
|
</TableCell>
|
|
<TableCell align="left">{row?.code} / {row.code_log}</TableCell>
|
|
{/* <TableCell align="left">{row.code}</TableCell> */}
|
|
<TableCell align="left">{row?.name}</TableCell>
|
|
<TableCell align="left">{row?.member_id}</TableCell>
|
|
<TableCell align="left">{row?.created_at ? fDateTime(row?.created_at) : ''}</TableCell>
|
|
<TableCell align="left">{row?.plan_code}</TableCell>
|
|
<TableCell align="left">{row?.service_code}</TableCell>
|
|
<TableCell align="left">{row?.corporate_policies}</TableCell>
|
|
<TableCell align="left">{row?.provider}</TableCell>
|
|
<TableCell align="left">Rp. {row?.tot_bill?.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ".")}</TableCell>
|
|
<TableCell align="left">
|
|
{row.status == 'draft' && (<Label color='secondary' variant='ghost'>{capitalizeFirstLetter(row.status)}</Label>)}
|
|
{row.status == 'requested' && (<Label color='primary' variant='ghost'>{capitalizeFirstLetter(row.status)}</Label>)}
|
|
{row.status == 'received' && (<Label color='secondary' variant='ghost'>{capitalizeFirstLetter(row.status)}</Label>)}
|
|
{row.status == 'approved' && (<Label color='success' variant='ghost'>{capitalizeFirstLetter(row.status)}</Label>)}
|
|
{row.status == 'postpone' && (<Label color='secondary' variant='ghost'>{capitalizeFirstLetter(row.status)}</Label>)}
|
|
{row.status == 'paid' && (<Label color='secondary' variant='ghost'>{capitalizeFirstLetter(row.status)}</Label>)}
|
|
{row.status == 'declined' && (<Label color='error' variant='ghost'>{capitalizeFirstLetter(row.status)}</Label>)}
|
|
</TableCell>
|
|
|
|
<TableCell align="left">
|
|
<TableMoreMenu actions={
|
|
<>
|
|
<MenuItem onClick={() => navigate('/claims/detail/'+row.id_log+'/'+row.id+'') }>
|
|
<FindInPageOutlinedIcon />
|
|
Detail
|
|
</MenuItem>
|
|
</>
|
|
} />
|
|
</TableCell>
|
|
|
|
|
|
|
|
</TableRow>
|
|
{/* COLLAPSIBLE ROW */}
|
|
<TableRow>
|
|
<TableCell style={{ paddingBottom: 0, paddingTop: 0 }} colSpan={99}>
|
|
<Collapse in={open} timeout="auto" unmountOnExit>
|
|
{/* <Box sx={{ borderBottom: 1 }}>
|
|
<Typography variant="body2" gutterBottom component="div">
|
|
Description : {row.description}
|
|
</Typography>
|
|
</Box> */}
|
|
</Collapse>
|
|
</TableCell>
|
|
</TableRow>
|
|
</React.Fragment>
|
|
);
|
|
}
|
|
{
|
|
/* ------------------ END TABLE ROW ------------------ */
|
|
}
|
|
|
|
|
|
|
|
function TableContent() {
|
|
return (
|
|
<Table aria-label="collapsible table">
|
|
{/* ------------------ TABLE HEADER ------------------ */}
|
|
<TableHead>
|
|
<TableRow>
|
|
{selectedRows.length > 0 ? (
|
|
<>
|
|
<TableCell style={{ backgroundColor: '#D1F1F1' }} align="left" colSpan={2}>
|
|
<Stack direction="row">
|
|
<Checkbox checked={selectAll} onChange={handleSelectAll} />
|
|
{selectedRows.length > 0 ? selectedRows.length : '0'} <Typography variant='subtitle2'>Selected</Typography>
|
|
</Stack>
|
|
</TableCell>
|
|
<TableCell style={{ backgroundColor: '#D1F1F1' }} align="left" colSpan={6}>
|
|
|
|
</TableCell>
|
|
<TableCell style={{ backgroundColor: '#D1F1F1' }} align="right" colSpan={2}>
|
|
<Button variant="text" color="error" startIcon={<CancelIcon />} onClick={() => {setOpenDialogSubmit(true);
|
|
setApprove('decline');}}>
|
|
<Typography variant='subtitle2'>Decline</Typography>
|
|
</Button>
|
|
</TableCell>
|
|
<TableCell style={{ backgroundColor: '#D1F1F1' }} align="left" colSpan={2}>
|
|
<Button variant="text" color="primary" startIcon={<CheckCircleIcon />} onClick={() => {setOpenDialogSubmit(true);
|
|
setApprove('approve');}}>
|
|
<Typography variant='subtitle2'>Approve</Typography>
|
|
</Button>
|
|
</TableCell>
|
|
|
|
</>
|
|
) : (
|
|
<>
|
|
<TableCell style={headStyle} align="left">
|
|
<Checkbox checked={selectAll} onChange={handleSelectAll} />
|
|
</TableCell>
|
|
{headCells &&
|
|
headCells.map((headCell, index) => (
|
|
<TableCell
|
|
key={index}
|
|
sortDirection={orders?.orderBy === headCell.id ? orders.order : false}
|
|
// @ts-ignore
|
|
align={headCell.align}
|
|
sx={{ padding: 2 }}
|
|
width={headCell.width ? headCell.width : 'auto'}
|
|
>
|
|
{headCell.isSort ? (
|
|
<TableSortLabel
|
|
active={orders?.orderBy === headCell.id}
|
|
direction={orders?.orderBy === headCell.id ? orders.order : 'asc'}
|
|
onClick={createSortHandler(headCell.id)}
|
|
>
|
|
{headCell.label}
|
|
{orders?.orderBy === headCell.id ? (
|
|
<Box component="span" sx={visuallyHidden}>
|
|
{orders.order === 'desc' ? 'sorted descending' : 'sorted ascending'}
|
|
</Box>
|
|
) : null}
|
|
</TableSortLabel>
|
|
) : (
|
|
headCell.label
|
|
)}
|
|
</TableCell>
|
|
))}
|
|
</>
|
|
|
|
)}
|
|
|
|
|
|
</TableRow>
|
|
</TableHead>
|
|
{/* ------------------ END TABLE HEADER ------------------ */}
|
|
|
|
{/* ------------------ TABLE ROW ------------------ */}
|
|
{dataTableIsLoading ? (
|
|
<TableBody>
|
|
<TableRow>
|
|
<TableCell colSpan={11} align="center">
|
|
Loading
|
|
</TableCell>
|
|
</TableRow>
|
|
</TableBody>
|
|
) : dataTableData.data.length === 0 ? (
|
|
<TableBody>
|
|
<TableRow>
|
|
<TableCell colSpan={11} align="center">
|
|
No Data
|
|
</TableCell>
|
|
</TableRow>
|
|
</TableBody>
|
|
) : (
|
|
<TableBody>
|
|
{dataTableData.data.map((row) => (
|
|
<Row key={row.id} row={row} isSelected={selectedRows.includes(row.id)} onSelect={handleRowSelect} />
|
|
))}
|
|
</TableBody>
|
|
)}
|
|
{/* ------------------ END TABLE ROW ------------------ */}
|
|
</Table>
|
|
);
|
|
}
|
|
|
|
return (
|
|
<Card>
|
|
<Grid
|
|
container
|
|
spacing={2}
|
|
sx={{ p: 2, justifyContent: 'space-between', alignItems: 'center' }}
|
|
>
|
|
<Grid item xs={12} md={12} lg={12}>
|
|
<form style={{ width: '100%' }}>
|
|
<Grid container spacing={1} sx={{ justifyContent: 'space-between', alignItems: 'center' }}>
|
|
<input
|
|
type="file"
|
|
id="file"
|
|
ref={importClaimManagement}
|
|
style={{ display: 'none' }}
|
|
onChange={handleImportChange}
|
|
accept=".csv, application/vnd.openxmlformats-officedocument.spreadsheetml.sheet, application/vnd.ms-excel, text/plain"
|
|
/>
|
|
{!currentImportFileName && (
|
|
<>
|
|
<Grid item xs={12} md={3}>
|
|
<TextField
|
|
id="search-input"
|
|
ref={searchInput}
|
|
variant="outlined"
|
|
value={searchText}
|
|
fullWidth
|
|
onChange={handleSearchChange}
|
|
onKeyDown={(event) => {
|
|
if (event.key === 'Enter') {
|
|
handleSearchSubmit(event);
|
|
}
|
|
}}
|
|
InputProps={{
|
|
startAdornment: (
|
|
<InputAdornment position="start">
|
|
<Search />
|
|
</InputAdornment>
|
|
),
|
|
placeholder: 'Search Code or Name',
|
|
}}
|
|
/>
|
|
</Grid>
|
|
<Grid item xs={12} md={4} display="flex" sx={{ gap: '16px' }}>
|
|
<LocalizationProvider dateAdapter={AdapterDateFns}>
|
|
<DesktopDatePicker
|
|
value={startDate}
|
|
inputFormat="dd/MM/yyyy"
|
|
onChange={(value) => {
|
|
|
|
// loadDataTableData();
|
|
setStartDate(value);
|
|
}}
|
|
renderInput={(params) => <TextField {...params} fullWidth label="Start" />}
|
|
/>
|
|
</LocalizationProvider>
|
|
|
|
<LocalizationProvider dateAdapter={AdapterDateFns}>
|
|
<DesktopDatePicker
|
|
value={endDate}
|
|
inputFormat="dd/MM/yyyy"
|
|
onChange={(value) => {
|
|
setEndDate(value);
|
|
}}
|
|
renderInput={(params) => (
|
|
<TextField
|
|
{...params}
|
|
fullWidth
|
|
label="End"
|
|
// error={!!error}
|
|
// helperText={error?.message}
|
|
// {...other}
|
|
/>
|
|
)}
|
|
/>
|
|
</LocalizationProvider>
|
|
</Grid>
|
|
<Grid item xs={12} md={2}>
|
|
{
|
|
providers && (
|
|
<Autocomplete
|
|
id="provider"
|
|
options={providers}
|
|
getOptionLabel={(option) => option.name || ''}
|
|
value={providers.find((item) => item.id === dataProvider) || null}
|
|
onChange={(event, value) => {
|
|
if (value) {
|
|
setDataProvider(value.id);
|
|
} else {
|
|
setDataProvider(null);
|
|
}
|
|
}}
|
|
renderInput={(params) => (
|
|
<TextField
|
|
{...params}
|
|
label="Provider"
|
|
fullWidth
|
|
/>
|
|
)}
|
|
/>
|
|
)
|
|
}
|
|
</Grid>
|
|
<Grid item xs={12} md={3} display="flex" sx={{ gap: '16px' }}>
|
|
<FormControl >
|
|
<LoadingButton
|
|
id="upload-button"
|
|
variant="outlined"
|
|
startIcon={<UploadIcon />}
|
|
sx={{ p: 1.8 }}
|
|
loading={isLoadingImport}
|
|
onClick={handleClick}
|
|
>
|
|
<Typography variant="inherit" sx={{ marginLeft: 1 }}>
|
|
Import
|
|
</Typography>
|
|
</LoadingButton>
|
|
<Menu
|
|
id="import-button"
|
|
anchorEl={anchorEl}
|
|
open={createMenu}
|
|
onClose={handleClose}
|
|
MenuListProps={{
|
|
'aria-labelledby': 'basic-button',
|
|
}}
|
|
>
|
|
<MenuItem onClick={handleImportButton}>
|
|
<Typography variant='body2'>Import</Typography>
|
|
</MenuItem>
|
|
<MenuItem
|
|
onClick={() => {
|
|
handleGetTemplate();
|
|
}}
|
|
>
|
|
<Typography variant='body2'> Download Template</Typography>
|
|
</MenuItem>
|
|
</Menu>
|
|
</FormControl>
|
|
<FormControl >
|
|
<LoadingButton
|
|
id="upload-button"
|
|
variant="contained"
|
|
startIcon={<Download />}
|
|
sx={{ p: 1.8 }}
|
|
onClick={handleExportReport}
|
|
loading={isLoading}
|
|
>
|
|
<Typography variant="inherit" sx={{ marginLeft: 1 }}>
|
|
Export
|
|
</Typography>
|
|
</LoadingButton>
|
|
</FormControl>
|
|
</Grid>
|
|
</>
|
|
)}
|
|
{currentImportFileName && (
|
|
<Grid item xs={12} md={12}>
|
|
<Stack direction={'row'} spacing={2} sx={{ p: 2 }}>
|
|
<ButtonGroup variant="outlined" aria-label="outlined button group" fullWidth>
|
|
<Button onClick={handleImportButton} fullWidth>
|
|
{currentImportFileName ?? 'No File Selected'}
|
|
</Button>
|
|
<Button
|
|
onClick={handleCancelImportButton}
|
|
size="small"
|
|
fullWidth={false}
|
|
sx={{ p: 1.8 }}
|
|
>
|
|
<CancelIcon color="error" />
|
|
</Button>
|
|
</ButtonGroup>
|
|
|
|
<LoadingButton
|
|
id="upload-button"
|
|
variant="outlined"
|
|
startIcon={<UploadIcon />}
|
|
sx={{ p: 1.8 }}
|
|
onClick={handleUpload}
|
|
loading={importLoading}
|
|
>
|
|
Upload
|
|
</LoadingButton>
|
|
</Stack>
|
|
</Grid>
|
|
)}
|
|
{importResult && (
|
|
<Stack direction={'row'} sx={{ px: 2, pb: 2 }}>
|
|
<Box sx={{ color: 'text.secondary' }}>
|
|
Last Import Result :{' '}
|
|
<Box sx={{ color: 'success.main', display: 'inline' }}>
|
|
{importResult.data.total_success_row ?? 0}
|
|
</Box>{' '}
|
|
Row Processed,{' '}
|
|
<Box sx={{ color: 'error.main', display: 'inline' }}>
|
|
{importResult.data.total_failed_row}
|
|
</Box>{' '}
|
|
Failed,
|
|
{/* {importResult.data.failed_rows.map((row, index) => (
|
|
<Typography variant='body' key={index} color="error"> [Code={row.code ? row.code : 'Required'}]</Typography>
|
|
))} */}
|
|
Report:
|
|
<u onClick={handleExportReportFiled} style={{cursor:'pointer'}}>Download Data Result Import</u>
|
|
</Box>
|
|
</Stack>
|
|
)}
|
|
</Grid>
|
|
</form>
|
|
</Grid>
|
|
</Grid>
|
|
|
|
<DataTable
|
|
isLoading={dataTableIsLoading}
|
|
lastRequest={0}
|
|
data={dataTableData}
|
|
handlePageChange={handlePageChange}
|
|
TableContent={<TableContent />}
|
|
/>
|
|
<Dialog open={openDialogSubmit} onClose={handleCloseDialogSubmit} fullWidth={true}>
|
|
<DialogTitle sx={{ backgroundColor: '#19BBBB', color: '#FFF', padding: 2 }}>
|
|
<Stack direction="row" alignItems="center" justifyContent="space-between">
|
|
<Stack direction="row" alignItems='center' spacing={1}>
|
|
<Typography variant="h6">Confirmation</Typography>
|
|
</Stack>
|
|
<IconButton sx={{ color: '#FFF' }} onClick={handleCloseDialogSubmit}>
|
|
<CloseIcon />
|
|
</IconButton>
|
|
</Stack>
|
|
</DialogTitle>
|
|
<DialogContent>
|
|
|
|
<Stack spacing={2} padding={2}>
|
|
<Typography variant='body1'>Are you sure to {toTitleCase(approve)} this claim ?</Typography>
|
|
{approve == "decline" ? (
|
|
<Stack direction='row' spacing={2} marginTop={2}>
|
|
<TextField
|
|
id="outlined-multiline-static"
|
|
label="Reason decline"
|
|
multiline
|
|
rows={4} // Tentukan jumlah baris yang diinginkan
|
|
defaultValue=""
|
|
onChange={handleReasonDeclineChange}
|
|
variant="outlined"
|
|
sx={{width:'100%'}}
|
|
// fullWidth // Gunakan ini jika Anda ingin input memenuhi lebar Stack
|
|
/>
|
|
</Stack>
|
|
): ''}
|
|
</Stack>
|
|
</DialogContent>
|
|
<DialogActions>
|
|
<Button variant="outlined" sx={{color: '#212B36', borderColor: '#919EAB52'}} onClick={handleCloseDialogSubmit}>Cancel</Button>
|
|
<Button sx={{backgroundColor: (approve === 'decline' ? '' : '#19BBBB'), color: (approve === 'decline' ? '#FF4842' : ''), borderColor: '#FF4842'}} onClick={handleSubmitData} variant={(approve === 'decline' ? 'outlined' : 'contained')}>{(approve === "decline" ? 'Decline' : 'Approve')}</Button>
|
|
</DialogActions>
|
|
</Dialog>
|
|
</Card>
|
|
);
|
|
}
|