Files
HKSingleParty/03_source/frontend/src/sections/user/user-table-toolbar.tsx
2025-05-28 09:55:51 +08:00

154 lines
4.5 KiB
TypeScript

import type { IUserTableFilters } from 'src/types/user';
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 { Iconify } from 'src/components/iconify';
import { CustomPopover } from 'src/components/custom-popover';
// ----------------------------------------------------------------------
type Props = {
onResetPage: () => void;
filters: UseSetStateReturn<IUserTableFilters>;
options: {
roles: string[];
};
};
export function UserTableToolbar({ filters, options, onResetPage }: Props) {
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 handleFilterRole = useCallback(
(event: SelectChangeEvent<string[]>) => {
const newValue =
typeof event.target.value === 'string' ? event.target.value.split(',') : event.target.value;
onResetPage();
updateFilters({ role: 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" />
Print
</MenuItem>
<MenuItem onClick={() => menuActions.onClose()}>
<Iconify icon="solar:import-bold" />
Import
</MenuItem>
<MenuItem onClick={() => menuActions.onClose()}>
<Iconify icon="solar:export-bold" />
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: 200 } }}>
<InputLabel htmlFor="filter-role-select">Role</InputLabel>
<Select
multiple
value={currentFilters.role}
onChange={handleFilterRole}
input={<OutlinedInput label="Role" />}
renderValue={(selected) => selected.map((value) => value).join(', ')}
inputProps={{ id: 'filter-role-select' }}
MenuProps={{ PaperProps: { sx: { maxHeight: 240 } } }}
>
{options.roles.map((option) => (
<MenuItem key={option} value={option}>
<Checkbox
disableRipple
size="small"
checked={currentFilters.role.includes(option)}
/>
{option}
</MenuItem>
))}
</Select>
</FormControl>
<Box
sx={{
gap: 2,
width: 1,
flexGrow: 1,
display: 'flex',
alignItems: 'center',
}}
>
<TextField
fullWidth
value={currentFilters.name}
onChange={handleFilterName}
placeholder="Search..."
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()}
</>
);
}