Merge branch 'feature/mohammad_refactor_filter' into 'develop'
complete toast and notification for keeping data in local storage for... See merge request witel-front-end/rms!7
This commit is contained in:
@@ -22,12 +22,15 @@
|
|||||||
"formik": "^2.4.5",
|
"formik": "^2.4.5",
|
||||||
"jalali-moment": "^3.3.11",
|
"jalali-moment": "^3.3.11",
|
||||||
"material-react-table": "^2.11.2",
|
"material-react-table": "^2.11.2",
|
||||||
"next": "14.1.0",
|
"next": "^14.2.3",
|
||||||
"react": "^18",
|
"react": "^18",
|
||||||
"react-dom": "^18",
|
"react-dom": "^18",
|
||||||
|
"react-toastify": "^10.0.5",
|
||||||
"sass": "^1.75.0",
|
"sass": "^1.75.0",
|
||||||
"stylis": "^4.3.1",
|
"stylis": "^4.3.1",
|
||||||
"stylis-plugin-rtl": "^2.1.1"
|
"stylis-plugin-rtl": "^2.1.1",
|
||||||
|
"swr": "^2.2.5",
|
||||||
|
"yup": "^1.4.0"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"eslint": "^8",
|
"eslint": "^8",
|
||||||
|
|||||||
@@ -1 +1,7 @@
|
|||||||
@import "fontiran";
|
@import "fontiran";
|
||||||
|
|
||||||
|
.filter-toast {
|
||||||
|
box-shadow: rgba(50, 50, 93, 0.25) 0px 13px 27px -5px, rgba(0, 0, 0, 0.3) 0px 8px 16px -8px;
|
||||||
|
background-color: #d0dfe8;
|
||||||
|
border: 1px dashed #095b8c;
|
||||||
|
}
|
||||||
@@ -1,6 +1,10 @@
|
|||||||
|
import 'react-toastify/dist/ReactToastify.css';
|
||||||
|
|
||||||
const Layout = ({children}) => {
|
const Layout = ({children}) => {
|
||||||
return (
|
return (
|
||||||
<>{children}</>
|
<>
|
||||||
|
{children}
|
||||||
|
</>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import {Box, Stack} from "@mui/material";
|
import {Box, Stack} from "@mui/material";
|
||||||
import HeaderWithLogo from "@/components/layouts/dashboard/headerWithLogo";
|
import HeaderWithLogo from "@/components/layouts/dashboard/headerWithLogo";
|
||||||
import HeaderWithSidebar from "@/components/layouts/dashboard/headerWithSidebar";
|
import HeaderWithSidebar from "@/components/layouts/dashboard/headerWithSidebar";
|
||||||
|
import 'react-toastify/dist/ReactToastify.css';
|
||||||
|
|
||||||
const Template = ({children}) => {
|
const Template = ({children}) => {
|
||||||
return (<Stack>
|
return (<Stack>
|
||||||
|
|||||||
@@ -2,7 +2,9 @@ import cacheProviderRtl from "@/core/utils/cacheRtl";
|
|||||||
import {CssBaseline, ThemeProvider} from "@mui/material";
|
import {CssBaseline, ThemeProvider} from "@mui/material";
|
||||||
import theme from "@/core/utils/theme";
|
import theme from "@/core/utils/theme";
|
||||||
import {AppRouterCacheProvider} from "@mui/material-nextjs/v14-appRouter";
|
import {AppRouterCacheProvider} from "@mui/material-nextjs/v14-appRouter";
|
||||||
import "^/global.scss"
|
import 'react-toastify/dist/ReactToastify.css';
|
||||||
|
import "^/global.scss";
|
||||||
|
import {ToastContainer} from "react-toastify";
|
||||||
|
|
||||||
const Template = ({children}) => {
|
const Template = ({children}) => {
|
||||||
return (
|
return (
|
||||||
@@ -10,6 +12,7 @@ const Template = ({children}) => {
|
|||||||
<ThemeProvider theme={theme}>
|
<ThemeProvider theme={theme}>
|
||||||
<CssBaseline/>
|
<CssBaseline/>
|
||||||
{children}
|
{children}
|
||||||
|
<ToastContainer rtl containerId="filtering" closeButton={false}/>
|
||||||
</ThemeProvider>
|
</ThemeProvider>
|
||||||
</AppRouterCacheProvider>
|
</AppRouterCacheProvider>
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -2,7 +2,9 @@ import {Button} from "@mui/material";
|
|||||||
|
|
||||||
const Toolbar = ({columns}) => {
|
const Toolbar = ({columns}) => {
|
||||||
return (
|
return (
|
||||||
<Button>add something</Button>
|
<>
|
||||||
|
<Button>add something</Button>
|
||||||
|
</>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
export default Toolbar
|
export default Toolbar
|
||||||
|
|||||||
@@ -17,7 +17,6 @@ function HomeComponent() {
|
|||||||
enableColumnFilter: true,
|
enableColumnFilter: true,
|
||||||
datatype: "text",
|
datatype: "text",
|
||||||
filterFn: "contains",
|
filterFn: "contains",
|
||||||
inputType: "textField",
|
|
||||||
enableClickToCopy: true,
|
enableClickToCopy: true,
|
||||||
columnFilterModeOptions: [
|
columnFilterModeOptions: [
|
||||||
"equals",
|
"equals",
|
||||||
@@ -32,7 +31,6 @@ function HomeComponent() {
|
|||||||
enableColumnFilter: true,
|
enableColumnFilter: true,
|
||||||
datatype: "text",
|
datatype: "text",
|
||||||
filterFn: "equals",
|
filterFn: "equals",
|
||||||
inputType: "textField",
|
|
||||||
columnFilterModeOptions: [
|
columnFilterModeOptions: [
|
||||||
"equals",
|
"equals",
|
||||||
"notEquals",
|
"notEquals",
|
||||||
@@ -48,7 +46,6 @@ function HomeComponent() {
|
|||||||
enableColumnFilter: true,
|
enableColumnFilter: true,
|
||||||
datatype: "text",
|
datatype: "text",
|
||||||
filterFn: "notEquals",
|
filterFn: "notEquals",
|
||||||
inputType: "textField",
|
|
||||||
columnFilterModeOptions: [
|
columnFilterModeOptions: [
|
||||||
"equals",
|
"equals",
|
||||||
"notEquals",
|
"notEquals",
|
||||||
@@ -62,7 +59,6 @@ function HomeComponent() {
|
|||||||
enableColumnFilter: true,
|
enableColumnFilter: true,
|
||||||
datatype: "text",
|
datatype: "text",
|
||||||
filterFn: "equals",
|
filterFn: "equals",
|
||||||
inputType: "textField",
|
|
||||||
columnFilterModeOptions: [
|
columnFilterModeOptions: [
|
||||||
"equals",
|
"equals",
|
||||||
"notEquals",
|
"notEquals",
|
||||||
@@ -71,7 +67,6 @@ function HomeComponent() {
|
|||||||
"greaterThan",
|
"greaterThan",
|
||||||
"fuzzy"
|
"fuzzy"
|
||||||
],
|
],
|
||||||
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
accessorKey: 'state',
|
accessorKey: 'state',
|
||||||
@@ -80,7 +75,6 @@ function HomeComponent() {
|
|||||||
enableColumnFilter: true,
|
enableColumnFilter: true,
|
||||||
datatype: "text",
|
datatype: "text",
|
||||||
filterFn: "contains",
|
filterFn: "contains",
|
||||||
inputType: "textField",
|
|
||||||
columnFilterModeOptions: [
|
columnFilterModeOptions: [
|
||||||
"equals",
|
"equals",
|
||||||
"notEquals",
|
"notEquals",
|
||||||
@@ -92,9 +86,20 @@ function HomeComponent() {
|
|||||||
header: 'محدوده',
|
header: 'محدوده',
|
||||||
id: "price",
|
id: "price",
|
||||||
enableColumnFilter: true,
|
enableColumnFilter: true,
|
||||||
datatype: "nemeric",
|
datatype: "numeric",
|
||||||
|
filterFn: "equals",
|
||||||
|
columnFilterModeOptions: [
|
||||||
|
"equals",
|
||||||
|
"notEquals",
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
accessorKey: 'created_at',
|
||||||
|
header: 'تاریخ ساخت',
|
||||||
|
id: "created_at",
|
||||||
|
enableColumnFilter: true,
|
||||||
|
datatype: "date",
|
||||||
filterFn: "between",
|
filterFn: "between",
|
||||||
inputType: "betweenNum",
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
accessorKey: 'updated_at',
|
accessorKey: 'updated_at',
|
||||||
@@ -102,26 +107,33 @@ function HomeComponent() {
|
|||||||
id: "updated_at",
|
id: "updated_at",
|
||||||
enableColumnFilter: true,
|
enableColumnFilter: true,
|
||||||
datatype: "date",
|
datatype: "date",
|
||||||
filterFn: "between",
|
filterFn: "equals",
|
||||||
inputType: "betweenDate",
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
accessorKey: 'company',
|
accessorKey: 'company',
|
||||||
header: 'نام شرکت',
|
header: 'نام شرکت',
|
||||||
id: "company",
|
id: "company",
|
||||||
enableColumnFilter: true,
|
enableColumnFilter: true,
|
||||||
datatype: "text",
|
datatype: "numeric",
|
||||||
filterFn: "equals",
|
filterFn: "equals",
|
||||||
inputType: "select2",
|
columnSelectOption: [
|
||||||
|
{value: 1, label: "وایتل"},
|
||||||
|
{value: 2, label: "اسنپ"},
|
||||||
|
{value: 3, label: "تپسی"}
|
||||||
|
],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
accessorKey: 'area',
|
accessorKey: 'area',
|
||||||
header: 'منطقه',
|
header: 'منطقه',
|
||||||
id: "area",
|
id: "area",
|
||||||
enableColumnFilter: true,
|
enableColumnFilter: true,
|
||||||
datatype: "text",
|
datatype: "array",
|
||||||
filterFn: "equals",
|
filterFn: "equals",
|
||||||
inputType: "select",
|
columnSelectOption: [
|
||||||
|
{value: 1, label: "وایتل"},
|
||||||
|
{value: 2, label: "اسنپ"},
|
||||||
|
{value: 3, label: "تپسی"}
|
||||||
|
],
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
[],
|
[],
|
||||||
@@ -129,7 +141,7 @@ function HomeComponent() {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<DataTable columns={columns} userId={0} pageName={'testPage'} tableName={'testTable'}/>
|
<DataTable columns={columns} table_url={"api"} user_id={0} page_name={'testPage'} table_name={'testTable'}/>
|
||||||
</>
|
</>
|
||||||
|
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -1,19 +1,174 @@
|
|||||||
import {useMaterialReactTable} from "material-react-table";
|
|
||||||
import DataTable_Paper from "./table/Paper";
|
import DataTable_Paper from "./table/Paper";
|
||||||
|
import {useMaterialReactTable} from "material-react-table";
|
||||||
|
import {FA_DATATABLE_LOCALIZATION} from "./localization/fa/datatable";
|
||||||
|
import useTableSetting from "@/lib/hooks/useTableSetting";
|
||||||
|
import {flattenArrayOfObjects} from "@/core/utils/flattenArrayOfObjects";
|
||||||
|
import Toolbar from "@/components/home/Toolbar";
|
||||||
|
import useDataTable from "@/lib/hooks/useDataTable";
|
||||||
|
import {useMemo, useState} from "react";
|
||||||
|
|
||||||
const isTableInstanceProp = (props) => props.table !== undefined;
|
const data = [
|
||||||
|
{
|
||||||
|
name: {
|
||||||
|
firstName: 'امین',
|
||||||
|
lastName: 'قاسمپور',
|
||||||
|
},
|
||||||
|
address: 'فلان جا',
|
||||||
|
city: 'تهران',
|
||||||
|
state: 'بررسی شده',
|
||||||
|
price: '20',
|
||||||
|
updated_at: '2024/05/02',
|
||||||
|
company: 'همراه اول',
|
||||||
|
area: 'منطقه 5',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: {
|
||||||
|
firstName: 'امیر حسین',
|
||||||
|
lastName: 'محمودی',
|
||||||
|
},
|
||||||
|
address: 'فلان جا',
|
||||||
|
city: 'تهران',
|
||||||
|
state: 'تکمیل شده',
|
||||||
|
price: '27',
|
||||||
|
updated_at: '2024/05/02',
|
||||||
|
company: 'وایتل',
|
||||||
|
area: 'منطقه 27',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: {
|
||||||
|
firstName: 'یاسمن',
|
||||||
|
lastName: 'علی اکبری',
|
||||||
|
},
|
||||||
|
address: 'فلان جا',
|
||||||
|
city: 'شیراز',
|
||||||
|
state: 'بررسی شده',
|
||||||
|
price: '32',
|
||||||
|
updated_at: '2024/05/02',
|
||||||
|
company: 'ایرانسل',
|
||||||
|
area: 'منطقه 23',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: {
|
||||||
|
firstName: 'حمیدرضا',
|
||||||
|
lastName: 'رنجبرپور',
|
||||||
|
},
|
||||||
|
address: 'فلان جا',
|
||||||
|
city: 'اصفهان',
|
||||||
|
state: 'بررسی شده',
|
||||||
|
price: '45',
|
||||||
|
updated_at: '2024/05/02',
|
||||||
|
company: 'ایرانول',
|
||||||
|
area: 'منطقه 21',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: {
|
||||||
|
firstName: 'محمد',
|
||||||
|
lastName: 'جلالی',
|
||||||
|
},
|
||||||
|
address: 'فلان جا',
|
||||||
|
city: 'رشت',
|
||||||
|
state: 'درحال بررسی',
|
||||||
|
price: '8',
|
||||||
|
updated_at: '2024/05/02',
|
||||||
|
company: 'فیلیمو',
|
||||||
|
area: 'منطقه 8',
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
const DataTable_Main = (props) => {
|
const DataTable_Main = (props) => {
|
||||||
let table;
|
const {filterData} = useDataTable();
|
||||||
|
const {table_url, user_id, page_name, table_name, columns, initialStateProps} = props
|
||||||
|
const flatColumns = flattenArrayOfObjects(columns, 'columns')
|
||||||
|
const {settingStore, hideAction, sortAction} = useTableSetting();
|
||||||
|
const [pagination, setPagination] = useState({pageIndex: 0, pageSize: 10});
|
||||||
|
const filters = Object.keys(filterData)
|
||||||
|
.map(key => {
|
||||||
|
const value = filterData[key].value;
|
||||||
|
if (value !== "" &&
|
||||||
|
!(Array.isArray(value) && (value.length === 0 || (value.length === 2 && value[0] === "" && value[1] === "")))) {
|
||||||
|
return filterData[key];
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.filter(Boolean);
|
||||||
|
const storedFilters = settingStore?.[user_id]?.[page_name]?.[table_name]?.filters;
|
||||||
|
const finalFilters = storedFilters || filters;
|
||||||
|
|
||||||
if (isTableInstanceProp(props)) {
|
const fetchUrl = useMemo(() => {
|
||||||
table = props.table;
|
const params = new URLSearchParams();
|
||||||
} else {
|
params.set("start", `${pagination.pageIndex * pagination.pageSize}`);
|
||||||
// eslint-disable-next-line react-hooks/rules-of-hooks
|
params.set("size", pagination.pageSize);
|
||||||
table = useMaterialReactTable(props);
|
params.set("filters", JSON.stringify(finalFilters ?? []));
|
||||||
|
params.set("sorting", JSON.stringify(settingStore?.[user_id]?.[page_name]?.[table_name]?.['sorts'] ?? []));
|
||||||
|
return `${table_url}?${params}`;
|
||||||
|
}, [table_url, finalFilters, pagination, columns]);
|
||||||
|
|
||||||
|
const onColumnVisibilityChange = (event) => {
|
||||||
|
const settingValue = event();
|
||||||
|
hideAction(user_id, page_name, table_name, settingValue, flatColumns);
|
||||||
|
};
|
||||||
|
const onSortingChange = (event) => {
|
||||||
|
const settingValue = event(settingStore?.[user_id]?.[page_name]?.[table_name]?.['sorts'] || []);
|
||||||
|
sortAction(user_id, page_name, table_name, settingValue, flatColumns);
|
||||||
}
|
}
|
||||||
|
|
||||||
return <DataTable_Paper table={table} columns={props.columns}/>;
|
const table = useMaterialReactTable({
|
||||||
|
localization: FA_DATATABLE_LOCALIZATION,
|
||||||
|
columns,
|
||||||
|
data: data,
|
||||||
|
// manualSorting: true,
|
||||||
|
renderTopToolbarCustomActions: ({table}) => (<>
|
||||||
|
<Toolbar
|
||||||
|
columns={flatColumns}
|
||||||
|
/>
|
||||||
|
</>),
|
||||||
|
initialState: {
|
||||||
|
density: 'compact',
|
||||||
|
columnVisibility: settingStore?.[user_id]?.[page_name]?.[table_name]?.['hides'],
|
||||||
|
sorting: settingStore?.[user_id]?.[page_name]?.[table_name]?.['sorts'] || [],
|
||||||
|
...initialStateProps
|
||||||
|
},
|
||||||
|
state: {
|
||||||
|
columnVisibility: settingStore?.[user_id]?.[page_name]?.[table_name]?.['hides'],
|
||||||
|
sorting: settingStore?.[user_id]?.[page_name]?.[table_name]?.['sorts'] || [],
|
||||||
|
pagination
|
||||||
|
},
|
||||||
|
muiTableHeadProps: {
|
||||||
|
sx: {
|
||||||
|
borderTop: "1px solid #e1e1e1",
|
||||||
|
borderBottom: "2px solid #e1e1e1",
|
||||||
|
}
|
||||||
|
},
|
||||||
|
muiTableHeadCellProps: {
|
||||||
|
sx: {
|
||||||
|
color: "primary.main",
|
||||||
|
borderLeft: "1px solid #e1e1e1",
|
||||||
|
"&:first-of-type": {
|
||||||
|
borderLeft: "unset"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
},
|
||||||
|
muiTableBodyCellProps: {
|
||||||
|
sx: {
|
||||||
|
borderLeft: "1px solid #e1e1e1",
|
||||||
|
"&:first-of-type": {
|
||||||
|
borderLeft: "unset"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
},
|
||||||
|
manualFiltering: true,
|
||||||
|
manualPagination: true,
|
||||||
|
onPaginationChange: setPagination,
|
||||||
|
manualSorting: true,
|
||||||
|
onColumnVisibilityChange: onColumnVisibilityChange,
|
||||||
|
onSortingChange: onSortingChange,
|
||||||
|
...props
|
||||||
|
})
|
||||||
|
|
||||||
|
return <DataTable_Paper table={table} columns={flatColumns} user_id={user_id} page_name={page_name}
|
||||||
|
table_name={table_name}/>;
|
||||||
};
|
};
|
||||||
|
|
||||||
export default DataTable_Main;
|
export default DataTable_Main;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -1,58 +0,0 @@
|
|||||||
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;
|
|
||||||
@@ -1,35 +0,0 @@
|
|||||||
import {Grid} from '@mui/material';
|
|
||||||
import MuiDatePicker from "@/core/components/DataTable/filter/DatePicker/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;
|
|
||||||
@@ -1,67 +0,0 @@
|
|||||||
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, InputAdornment, TextField } 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={{ position: 'relative' }}>
|
|
||||||
<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,
|
|
||||||
InputProps: {
|
|
||||||
endAdornment: (
|
|
||||||
<InputAdornment position="end">
|
|
||||||
<IconButton
|
|
||||||
size="small"
|
|
||||||
onClick={(event) => {
|
|
||||||
event.stopPropagation();
|
|
||||||
formik.setFieldValue(name, "");
|
|
||||||
setPickerValue(null);
|
|
||||||
}}
|
|
||||||
sx={{
|
|
||||||
color: "#bfbfbf",
|
|
||||||
'&:hover': {
|
|
||||||
backgroundColor: 'rgba(189, 189, 189, 0.1)',
|
|
||||||
},
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<ClearIcon />
|
|
||||||
</IconButton>
|
|
||||||
</InputAdornment>
|
|
||||||
),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}}
|
|
||||||
value={pickerValue}
|
|
||||||
minDate={minDate ? new Date(minDate) : null}
|
|
||||||
maxDate={maxDate ? new Date(maxDate) : null}
|
|
||||||
/>
|
|
||||||
</LocalizationProvider>
|
|
||||||
</Box>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
207
src/core/components/DataTable/filter/FilterBody.jsx
Normal file
207
src/core/components/DataTable/filter/FilterBody.jsx
Normal file
@@ -0,0 +1,207 @@
|
|||||||
|
'use client'
|
||||||
|
|
||||||
|
import {Box, Button, Drawer, styled} from "@mui/material";
|
||||||
|
import {Form, Formik} from "formik";
|
||||||
|
import useTableSetting from "@/lib/hooks/useTableSetting";
|
||||||
|
import {useEffect, useRef, useState} from "react";
|
||||||
|
import FilterHeader from "@/core/components/DataTable/filter/FilterHeader";
|
||||||
|
import * as Yup from "yup";
|
||||||
|
import FilterBodyField from "@/core/components/DataTable/filter/FilterBodyField";
|
||||||
|
import {toast} from "react-toastify";
|
||||||
|
import AskForKeep from "@/core/components/NotificationDesign/AskForKeep";
|
||||||
|
import useDataTable from "@/lib/hooks/useDataTable";
|
||||||
|
|
||||||
|
const ScrollBox = styled(Box)({
|
||||||
|
flexGrow: 1,
|
||||||
|
overflowY: 'scroll',
|
||||||
|
maxWidth: "450px",
|
||||||
|
'::-webkit-scrollbar': {
|
||||||
|
width: '5px',
|
||||||
|
},
|
||||||
|
'::-webkit-scrollbar-track': {
|
||||||
|
boxShadow: 'inset 0 0 5px #fff',
|
||||||
|
borderRadius: '5px',
|
||||||
|
},
|
||||||
|
'::-webkit-scrollbar-thumb': {
|
||||||
|
background: '#155175',
|
||||||
|
borderRadius: '0px',
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
function FilterBody({columns, drawerState, setDrawerState, user_id, page_name, table_name}) {
|
||||||
|
const {settingStore, filterAction} = useTableSetting();
|
||||||
|
const [initialValues, setInitialValues] = useState({});
|
||||||
|
const [validationSchema, setValidationSchema] = useState({});
|
||||||
|
const {filterData, setFilterData} = useDataTable();
|
||||||
|
const filterDataRef = useRef(filterData);
|
||||||
|
useEffect(() => {
|
||||||
|
filterDataRef.current = filterData;
|
||||||
|
}, [filterData]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const values = columns.reduce((acc, column) => {
|
||||||
|
if (!column.enableColumnFilter) return acc;
|
||||||
|
const filter = settingStore?.[user_id]?.[page_name]?.[table_name]?.['filters']?.find((filter) => filter.id === column.id);
|
||||||
|
if (column.datatype === 'array') {
|
||||||
|
acc[column.id] = {
|
||||||
|
id: column.id,
|
||||||
|
value: filter?.value || [],
|
||||||
|
filterFn: filter?.fn || column._filterFn,
|
||||||
|
datatype: column.datatype
|
||||||
|
};
|
||||||
|
} else if (column._filterFn === "between") {
|
||||||
|
acc[column.id] = {
|
||||||
|
id: column.id,
|
||||||
|
value: filter?.value || ["", ""],
|
||||||
|
filterFn: filter?.fn || column._filterFn,
|
||||||
|
datatype: column.datatype
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
acc[column.id] = {
|
||||||
|
id: column.id,
|
||||||
|
value: filter?.value || '',
|
||||||
|
filterFn: filter?.fn || column._filterFn,
|
||||||
|
datatype: column.datatype
|
||||||
|
};
|
||||||
|
}
|
||||||
|
return acc;
|
||||||
|
}, {});
|
||||||
|
setInitialValues(Object.keys(filterData).length !== 0 ? filterData : values);
|
||||||
|
}, [columns, settingStore, user_id, page_name, table_name, filterData]);
|
||||||
|
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const generatedSchema = Yup.object().shape(
|
||||||
|
Object.keys(initialValues).reduce((acc, key) => {
|
||||||
|
const initialValue = initialValues[key];
|
||||||
|
if (initialValue.filterFn === "between") {
|
||||||
|
acc[key] = Yup.object().shape({
|
||||||
|
value: Yup.array()
|
||||||
|
.of(Yup.string().nullable())
|
||||||
|
.test({
|
||||||
|
test(value, ctx) {
|
||||||
|
const [start, end] = value || ["", ""];
|
||||||
|
if (initialValue.datatype === "numeric" && parseInt(end, 10) <= parseInt(start, 10)) {
|
||||||
|
return ctx.createError({
|
||||||
|
message: `مقدار وارده باید بیشتر از (${start}) باشد`,
|
||||||
|
});
|
||||||
|
} else if ((start && !end) || (!start && end)) {
|
||||||
|
return ctx.createError({
|
||||||
|
message: "این بخش را تکمیل نمایید",
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return acc;
|
||||||
|
}, {})
|
||||||
|
);
|
||||||
|
|
||||||
|
setValidationSchema(generatedSchema);
|
||||||
|
}, [initialValues]);
|
||||||
|
|
||||||
|
|
||||||
|
const handleSubmit = (values, {setSubmitting}) => {
|
||||||
|
toast.dismiss({containerId: "filtering"});
|
||||||
|
setDrawerState(false);
|
||||||
|
setFilterData(values);
|
||||||
|
toast(<AskForKeep onSaveFilter={onSaveFilter}/>, {
|
||||||
|
containerId: "filtering",
|
||||||
|
className: "filter-toast",
|
||||||
|
position: "bottom-left",
|
||||||
|
draggable: true,
|
||||||
|
autoClose: false,
|
||||||
|
});
|
||||||
|
setSubmitting(false);
|
||||||
|
};
|
||||||
|
|
||||||
|
const onSaveFilter = () => {
|
||||||
|
const currentFilterData = filterDataRef.current;
|
||||||
|
const arrayOfObjects = Object.keys(currentFilterData).map(key => {
|
||||||
|
const value = currentFilterData[key].value;
|
||||||
|
if (value !== "" &&
|
||||||
|
!(Array.isArray(value) && (value.length === 0 || (value.length === 2 && value[0] === "" && value[1] === "")))) {
|
||||||
|
return currentFilterData[key];
|
||||||
|
}
|
||||||
|
}).filter(Boolean);
|
||||||
|
filterAction(user_id, page_name, table_name, arrayOfObjects, columns)
|
||||||
|
toast.dismiss({containerId: "filtering"});
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Drawer open={drawerState} onClose={() => setDrawerState(false)}
|
||||||
|
sx={{overflowY: "hidden", display: "flex", flexDirection: "column", height: "100%"}}>
|
||||||
|
<FilterHeader setDrawerState={setDrawerState}/>
|
||||||
|
{Object.keys(initialValues).length > 0 && (
|
||||||
|
<ScrollBox>
|
||||||
|
<Formik
|
||||||
|
initialValues={initialValues}
|
||||||
|
onSubmit={handleSubmit}
|
||||||
|
validationSchema={validationSchema}
|
||||||
|
>
|
||||||
|
{
|
||||||
|
({
|
||||||
|
values,
|
||||||
|
handleChange,
|
||||||
|
handleBlur,
|
||||||
|
setFieldValue,
|
||||||
|
errors,
|
||||||
|
touched,
|
||||||
|
isSubmitting,
|
||||||
|
isValid,
|
||||||
|
dirty,
|
||||||
|
resetForm
|
||||||
|
}) => (
|
||||||
|
<Form>
|
||||||
|
<Box sx={{px: 1, py: 2}}>
|
||||||
|
{
|
||||||
|
columns.map((column) => (
|
||||||
|
column.enableColumnFilter && (
|
||||||
|
<FilterBodyField
|
||||||
|
key={column.id}
|
||||||
|
column={column}
|
||||||
|
filterParameters={values[column.id]}
|
||||||
|
handleChange={handleChange}
|
||||||
|
handleBlur={handleBlur}
|
||||||
|
setFieldValue={setFieldValue}
|
||||||
|
resetForm={resetForm}
|
||||||
|
errors={errors}
|
||||||
|
touched={touched}
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
))
|
||||||
|
}
|
||||||
|
</Box>
|
||||||
|
<Box sx={{
|
||||||
|
display: 'flex',
|
||||||
|
justifyContent: 'center',
|
||||||
|
alignItems: 'center',
|
||||||
|
pb: 2
|
||||||
|
}}>
|
||||||
|
<Button
|
||||||
|
type="submit"
|
||||||
|
variant="contained"
|
||||||
|
size="large"
|
||||||
|
disabled={isSubmitting || !isValid || !dirty}
|
||||||
|
sx={{
|
||||||
|
px: 8,
|
||||||
|
boxShadow: "rgba(0, 0, 0, 0.23) 0px 6px 6px, rgba(0, 0, 0, 0.19) 10px 0px 20px",
|
||||||
|
backgroundColor: "#155175", ':hover': {
|
||||||
|
backgroundColor: "#155175",
|
||||||
|
}
|
||||||
|
}}>
|
||||||
|
اعمال فیلتر
|
||||||
|
</Button>
|
||||||
|
</Box>
|
||||||
|
</Form>
|
||||||
|
)}
|
||||||
|
</Formik>
|
||||||
|
</ScrollBox>
|
||||||
|
)}
|
||||||
|
</Drawer>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default FilterBody;
|
||||||
111
src/core/components/DataTable/filter/FilterBodyField.jsx
Normal file
111
src/core/components/DataTable/filter/FilterBodyField.jsx
Normal file
@@ -0,0 +1,111 @@
|
|||||||
|
import {useState} from "react";
|
||||||
|
import FilterOptionList from "@/core/components/DataTable/filter/FilterOptionList";
|
||||||
|
import CustomSelect from "@/core/components/DataTable/filter/fieldsType/CustomSelect";
|
||||||
|
import CustomTextField from "@/core/components/DataTable/filter/fieldsType/CustomTextField";
|
||||||
|
import CustomTextFieldRange from "@/core/components/DataTable/filter/fieldsType/CustomTextFieldRange";
|
||||||
|
import CustomDatePickerRange from "@/core/components/DataTable/filter/fieldsType/CustomDate/CustomDatePickerRange";
|
||||||
|
import CustomDatePicker from "@/core/components/DataTable/filter/fieldsType/CustomDate/CustomDatePicker";
|
||||||
|
import CustomSelectMultiple from "@/core/components/DataTable/filter/fieldsType/CustomSelectMultiple";
|
||||||
|
|
||||||
|
const columnFilterModeOptionFa = {
|
||||||
|
equals: "برابر",
|
||||||
|
notEquals: "نابرابر",
|
||||||
|
contains: "شامل",
|
||||||
|
lessThan: "کوچکتر",
|
||||||
|
greaterThan: "بزرگتر",
|
||||||
|
fuzzy: "فازی",
|
||||||
|
between: "مابین"
|
||||||
|
};
|
||||||
|
|
||||||
|
function FilterBodyField({
|
||||||
|
column,
|
||||||
|
filterParameters,
|
||||||
|
handleChange,
|
||||||
|
handleBlur,
|
||||||
|
setFieldValue,
|
||||||
|
errors,
|
||||||
|
touched,
|
||||||
|
resetForm
|
||||||
|
}) {
|
||||||
|
const [anchorEl, setAnchorEl] = useState(null);
|
||||||
|
const defaultFilterTranslation = columnFilterModeOptionFa[filterParameters.filterFn] || filterParameters.filterFn;
|
||||||
|
|
||||||
|
const handleOpenFilterBox = (event) => {
|
||||||
|
setAnchorEl(event.currentTarget);
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
{filterParameters.datatype === "numeric" && filterParameters.filterFn === "between" ? (
|
||||||
|
<CustomTextFieldRange
|
||||||
|
column={column}
|
||||||
|
filterParameters={filterParameters}
|
||||||
|
defaultFilterTranslation={defaultFilterTranslation}
|
||||||
|
handleOpenFilterBox={handleOpenFilterBox}
|
||||||
|
handleBlur={handleBlur}
|
||||||
|
handleChange={handleChange}
|
||||||
|
errors={errors}
|
||||||
|
touched={touched}
|
||||||
|
/>
|
||||||
|
) : filterParameters.datatype === "numeric" && filterParameters.filterFn === "equals" && Array.isArray(column.columnSelectOption) ? (
|
||||||
|
<CustomSelect
|
||||||
|
column={column}
|
||||||
|
filterParameters={filterParameters}
|
||||||
|
setFieldValue={setFieldValue}
|
||||||
|
defaultFilterTranslation={defaultFilterTranslation}
|
||||||
|
handleOpenFilterBox={handleOpenFilterBox}
|
||||||
|
/>
|
||||||
|
) : filterParameters.datatype === "date" && filterParameters.filterFn === "equals" ? (
|
||||||
|
<CustomDatePicker
|
||||||
|
column={column}
|
||||||
|
filterParameters={filterParameters}
|
||||||
|
setFieldValue={setFieldValue}
|
||||||
|
defaultFilterTranslation={defaultFilterTranslation}
|
||||||
|
handleOpenFilterBox={handleOpenFilterBox}
|
||||||
|
/>
|
||||||
|
) : filterParameters.datatype === "date" && filterParameters.filterFn === "between" ? (
|
||||||
|
<CustomDatePickerRange
|
||||||
|
column={column}
|
||||||
|
filterParameters={filterParameters}
|
||||||
|
setFieldValue={setFieldValue}
|
||||||
|
defaultFilterTranslation={defaultFilterTranslation}
|
||||||
|
handleOpenFilterBox={handleOpenFilterBox}
|
||||||
|
errors={errors}
|
||||||
|
touched={touched}
|
||||||
|
/>
|
||||||
|
) : filterParameters.datatype === "array" && filterParameters.filterFn === "equals" ? (
|
||||||
|
<CustomSelectMultiple
|
||||||
|
column={column}
|
||||||
|
filterParameters={filterParameters}
|
||||||
|
setFieldValue={setFieldValue}
|
||||||
|
defaultFilterTranslation={defaultFilterTranslation}
|
||||||
|
handleOpenFilterBox={handleOpenFilterBox}
|
||||||
|
/>
|
||||||
|
) : (
|
||||||
|
<CustomTextField
|
||||||
|
column={column}
|
||||||
|
filterParameters={filterParameters}
|
||||||
|
defaultFilterTranslation={defaultFilterTranslation}
|
||||||
|
handleOpenFilterBox={handleOpenFilterBox}
|
||||||
|
handleBlur={handleBlur}
|
||||||
|
handleChange={(e) => setFieldValue(`${column.id}.value`, e.target.value)}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
{Array.isArray(column.columnFilterModeOptions) && (
|
||||||
|
<FilterOptionList
|
||||||
|
column={column}
|
||||||
|
anchorEl={anchorEl}
|
||||||
|
setAnchorEl={setAnchorEl}
|
||||||
|
filterParameters={filterParameters}
|
||||||
|
filterType={filterParameters.filterFn}
|
||||||
|
setFieldValue={setFieldValue}
|
||||||
|
resetForm={resetForm}
|
||||||
|
filterOption={column.columnFilterModeOptions}
|
||||||
|
columnFilterModeOptionFa={columnFilterModeOptionFa}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default FilterBodyField;
|
||||||
17
src/core/components/DataTable/filter/FilterButton.jsx
Normal file
17
src/core/components/DataTable/filter/FilterButton.jsx
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
'use client'
|
||||||
|
import FilterAltIcon from '@mui/icons-material/FilterAlt';
|
||||||
|
import {IconButton, Tooltip} from "@mui/material";
|
||||||
|
|
||||||
|
function FilterButton({drawerState, setDrawerState}) {
|
||||||
|
return (
|
||||||
|
<Tooltip title="فیلتر">
|
||||||
|
<IconButton onClick={() => {
|
||||||
|
setDrawerState(!drawerState)
|
||||||
|
}} aria-label="filter table">
|
||||||
|
<FilterAltIcon/>
|
||||||
|
</IconButton>
|
||||||
|
</Tooltip>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default FilterButton;
|
||||||
@@ -1,201 +0,0 @@
|
|||||||
"use client"
|
|
||||||
import {Box, Button, Divider, Drawer, FormControl, IconButton, styled, Tooltip, Typography} from '@mui/material';
|
|
||||||
import {useFormik} from 'formik';
|
|
||||||
import {useEffect, useState} from "react";
|
|
||||||
import useTableSetting from "@/lib/hooks/useTableSetting";
|
|
||||||
import BetweenNumberFilter from "@/core/components/DataTable/filter/BetweenNumberFilter";
|
|
||||||
import BetWeenDateFilter from "@/core/components/DataTable/filter/DatePicker/BetweenDateFilter";
|
|
||||||
import SelectBoxMultiple from "@/core/components/DataTable/filter/SelectBoxMultiple";
|
|
||||||
import SelectBox from "@/core/components/DataTable/filter/SelectBox";
|
|
||||||
import FilterAltIcon from '@mui/icons-material/FilterAlt';
|
|
||||||
import CloseIcon from '@mui/icons-material/Close';
|
|
||||||
import TextFieldWithFnBox from "@/core/components/DataTable/filter/TextFieldWithFnBox/TextFieldWithFnBox";
|
|
||||||
|
|
||||||
function FilterColumn({columns}) {
|
|
||||||
const [open, setOpen] = useState(false);
|
|
||||||
const [selectedFilters, setSelectedFilters] = useState([]);
|
|
||||||
const [userId, setUserId] = useState(0);
|
|
||||||
const [pageName, setPageName] = useState('testPage');
|
|
||||||
const [tableName, setTableName] = useState('testTable');
|
|
||||||
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(() => {
|
|
||||||
const settingValue = settingStore?.[userId]?.[pageName]?.[tableName]?.['filters'] || [];
|
|
||||||
setSelectedFilters(settingValue.length > 0 ? settingValue : []);
|
|
||||||
if (!settingValue.length > 0) {
|
|
||||||
formik.resetForm();
|
|
||||||
}
|
|
||||||
}, [settingStore]);
|
|
||||||
|
|
||||||
const handleSelectFilter = (fieldName, filterFn) => {
|
|
||||||
const filterIndex = selectedFilters.findIndex(filter => filter.id === fieldName);
|
|
||||||
if (filterIndex !== -1) {
|
|
||||||
const updatedFilters = [...selectedFilters];
|
|
||||||
updatedFilters[filterIndex].fn = filterFn;
|
|
||||||
setSelectedFilters(updatedFilters);
|
|
||||||
} else {
|
|
||||||
const newFilter = {id: fieldName, fn: filterFn};
|
|
||||||
const updatedFilters = [...selectedFilters, newFilter];
|
|
||||||
setSelectedFilters(updatedFilters);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const initialValues = columns.reduce((acc, column) => {
|
|
||||||
if (column.enableColumnFilter) {
|
|
||||||
const filter = settingStore?.[userId]?.[pageName]?.[tableName]?.['filters']?.find((filter) => filter.id === column.id);
|
|
||||||
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;
|
|
||||||
}, {});
|
|
||||||
|
|
||||||
const formik = useFormik({
|
|
||||||
initialValues,
|
|
||||||
onSubmit: (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);
|
|
||||||
}
|
|
||||||
|
|
||||||
});
|
|
||||||
console.log(settingStore?.[userId]?.[pageName]?.[tableName]?.['filters'])
|
|
||||||
return (
|
|
||||||
<>
|
|
||||||
<Tooltip title="فیلتر">
|
|
||||||
<IconButton onClick={toggleDrawer(true)} aria-label="filter table">
|
|
||||||
<FilterAltIcon/>
|
|
||||||
</IconButton>
|
|
||||||
</Tooltip>
|
|
||||||
<Drawer open={open} onClose={toggleDrawer(false)}
|
|
||||||
sx={{
|
|
||||||
"& .MuiDrawer-paper": {
|
|
||||||
padding: '16px',
|
|
||||||
overflowY: 'auto',
|
|
||||||
display: 'flex',
|
|
||||||
flexDirection: 'column',
|
|
||||||
justifyContent: 'space-between',
|
|
||||||
scrollbarWidth: 'thin',
|
|
||||||
width: 450,
|
|
||||||
"&::-webkit-scrollbar": {
|
|
||||||
width: '8px',
|
|
||||||
},
|
|
||||||
"&::-webkit-scrollbar-thumb": {
|
|
||||||
backgroundColor: '#ccc',
|
|
||||||
borderRadius: '4px',
|
|
||||||
},
|
|
||||||
"@media (max-width: 600px)": {
|
|
||||||
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.inputType === 'betweenDate' ?
|
|
||||||
<BetWeenDateFilter
|
|
||||||
key={index}
|
|
||||||
id={column.id}
|
|
||||||
formik={formik}
|
|
||||||
defaultValue={(settingStore?.[userId]?.[pageName]?.[tableName]?.['filters'] || []).find(filter => filter.id === column.id)?.value || ''}
|
|
||||||
/>
|
|
||||||
: column.inputType === 'betweenNum' ?
|
|
||||||
<BetweenNumberFilter
|
|
||||||
key={index}
|
|
||||||
id={column.id}
|
|
||||||
formik={formik}
|
|
||||||
defaultValue={(settingStore?.[userId]?.[pageName]?.[tableName]?.['filters'] || []).find(filter => filter.id === column.id)?.value || ["", ""]}
|
|
||||||
/>
|
|
||||||
: column.inputType === 'select2' ?
|
|
||||||
<SelectBoxMultiple
|
|
||||||
key={index}
|
|
||||||
id={column.id}
|
|
||||||
formik={formik}
|
|
||||||
defaultValue={(settingStore?.[userId]?.[pageName]?.[tableName]?.['filters'] || []).find(filter => filter.id === column.id)?.value || []}
|
|
||||||
/>
|
|
||||||
: column.inputType === 'select' ?
|
|
||||||
<SelectBox
|
|
||||||
key={index}
|
|
||||||
id={column.id}
|
|
||||||
formik={formik}
|
|
||||||
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>
|
|
||||||
</>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
export default FilterColumn;
|
|
||||||
|
|
||||||
|
|
||||||
32
src/core/components/DataTable/filter/FilterHeader.jsx
Normal file
32
src/core/components/DataTable/filter/FilterHeader.jsx
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
'use client'
|
||||||
|
|
||||||
|
import {Box, IconButton, Typography} from "@mui/material";
|
||||||
|
import CancelIcon from '@mui/icons-material/Cancel';
|
||||||
|
import FilterAltIcon from '@mui/icons-material/FilterAlt';
|
||||||
|
|
||||||
|
function FilterHeader({setDrawerState}) {
|
||||||
|
return (
|
||||||
|
<Box
|
||||||
|
sx={{
|
||||||
|
display: "flex",
|
||||||
|
alignItems: "center",
|
||||||
|
justifyContent: "space-between",
|
||||||
|
px: 2,
|
||||||
|
py: 1,
|
||||||
|
backgroundColor: "#155175",
|
||||||
|
boxShadow: "rgba(0, 0, 0, 0.19) 0px 10px 20px, rgba(0, 0, 0, 0.23) 0px 6px 6px",
|
||||||
|
maxWidth: "450px"
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Box sx={{display: "flex", alignItems: "center"}}>
|
||||||
|
<FilterAltIcon sx={{color: "#fff"}}/>
|
||||||
|
<Typography variant="h6" sx={{color: "#fff"}}>فیلتر</Typography>
|
||||||
|
</Box>
|
||||||
|
<IconButton sx={{color: "#fff"}} onClick={() => setDrawerState(false)}>
|
||||||
|
<CancelIcon sx={{fontSize: "1em"}}/>
|
||||||
|
</IconButton>
|
||||||
|
</Box>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default FilterHeader;
|
||||||
48
src/core/components/DataTable/filter/FilterOptionList.jsx
Normal file
48
src/core/components/DataTable/filter/FilterOptionList.jsx
Normal file
@@ -0,0 +1,48 @@
|
|||||||
|
'use client'
|
||||||
|
|
||||||
|
import {ListItem, Menu} from "@mui/material";
|
||||||
|
import {useState} from "react";
|
||||||
|
|
||||||
|
function FilterOptionList({
|
||||||
|
column,
|
||||||
|
filterType,
|
||||||
|
filterOption,
|
||||||
|
anchorEl,
|
||||||
|
columnFilterModeOptionFa,
|
||||||
|
setAnchorEl,
|
||||||
|
setFieldValue
|
||||||
|
}) {
|
||||||
|
const [selectedFilter, setSelectedFilter] = useState(filterType);
|
||||||
|
|
||||||
|
const handleChangeItem = (event, index) => {
|
||||||
|
setFieldValue(`${column.id}.value`, filterOption[index] === "between" ? ["", ""] : "");
|
||||||
|
setFieldValue(`${column.id}.filterFn`, filterOption[index]);
|
||||||
|
setSelectedFilter(filterOption[index]);
|
||||||
|
setAnchorEl(null);
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleCloseFilterBox = () => {
|
||||||
|
setAnchorEl(null);
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Menu
|
||||||
|
id="simple-menu"
|
||||||
|
anchorEl={anchorEl}
|
||||||
|
keepMounted
|
||||||
|
open={Boolean(anchorEl)}
|
||||||
|
onClose={handleCloseFilterBox}
|
||||||
|
>
|
||||||
|
{filterOption.map((option, index) => (
|
||||||
|
<ListItem key={index}
|
||||||
|
onClick={(event) => handleChangeItem(event, index)}
|
||||||
|
selected={option === selectedFilter}
|
||||||
|
sx={{cursor: 'pointer', width: "100px", display: "flex", justifyContent: "center"}}>
|
||||||
|
{columnFilterModeOptionFa[option]}
|
||||||
|
</ListItem>
|
||||||
|
))}
|
||||||
|
</Menu>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default FilterOptionList;
|
||||||
@@ -1,53 +0,0 @@
|
|||||||
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;
|
|
||||||
@@ -1,116 +0,0 @@
|
|||||||
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;
|
|
||||||
|
|
||||||
const selectedValues = typeof value === 'string' ? value.split(',').filter(item => item.trim() !== '') : value;
|
|
||||||
|
|
||||||
formik.setFieldValue(id, []);
|
|
||||||
|
|
||||||
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,46 +0,0 @@
|
|||||||
import {ClickAwayListener, List, ListItem, ListItemText, Paper, Popper} from '@mui/material';
|
|
||||||
import {useState} from "react";
|
|
||||||
|
|
||||||
const columnFilterModeOptionFa = {
|
|
||||||
equals: "برابر",
|
|
||||||
notEquals: "نابرابر",
|
|
||||||
contains: "شامل",
|
|
||||||
lessThan: "کوچکتر",
|
|
||||||
greaterThan: "بزرگتر",
|
|
||||||
fuzzy: "فازی",
|
|
||||||
}
|
|
||||||
|
|
||||||
function FilterBox({
|
|
||||||
anchorEl, open = false, handleClose = () => {
|
|
||||||
}, columnFilterModeOptions, onSelectFilter, defaultFilter
|
|
||||||
}) {
|
|
||||||
const [selectedFilter, setSelectedFilter] = useState(defaultFilter);
|
|
||||||
|
|
||||||
const id = open ? 'simple-popper' : undefined;
|
|
||||||
const handleSelectFilter = (filterFn) => {
|
|
||||||
setSelectedFilter(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 === selectedFilter} sx={{cursor: 'pointer'}}>
|
|
||||||
<ListItemText primary={columnFilterModeOptionFa[option]}/>
|
|
||||||
</ListItem>
|
|
||||||
))}
|
|
||||||
</List>
|
|
||||||
</Paper>
|
|
||||||
</ClickAwayListener>
|
|
||||||
</Popper>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
export default FilterBox;
|
|
||||||
@@ -1,61 +0,0 @@
|
|||||||
import {IconButton, TextField} from '@mui/material';
|
|
||||||
import ArtTrackIcon from '@mui/icons-material/ArtTrack';
|
|
||||||
import {useEffect, useState} from "react";
|
|
||||||
import FilterBox from "@/core/components/DataTable/filter/TextFieldWithFnBox/FilterBox";
|
|
||||||
|
|
||||||
const TextFieldWithFnBox = ({
|
|
||||||
formik,
|
|
||||||
id,
|
|
||||||
header,
|
|
||||||
defaultValue,
|
|
||||||
defaultFilter,
|
|
||||||
columnFilterModeOptions,
|
|
||||||
onSelectFilter
|
|
||||||
}) => {
|
|
||||||
|
|
||||||
const [anchorEl, setAnchorEl] = useState(null);
|
|
||||||
const [open, setOpen] = useState(false);
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
formik.setFieldValue(id, defaultValue || '');
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
const handleClick = (event) => {
|
|
||||||
setOpen((prevOpen) => !prevOpen);
|
|
||||||
setAnchorEl(anchorEl ? null : event.currentTarget);
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleClose = () => {
|
|
||||||
setOpen(false);
|
|
||||||
setAnchorEl(null);
|
|
||||||
};
|
|
||||||
|
|
||||||
return (
|
|
||||||
<>
|
|
||||||
<TextField
|
|
||||||
name={id}
|
|
||||||
label={header}
|
|
||||||
id={id}
|
|
||||||
onChange={formik.handleChange}
|
|
||||||
fullWidth
|
|
||||||
value={formik.values[id]}
|
|
||||||
margin="normal"
|
|
||||||
InputProps={{
|
|
||||||
endAdornment: (
|
|
||||||
<IconButton onClick={handleClick}>
|
|
||||||
<ArtTrackIcon/>
|
|
||||||
</IconButton>
|
|
||||||
)
|
|
||||||
}}
|
|
||||||
sx={{
|
|
||||||
position: 'relative'
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
<FilterBox anchorEl={anchorEl} open={open} handleClose={handleClose}
|
|
||||||
columnFilterModeOptions={columnFilterModeOptions} onSelectFilter={onSelectFilter}
|
|
||||||
defaultFilter={defaultFilter}/>
|
|
||||||
</>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
export default TextFieldWithFnBox;
|
|
||||||
@@ -0,0 +1,21 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import MuiDatePicker from "@/core/components/DataTable/filter/fieldsType/CustomDate/MuiDatePicker";
|
||||||
|
import {Typography} from "@mui/material";
|
||||||
|
|
||||||
|
function CustomDatePicker({column, filterParameters, defaultFilterTranslation, setFieldValue}) {
|
||||||
|
return (
|
||||||
|
<MuiDatePicker
|
||||||
|
name={`${column.id}.value`}
|
||||||
|
value={filterParameters.value}
|
||||||
|
setFieldValue={setFieldValue}
|
||||||
|
placeholder={column.header}
|
||||||
|
helperText={
|
||||||
|
<Typography variant="button" sx={{color: "#155175"}}>
|
||||||
|
نوع فیلتر: {defaultFilterTranslation} (تاریخ)
|
||||||
|
</Typography>
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default CustomDatePicker;
|
||||||
@@ -0,0 +1,35 @@
|
|||||||
|
'use client'
|
||||||
|
|
||||||
|
import React from "react";
|
||||||
|
import {Box, Typography} from "@mui/material";
|
||||||
|
import MuiDatePicker from "@/core/components/DataTable/filter/fieldsType/CustomDate/MuiDatePicker";
|
||||||
|
|
||||||
|
function CustomDatePickerRange({column, filterParameters, defaultFilterTranslation, setFieldValue, errors, touched}) {
|
||||||
|
return (
|
||||||
|
<Box sx={{display: "flex", gap: 1}}>
|
||||||
|
<MuiDatePicker
|
||||||
|
name={`${column.id}.value[0]`}
|
||||||
|
value={filterParameters.value[0]}
|
||||||
|
setFieldValue={setFieldValue}
|
||||||
|
maxDate={filterParameters.value[1]}
|
||||||
|
placeholder={`از تاریخ`}
|
||||||
|
helperText={
|
||||||
|
<Typography variant="button" sx={{color: "#155175"}}>
|
||||||
|
نوع فیلتر: {defaultFilterTranslation} (تاریخ)
|
||||||
|
</Typography>
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
<MuiDatePicker
|
||||||
|
name={`${column.id}.value[1]`}
|
||||||
|
value={filterParameters.value[1]}
|
||||||
|
setFieldValue={setFieldValue}
|
||||||
|
minDate={filterParameters.value[0]}
|
||||||
|
placeholder={`تا تاریخ`}
|
||||||
|
helperText={errors?.[`${column.id}`]?.value ? errors?.[`${column.id}`]?.value : null}
|
||||||
|
error={Boolean(errors?.[`${column.id}`]?.value)}
|
||||||
|
/>
|
||||||
|
</Box>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default CustomDatePickerRange;
|
||||||
@@ -0,0 +1,72 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import {LocalizationProvider, MobileDatePicker} from "@mui/x-date-pickers";
|
||||||
|
import {AdapterDateFnsJalali} from "@mui/x-date-pickers/AdapterDateFnsJalali";
|
||||||
|
import {faIR} from "@mui/x-date-pickers/locales";
|
||||||
|
import {Box, FormHelperText, IconButton, InputAdornment} from "@mui/material";
|
||||||
|
import ClearIcon from "@mui/icons-material/Clear";
|
||||||
|
import moment from "jalali-moment";
|
||||||
|
|
||||||
|
function MuiDatePicker({value, setFieldValue, name, minDate, maxDate, helperText, placeholder, error}) {
|
||||||
|
|
||||||
|
// console.log("error", error);
|
||||||
|
//
|
||||||
|
// console.log("helperText", helperText)
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Box sx={{display: "flex", flexDirection: "column", my: 1}}>
|
||||||
|
<LocalizationProvider dateAdapter={AdapterDateFnsJalali}
|
||||||
|
localeText={faIR.components.MuiLocalizationProvider.defaultProps.localeText}
|
||||||
|
>
|
||||||
|
<MobileDatePicker
|
||||||
|
value={value ? new Date(value) : null}
|
||||||
|
sx={{width: "100%"}}
|
||||||
|
id={name}
|
||||||
|
name={name}
|
||||||
|
aria-describedby="component-helper-text"
|
||||||
|
onChange={(value) => {
|
||||||
|
const date = new Date(value);
|
||||||
|
const formattedDate = moment(date)
|
||||||
|
.locale("en")
|
||||||
|
.format("YYYY-MM-DD");
|
||||||
|
setFieldValue(name, formattedDate);
|
||||||
|
}}
|
||||||
|
minDate={minDate ? new Date(minDate) : null}
|
||||||
|
maxDate={maxDate ? new Date(maxDate) : null}
|
||||||
|
slotProps={{
|
||||||
|
textField: {
|
||||||
|
error: error,
|
||||||
|
placeholder: placeholder,
|
||||||
|
InputProps: {
|
||||||
|
endAdornment: (
|
||||||
|
<InputAdornment position="end">
|
||||||
|
<IconButton
|
||||||
|
size="small"
|
||||||
|
onClick={(event) => {
|
||||||
|
event.stopPropagation();
|
||||||
|
setFieldValue(name, "");
|
||||||
|
}}
|
||||||
|
sx={{
|
||||||
|
color: "#bfbfbf",
|
||||||
|
'&:hover': {
|
||||||
|
backgroundColor: 'rgba(189, 189, 189, 0.1)',
|
||||||
|
color: "#363434"
|
||||||
|
},
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<ClearIcon/>
|
||||||
|
</IconButton>
|
||||||
|
</InputAdornment>
|
||||||
|
),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
<FormHelperText id="component-helper-text" sx={{ml: 2, color: error ? '#d32f2f' : "unset"}}>
|
||||||
|
{helperText ? helperText : ""}
|
||||||
|
</FormHelperText>
|
||||||
|
</LocalizationProvider>
|
||||||
|
</Box>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default MuiDatePicker;
|
||||||
@@ -0,0 +1,40 @@
|
|||||||
|
'use client'
|
||||||
|
|
||||||
|
import {FormControl, FormHelperText, InputLabel, MenuItem, OutlinedInput, Select, Typography} from "@mui/material";
|
||||||
|
|
||||||
|
function CustomSelect({column, filterParameters, defaultFilterTranslation, setFieldValue}) {
|
||||||
|
const columnSelectOption = column.columnSelectOption;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<FormControl fullWidth sx={{marginY: 1}}>
|
||||||
|
<InputLabel id={`label${column.id}`}>{column.header}</InputLabel>
|
||||||
|
<Select
|
||||||
|
labelId={`label${column.id}`}
|
||||||
|
id={column.id}
|
||||||
|
name={`${column.id}.value`}
|
||||||
|
value={filterParameters.value}
|
||||||
|
input={<OutlinedInput label={column.header}/>}
|
||||||
|
onChange={(e) => {
|
||||||
|
setFieldValue(`${column.id}.value`, e.target.value)
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<MenuItem value="">{column.header}</MenuItem>
|
||||||
|
{columnSelectOption.map((option) => (
|
||||||
|
<MenuItem
|
||||||
|
key={option.value}
|
||||||
|
value={option.value}
|
||||||
|
>
|
||||||
|
{option.label}
|
||||||
|
</MenuItem>
|
||||||
|
))}
|
||||||
|
</Select>
|
||||||
|
<FormHelperText>
|
||||||
|
<Typography variant="button" sx={{color: "#155175"}}>
|
||||||
|
نوع فیلتر: {defaultFilterTranslation}
|
||||||
|
</Typography>
|
||||||
|
</FormHelperText>
|
||||||
|
</FormControl>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default CustomSelect;
|
||||||
@@ -0,0 +1,62 @@
|
|||||||
|
'use client'
|
||||||
|
|
||||||
|
import {
|
||||||
|
Box,
|
||||||
|
Chip,
|
||||||
|
FormControl,
|
||||||
|
FormHelperText,
|
||||||
|
InputLabel,
|
||||||
|
MenuItem,
|
||||||
|
OutlinedInput,
|
||||||
|
Select,
|
||||||
|
Typography
|
||||||
|
} from "@mui/material";
|
||||||
|
|
||||||
|
function CustomSelectMultiple({column, filterParameters, defaultFilterTranslation, setFieldValue}) {
|
||||||
|
const columnSelectOption = column.columnSelectOption;
|
||||||
|
|
||||||
|
const getLabelForValue = (value) => {
|
||||||
|
const option = columnSelectOption.find(opt => opt.value === value);
|
||||||
|
return option ? option.label : value;
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<FormControl fullWidth sx={{marginY: 1}}>
|
||||||
|
<InputLabel htmlFor="uncontrolled-native"
|
||||||
|
id={`label${column.id}`}>{column.header}</InputLabel>
|
||||||
|
<Select
|
||||||
|
labelId={`label${column.id}`}
|
||||||
|
id={column.id}
|
||||||
|
value={filterParameters.value}
|
||||||
|
multiple
|
||||||
|
onChange={(e) => {
|
||||||
|
setFieldValue(`${column.id}.value`, e.target.value)
|
||||||
|
}}
|
||||||
|
renderValue={(selected) => (
|
||||||
|
<Box sx={{display: 'flex', flexWrap: 'wrap', gap: 0.5}}>
|
||||||
|
{selected.map((value) => (
|
||||||
|
<Chip key={value} label={getLabelForValue(value)}/>
|
||||||
|
))}
|
||||||
|
</Box>
|
||||||
|
)}
|
||||||
|
input={<OutlinedInput label={column.header}/>}
|
||||||
|
>
|
||||||
|
{columnSelectOption.map((option) => (
|
||||||
|
<MenuItem
|
||||||
|
key={option.value}
|
||||||
|
value={option.value}
|
||||||
|
>
|
||||||
|
{option.label}
|
||||||
|
</MenuItem>
|
||||||
|
))}
|
||||||
|
</Select>
|
||||||
|
<FormHelperText>
|
||||||
|
<Typography variant="button" sx={{color: "#155175"}}>
|
||||||
|
نوع فیلتر: {defaultFilterTranslation}
|
||||||
|
</Typography>
|
||||||
|
</FormHelperText>
|
||||||
|
</FormControl>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default CustomSelectMultiple;
|
||||||
@@ -0,0 +1,39 @@
|
|||||||
|
import {InputAdornment, TextField, Typography} from "@mui/material";
|
||||||
|
import FilterListIcon from '@mui/icons-material/FilterList';
|
||||||
|
|
||||||
|
function CustomTextField({
|
||||||
|
column,
|
||||||
|
filterParameters,
|
||||||
|
defaultFilterTranslation,
|
||||||
|
handleOpenFilterBox,
|
||||||
|
handleChange,
|
||||||
|
handleBlur
|
||||||
|
}) {
|
||||||
|
|
||||||
|
return (
|
||||||
|
<TextField
|
||||||
|
id={column.id}
|
||||||
|
name={column.id}
|
||||||
|
label={column.header}
|
||||||
|
value={filterParameters.value}
|
||||||
|
onChange={handleChange}
|
||||||
|
onBlur={handleBlur}
|
||||||
|
fullWidth
|
||||||
|
helperText={<Typography variant="button" sx={{color: "#155175"}}>
|
||||||
|
نوع فیلتر: {defaultFilterTranslation}
|
||||||
|
</Typography>}
|
||||||
|
variant="outlined"
|
||||||
|
size="normal"
|
||||||
|
sx={{marginY: 1}}
|
||||||
|
InputProps={{
|
||||||
|
endAdornment: (
|
||||||
|
<InputAdornment position="end" sx={{cursor: "pointer"}} onClick={handleOpenFilterBox}>
|
||||||
|
<FilterListIcon/>
|
||||||
|
</InputAdornment>
|
||||||
|
),
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default CustomTextField;
|
||||||
@@ -0,0 +1,56 @@
|
|||||||
|
import {Box, InputAdornment, TextField, Typography} from "@mui/material";
|
||||||
|
import FilterListIcon from '@mui/icons-material/FilterList';
|
||||||
|
|
||||||
|
function CustomTextFieldRange({
|
||||||
|
column,
|
||||||
|
filterParameters,
|
||||||
|
defaultFilterTranslation,
|
||||||
|
handleOpenFilterBox,
|
||||||
|
handleChange,
|
||||||
|
handleBlur,
|
||||||
|
errors,
|
||||||
|
touched
|
||||||
|
}) {
|
||||||
|
return (
|
||||||
|
<Box sx={{display: "flex"}}>
|
||||||
|
<TextField
|
||||||
|
id={`${column.id}.value[0]`}
|
||||||
|
name={`${column.id}.value[0]`}
|
||||||
|
onChange={handleChange}
|
||||||
|
onBlur={handleBlur}
|
||||||
|
label={<Typography>از {column.header}</Typography>}
|
||||||
|
value={filterParameters.value[0]}
|
||||||
|
fullWidth
|
||||||
|
error={touched?.[`${column.id}`]?.value && Boolean(errors?.[`${column.id}`]?.value)}
|
||||||
|
helperText={<Typography variant="button" sx={{color: "#155175"}}>نوع
|
||||||
|
فیلتر: {defaultFilterTranslation}</Typography>}
|
||||||
|
variant="outlined"
|
||||||
|
size="normal"
|
||||||
|
sx={{marginY: 1, marginRight: 1}}
|
||||||
|
/>
|
||||||
|
<TextField
|
||||||
|
id={`${column.id}.value[1]`}
|
||||||
|
name={`${column.id}.value[1]`}
|
||||||
|
onChange={handleChange}
|
||||||
|
onBlur={handleBlur}
|
||||||
|
error={touched?.[`${column.id}`]?.value && Boolean(errors?.[`${column.id}`]?.value)}
|
||||||
|
helperText={touched?.[`${column.id}`]?.value ? errors?.[`${column.id}`]?.value : null}
|
||||||
|
label={<Typography>تا {column.header}</Typography>}
|
||||||
|
value={filterParameters.value[1]}
|
||||||
|
fullWidth
|
||||||
|
variant="outlined"
|
||||||
|
size="normal"
|
||||||
|
sx={{marginY: 1}}
|
||||||
|
InputProps={{
|
||||||
|
endAdornment: (
|
||||||
|
<InputAdornment position="end" sx={{cursor: "pointer"}} onClick={handleOpenFilterBox}>
|
||||||
|
<FilterListIcon/>
|
||||||
|
</InputAdornment>
|
||||||
|
),
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</Box>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default CustomTextFieldRange;
|
||||||
19
src/core/components/DataTable/filter/index.jsx
Normal file
19
src/core/components/DataTable/filter/index.jsx
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
'use client'
|
||||||
|
|
||||||
|
import {useState} from "react";
|
||||||
|
import FilterButton from "@/core/components/DataTable/filter/FilterButton";
|
||||||
|
import FilterBody from "@/core/components/DataTable/filter/FilterBody";
|
||||||
|
|
||||||
|
function FilterColumn({columns, user_id, page_name, table_name}) {
|
||||||
|
const [open, setOpen] = useState(false);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<FilterButton drawerState={open} setDrawerState={setOpen}/>
|
||||||
|
<FilterBody columns={columns} drawerState={open} setDrawerState={setOpen} user_id={user_id}
|
||||||
|
page_name={page_name} table_name={table_name}/>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default FilterColumn;
|
||||||
@@ -1,142 +1,12 @@
|
|||||||
import {useMaterialReactTable} from "material-react-table";
|
|
||||||
import DataTable_Main from "./Main";
|
import DataTable_Main from "./Main";
|
||||||
import {FA_DATATABLE_LOCALIZATION} from "./localization/fa/datatable";
|
import DataTableProvider from "@/lib/contexts/DataTable";
|
||||||
import useTableSetting from "@/lib/hooks/useTableSetting";
|
|
||||||
import {flattenArrayOfObjects} from "@/core/utils/flattenArrayOfObjects";
|
|
||||||
import Toolbar from "@/components/home/Toolbar";
|
|
||||||
|
|
||||||
const data = [
|
|
||||||
{
|
|
||||||
name: {
|
|
||||||
firstName: 'امین',
|
|
||||||
lastName: 'قاسمپور',
|
|
||||||
},
|
|
||||||
address: 'فلان جا',
|
|
||||||
city: 'تهران',
|
|
||||||
state: 'بررسی شده',
|
|
||||||
price: '20',
|
|
||||||
updated_at: '2024/05/02',
|
|
||||||
company: 'همراه اول',
|
|
||||||
area: 'منطقه 5',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: {
|
|
||||||
firstName: 'امیر حسین',
|
|
||||||
lastName: 'محمودی',
|
|
||||||
},
|
|
||||||
address: 'فلان جا',
|
|
||||||
city: 'تهران',
|
|
||||||
state: 'تکمیل شده',
|
|
||||||
price: '27',
|
|
||||||
updated_at: '2024/05/02',
|
|
||||||
company: 'وایتل',
|
|
||||||
area: 'منطقه 27',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: {
|
|
||||||
firstName: 'یاسمن',
|
|
||||||
lastName: 'علی اکبری',
|
|
||||||
},
|
|
||||||
address: 'فلان جا',
|
|
||||||
city: 'شیراز',
|
|
||||||
state: 'بررسی شده',
|
|
||||||
price: '32',
|
|
||||||
updated_at: '2024/05/02',
|
|
||||||
company: 'ایرانسل',
|
|
||||||
area: 'منطقه 23',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: {
|
|
||||||
firstName: 'حمیدرضا',
|
|
||||||
lastName: 'رنجبرپور',
|
|
||||||
},
|
|
||||||
address: 'فلان جا',
|
|
||||||
city: 'اصفهان',
|
|
||||||
state: 'بررسی شده',
|
|
||||||
price: '45',
|
|
||||||
updated_at: '2024/05/02',
|
|
||||||
company: 'ایرانول',
|
|
||||||
area: 'منطقه 21',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: {
|
|
||||||
firstName: 'محمد',
|
|
||||||
lastName: 'جلالی',
|
|
||||||
},
|
|
||||||
address: 'فلان جا',
|
|
||||||
city: 'رشت',
|
|
||||||
state: 'درحال بررسی',
|
|
||||||
price: '8',
|
|
||||||
updated_at: '2024/05/02',
|
|
||||||
company: 'فیلیمو',
|
|
||||||
area: 'منطقه 8',
|
|
||||||
},
|
|
||||||
];
|
|
||||||
|
|
||||||
const DataTable = (props) => {
|
const DataTable = (props) => {
|
||||||
const {userId, pageName, tableName, columns, initialStateProps} = props
|
return (
|
||||||
const {settingStore, hideAction, sortAction} = useTableSetting();
|
<DataTableProvider>
|
||||||
const flatColumns = flattenArrayOfObjects(columns, 'columns')
|
<DataTable_Main {...props}/>
|
||||||
|
</DataTableProvider>
|
||||||
const onColumnVisibilityChange = (event) => {
|
);
|
||||||
const settingValue = event();
|
|
||||||
hideAction(userId, pageName, tableName, settingValue, flatColumns);
|
|
||||||
};
|
|
||||||
const onSortingChange = (event) => {
|
|
||||||
const settingValue = event(settingStore?.[userId]?.[pageName]?.[tableName]?.['sorts'] || []);
|
|
||||||
sortAction(userId, pageName, tableName, settingValue, flatColumns);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
const table = useMaterialReactTable({
|
|
||||||
localization: FA_DATATABLE_LOCALIZATION,
|
|
||||||
columns,
|
|
||||||
data: data,
|
|
||||||
// manualSorting: true,
|
|
||||||
renderTopToolbarCustomActions: ({table}) => (<>
|
|
||||||
<Toolbar
|
|
||||||
columns={flatColumns}
|
|
||||||
/>
|
|
||||||
</>),
|
|
||||||
initialState: {
|
|
||||||
density: 'compact',
|
|
||||||
columnVisibility: settingStore?.[userId]?.[pageName]?.[tableName]?.['hides'],
|
|
||||||
sorting: settingStore?.[userId]?.[pageName]?.[tableName]?.['sorts'] || [],
|
|
||||||
...initialStateProps
|
|
||||||
},
|
|
||||||
state: {
|
|
||||||
columnVisibility: settingStore?.[userId]?.[pageName]?.[tableName]?.['hides'],
|
|
||||||
sorting: settingStore?.[userId]?.[pageName]?.[tableName]?.['sorts'] || []
|
|
||||||
},
|
|
||||||
muiTableHeadProps: {
|
|
||||||
sx: {
|
|
||||||
borderTop: "1px solid #e1e1e1",
|
|
||||||
borderBottom: "2px solid #e1e1e1",
|
|
||||||
}
|
|
||||||
},
|
|
||||||
muiTableHeadCellProps: {
|
|
||||||
sx: {
|
|
||||||
color: "primary.main",
|
|
||||||
borderLeft: "1px solid #e1e1e1",
|
|
||||||
"&:first-of-type": {
|
|
||||||
borderLeft: "unset"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
},
|
|
||||||
muiTableBodyCellProps: {
|
|
||||||
sx: {
|
|
||||||
borderLeft: "1px solid #e1e1e1",
|
|
||||||
"&:first-of-type": {
|
|
||||||
borderLeft: "unset"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
},
|
|
||||||
onColumnVisibilityChange: onColumnVisibilityChange,
|
|
||||||
onSortingChange: onSortingChange,
|
|
||||||
...props
|
|
||||||
})
|
|
||||||
|
|
||||||
return <DataTable_Main table={table} columns={flatColumns}/>;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export default DataTable;
|
export default DataTable;
|
||||||
@@ -6,9 +6,9 @@ import {useState} from "react";
|
|||||||
|
|
||||||
function RefactorTable() {
|
function RefactorTable() {
|
||||||
const {refactorAction} = useTableSetting();
|
const {refactorAction} = useTableSetting();
|
||||||
const [userId, setUserId] = useState(2);
|
const [userId, setUserId] = useState(0);
|
||||||
const [pageName, setPageName] = useState('loan');
|
const [pageName, setPageName] = useState('testPage');
|
||||||
const [tableName, setTableName] = useState('loan_table');
|
const [tableName, setTableName] = useState('testTable');
|
||||||
|
|
||||||
const refactor = () => {
|
const refactor = () => {
|
||||||
refactorAction(userId, pageName, tableName);
|
refactorAction(userId, pageName, tableName);
|
||||||
|
|||||||
@@ -65,7 +65,10 @@ const DataTable_Paper = ({table, ...rest}) => {
|
|||||||
>
|
>
|
||||||
{enableTopToolbar &&
|
{enableTopToolbar &&
|
||||||
(parseFromValuesOrFunc(renderTopToolbar, {table}) ?? (
|
(parseFromValuesOrFunc(renderTopToolbar, {table}) ?? (
|
||||||
<DataTable_TopToolbar table={table} columns={paperProps.columns}/>
|
<DataTable_TopToolbar table={table} columns={paperProps.columns} table_url={paperProps.table_url}
|
||||||
|
user_id={paperProps.user_id}
|
||||||
|
page_name={paperProps.page_name}
|
||||||
|
table_name={paperProps.table_name}/>
|
||||||
))}
|
))}
|
||||||
<DataTable_TableContainer table={table}/>
|
<DataTable_TableContainer table={table}/>
|
||||||
{enableBottomToolbar &&
|
{enableBottomToolbar &&
|
||||||
|
|||||||
@@ -3,10 +3,10 @@ import {Box, useMediaQuery} from "@mui/material";
|
|||||||
import DataTable_LinearProgressBar from "./LinearProgressBar";
|
import DataTable_LinearProgressBar from "./LinearProgressBar";
|
||||||
import DataTable_TablePagination from "./TablePagination";
|
import DataTable_TablePagination from "./TablePagination";
|
||||||
import DataTable_ToolbarInternalButtons from "./ToolbarInternalButtons";
|
import DataTable_ToolbarInternalButtons from "./ToolbarInternalButtons";
|
||||||
import FilterColumn from "@/core/components/DataTable/filter/FilterColumn";
|
import FilterColumn from "@/core/components/DataTable/filter";
|
||||||
import RefactorTable from "@/core/components/DataTable/refactor/RefactorTable";
|
import RefactorTable from "@/core/components/DataTable/refactor/RefactorTable";
|
||||||
|
|
||||||
const DataTable_TopToolbar = ({table, columns}) => {
|
const DataTable_TopToolbar = ({table, columns, table_url, user_id, page_name, table_name}) => {
|
||||||
const {
|
const {
|
||||||
getState,
|
getState,
|
||||||
options: {
|
options: {
|
||||||
@@ -73,7 +73,8 @@ const DataTable_TopToolbar = ({table, columns}) => {
|
|||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<RefactorTable/>
|
<RefactorTable/>
|
||||||
<FilterColumn columns={columns}/>
|
<FilterColumn columns={columns} table_url={table_url} user_id={user_id} page_name={page_name}
|
||||||
|
table_name={table_name}/>
|
||||||
<DataTable_ToolbarInternalButtons table={table}/>
|
<DataTable_ToolbarInternalButtons table={table}/>
|
||||||
</Box>
|
</Box>
|
||||||
)}
|
)}
|
||||||
|
|||||||
47
src/core/components/NotificationDesign/AskForKeep.jsx
Normal file
47
src/core/components/NotificationDesign/AskForKeep.jsx
Normal file
@@ -0,0 +1,47 @@
|
|||||||
|
'use client'
|
||||||
|
|
||||||
|
import SaveIcon from '@mui/icons-material/Save';
|
||||||
|
import {Box, Button, Typography} from "@mui/material";
|
||||||
|
import DownloadIcon from '@mui/icons-material/Download';
|
||||||
|
import {toast} from "react-toastify";
|
||||||
|
|
||||||
|
function AskForKeep({onSaveFilter}) {
|
||||||
|
|
||||||
|
const handleDismiss = () => {
|
||||||
|
toast.dismiss({containerId: "filtering"});
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Box sx={{width: "100%"}}>
|
||||||
|
<Box sx={{display: "flex", alignItems: "center", justifyContent: "space-between", mb: 1}}>
|
||||||
|
<Typography color="#155175" variant="subtitle1" sx={{fontWeight: "500"}}>
|
||||||
|
ذخیره سازی اطلاعات
|
||||||
|
</Typography>
|
||||||
|
<SaveIcon sx={{color: "#155175"}}/>
|
||||||
|
</Box>
|
||||||
|
<Box sx={{display: "flex", flexDirection: "column"}}>
|
||||||
|
<Typography variant="caption">
|
||||||
|
آیا مایل به ذخیره فیلتر های اعمال شده برای دفعات بعد هستید؟
|
||||||
|
</Typography>
|
||||||
|
</Box>
|
||||||
|
<Box sx={{display: "flex", gap: 1, mt: 1}}>
|
||||||
|
<Button variant="contained" onClick={handleDismiss} sx={{
|
||||||
|
backgroundColor: "#792626",
|
||||||
|
':hover': {backgroundColor: "#792626"},
|
||||||
|
boxShadow: "rgba(0, 0, 0, 0.23) 0px 6px 6px, rgba(0, 0, 0, 0.19) 10px 0px 20px",
|
||||||
|
}}>رد
|
||||||
|
کردن</Button>
|
||||||
|
<Button variant="contained" component="label" endIcon={<DownloadIcon/>}
|
||||||
|
onClick={onSaveFilter}
|
||||||
|
sx={{
|
||||||
|
backgroundColor: "#155175",
|
||||||
|
':hover': {backgroundColor: "#155175"},
|
||||||
|
boxShadow: "rgba(0, 0, 0, 0.23) 0px 6px 6px, rgba(0, 0, 0, 0.19) 10px 0px 20px",
|
||||||
|
}}>ذخیره
|
||||||
|
فیلتر</Button>
|
||||||
|
</Box>
|
||||||
|
</Box>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default AskForKeep;
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
'use client'
|
'use client'
|
||||||
import { createTheme } from "@mui/material";
|
import {createTheme} from "@mui/material";
|
||||||
|
|
||||||
const theme = createTheme({
|
const theme = createTheme({
|
||||||
direction: 'rtl',
|
direction: 'rtl',
|
||||||
|
|||||||
15
src/lib/contexts/DataTable.jsx
Normal file
15
src/lib/contexts/DataTable.jsx
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
import {createContext, useState} from "react";
|
||||||
|
|
||||||
|
export const DataTableContext = createContext();
|
||||||
|
|
||||||
|
const DataTableProvider = ({children}) => {
|
||||||
|
const [filterData, setFilterData] = useState({});
|
||||||
|
|
||||||
|
return (
|
||||||
|
<DataTableContext.Provider value={{filterData, setFilterData}}>
|
||||||
|
{children}
|
||||||
|
</DataTableContext.Provider>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default DataTableProvider;
|
||||||
9
src/lib/hooks/useDataTable.jsx
Normal file
9
src/lib/hooks/useDataTable.jsx
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
import {useContext} from "react";
|
||||||
|
import {DataTableContext} from "@/lib/contexts/DataTable";
|
||||||
|
|
||||||
|
const useTableSetting = () => {
|
||||||
|
const {filterData, setFilterData} = useContext(DataTableContext);
|
||||||
|
return {filterData, setFilterData};
|
||||||
|
};
|
||||||
|
|
||||||
|
export default useTableSetting;
|
||||||
Reference in New Issue
Block a user