filter
This commit is contained in:
@@ -15,7 +15,12 @@
|
|||||||
"@mui/icons-material": "^5.15.6",
|
"@mui/icons-material": "^5.15.6",
|
||||||
"@mui/material": "^5.15.6",
|
"@mui/material": "^5.15.6",
|
||||||
"@mui/material-nextjs": "^5.15.6",
|
"@mui/material-nextjs": "^5.15.6",
|
||||||
|
"@mui/x-date-pickers": "^6.19.5",
|
||||||
|
"date-fns": "^3.3.1",
|
||||||
|
"date-fns-jalali": "^2.13.0-0",
|
||||||
|
"dayjs": "^1.11.10",
|
||||||
"formik": "^2.4.5",
|
"formik": "^2.4.5",
|
||||||
|
"jalali-moment": "^3.3.11",
|
||||||
"material-react-table": "^2.11.2",
|
"material-react-table": "^2.11.2",
|
||||||
"next": "14.1.0",
|
"next": "14.1.0",
|
||||||
"react": "^18",
|
"react": "^18",
|
||||||
|
|||||||
31
src/components/BetweenDateFilter.jsx
Normal file
31
src/components/BetweenDateFilter.jsx
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
import {Grid} from '@mui/material';
|
||||||
|
import MuiDatePicker from "@/components/MuiDatePicker";
|
||||||
|
import {useEffect, useState} from "react";
|
||||||
|
|
||||||
|
const BetWeenDateFilter = ({formik, id , defaultValue}) => {
|
||||||
|
useEffect(() => {
|
||||||
|
formik.setFieldValue(`${id}[0]`, defaultValue?.[0] || '');
|
||||||
|
formik.setFieldValue(`${id}[1]`, defaultValue?.[1] || '');
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
const [dateRange, setDateRange] = useState(defaultValue);
|
||||||
|
|
||||||
|
const handleDateChange = (index, value) => {
|
||||||
|
const newRange = [...dateRange];
|
||||||
|
newRange[index] = value;
|
||||||
|
setDateRange(newRange);
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Grid container spacing={1} mt={1} mb={2}>
|
||||||
|
<Grid item xs={6}>
|
||||||
|
<MuiDatePicker label="تاریخ شروع " name={`${id}[0]`} formik={formik} defaultValue={defaultValue?.[0]} minDate={null} maxDate={dateRange[1]} onDateChange={(value) => handleDateChange(0, value)}/>
|
||||||
|
</Grid>
|
||||||
|
<Grid item xs={6}>
|
||||||
|
<MuiDatePicker label="تاریخ پایان" name={`${id}[1]`} formik={formik} defaultValue={defaultValue?.[1]} minDate={dateRange[0]} maxDate={null} onDateChange={(value) => handleDateChange(1, value)}/>
|
||||||
|
</Grid>
|
||||||
|
</Grid>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default BetWeenDateFilter;
|
||||||
58
src/components/BetweenNumberFilter.jsx
Normal file
58
src/components/BetweenNumberFilter.jsx
Normal file
@@ -0,0 +1,58 @@
|
|||||||
|
import {Grid, TextField} from '@mui/material';
|
||||||
|
import {useEffect} from "react";
|
||||||
|
|
||||||
|
const BetweenNumberFilter = ({formik, id , defaultValue}) => {
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
formik.setFieldValue(`${id}[0]`, defaultValue?.[0] || '');
|
||||||
|
formik.setFieldValue(`${id}[1]`, defaultValue?.[1] || '');
|
||||||
|
}, []);
|
||||||
|
const handleBlur = (index) => () => {
|
||||||
|
const minValue = formik.values[id][0];
|
||||||
|
const maxValue = formik.values[id][1];
|
||||||
|
|
||||||
|
if (index === 0 && minValue !== '' && maxValue !== '' && parseInt(minValue) > parseInt(maxValue)) {
|
||||||
|
formik.setFieldValue(`${id}[0]`, maxValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (index === 1 && minValue !== '' && maxValue !== '' && parseInt(maxValue) < parseInt(minValue)) {
|
||||||
|
formik.setFieldValue(`${id}[1]`, minValue);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
return (
|
||||||
|
<Grid container spacing={2}>
|
||||||
|
<Grid item xs={6}>
|
||||||
|
<TextField
|
||||||
|
name={`${id}[0]`}
|
||||||
|
label="کمترین رقم"
|
||||||
|
id={`${id}_min`}
|
||||||
|
onChange={formik.handleChange}
|
||||||
|
onBlur={handleBlur(0)}
|
||||||
|
fullWidth
|
||||||
|
value={formik.values[id][0] || ''}
|
||||||
|
margin="normal"
|
||||||
|
sx={{
|
||||||
|
position: 'relative'
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</Grid>
|
||||||
|
<Grid item xs={6}>
|
||||||
|
<TextField
|
||||||
|
name={`${id}[1]`}
|
||||||
|
label="بیشترین رقم"
|
||||||
|
id={`${id}_max`}
|
||||||
|
onChange={formik.handleChange}
|
||||||
|
onBlur={handleBlur(1)}
|
||||||
|
fullWidth
|
||||||
|
value={formik.values[id][1] || ''}
|
||||||
|
margin="normal"
|
||||||
|
sx={{
|
||||||
|
position: 'relative'
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</Grid>
|
||||||
|
</Grid>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default BetweenNumberFilter;
|
||||||
20
src/components/CustomToolbar.jsx
Normal file
20
src/components/CustomToolbar.jsx
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
import FilterColumn from "@/components/FilterColumn";
|
||||||
|
|
||||||
|
const CustomToolbar = ({columns}) => {
|
||||||
|
return (
|
||||||
|
<FilterColumn columns={columns}/>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
export default CustomToolbar
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -1,9 +1,9 @@
|
|||||||
import DataTableTest from "@/components/DataTableTest";
|
import DataTableTest from "@/components/DataTableTest";
|
||||||
import FilterColumn from "@/components/FilterColumn";
|
import FilterColumn from "@/components/FilterColumn";
|
||||||
import {useMemo} from "react";
|
import {useMemo} from "react";
|
||||||
|
import {Button} from "@mui/material";
|
||||||
|
|
||||||
function DataTableMain() {
|
function DataTableMain() {
|
||||||
|
|
||||||
const columns = useMemo(
|
const columns = useMemo(
|
||||||
() => [
|
() => [
|
||||||
{
|
{
|
||||||
@@ -81,13 +81,58 @@ function DataTableMain() {
|
|||||||
"contains"
|
"contains"
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
accessorKey: 'state',
|
||||||
|
header: 'محدوده',
|
||||||
|
size: 150,
|
||||||
|
id: "betweenNum",
|
||||||
|
text:'محدوده',
|
||||||
|
enableColumnFilter: true,
|
||||||
|
datatype: "text",
|
||||||
|
filterFn: "betweenNum",
|
||||||
|
columnFilterModeOptions: [],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
accessorKey: 'state',
|
||||||
|
header: 'تاریخ',
|
||||||
|
size: 150,
|
||||||
|
id: "betweenDate",
|
||||||
|
text:'تاریخ',
|
||||||
|
enableColumnFilter: true,
|
||||||
|
datatype: "text",
|
||||||
|
filterFn: "betweenDate",
|
||||||
|
columnFilterModeOptions: [],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
accessorKey: 'state',
|
||||||
|
header: 'شلکت',
|
||||||
|
size: 150,
|
||||||
|
id: "select2",
|
||||||
|
text:'تاریخ',
|
||||||
|
type: 'select2',
|
||||||
|
enableColumnFilter: true,
|
||||||
|
datatype: "text",
|
||||||
|
filterFn: "equals",
|
||||||
|
columnFilterModeOptions: [],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
accessorKey: 'state',
|
||||||
|
header: 'سلکت',
|
||||||
|
size: 150,
|
||||||
|
id: "select",
|
||||||
|
text:'تنتنت',
|
||||||
|
type: 'select',
|
||||||
|
enableColumnFilter: true,
|
||||||
|
datatype: "text",
|
||||||
|
filterFn: "equals",
|
||||||
|
columnFilterModeOptions: [],
|
||||||
|
},
|
||||||
],
|
],
|
||||||
[],
|
[],
|
||||||
);
|
);
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<DataTableTest columns={columns}/>
|
<DataTableTest columns={columns}/>
|
||||||
<FilterColumn column={columns}/>
|
|
||||||
</>
|
</>
|
||||||
|
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -2,7 +2,8 @@
|
|||||||
import {useMemo, useState} from 'react';
|
import {useMemo, useState} from 'react';
|
||||||
import {MaterialReactTable} from 'material-react-table';
|
import {MaterialReactTable} from 'material-react-table';
|
||||||
import useTableSetting from "@/lib/hooks/useTableSetting";
|
import useTableSetting from "@/lib/hooks/useTableSetting";
|
||||||
import {Typography} from "@mui/material";
|
import {IconButton, Tooltip, Typography} from "@mui/material";
|
||||||
|
import CustomToolbar from "@/components/CustomToolbar";
|
||||||
|
|
||||||
|
|
||||||
const data = [
|
const data = [
|
||||||
@@ -53,13 +54,16 @@ const data = [
|
|||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
|
function RefreshIcon() {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
const TestDataTable = ({columns}) => {
|
const TestDataTable = ({columns}) => {
|
||||||
const [userId, setUserId] = useState(2);
|
const [userId, setUserId] = useState(2);
|
||||||
const [pageName, setPageName] = useState('loan');
|
const [pageName, setPageName] = useState('loan');
|
||||||
const [tableName, setTableName] = useState('loan_table');
|
const [tableName, setTableName] = useState('loan_table');
|
||||||
const {settingStore, hideAction, filterAction, sortAction,} = useTableSetting();
|
const {settingStore, hideAction, filterAction, sortAction,} = useTableSetting();
|
||||||
|
|
||||||
|
|
||||||
const onColumnVisibilityChange = (event) => {
|
const onColumnVisibilityChange = (event) => {
|
||||||
const settingValue = event();
|
const settingValue = event();
|
||||||
hideAction(userId, pageName, tableName, settingValue, columns);
|
hideAction(userId, pageName, tableName, settingValue, columns);
|
||||||
@@ -76,6 +80,11 @@ const TestDataTable = ({columns}) => {
|
|||||||
columns={columns}
|
columns={columns}
|
||||||
data={data}
|
data={data}
|
||||||
manualSorting={true}
|
manualSorting={true}
|
||||||
|
renderTopToolbarCustomActions={({table}) => (<>
|
||||||
|
<CustomToolbar
|
||||||
|
columns={columns}
|
||||||
|
/>
|
||||||
|
</>)}
|
||||||
initialState={{
|
initialState={{
|
||||||
columnVisibility: settingStore?.[userId]?.[pageName]?.[tableName]?.['hides'],
|
columnVisibility: settingStore?.[userId]?.[pageName]?.[tableName]?.['hides'],
|
||||||
sorting: settingStore?.[userId]?.[pageName]?.[tableName]?.['sorts'] || []
|
sorting: settingStore?.[userId]?.[pageName]?.[tableName]?.['sorts'] || []
|
||||||
|
|||||||
30
src/components/FilterBox.jsx
Normal file
30
src/components/FilterBox.jsx
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
import { Popper, Paper, List, ListItem, ListItemText, ClickAwayListener } from '@mui/material';
|
||||||
|
|
||||||
|
function FilterBox({anchorEl , open = false, handleClose = () => {} , columnFilterModeOptions , onSelectFilter , defaultFilter}) {
|
||||||
|
|
||||||
|
const id = open ? 'simple-popper' : undefined;
|
||||||
|
const handleSelectFilter = (filterFn) => {
|
||||||
|
onSelectFilter(filterFn);
|
||||||
|
handleClose();
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<Popper id={id} open={open} anchorEl={anchorEl} placement="bottom" style={{ zIndex: 1301 }}>
|
||||||
|
<ClickAwayListener onClickAway={handleClose}>
|
||||||
|
<Paper>
|
||||||
|
<List>
|
||||||
|
{columnFilterModeOptions.map((option, index) => (
|
||||||
|
<ListItem key={index} onClick={() => handleSelectFilter(option)} selected={option === defaultFilter} sx={{ cursor: 'pointer' }}>
|
||||||
|
<ListItemText primary={option} />
|
||||||
|
</ListItem>
|
||||||
|
))}
|
||||||
|
</List>
|
||||||
|
</Paper>
|
||||||
|
</ClickAwayListener>
|
||||||
|
</Popper>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default FilterBox;
|
||||||
@@ -1,83 +1,203 @@
|
|||||||
"use client"
|
"use client"
|
||||||
import {
|
import {
|
||||||
Button,
|
Box,
|
||||||
Dialog, DialogActions,
|
Button, Divider, Drawer,
|
||||||
DialogContent,
|
FormControl, IconButton, styled, Typography
|
||||||
DialogTitle,
|
|
||||||
FormControl
|
|
||||||
} from '@mui/material';
|
} from '@mui/material';
|
||||||
import {useFormik} from 'formik';
|
import {useFormik} from 'formik';
|
||||||
import TextFieldWithFnBox from "@/components/TextFieldWithFnBox";
|
import TextFieldWithFnBox from "@/components/TextFieldWithFnBox";
|
||||||
import {useEffect, useState} from "react";
|
import {useEffect, useState} from "react";
|
||||||
import useTableSetting from "@/lib/hooks/useTableSetting";
|
import useTableSetting from "@/lib/hooks/useTableSetting";
|
||||||
|
import BetweenNumberFilter from "@/components/BetweenNumberFilter";
|
||||||
|
import BetWeenDateFilter from "@/components/BetweenDateFilter";
|
||||||
|
import SelectBoxMultiple from "@/components/SelectBoxMultiple";
|
||||||
|
import SelectBox from "@/components/SelectBox";
|
||||||
|
import CloseIcon from '@mui/icons-material/Close';
|
||||||
|
import { useTheme } from '@mui/material/styles';
|
||||||
|
|
||||||
function FilterColumn({ onSubmit , column }) {
|
function FilterColumn({ columns }) {
|
||||||
|
const [open, setOpen] = useState(false);
|
||||||
const [selectedFilters, setSelectedFilters] = useState([]);
|
const [selectedFilters, setSelectedFilters] = useState([]);
|
||||||
const [userId, setUserId] = useState(2);
|
const [userId, setUserId] = useState(2);
|
||||||
const [pageName, setPageName] = useState('loan');
|
const [pageName, setPageName] = useState('loan');
|
||||||
const [tableName, setTableName] = useState('loan_table');
|
const [tableName, setTableName] = useState('loan_table');
|
||||||
const {settingStore, hideAction, filterAction, sortAction,} = useTableSetting();
|
const {settingStore, hideAction, filterAction, sortAction,} = useTableSetting();
|
||||||
|
|
||||||
|
const DrawerHeader = styled('div')(({ theme }) => ({
|
||||||
|
display: 'flex',
|
||||||
|
alignItems: 'center',
|
||||||
|
padding: theme.spacing(0, 1),
|
||||||
|
justifyContent: 'space-between',
|
||||||
|
}));
|
||||||
|
const toggleDrawer = (newOpen) => () => {
|
||||||
|
setOpen(newOpen);
|
||||||
|
};
|
||||||
|
const handleDrawerClose = () => {
|
||||||
|
setOpen(false);
|
||||||
|
};
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
|
||||||
const settingValue = settingStore?.[userId]?.[pageName]?.[tableName]?.['filters'] || [];
|
const settingValue = settingStore?.[userId]?.[pageName]?.[tableName]?.['filters'] || [];
|
||||||
setSelectedFilters(settingValue.length > 0 ? settingValue : []);
|
setSelectedFilters(settingValue.length > 0 ? settingValue : []);
|
||||||
console.log(selectedFilters)
|
|
||||||
|
|
||||||
}, [settingStore]);
|
}, [settingStore]);
|
||||||
|
|
||||||
const handleSelectFilter = (fieldName, filterFn) => {
|
const handleSelectFilter = (fieldName, filterFn) => {
|
||||||
const updatedFilters = [...selectedFilters];
|
const filterIndex = selectedFilters.findIndex(filter => filter.id === fieldName);
|
||||||
const filterIndex = updatedFilters.findIndex(filter => filter.id === fieldName);
|
|
||||||
if (filterIndex !== -1) {
|
if (filterIndex !== -1) {
|
||||||
|
const updatedFilters = [...selectedFilters];
|
||||||
updatedFilters[filterIndex].fn = filterFn;
|
updatedFilters[filterIndex].fn = filterFn;
|
||||||
|
setSelectedFilters(updatedFilters);
|
||||||
} else {
|
} else {
|
||||||
updatedFilters.push({ id: fieldName, fn: filterFn });
|
const newFilter = { id: fieldName, fn: filterFn };
|
||||||
|
const updatedFilters = [...selectedFilters, newFilter];
|
||||||
|
setSelectedFilters(updatedFilters);
|
||||||
}
|
}
|
||||||
setSelectedFilters(updatedFilters);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const formik = useFormik({
|
const initialValues = columns.reduce((acc, column) => {
|
||||||
initialValues: column.reduce((acc, column) => {
|
if (column.enableColumnFilter) {
|
||||||
if (column.enableColumnFilter) {
|
const filter = settingStore?.[userId]?.[pageName]?.[tableName]?.['filters'].find((filter) => filter.id === column.id);
|
||||||
acc[column.field] = '';
|
if (column.filterFn === 'betweenNum' || column.filterFn === 'betweenDate') {
|
||||||
|
acc[column.id] = filter?.value || ["", ""];
|
||||||
|
}
|
||||||
|
else if ( column.type === 'select2' ) {
|
||||||
|
acc[column.id] = filter?.value || [];
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
acc[column.id] = filter?.value || '';
|
||||||
}
|
}
|
||||||
return acc;
|
|
||||||
}, {}),
|
|
||||||
onSubmit: (values) => {
|
|
||||||
// const selectedFilters = [
|
|
||||||
// { "id": "name", "value": values.name1, "fn": values.cityFn, "datatype": values.nameDatatype },
|
|
||||||
// { "id": "navgan_id", "value": values.name2, "fn": values.nameFn, "datatype": values.nameDatatype }
|
|
||||||
// ];
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
return acc;
|
||||||
|
}, {});
|
||||||
|
|
||||||
|
const formik = useFormik({
|
||||||
|
initialValues,
|
||||||
|
onSubmit: (values) => {
|
||||||
|
console.log(values)
|
||||||
|
const updatedFilters = selectedFilters.map(filter => {
|
||||||
|
const value = values[filter.id];
|
||||||
|
if (value !== undefined) {
|
||||||
|
return { ...filter, value };
|
||||||
|
}
|
||||||
|
return filter;
|
||||||
|
});
|
||||||
|
|
||||||
|
Object.entries(values).forEach(([fieldName, value]) => {
|
||||||
|
const filterIndex = updatedFilters.findIndex(filter => filter.id === fieldName);
|
||||||
|
if (filterIndex === -1 && value !== '' && value !== null && value !== undefined) {
|
||||||
|
const column = columns.find(col => col.id === fieldName);
|
||||||
|
updatedFilters.push({ id: fieldName, value, fn: column.filterFn, datatype: column.datatype });
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
const newArrayFilter = updatedFilters.filter((filter) => {
|
||||||
|
const value = values[filter.id];
|
||||||
|
|
||||||
|
return (
|
||||||
|
value !== '' &&
|
||||||
|
value !== null &&
|
||||||
|
value !== undefined &&
|
||||||
|
!(Array.isArray(value) && (value.length === 0 || (value.length === 2 && value.every((v) => v === ''))))
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
setSelectedFilters(newArrayFilter);
|
||||||
|
filterAction(userId, pageName, tableName, newArrayFilter, columns);
|
||||||
|
}
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Dialog open={true}>
|
<>
|
||||||
<DialogTitle>Select Filters</DialogTitle>
|
<Button onClick={toggleDrawer(true)}>Open drawer</Button>
|
||||||
<DialogContent>
|
<Drawer open={open} onClose={toggleDrawer(false)}
|
||||||
<FormControl fullWidth>
|
sx={{
|
||||||
{column.map((column, index) => (
|
"& .MuiDrawer-paper": {
|
||||||
column.enableColumnFilter &&
|
padding: '16px',
|
||||||
<TextFieldWithFnBox
|
overflowY: 'auto',
|
||||||
key={index}
|
display: 'flex',
|
||||||
id={column.id}
|
flexDirection: 'column',
|
||||||
formik={formik}
|
justifyContent: 'space-between',
|
||||||
defaultFilter={column.filterFn}
|
scrollbarWidth: 'thin',
|
||||||
columnFilterModeOptions={column.columnFilterModeOptions}
|
width:450,
|
||||||
onSelectFilter={(filterFn) => handleSelectFilter(column.field, filterFn)}
|
"&::-webkit-scrollbar": {
|
||||||
/>
|
width: '8px',
|
||||||
))}
|
},
|
||||||
</FormControl>
|
"&::-webkit-scrollbar-thumb": {
|
||||||
</DialogContent>
|
backgroundColor: '#ccc',
|
||||||
<DialogActions>
|
borderRadius: '4px',
|
||||||
<Button onClick={formik.handleSubmit}>Submit</Button>
|
},
|
||||||
</DialogActions>
|
"@media (max-width: 600px)": {
|
||||||
</Dialog>
|
width: '100%'
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<DrawerHeader>
|
||||||
|
<Typography variant="h6" mb={2}>فیلتر</Typography>
|
||||||
|
<IconButton onClick={handleDrawerClose}>
|
||||||
|
<CloseIcon/>
|
||||||
|
</IconButton>
|
||||||
|
</DrawerHeader>
|
||||||
|
<Box sx={{ display: 'flex', flexDirection: 'column' }}>
|
||||||
|
<FormControl fullWidth>
|
||||||
|
{columns.map((column, index) => (
|
||||||
|
column.enableColumnFilter &&
|
||||||
|
(column.filterFn === 'betweenDate' ?
|
||||||
|
<BetWeenDateFilter
|
||||||
|
key={index}
|
||||||
|
id={column.id}
|
||||||
|
formik={formik}
|
||||||
|
onSelectFilter={(filterFn) => handleSelectFilter(column.id, filterFn)}
|
||||||
|
defaultValue={(settingStore?.[userId]?.[pageName]?.[tableName]?.['filters'] || []).find(filter => filter.id === column.id)?.value || ''}
|
||||||
|
/>
|
||||||
|
: column.filterFn === 'betweenNum' ?
|
||||||
|
<BetweenNumberFilter
|
||||||
|
key={index}
|
||||||
|
id={column.id}
|
||||||
|
formik={formik}
|
||||||
|
onSelectFilter={(filterFn) => handleSelectFilter(column.id, filterFn)}
|
||||||
|
defaultValue={(settingStore?.[userId]?.[pageName]?.[tableName]?.['filters'] || []).find(filter => filter.id === column.id)?.value || ["", ""]}
|
||||||
|
/>
|
||||||
|
: column.type === 'select2' ?
|
||||||
|
<SelectBoxMultiple
|
||||||
|
key={index}
|
||||||
|
id={column.id}
|
||||||
|
formik={formik}
|
||||||
|
onSelectFilter={(filterFn) => handleSelectFilter(column.id, filterFn)}
|
||||||
|
defaultValue={(settingStore?.[userId]?.[pageName]?.[tableName]?.['filters'] || []).find(filter => filter.id === column.id)?.value || []}
|
||||||
|
/>
|
||||||
|
: column.type === 'select' ?
|
||||||
|
<SelectBox
|
||||||
|
key={index}
|
||||||
|
id={column.id}
|
||||||
|
formik={formik}
|
||||||
|
onSelectFilter={(filterFn) => handleSelectFilter(column.id, filterFn)}
|
||||||
|
defaultValue={(settingStore?.[userId]?.[pageName]?.[tableName]?.['filters'] || []).find(filter => filter.id === column.id)?.value || ''}
|
||||||
|
/>
|
||||||
|
:
|
||||||
|
<TextFieldWithFnBox
|
||||||
|
key={index}
|
||||||
|
id={column.id}
|
||||||
|
header={column.header}
|
||||||
|
formik={formik}
|
||||||
|
defaultFilter={(settingStore?.[userId]?.[pageName]?.[tableName]?.['filters'] || []).find(filter => filter.id === column.id)?.fn || column.filterFn}
|
||||||
|
columnFilterModeOptions={column.columnFilterModeOptions}
|
||||||
|
onSelectFilter={(filterFn) => handleSelectFilter(column.id, filterFn)}
|
||||||
|
defaultValue={formik.values[column.id] || (settingStore?.[userId]?.[pageName]?.[tableName]?.['filters'] || []).find(filter => filter.id === column.id)?.value || ''}
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
))}
|
||||||
|
</FormControl>
|
||||||
|
</Box>
|
||||||
|
<Box sx={{ mt:2 }}>
|
||||||
|
<Divider />
|
||||||
|
<Box sx={{ display: 'flex', justifyContent: 'flex-end', alignItems: 'center' }}>
|
||||||
|
<Button variant="contained" size="medium" onClick={formik.handleSubmit} sx={{ mt: 1 }}>ثبت</Button>
|
||||||
|
</Box>
|
||||||
|
</Box>
|
||||||
|
</Drawer>
|
||||||
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
63
src/components/MuiDatePicker.jsx
Normal file
63
src/components/MuiDatePicker.jsx
Normal file
@@ -0,0 +1,63 @@
|
|||||||
|
import { LocalizationProvider, MobileDateTimePicker } from "@mui/x-date-pickers";
|
||||||
|
import { AdapterDateFnsJalali } from "@mui/x-date-pickers/AdapterDateFnsJalali";
|
||||||
|
import moment from "jalali-moment";
|
||||||
|
import { faIR } from "@mui/x-date-pickers/locales";
|
||||||
|
import { Box, IconButton } from "@mui/material";
|
||||||
|
import ClearIcon from "@mui/icons-material/Clear";
|
||||||
|
import {useState} from "react";
|
||||||
|
|
||||||
|
export default function MuiDatePicker({label, name, formik, defaultValue, minDate, maxDate, onDateChange }) {
|
||||||
|
const [pickerValue, setPickerValue] = useState(defaultValue ? new Date(defaultValue) : null);
|
||||||
|
return (
|
||||||
|
<Box sx={{ padding: '4px', position: 'relative' }}>
|
||||||
|
<Box sx={{ display: "flex", alignItems: "center" }}>
|
||||||
|
<LocalizationProvider
|
||||||
|
dateAdapter={AdapterDateFnsJalali}
|
||||||
|
localeText={
|
||||||
|
faIR.components.MuiLocalizationProvider.defaultProps
|
||||||
|
.localeText
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<MobileDateTimePicker
|
||||||
|
key={formik.values[name]}
|
||||||
|
ampm={false}
|
||||||
|
onChange={(newValue) => {
|
||||||
|
const date = new Date(newValue);
|
||||||
|
const formattedDate = moment(date)
|
||||||
|
.locale("en")
|
||||||
|
.format("YYYY-MM-DD HH:mm");
|
||||||
|
formik.setFieldValue(name, formattedDate);
|
||||||
|
onDateChange(formattedDate);
|
||||||
|
setPickerValue(newValue);
|
||||||
|
}}
|
||||||
|
slotProps={{
|
||||||
|
textField: {
|
||||||
|
placeholder: "تاریخ خود را وارد کنید",
|
||||||
|
helperText: label,
|
||||||
|
},
|
||||||
|
}}
|
||||||
|
value={pickerValue}
|
||||||
|
minDate={minDate ? new Date(minDate) : null}
|
||||||
|
maxDate={maxDate ? new Date(maxDate) : null}
|
||||||
|
/>
|
||||||
|
</LocalizationProvider>
|
||||||
|
</Box>
|
||||||
|
<IconButton
|
||||||
|
size="small"
|
||||||
|
onClick={() => {
|
||||||
|
formik.setFieldValue(name, "");
|
||||||
|
setPickerValue(null);
|
||||||
|
}}
|
||||||
|
sx={{
|
||||||
|
color: "#bfbfbf",
|
||||||
|
position: 'absolute',
|
||||||
|
right: '4px',
|
||||||
|
top: '35%',
|
||||||
|
transform: 'translateY(-50%)',
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<ClearIcon />
|
||||||
|
</IconButton>
|
||||||
|
</Box>
|
||||||
|
);
|
||||||
|
}
|
||||||
53
src/components/SelectBox.jsx
Normal file
53
src/components/SelectBox.jsx
Normal file
@@ -0,0 +1,53 @@
|
|||||||
|
import InputLabel from '@mui/material/InputLabel';
|
||||||
|
import MenuItem from '@mui/material/MenuItem';
|
||||||
|
import FormControl from '@mui/material/FormControl';
|
||||||
|
import Select from '@mui/material/Select';
|
||||||
|
import {useEffect, useState} from "react";
|
||||||
|
const names = [
|
||||||
|
'Oliver Hansen',
|
||||||
|
'Van Henry',
|
||||||
|
'April Tucker',
|
||||||
|
'Ralph Hubbard',
|
||||||
|
'Omar Alexander',
|
||||||
|
'Carlos Abbott',
|
||||||
|
'Miriam Wagner',
|
||||||
|
'Bradley Wilkerson',
|
||||||
|
'Virginia Andrews',
|
||||||
|
'Kelly Snyder',
|
||||||
|
];
|
||||||
|
const SelectBox = ({ formik, id, defaultValue }) => {
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
formik.setFieldValue(id, defaultValue || '');
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
const [selectedValue, setSelectedValue] = useState(defaultValue || '');
|
||||||
|
|
||||||
|
const handleChange = (event) => {
|
||||||
|
const { value } = event.target;
|
||||||
|
setSelectedValue(value);
|
||||||
|
formik.setFieldValue(id, value);
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<FormControl sx={{ mt: 3 }}>
|
||||||
|
<InputLabel>انتخاب</InputLabel>
|
||||||
|
<Select
|
||||||
|
id={id}
|
||||||
|
value={selectedValue}
|
||||||
|
onChange={handleChange}
|
||||||
|
label="انتخاب"
|
||||||
|
>
|
||||||
|
{names.map((name) => (
|
||||||
|
<MenuItem key={name} value={name}>
|
||||||
|
{name}
|
||||||
|
</MenuItem>
|
||||||
|
))}
|
||||||
|
</Select>
|
||||||
|
</FormControl>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default SelectBox;
|
||||||
113
src/components/SelectBoxMultiple.jsx
Normal file
113
src/components/SelectBoxMultiple.jsx
Normal file
@@ -0,0 +1,113 @@
|
|||||||
|
import { useTheme } from '@mui/material/styles';
|
||||||
|
import Box from '@mui/material/Box';
|
||||||
|
import OutlinedInput from '@mui/material/OutlinedInput';
|
||||||
|
import InputLabel from '@mui/material/InputLabel';
|
||||||
|
import MenuItem from '@mui/material/MenuItem';
|
||||||
|
import FormControl from '@mui/material/FormControl';
|
||||||
|
import Select from '@mui/material/Select';
|
||||||
|
import Chip from '@mui/material/Chip';
|
||||||
|
import {useEffect, useState} from "react";
|
||||||
|
|
||||||
|
const ITEM_HEIGHT = 48;
|
||||||
|
const ITEM_PADDING_TOP = 8;
|
||||||
|
const MenuProps = {
|
||||||
|
PaperProps: {
|
||||||
|
style: {
|
||||||
|
maxHeight: ITEM_HEIGHT * 4.5 + ITEM_PADDING_TOP,
|
||||||
|
width: 250,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
const names = [
|
||||||
|
'Oliver Hansen',
|
||||||
|
'Van Henry',
|
||||||
|
'April Tucker',
|
||||||
|
'Ralph Hubbard',
|
||||||
|
'Omar Alexander',
|
||||||
|
'Carlos Abbott',
|
||||||
|
'Miriam Wagner',
|
||||||
|
'Bradley Wilkerson',
|
||||||
|
'Virginia Andrews',
|
||||||
|
'Kelly Snyder',
|
||||||
|
];
|
||||||
|
|
||||||
|
function getStyles(name, personName, theme) {
|
||||||
|
return {
|
||||||
|
fontWeight:
|
||||||
|
personName.indexOf(name) === -1
|
||||||
|
? theme.typography.fontWeightRegular
|
||||||
|
: theme.typography.fontWeightMedium,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
const SelectBoxMultiple = ({formik, id , defaultValue}) => {
|
||||||
|
const theme = useTheme();
|
||||||
|
const [personName, setPersonName] = useState(defaultValue || []);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
defaultValue.forEach((value, index) => {
|
||||||
|
formik.setFieldValue(`${id}[${index}]`, value || '');
|
||||||
|
});
|
||||||
|
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
const handleChange = (event) => {
|
||||||
|
const {
|
||||||
|
target: { value },
|
||||||
|
} = event;
|
||||||
|
console.log(value)
|
||||||
|
const selectedValues = typeof value === 'string' ? value.split(',') : value;
|
||||||
|
if (selectedValues.length === 0) {
|
||||||
|
setPersonName([]);
|
||||||
|
formik.setFieldValue(id, []);
|
||||||
|
} else {
|
||||||
|
setPersonName(selectedValues);
|
||||||
|
selectedValues.forEach((selectedValue, index) => {
|
||||||
|
formik.setFieldValue(`${id}[${index}]`, selectedValue);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<FormControl sx={{width: '100%' }}>
|
||||||
|
<InputLabel id={id}>انتخاب</InputLabel>
|
||||||
|
<Select
|
||||||
|
id={id}
|
||||||
|
multiple
|
||||||
|
value={personName}
|
||||||
|
onChange={handleChange}
|
||||||
|
input={<OutlinedInput label="Chip" />}
|
||||||
|
renderValue={(selected) => (
|
||||||
|
<Box sx={{ display: 'flex', flexWrap: 'wrap', gap: 0.5 }}>
|
||||||
|
{selected.map((value) => (
|
||||||
|
<Chip key={value} label={value} />
|
||||||
|
))}
|
||||||
|
</Box>
|
||||||
|
)}
|
||||||
|
MenuProps={MenuProps}
|
||||||
|
sx={{
|
||||||
|
"&.MuiSelect-select": {
|
||||||
|
minWidth: 0,
|
||||||
|
maxWidth: '100%',
|
||||||
|
overflow: 'hidden',
|
||||||
|
},
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{names.map((name) => (
|
||||||
|
<MenuItem
|
||||||
|
key={name}
|
||||||
|
value={name}
|
||||||
|
style={getStyles(name, personName, theme)}
|
||||||
|
>
|
||||||
|
{name}
|
||||||
|
</MenuItem>
|
||||||
|
))}
|
||||||
|
</Select>
|
||||||
|
</FormControl>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default SelectBoxMultiple;
|
||||||
@@ -1,12 +1,17 @@
|
|||||||
import {IconButton, Paper, TextField} from '@mui/material';
|
import {IconButton, Paper, TextField} from '@mui/material';
|
||||||
import AlignHorizontalCenterIcon from '@mui/icons-material/AlignHorizontalCenter';
|
import ArtTrackIcon from '@mui/icons-material/ArtTrack';
|
||||||
import {useState} from "react";
|
import {useEffect, useState} from "react";
|
||||||
// import FilterBox from "@/components/FiterBox";
|
import FilterBox from "@/components/FilterBox";
|
||||||
|
|
||||||
|
const TextFieldWithFnBox = ({formik, id , header, defaultValue, defaultFilter , columnFilterModeOptions ,onSelectFilter}) => {
|
||||||
|
|
||||||
const TextFieldWithFnBox = ({formik, id , defaultFilter , columnFilterModeOptions ,onSelectFilter}) => {
|
|
||||||
const [anchorEl, setAnchorEl] = useState(null);
|
const [anchorEl, setAnchorEl] = useState(null);
|
||||||
const [open, setOpen] = useState(false);
|
const [open, setOpen] = useState(false);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
formik.setFieldValue(id, defaultValue || '');
|
||||||
|
}, []);
|
||||||
|
|
||||||
const handleClick = (event) => {
|
const handleClick = (event) => {
|
||||||
setOpen((prevOpen) => !prevOpen);
|
setOpen((prevOpen) => !prevOpen);
|
||||||
setAnchorEl(anchorEl ? null : event.currentTarget);
|
setAnchorEl(anchorEl ? null : event.currentTarget);
|
||||||
@@ -21,16 +26,16 @@ const TextFieldWithFnBox = ({formik, id , defaultFilter , columnFilterModeOptio
|
|||||||
<>
|
<>
|
||||||
<TextField
|
<TextField
|
||||||
name={id}
|
name={id}
|
||||||
label={id}
|
label={header}
|
||||||
id={id}
|
id={id}
|
||||||
value={formik.values[id]}
|
|
||||||
onChange={formik.handleChange}
|
onChange={formik.handleChange}
|
||||||
fullWidth
|
fullWidth
|
||||||
|
value={formik.values[id]}
|
||||||
margin="normal"
|
margin="normal"
|
||||||
InputProps={{
|
InputProps={{
|
||||||
endAdornment: (
|
endAdornment: (
|
||||||
<IconButton onClick={handleClick}>
|
<IconButton onClick={handleClick}>
|
||||||
<AlignHorizontalCenterIcon />
|
<ArtTrackIcon />
|
||||||
</IconButton>
|
</IconButton>
|
||||||
)
|
)
|
||||||
}}
|
}}
|
||||||
@@ -38,7 +43,7 @@ const TextFieldWithFnBox = ({formik, id , defaultFilter , columnFilterModeOptio
|
|||||||
position: 'relative'
|
position: 'relative'
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
{/*<FilterBox anchorEl={anchorEl} open={open} handleClose={handleClose} columnFilterModeOptions={columnFilterModeOptions} onSelectFilter={onSelectFilter}/>*/}
|
<FilterBox anchorEl={anchorEl} open={open} handleClose={handleClose} columnFilterModeOptions={columnFilterModeOptions} onSelectFilter={onSelectFilter} defaultFilter={defaultFilter}/>
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -19,8 +19,8 @@ export const TableSettingProvider = ({children}) => {
|
|||||||
const sortAction = useCallback((user_id, page_name, table_name, settingValue, columns) => {
|
const sortAction = useCallback((user_id, page_name, table_name, settingValue, columns) => {
|
||||||
updateSettingStorage(user_id, page_name, table_name, "sorts", settingValue, columns);
|
updateSettingStorage(user_id, page_name, table_name, "sorts", settingValue, columns);
|
||||||
}, [])
|
}, [])
|
||||||
const filterAction = (user_id, page_name, table_name, settingValue) => {
|
const filterAction = (user_id, page_name, table_name, settingValue, columns) => {
|
||||||
updateSettingStorage(user_id, page_name, table_name, "filters", settingValue);
|
updateSettingStorage(user_id, page_name, table_name, "filters", settingValue, columns);
|
||||||
}
|
}
|
||||||
const updateSettingStorage = (user_id, page_name, table_name, settingType, settingValue, columns) => {
|
const updateSettingStorage = (user_id, page_name, table_name, settingType, settingValue, columns) => {
|
||||||
const prevLocalStorage = JSON.parse(localStorage.getItem("_setting-app")) || {};
|
const prevLocalStorage = JSON.parse(localStorage.getItem("_setting-app")) || {};
|
||||||
@@ -28,7 +28,7 @@ export const TableSettingProvider = ({children}) => {
|
|||||||
const pageSettings = userSettings[page_name] || {};
|
const pageSettings = userSettings[page_name] || {};
|
||||||
const tableSettings = pageSettings[table_name] || {};
|
const tableSettings = pageSettings[table_name] || {};
|
||||||
let newSettings;
|
let newSettings;
|
||||||
if (settingType === "sorts") {
|
if (settingType === "sorts" || settingType === "filters") {
|
||||||
newSettings = [...settingValue];
|
newSettings = [...settingValue];
|
||||||
} else {
|
} else {
|
||||||
newSettings = {...tableSettings[settingType] || {}, ...settingValue};
|
newSettings = {...tableSettings[settingType] || {}, ...settingValue};
|
||||||
|
|||||||
Reference in New Issue
Block a user