Files
HKSingleParty/03_source/frontend/src/sections/invoice/invoice-table-toolbar.tsx

217 lines
6.4 KiB
TypeScript

// src/sections/invoice/invoice-table-toolbar.tsx
import type { IDatePickerControl } from 'src/types/common';
import type { IInvoiceTableFilters } from 'src/types/invoice';
import type { SelectChangeEvent } from '@mui/material/Select';
import type { UseSetStateReturn } from 'minimal-shared/hooks';
import { useCallback } from 'react';
import { usePopover } from 'minimal-shared/hooks';
import Box from '@mui/material/Box';
import Select from '@mui/material/Select';
import MenuList from '@mui/material/MenuList';
import MenuItem from '@mui/material/MenuItem';
import Checkbox from '@mui/material/Checkbox';
import TextField from '@mui/material/TextField';
import InputLabel from '@mui/material/InputLabel';
import IconButton from '@mui/material/IconButton';
import FormControl from '@mui/material/FormControl';
import OutlinedInput from '@mui/material/OutlinedInput';
import InputAdornment from '@mui/material/InputAdornment';
import { DatePicker } from '@mui/x-date-pickers/DatePicker';
import { formHelperTextClasses } from '@mui/material/FormHelperText';
import { Iconify } from 'src/components/iconify';
import { CustomPopover } from 'src/components/custom-popover';
import { useTranslation } from 'react-i18next';
// ----------------------------------------------------------------------
type Props = {
dateError: boolean;
onResetPage: () => void;
filters: UseSetStateReturn<IInvoiceTableFilters>;
options: {
services: string[];
};
};
export function InvoiceTableToolbar({
//
filters,
options,
dateError,
onResetPage,
}: Props) {
const { t } = useTranslation();
const menuActions = usePopover();
const { state: currentFilters, setState: updateFilters } = filters;
const handleFilterName = useCallback(
(event: React.ChangeEvent<HTMLInputElement>) => {
onResetPage();
updateFilters({ name: event.target.value });
},
[onResetPage, updateFilters]
);
const handleFilterService = useCallback(
(event: SelectChangeEvent<string[]>) => {
const newValue =
typeof event.target.value === 'string' ? event.target.value.split(',') : event.target.value;
onResetPage();
updateFilters({ service: newValue });
},
[onResetPage, updateFilters]
);
const handleFilterStartDate = useCallback(
(newValue: IDatePickerControl) => {
onResetPage();
updateFilters({ startDate: newValue });
},
[onResetPage, updateFilters]
);
const handleFilterEndDate = useCallback(
(newValue: IDatePickerControl) => {
onResetPage();
updateFilters({ endDate: newValue });
},
[onResetPage, updateFilters]
);
const renderMenuActions = () => (
<CustomPopover
open={menuActions.open}
anchorEl={menuActions.anchorEl}
onClose={menuActions.onClose}
slotProps={{ arrow: { placement: 'right-top' } }}
>
<MenuList>
<MenuItem onClick={() => menuActions.onClose()}>
<Iconify icon="solar:printer-minimalistic-bold" />
{t('Print')}
</MenuItem>
<MenuItem onClick={() => menuActions.onClose()}>
<Iconify icon="solar:import-bold" />
{t('Import')}
</MenuItem>
<MenuItem onClick={() => menuActions.onClose()}>
<Iconify icon="solar:export-bold" />
{t('Export')}
</MenuItem>
</MenuList>
</CustomPopover>
);
return (
<>
<Box
sx={{
p: 2.5,
gap: 2,
display: 'flex',
pr: { xs: 2.5, md: 1 },
flexDirection: { xs: 'column', md: 'row' },
alignItems: { xs: 'flex-end', md: 'center' },
}}
>
<FormControl sx={{ flexShrink: 0, width: { xs: 1, md: 180 } }}>
<InputLabel htmlFor="filter-service-select">{t('Service')}</InputLabel>
<Select
multiple
value={currentFilters.service}
onChange={handleFilterService}
input={<OutlinedInput label="Service" />}
renderValue={(selected) => selected.map((value) => value).join(', ')}
inputProps={{ id: 'filter-service-select' }}
sx={{ textTransform: 'capitalize' }}
>
{options.services.map((option) => (
<MenuItem key={option} value={option}>
<Checkbox
disableRipple
size="small"
checked={currentFilters.service.includes(option)}
slotProps={{
input: {
id: `${option}-checkbox`,
'aria-label': `${option} checkbox`,
},
}}
/>
{option}
</MenuItem>
))}
</Select>
</FormControl>
<DatePicker
label={t('Start date')}
value={currentFilters.endDate}
onChange={handleFilterStartDate}
slotProps={{ textField: { fullWidth: true } }}
sx={{ maxWidth: { md: 180 } }}
/>
<DatePicker
label={t('End date')}
value={currentFilters.endDate}
onChange={handleFilterEndDate}
slotProps={{
textField: {
fullWidth: true,
error: dateError,
helperText: dateError ? t('End date must be later than start date') : null,
},
}}
sx={{
maxWidth: { md: 180 },
[`& .${formHelperTextClasses.root}`]: {
bottom: { md: -40 },
position: { md: 'absolute' },
},
}}
/>
<Box
sx={{
gap: 2,
width: 1,
flexGrow: 1,
display: 'flex',
alignItems: 'center',
}}
>
<TextField
fullWidth
value={currentFilters.name}
onChange={handleFilterName}
placeholder={t('Search customer or invoice number...')}
slotProps={{
input: {
startAdornment: (
<InputAdornment position="start">
<Iconify icon="eva:search-fill" sx={{ color: 'text.disabled' }} />
</InputAdornment>
),
},
}}
/>
<IconButton onClick={menuActions.onOpen}>
<Iconify icon="eva:more-vertical-fill" />
</IconButton>
</Box>
</Box>
{renderMenuActions()}
</>
);
}