Update slicing hospital portal
This commit is contained in:
ivan-sim
2023-10-16 16:21:47 +07:00
parent 827ce472ba
commit f2e5a22c64
11 changed files with 1144 additions and 8 deletions

View File

@@ -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 (
<RootStyle ownerState={{ color, variant }} sx={sx} theme={theme}>
{children}
</RootStyle>
);
}

View File

@@ -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<T>({
headCells,
rows,
paginations,
orders,
loadings,
params,
filters,
filterStatus,
filterStartDate,
filterEndDate,
searchs,
exportReport,
}: TableListProps<T>) {
/* ------------------------------- handle sort ------------------------------ */
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);
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<unknown>) => {
handleRequestSort(event, property);
};
return (
<TableHead>
<TableRow>
{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>
);
};
/* -------------------------------------------------------------------------- */
/* ------------------------ button change pagination ------------------------ */
const onPageChangeHandle = async (
event: React.MouseEvent<HTMLButtonElement> | 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<HTMLInputElement>) => {
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 (
// <Card>
<Grid container>
{/* Field 1 */}
<Grid item xs={12} paddingX="24px" paddingY="20px">
<Grid container spacing={2}>
{filters && filters.useFilter ? (
<Fragment>
<Grid item xs={12} lg={3} xl={2}>
<FormControl fullWidth>
<InputLabel id="simple-division-select-lable">Division</InputLabel>
<Select
labelId="simple-division-select-lable"
id="division-select-lable"
value={filters.config.divisionValue}
label="Division"
onChange={filters.config.handleDivisionChange}
>
<MenuItem value="all">All</MenuItem>
{filters.config.divisionData.map((row: DivisionDataProps, index) => (
<MenuItem key={index} value={row.id}>
{row.name}
</MenuItem>
))}
</Select>
</FormControl>
</Grid>
<Grid item xs={12} lg={9} xl={10}>
<form onSubmit={searchs.handleSearchSubmit}>
<TextField
id="search-input"
label="Search"
variant="outlined"
onChange={(event) => searchs.setSearchText(event.target.value)}
value={searchs.searchText}
fullWidth
/>
</form>
</Grid>
</Fragment>
) : null }
{searchs && searchs.useSearchs ? (
<Fragment>
{filterStatus && filterStatus.useFilter ? (
<Grid item xs={12} lg={4} xl={4}>
<form onSubmit={searchs.handleSearchSubmit}>
<TextField
id="search-input"
variant="outlined"
onChange={(event) => searchs.setSearchText(event.target.value)}
value={searchs.searchText}
fullWidth
InputProps={{
startAdornment: (
<InputAdornment position="start">
<SearchIcon />
</InputAdornment>
),
}}
placeholder="Search Name or Member ID... "
/>
</form>
</Grid>
) :
<Grid item xs={12} lg={6} xl={6}>
<form onSubmit={searchs.handleSearchSubmit}>
<TextField
id="search-input"
variant="outlined"
onChange={(event) => searchs.setSearchText(event.target.value)}
value={searchs.searchText}
fullWidth
InputProps={{
startAdornment: (
<InputAdornment position="start">
<SearchIcon />
</InputAdornment>
),
}}
placeholder="Search Name or Member ID... "
/>
</form>
</Grid>
}
</Fragment>
) : null }
{/* Start date */}
{filterStartDate && filterStartDate.useFilter ? (
<Grid item xs={12} lg={2} xl={2}>
<form onChange={filterStartDate.handleStartDateChange}>
<TextField
id="date-input"
type="date"
variant="outlined"
value={filterStartDate.startDate}
onChange={(event) => filterStartDate.setStartDate(event.target.value)}
fullWidth
label="Start Date"
InputLabelProps={{
shrink: true,
}}
/>
</form>
</Grid>
) : null }
{/* End Date */}
{filterEndDate && filterEndDate.useFilter ? (
<Grid item xs={12} lg={2} xl={2}>
<form onChange={filterEndDate.handleEndDateChange}>
<TextField
id="date-input"
type="date"
variant="outlined"
value={filterEndDate.endDate}
onChange={(event) => filterEndDate.setEndDate(event.target.value)}
fullWidth
label="End Date"
InputLabelProps={{
shrink: true,
}}
/>
</form>
</Grid>
) : null }
{/* Filter status */}
{filterStatus && filterStatus.useFilter ? (
<Grid item xs={12} lg={2} xl={2}>
<FormControl fullWidth>
<InputLabel id="simple-status-select-lable">Status</InputLabel>
<Select
labelId="simple-status-select-lable"
id="status-select-lable"
value={filterStatus.config.statusValue}
label="Status"
onChange={filterStatus.config.handleStatusChange}
>
<MenuItem value="all">All</MenuItem>
{filterStatus.config.filterData.map((row: StatusDataProps, index) => (
<MenuItem key={index} value={row.id}>
{row.name}
</MenuItem>
))}
</Select>
</FormControl>
</Grid>
) : null }
{/* Export Report */}
{exportReport && exportReport.useExport ? (
<Grid item xs={12} lg={2} xl={2}>
<FormControl fullWidth>
<Button variant='contained' sx={{p:2}}>
<Download />
<Typography variant='inherit' sx={{marginLeft: 1}}>Export</Typography>
</Button>
</FormControl>
</Grid>
) : null }
</Grid>
</Grid>
{/* End Field 1 */}
{/* Field 2 */}
<Grid item xs={12}>
{/* Table */}
<TableContainer component={Paper}>
<TableContent aria-label="collapsible table" size="small">
{/* Table Header */}
<EnhancedTableHead />
{/* End Table Header */}
{/* Table Body */}
<TableBody>
{loadings.isLoading && rows.length >= 1 ? (
<TableRow>
<TableCell colSpan={headCells?.length} align="center">
Loading . . .
</TableCell>
</TableRow>
) : rows && rows.length >= 1 ? (
rows.map((row, rowIndex) => (
<TableRow key={rowIndex}>
{headCells &&
//@ts-ignore
headCells.map((head, headIndex) => (
//@ts-ignore
<TableCell align={head.align} key={headIndex}>
{row[head.id]}
</TableCell>
))}
</TableRow>
))
) : (
<TableRow>
<TableCell colSpan={6} align="center">
No Data Found
</TableCell>
</TableRow>
)}
</TableBody>
{/* End Table Body */}
</TableContent>
</TableContainer>
{/* End Table */}
{/* Pagination */}
<BaseTablePagination
count={paginations.paginationTable.total}
onPageChange={onPageChangeHandle}
page={paginations.page}
rowsPerPage={paginations.rowsPerPage}
onRowsPerPageChange={onRowsPerPageChangeHandle}
/>
{/* End Pagination */}
</Grid>
{/* End Field 2 */}
</Grid>
// </Card>
);
}