From 23f1b9a4b14e28030c4223746758372228ff355b Mon Sep 17 00:00:00 2001 From: Mohammad Jalali Date: Sat, 18 May 2024 18:00:02 +0330 Subject: [PATCH 01/13] start refactor --- .../DataTable/filter/BetweenNumberFilter.jsx | 58 ----- .../filter/DatePicker/BetweenDateFilter.jsx | 35 --- .../filter/DatePicker/MuiDatePicker.jsx | 67 ------ .../DataTable/filter/FilterBody.jsx | 58 +++++ .../DataTable/filter/FilterBodyField.jsx | 9 + .../DataTable/filter/FilterButton.jsx | 17 ++ .../DataTable/filter/FilterColumn.jsx | 201 ------------------ .../components/DataTable/filter/SelectBox.jsx | 53 ----- .../DataTable/filter/SelectBoxMultiple.jsx | 116 ---------- .../filter/TextFieldWithFnBox/FilterBox.jsx | 46 ---- .../TextFieldWithFnBox/TextFieldWithFnBox.jsx | 61 ------ .../components/DataTable/filter/index.jsx | 18 ++ .../DataTable/refactor/RefactorTable.jsx | 6 +- .../DataTable/toolbar/TopToolbar.js | 2 +- 14 files changed, 106 insertions(+), 641 deletions(-) delete mode 100644 src/core/components/DataTable/filter/BetweenNumberFilter.jsx delete mode 100644 src/core/components/DataTable/filter/DatePicker/BetweenDateFilter.jsx delete mode 100644 src/core/components/DataTable/filter/DatePicker/MuiDatePicker.jsx create mode 100644 src/core/components/DataTable/filter/FilterBody.jsx create mode 100644 src/core/components/DataTable/filter/FilterBodyField.jsx create mode 100644 src/core/components/DataTable/filter/FilterButton.jsx delete mode 100644 src/core/components/DataTable/filter/FilterColumn.jsx delete mode 100644 src/core/components/DataTable/filter/SelectBox.jsx delete mode 100644 src/core/components/DataTable/filter/SelectBoxMultiple.jsx delete mode 100644 src/core/components/DataTable/filter/TextFieldWithFnBox/FilterBox.jsx delete mode 100644 src/core/components/DataTable/filter/TextFieldWithFnBox/TextFieldWithFnBox.jsx create mode 100644 src/core/components/DataTable/filter/index.jsx diff --git a/src/core/components/DataTable/filter/BetweenNumberFilter.jsx b/src/core/components/DataTable/filter/BetweenNumberFilter.jsx deleted file mode 100644 index 0b3512a..0000000 --- a/src/core/components/DataTable/filter/BetweenNumberFilter.jsx +++ /dev/null @@ -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 ( - - - - - - - - - ); -}; - -export default BetweenNumberFilter; diff --git a/src/core/components/DataTable/filter/DatePicker/BetweenDateFilter.jsx b/src/core/components/DataTable/filter/DatePicker/BetweenDateFilter.jsx deleted file mode 100644 index 0e4a325..0000000 --- a/src/core/components/DataTable/filter/DatePicker/BetweenDateFilter.jsx +++ /dev/null @@ -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 ( - - - handleDateChange(0, value)}/> - - - handleDateChange(1, value)}/> - - - ); -}; - -export default BetWeenDateFilter; diff --git a/src/core/components/DataTable/filter/DatePicker/MuiDatePicker.jsx b/src/core/components/DataTable/filter/DatePicker/MuiDatePicker.jsx deleted file mode 100644 index f2b0876..0000000 --- a/src/core/components/DataTable/filter/DatePicker/MuiDatePicker.jsx +++ /dev/null @@ -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 ( - - - { - 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: ( - - { - event.stopPropagation(); - formik.setFieldValue(name, ""); - setPickerValue(null); - }} - sx={{ - color: "#bfbfbf", - '&:hover': { - backgroundColor: 'rgba(189, 189, 189, 0.1)', - }, - }} - > - - - - ), - }, - }, - }} - value={pickerValue} - minDate={minDate ? new Date(minDate) : null} - maxDate={maxDate ? new Date(maxDate) : null} - /> - - - ); -} diff --git a/src/core/components/DataTable/filter/FilterBody.jsx b/src/core/components/DataTable/filter/FilterBody.jsx new file mode 100644 index 0000000..b87f980 --- /dev/null +++ b/src/core/components/DataTable/filter/FilterBody.jsx @@ -0,0 +1,58 @@ +'use client' + +import {Box, Drawer, IconButton, Typography} from "@mui/material"; +import CancelIcon from '@mui/icons-material/Cancel'; +import FilterBodyField from "@/core/components/DataTable/filter/FilterBodyField"; + +function FilterBody({columns, drawerState, setDrawerState}) { + // 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 initialValues = {}; + return ( + { + setDrawerState(false) + }}> + + فیلتر + { + setDrawerState(false) + }}> + + + + + {/**/} + {columns.map((column) => { + + })} + {/**/} + + + ); +} + +export default FilterBody; diff --git a/src/core/components/DataTable/filter/FilterBodyField.jsx b/src/core/components/DataTable/filter/FilterBodyField.jsx new file mode 100644 index 0000000..e78697e --- /dev/null +++ b/src/core/components/DataTable/filter/FilterBodyField.jsx @@ -0,0 +1,9 @@ +'use client' + +function FilterBodyField({column}) { + return ( + asdasdasd + ); +} + +export default FilterBodyField; diff --git a/src/core/components/DataTable/filter/FilterButton.jsx b/src/core/components/DataTable/filter/FilterButton.jsx new file mode 100644 index 0000000..ec444bb --- /dev/null +++ b/src/core/components/DataTable/filter/FilterButton.jsx @@ -0,0 +1,17 @@ +'use client' +import FilterAltIcon from '@mui/icons-material/FilterAlt'; +import {IconButton, Tooltip} from "@mui/material"; + +function FilterButton({drawerState, setDrawerState}) { + return ( + + { + setDrawerState(!drawerState) + }} aria-label="filter table"> + + + + ); +} + +export default FilterButton; diff --git a/src/core/components/DataTable/filter/FilterColumn.jsx b/src/core/components/DataTable/filter/FilterColumn.jsx deleted file mode 100644 index 3c0a16c..0000000 --- a/src/core/components/DataTable/filter/FilterColumn.jsx +++ /dev/null @@ -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 ( - <> - - - - - - - - فیلتر - - - - - - - {columns.map((column, index) => ( - column.enableColumnFilter && - (column.inputType === 'betweenDate' ? - filter.id === column.id)?.value || ''} - /> - : column.inputType === 'betweenNum' ? - filter.id === column.id)?.value || ["", ""]} - /> - : column.inputType === 'select2' ? - filter.id === column.id)?.value || []} - /> - : column.inputType === 'select' ? - filter.id === column.id)?.value || ''} - /> - : - 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 || ''} - /> - ) - ))} - - - - - - - - - - - ); -} - -export default FilterColumn; - - diff --git a/src/core/components/DataTable/filter/SelectBox.jsx b/src/core/components/DataTable/filter/SelectBox.jsx deleted file mode 100644 index 88cce6e..0000000 --- a/src/core/components/DataTable/filter/SelectBox.jsx +++ /dev/null @@ -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 ( - <> - - انتخاب - - - - ); -}; - -export default SelectBox; diff --git a/src/core/components/DataTable/filter/SelectBoxMultiple.jsx b/src/core/components/DataTable/filter/SelectBoxMultiple.jsx deleted file mode 100644 index 4355c72..0000000 --- a/src/core/components/DataTable/filter/SelectBoxMultiple.jsx +++ /dev/null @@ -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 ( - <> - - انتخاب - - - - ); -}; - -export default SelectBoxMultiple; diff --git a/src/core/components/DataTable/filter/TextFieldWithFnBox/FilterBox.jsx b/src/core/components/DataTable/filter/TextFieldWithFnBox/FilterBox.jsx deleted file mode 100644 index 3bba610..0000000 --- a/src/core/components/DataTable/filter/TextFieldWithFnBox/FilterBox.jsx +++ /dev/null @@ -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 ( -
- - - - - {columnFilterModeOptions.map((option, index) => ( - handleSelectFilter(option)} - selected={option === selectedFilter} sx={{cursor: 'pointer'}}> - - - ))} - - - - -
- ); -} - -export default FilterBox; diff --git a/src/core/components/DataTable/filter/TextFieldWithFnBox/TextFieldWithFnBox.jsx b/src/core/components/DataTable/filter/TextFieldWithFnBox/TextFieldWithFnBox.jsx deleted file mode 100644 index 18600dc..0000000 --- a/src/core/components/DataTable/filter/TextFieldWithFnBox/TextFieldWithFnBox.jsx +++ /dev/null @@ -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 ( - <> - - - - ) - }} - sx={{ - position: 'relative' - }} - /> - - - ); -}; - -export default TextFieldWithFnBox; diff --git a/src/core/components/DataTable/filter/index.jsx b/src/core/components/DataTable/filter/index.jsx new file mode 100644 index 0000000..b8872bf --- /dev/null +++ b/src/core/components/DataTable/filter/index.jsx @@ -0,0 +1,18 @@ +'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}) { + const [open, setOpen] = useState(false); + + return ( + <> + + + + ); +} + +export default FilterColumn; diff --git a/src/core/components/DataTable/refactor/RefactorTable.jsx b/src/core/components/DataTable/refactor/RefactorTable.jsx index 06f75c1..71e302c 100644 --- a/src/core/components/DataTable/refactor/RefactorTable.jsx +++ b/src/core/components/DataTable/refactor/RefactorTable.jsx @@ -6,9 +6,9 @@ import {useState} from "react"; function RefactorTable() { const {refactorAction} = useTableSetting(); - const [userId, setUserId] = useState(2); - const [pageName, setPageName] = useState('loan'); - const [tableName, setTableName] = useState('loan_table'); + const [userId, setUserId] = useState(0); + const [pageName, setPageName] = useState('testPage'); + const [tableName, setTableName] = useState('testTable'); const refactor = () => { refactorAction(userId, pageName, tableName); diff --git a/src/core/components/DataTable/toolbar/TopToolbar.js b/src/core/components/DataTable/toolbar/TopToolbar.js index 2b9641c..53c65da 100644 --- a/src/core/components/DataTable/toolbar/TopToolbar.js +++ b/src/core/components/DataTable/toolbar/TopToolbar.js @@ -3,7 +3,7 @@ import {Box, useMediaQuery} from "@mui/material"; import DataTable_LinearProgressBar from "./LinearProgressBar"; import DataTable_TablePagination from "./TablePagination"; 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"; const DataTable_TopToolbar = ({table, columns}) => { From fddf62921472fadc8a509308588ae1f29baff7d5 Mon Sep 17 00:00:00 2001 From: Mohammad Jalali Date: Sat, 25 May 2024 17:32:26 +0330 Subject: [PATCH 02/13] design filter part and do step1 (default value for filterFn) --- src/components/home/index.jsx | 33 +++-- .../DataTable/filter/FilterBody.jsx | 139 ++++++++++++------ .../DataTable/filter/FilterBodyField.jsx | 59 +++++++- .../DataTable/filter/FilterHeader.jsx | 32 ++++ .../DataTable/filter/FilterOptionList.jsx | 29 ++++ 5 files changed, 232 insertions(+), 60 deletions(-) create mode 100644 src/core/components/DataTable/filter/FilterHeader.jsx create mode 100644 src/core/components/DataTable/filter/FilterOptionList.jsx diff --git a/src/components/home/index.jsx b/src/components/home/index.jsx index 2682b64..f8a3d65 100644 --- a/src/components/home/index.jsx +++ b/src/components/home/index.jsx @@ -14,10 +14,9 @@ function HomeComponent() { accessorKey: 'name.firstName', header: 'نام', id: "firstName", - enableColumnFilter: true, + enableColumnFilter: false, datatype: "text", filterFn: "contains", - inputType: "textField", enableClickToCopy: true, columnFilterModeOptions: [ "equals", @@ -32,7 +31,6 @@ function HomeComponent() { enableColumnFilter: true, datatype: "text", filterFn: "equals", - inputType: "textField", columnFilterModeOptions: [ "equals", "notEquals", @@ -48,7 +46,6 @@ function HomeComponent() { enableColumnFilter: true, datatype: "text", filterFn: "notEquals", - inputType: "textField", columnFilterModeOptions: [ "equals", "notEquals", @@ -62,7 +59,6 @@ function HomeComponent() { enableColumnFilter: true, datatype: "text", filterFn: "equals", - inputType: "textField", columnFilterModeOptions: [ "equals", "notEquals", @@ -80,7 +76,6 @@ function HomeComponent() { enableColumnFilter: true, datatype: "text", filterFn: "contains", - inputType: "textField", columnFilterModeOptions: [ "equals", "notEquals", @@ -94,7 +89,11 @@ function HomeComponent() { enableColumnFilter: true, datatype: "nemeric", filterFn: "between", - inputType: "betweenNum", + columnFilterModeOptions: [ + "equals", + "notEquals", + "between" + ], }, { accessorKey: 'updated_at', @@ -103,16 +102,24 @@ function HomeComponent() { enableColumnFilter: true, datatype: "date", filterFn: "between", - inputType: "betweenDate", + columnFilterModeOptions: [ + "equals", + "notEquals", + "between" + ], }, { accessorKey: 'company', header: 'نام شرکت', id: "company", enableColumnFilter: true, - datatype: "text", + datatype: "select2", filterFn: "equals", - inputType: "select2", + columnFilterModeOptions: [ + "equals", + "notEquals", + "contains" + ], }, { accessorKey: 'area', @@ -121,7 +128,11 @@ function HomeComponent() { enableColumnFilter: true, datatype: "text", filterFn: "equals", - inputType: "select", + columnFilterModeOptions: [ + "equals", + "notEquals", + "contains" + ], }, ], [], diff --git a/src/core/components/DataTable/filter/FilterBody.jsx b/src/core/components/DataTable/filter/FilterBody.jsx index b87f980..42e826b 100644 --- a/src/core/components/DataTable/filter/FilterBody.jsx +++ b/src/core/components/DataTable/filter/FilterBody.jsx @@ -1,58 +1,103 @@ 'use client' -import {Box, Drawer, IconButton, Typography} from "@mui/material"; -import CancelIcon from '@mui/icons-material/Cancel'; +import {Box, Button, Drawer, styled} from "@mui/material"; +import {Form, Formik} from "formik"; +import useTableSetting from "@/lib/hooks/useTableSetting"; +import {useEffect, useState} from "react"; import FilterBodyField from "@/core/components/DataTable/filter/FilterBodyField"; +import FilterHeader from "@/core/components/DataTable/filter/FilterHeader"; + +const ScrollBox = styled(Box)({ + flexGrow: 1, + padding: '16px', + overflowY: 'scroll', + maxWidth: "450px", + '::-webkit-scrollbar': { + width: '5px', + }, + '::-webkit-scrollbar-track': { + boxShadow: 'inset 0 0 5px #fff', + borderRadius: '5px', + }, + '::-webkit-scrollbar-thumb': { + background: '#16534a', + borderRadius: '0px', + }, + '::-webkit-scrollbar-thumb:hover': { + background: '#ffffff', + }, +}); function FilterBody({columns, drawerState, setDrawerState}) { - // 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 initialValues = {}; + const [userId, setUserId] = useState(0); + const [pageName, setPageName] = useState('testPage'); + const [tableName, setTableName] = useState('testTable'); + const {settingStore, filterAction} = useTableSetting(); + + const [initialValues, setInitialValues] = useState({}); + + useEffect(() => { + const values = columns.reduce((acc, column) => { + if (!column.enableColumnFilter) return acc; + const filter = settingStore?.[userId]?.[pageName]?.[tableName]?.['filters']?.find((filter) => filter.id === column.id); + if (column.datatype === 'select2') { + acc[column.id] = filter?.value || []; + } else { + acc[column.id] = filter?.value || ''; + } + return acc; + }, {}); + setInitialValues(values); + }, [columns, settingStore, userId, pageName, tableName]); + + const handleSubmit = (values) => { + console.log("Form values:", values); + }; + return ( - { - setDrawerState(false) - }}> - - فیلتر - { - setDrawerState(false) - }}> - - - - - {/**/} - {columns.map((column) => { - - })} - {/**/} + setDrawerState(false)} + sx={{overflowY: "hidden", display: "flex", flexDirection: "column", height: "100%"}}> + + + {Object.keys(initialValues).length > 0 && ( + + {({values, handleChange, handleBlur}) => ( +
+ {columns.map((column) => ( + column.enableColumnFilter && ( + + ) + ))} + + )} +
+ )} +
+ +
); } -export default FilterBody; +export default FilterBody; \ No newline at end of file diff --git a/src/core/components/DataTable/filter/FilterBodyField.jsx b/src/core/components/DataTable/filter/FilterBodyField.jsx index e78697e..9d20133 100644 --- a/src/core/components/DataTable/filter/FilterBodyField.jsx +++ b/src/core/components/DataTable/filter/FilterBodyField.jsx @@ -1,8 +1,63 @@ 'use client' -function FilterBodyField({column}) { +import {InputAdornment, TextField, Typography} from "@mui/material"; +import FilterListIcon from '@mui/icons-material/FilterList'; +import {useState} from "react"; +import FilterOptionList from "@/core/components/DataTable/filter/FilterOptionList"; +import useTableSetting from "@/lib/hooks/useTableSetting"; + +const columnFilterModeOptionFa = { + equals: "برابر", + notEquals: "نابرابر", + contains: "شامل", + lessThan: "کوچکتر", + greaterThan: "بزرگتر", + fuzzy: "فازی", + between: "مابین" +} + +function FilterBodyField({column, value}) { + const [anchorEl, setAnchorEl] = useState(null); + const [userId, setUserId] = useState(0); + const [pageName, setPageName] = useState('testPage'); + const [tableName, setTableName] = useState('testTable'); + const {settingStore} = useTableSetting(); + const defaultFilter = (settingStore?.[userId]?.[pageName]?.[tableName]?.['filters'] || []).find(filter => filter.id === column.id)?.fn || column._filterFn; + const defaultFilterTranslation = columnFilterModeOptionFa[defaultFilter] || defaultFilter; + + const HandleOpenFilterBox = (event) => { + setAnchorEl(event.currentTarget); + }; + const handleCloseFilterBox = () => { + setAnchorEl(null); + }; + return ( - asdasdasd + <> + + نوع فیلتر: {defaultFilterTranslation} + } + variant="outlined" + size="normal" + sx={{marginY: 1}} + InputProps={{ + endAdornment: ( + + + + ), + }} + /> + + ); } diff --git a/src/core/components/DataTable/filter/FilterHeader.jsx b/src/core/components/DataTable/filter/FilterHeader.jsx new file mode 100644 index 0000000..015801d --- /dev/null +++ b/src/core/components/DataTable/filter/FilterHeader.jsx @@ -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 ( + + + + فیلتر + + setDrawerState(false)}> + + + + ); +} + +export default FilterHeader; \ No newline at end of file diff --git a/src/core/components/DataTable/filter/FilterOptionList.jsx b/src/core/components/DataTable/filter/FilterOptionList.jsx new file mode 100644 index 0000000..fb4fc46 --- /dev/null +++ b/src/core/components/DataTable/filter/FilterOptionList.jsx @@ -0,0 +1,29 @@ +'use client' + +import {ListItem, Menu} from "@mui/material"; +import {useState} from "react"; + +function FilterOptionList({defaultFilter, filterOption, handleCloseFilterBox, anchorEl, columnFilterModeOptionFa}) { + + const [selectedFilter, setSelectedFilter] = useState(defaultFilter); + + return ( + + {filterOption.map((option, index) => ( + + {columnFilterModeOptionFa[option]} + + ))} + + ); +} + +export default FilterOptionList; From 474e6f3e8dfe864f4a953c2c18b40f0e306d7eb8 Mon Sep 17 00:00:00 2001 From: Mohammad Jalali Date: Sat, 1 Jun 2024 17:19:56 +0330 Subject: [PATCH 03/13] create custom components for fileds and start to get hand dirty on datepicker (step2) --- src/components/home/index.jsx | 30 +++---- .../DataTable/filter/FilterBodyField.jsx | 88 +++++++++++++------ .../filter/fieldsType/CustomDatePicker.jsx | 30 +++++++ .../fieldsType/CustomDatePickerRange.jsx | 30 +++++++ .../filter/fieldsType/CustomSelect.jsx | 44 ++++++++++ .../fieldsType/CustomSelectMultiple.jsx | 36 ++++++++ .../filter/fieldsType/CustomTextField.jsx | 30 +++++++ .../fieldsType/CustomTextFieldRange.jsx | 45 ++++++++++ 8 files changed, 287 insertions(+), 46 deletions(-) create mode 100644 src/core/components/DataTable/filter/fieldsType/CustomDatePicker.jsx create mode 100644 src/core/components/DataTable/filter/fieldsType/CustomDatePickerRange.jsx create mode 100644 src/core/components/DataTable/filter/fieldsType/CustomSelect.jsx create mode 100644 src/core/components/DataTable/filter/fieldsType/CustomSelectMultiple.jsx create mode 100644 src/core/components/DataTable/filter/fieldsType/CustomTextField.jsx create mode 100644 src/core/components/DataTable/filter/fieldsType/CustomTextFieldRange.jsx diff --git a/src/components/home/index.jsx b/src/components/home/index.jsx index f8a3d65..ae8a116 100644 --- a/src/components/home/index.jsx +++ b/src/components/home/index.jsx @@ -14,7 +14,7 @@ function HomeComponent() { accessorKey: 'name.firstName', header: 'نام', id: "firstName", - enableColumnFilter: false, + enableColumnFilter: true, datatype: "text", filterFn: "contains", enableClickToCopy: true, @@ -67,7 +67,6 @@ function HomeComponent() { "greaterThan", "fuzzy" ], - }, { accessorKey: 'state', @@ -87,7 +86,7 @@ function HomeComponent() { header: 'محدوده', id: "price", enableColumnFilter: true, - datatype: "nemeric", + datatype: "numeric", filterFn: "between", columnFilterModeOptions: [ "equals", @@ -102,23 +101,18 @@ function HomeComponent() { enableColumnFilter: true, datatype: "date", filterFn: "between", - columnFilterModeOptions: [ - "equals", - "notEquals", - "between" - ], }, { accessorKey: 'company', header: 'نام شرکت', id: "company", enableColumnFilter: true, - datatype: "select2", + datatype: "numeric", filterFn: "equals", - columnFilterModeOptions: [ - "equals", - "notEquals", - "contains" + columnSelectOption: [ + {value: 1, label: "وایتل"}, + {value: 2, label: "اسنپ"}, + {value: 3, label: "تپسی"} ], }, { @@ -126,12 +120,12 @@ function HomeComponent() { header: 'منطقه', id: "area", enableColumnFilter: true, - datatype: "text", + datatype: "numeric", filterFn: "equals", - columnFilterModeOptions: [ - "equals", - "notEquals", - "contains" + columnSelectOption: [ + {value: 1, label: "وایتل"}, + {value: 2, label: "اسنپ"}, + {value: 3, label: "تپسی"} ], }, ], diff --git a/src/core/components/DataTable/filter/FilterBodyField.jsx b/src/core/components/DataTable/filter/FilterBodyField.jsx index 9d20133..f60f9df 100644 --- a/src/core/components/DataTable/filter/FilterBodyField.jsx +++ b/src/core/components/DataTable/filter/FilterBodyField.jsx @@ -1,10 +1,14 @@ 'use client' -import {InputAdornment, TextField, Typography} from "@mui/material"; -import FilterListIcon from '@mui/icons-material/FilterList'; import {useState} from "react"; import FilterOptionList from "@/core/components/DataTable/filter/FilterOptionList"; import useTableSetting from "@/lib/hooks/useTableSetting"; +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 CustomDatePicker from "@/core/components/DataTable/filter/fieldsType/CustomDatePicker"; +import CustomSelectMultiple from "@/core/components/DataTable/filter/fieldsType/CustomSelectMultiple"; +import CustomDatePickerRange from "@/core/components/DataTable/filter/fieldsType/CustomDatePickerRange"; const columnFilterModeOptionFa = { equals: "برابر", @@ -25,40 +29,68 @@ function FilterBodyField({column, value}) { const defaultFilter = (settingStore?.[userId]?.[pageName]?.[tableName]?.['filters'] || []).find(filter => filter.id === column.id)?.fn || column._filterFn; const defaultFilterTranslation = columnFilterModeOptionFa[defaultFilter] || defaultFilter; - const HandleOpenFilterBox = (event) => { + const handleOpenFilterBox = (event) => { setAnchorEl(event.currentTarget); }; const handleCloseFilterBox = () => { setAnchorEl(null); }; - return ( <> - - نوع فیلتر: {defaultFilterTranslation} - } - variant="outlined" - size="normal" - sx={{marginY: 1}} - InputProps={{ - endAdornment: ( - - - - ), - }} - /> - + {column.datatype === "numeric" && column._filterFn === "between" ? ( + + ) : column.datatype === "numeric" && column._filterFn === "equals" && Array.isArray(column.columnSelectOption) ? ( + + ) : column.datatype === "date" && column._filterFn === "equals" ? ( + + ) : column.datatype === "date" && column._filterFn === "between" ? ( + + ) : column.datatype === "array" && column._filterFn === "equals" ? ( + + ) : ( + + )} + {Array.isArray(column.columnFilterModeOptions) && anchorEl !== null && ( + + )} ); } -export default FilterBodyField; +export default FilterBodyField; \ No newline at end of file diff --git a/src/core/components/DataTable/filter/fieldsType/CustomDatePicker.jsx b/src/core/components/DataTable/filter/fieldsType/CustomDatePicker.jsx new file mode 100644 index 0000000..5e600f0 --- /dev/null +++ b/src/core/components/DataTable/filter/fieldsType/CustomDatePicker.jsx @@ -0,0 +1,30 @@ +'use client' + +import {InputAdornment, TextField, Typography} from "@mui/material"; +import FilterListIcon from '@mui/icons-material/FilterList'; + +function CustomDatePicker({column, value, defaultFilterTranslation, handleOpenFilterBox}) { + return ( + + نوع فیلتر: {defaultFilterTranslation} + } + variant="outlined" + size="normal" + sx={{marginY: 1}} + InputProps={{ + endAdornment: ( + + + + ), + }} + /> + ); +} + +export default CustomDatePicker; diff --git a/src/core/components/DataTable/filter/fieldsType/CustomDatePickerRange.jsx b/src/core/components/DataTable/filter/fieldsType/CustomDatePickerRange.jsx new file mode 100644 index 0000000..ace1e3f --- /dev/null +++ b/src/core/components/DataTable/filter/fieldsType/CustomDatePickerRange.jsx @@ -0,0 +1,30 @@ +'use client' + +import {InputAdornment, TextField, Typography} from "@mui/material"; +import FilterListIcon from '@mui/icons-material/FilterList'; + +function CustomDatePickerRange({column, value, defaultFilterTranslation, handleOpenFilterBox}) { + return ( + + نوع فیلتر: {defaultFilterTranslation} + } + variant="outlined" + size="normal" + sx={{marginY: 1}} + InputProps={{ + endAdornment: ( + + + + ), + }} + /> + ); +} + +export default CustomDatePickerRange; diff --git a/src/core/components/DataTable/filter/fieldsType/CustomSelect.jsx b/src/core/components/DataTable/filter/fieldsType/CustomSelect.jsx new file mode 100644 index 0000000..4c44a5f --- /dev/null +++ b/src/core/components/DataTable/filter/fieldsType/CustomSelect.jsx @@ -0,0 +1,44 @@ +'use client' + +import {FormControl, FormHelperText, InputLabel, MenuItem, OutlinedInput, Select, Typography} from "@mui/material"; +import {useState} from "react"; + +function CustomSelect({column, value, defaultFilterTranslation}) { + const [fieldValue, setFieldValue] = useState(value); + const columnSelectOption = column.columnSelectOption; + + const handleChange = (event) => { + setFieldValue(event.target.value); + }; + + return ( + + {column.header} + + + + نوع فیلتر: {defaultFilterTranslation} + + + + ); +} + +export default CustomSelect; diff --git a/src/core/components/DataTable/filter/fieldsType/CustomSelectMultiple.jsx b/src/core/components/DataTable/filter/fieldsType/CustomSelectMultiple.jsx new file mode 100644 index 0000000..af5200e --- /dev/null +++ b/src/core/components/DataTable/filter/fieldsType/CustomSelectMultiple.jsx @@ -0,0 +1,36 @@ +'use client' + +import {FormControl, FormHelperText, InputLabel, MenuItem, OutlinedInput, Select, Typography} from "@mui/material"; + +function CustomSelectMultiple({column, value, defaultFilterTranslation}) { + const columnSelectOption = column.columnSelectOption; + return ( + + {column.header} + + + + نوع فیلتر: {defaultFilterTranslation} + + + + ); +} + +export default CustomSelectMultiple; diff --git a/src/core/components/DataTable/filter/fieldsType/CustomTextField.jsx b/src/core/components/DataTable/filter/fieldsType/CustomTextField.jsx new file mode 100644 index 0000000..c760de2 --- /dev/null +++ b/src/core/components/DataTable/filter/fieldsType/CustomTextField.jsx @@ -0,0 +1,30 @@ +'use client' + +import {InputAdornment, TextField, Typography} from "@mui/material"; +import FilterListIcon from '@mui/icons-material/FilterList'; + +function CustomTextField({column, value, defaultFilterTranslation, handleOpenFilterBox}) { + return ( + + نوع فیلتر: {defaultFilterTranslation} + } + variant="outlined" + size="normal" + sx={{marginY: 1}} + InputProps={{ + endAdornment: ( + + + + ), + }} + /> + ); +} + +export default CustomTextField; diff --git a/src/core/components/DataTable/filter/fieldsType/CustomTextFieldRange.jsx b/src/core/components/DataTable/filter/fieldsType/CustomTextFieldRange.jsx new file mode 100644 index 0000000..1fbbd40 --- /dev/null +++ b/src/core/components/DataTable/filter/fieldsType/CustomTextFieldRange.jsx @@ -0,0 +1,45 @@ +'use client' + +import {Box, InputAdornment, TextField, Typography} from "@mui/material"; +import FilterListIcon from '@mui/icons-material/FilterList'; + +function CustomTextFieldRange({column, value, defaultFilterTranslation, handleOpenFilterBox}) { + return ( + + + از {column.header} + } + value={value} + fullWidth + helperText={ + نوع فیلتر: {defaultFilterTranslation} + } + variant="outlined" + size="normal" + sx={{marginY: 1, marginRight: 1}} + /> + + تا {column.header} + } + value={value} + fullWidth + variant="outlined" + size="normal" + sx={{marginY: 1}} + InputProps={{ + endAdornment: ( + + + + ), + }} + /> + + ); +} + +export default CustomTextFieldRange; From 3f896ef5e91868bf257d54b366d8305a30a7ffc5 Mon Sep 17 00:00:00 2001 From: Mohammad Jalali Date: Sun, 9 Jun 2024 16:43:53 +0330 Subject: [PATCH 04/13] working on datepickerrange problems --- package.json | 5 +- src/components/home/index.jsx | 12 ++- .../DataTable/filter/FilterBody.jsx | 99 +++++++++++++------ .../DataTable/filter/FilterBodyField.jsx | 16 ++- .../CustomDate/CustomDatePicker.jsx | 15 +++ .../CustomDate/CustomDatePickerRange.jsx | 25 +++++ .../fieldsType/CustomDate/DatePicker.jsx | 66 +++++++++++++ .../filter/fieldsType/CustomDatePicker.jsx | 30 ------ .../fieldsType/CustomDatePickerRange.jsx | 30 ------ .../filter/fieldsType/CustomSelect.jsx | 17 ++-- .../fieldsType/CustomSelectMultiple.jsx | 32 +++++- .../filter/fieldsType/CustomTextField.jsx | 5 +- .../fieldsType/CustomTextFieldRange.jsx | 44 +++++---- 13 files changed, 264 insertions(+), 132 deletions(-) create mode 100644 src/core/components/DataTable/filter/fieldsType/CustomDate/CustomDatePicker.jsx create mode 100644 src/core/components/DataTable/filter/fieldsType/CustomDate/CustomDatePickerRange.jsx create mode 100644 src/core/components/DataTable/filter/fieldsType/CustomDate/DatePicker.jsx delete mode 100644 src/core/components/DataTable/filter/fieldsType/CustomDatePicker.jsx delete mode 100644 src/core/components/DataTable/filter/fieldsType/CustomDatePickerRange.jsx diff --git a/package.json b/package.json index 3e7a01c..0290200 100644 --- a/package.json +++ b/package.json @@ -22,12 +22,13 @@ "formik": "^2.4.5", "jalali-moment": "^3.3.11", "material-react-table": "^2.11.2", - "next": "14.1.0", + "next": "^14.2.3", "react": "^18", "react-dom": "^18", "sass": "^1.75.0", "stylis": "^4.3.1", - "stylis-plugin-rtl": "^2.1.1" + "stylis-plugin-rtl": "^2.1.1", + "yup": "^1.4.0" }, "devDependencies": { "eslint": "^8", diff --git a/src/components/home/index.jsx b/src/components/home/index.jsx index ae8a116..359e13e 100644 --- a/src/components/home/index.jsx +++ b/src/components/home/index.jsx @@ -94,13 +94,21 @@ function HomeComponent() { "between" ], }, + { + accessorKey: 'created_at', + header: 'تاریخ ساخت', + id: "created_at", + enableColumnFilter: true, + datatype: "date", + filterFn: "between", + }, { accessorKey: 'updated_at', header: 'تاریخ بروزرسانی', id: "updated_at", enableColumnFilter: true, datatype: "date", - filterFn: "between", + filterFn: "equals", }, { accessorKey: 'company', @@ -120,7 +128,7 @@ function HomeComponent() { header: 'منطقه', id: "area", enableColumnFilter: true, - datatype: "numeric", + datatype: "array", filterFn: "equals", columnSelectOption: [ {value: 1, label: "وایتل"}, diff --git a/src/core/components/DataTable/filter/FilterBody.jsx b/src/core/components/DataTable/filter/FilterBody.jsx index 42e826b..fb6dcea 100644 --- a/src/core/components/DataTable/filter/FilterBody.jsx +++ b/src/core/components/DataTable/filter/FilterBody.jsx @@ -6,10 +6,10 @@ import useTableSetting from "@/lib/hooks/useTableSetting"; import {useEffect, useState} from "react"; import FilterBodyField from "@/core/components/DataTable/filter/FilterBodyField"; import FilterHeader from "@/core/components/DataTable/filter/FilterHeader"; +import * as Yup from "yup"; const ScrollBox = styled(Box)({ flexGrow: 1, - padding: '16px', overflowY: 'scroll', maxWidth: "450px", '::-webkit-scrollbar': { @@ -40,8 +40,10 @@ function FilterBody({columns, drawerState, setDrawerState}) { const values = columns.reduce((acc, column) => { if (!column.enableColumnFilter) return acc; const filter = settingStore?.[userId]?.[pageName]?.[tableName]?.['filters']?.find((filter) => filter.id === column.id); - if (column.datatype === 'select2') { + if (column.datatype === 'array') { acc[column.id] = filter?.value || []; + } else if (column._filterFn === "between") { + acc[column.id] = filter?.value || ["", ""]; } else { acc[column.id] = filter?.value || ''; } @@ -50,6 +52,33 @@ function FilterBody({columns, drawerState, setDrawerState}) { setInitialValues(values); }, [columns, settingStore, userId, pageName, tableName]); + console.log("initialValues", initialValues) + + const validationSchema = Yup.object().shape( + columns.reduce((acc, column) => { + if (column._filterFn === "between") { + acc[column.id] = Yup.array().of(Yup.string()).test({ + test(value, ctx) { + const [start, end] = value || ["", ""]; + const startInt = parseInt(start, 10); + const endInt = parseInt(end, 10); + if (start && end && endInt <= startInt) { + return ctx.createError({ + message: `مقدار وارده باید بیشتر از (${start}) باشد` + }); + } else if (start && !end) { + return ctx.createError({ + message: "این بخش را پر نمایید" + }); + } + return true; + } + }); + } + return acc; + }, {}) + ); + const handleSubmit = (values) => { console.log("Form values:", values); }; @@ -58,44 +87,50 @@ function FilterBody({columns, drawerState, setDrawerState}) { setDrawerState(false)} sx={{overflowY: "hidden", display: "flex", flexDirection: "column", height: "100%"}}> - - {Object.keys(initialValues).length > 0 && ( + {Object.keys(initialValues).length > 0 && ( + - {({values, handleChange, handleBlur}) => ( + {({values, handleChange, handleBlur, setFieldValue, errors, touched}) => (
- {columns.map((column) => ( - column.enableColumnFilter && ( - - ) - ))} + + {columns.map((column) => ( + column.enableColumnFilter && ( + + ) + ))} + + + + )}
- )} -
- - - +
+ )}
); } diff --git a/src/core/components/DataTable/filter/FilterBodyField.jsx b/src/core/components/DataTable/filter/FilterBodyField.jsx index f60f9df..879a5e0 100644 --- a/src/core/components/DataTable/filter/FilterBodyField.jsx +++ b/src/core/components/DataTable/filter/FilterBodyField.jsx @@ -6,9 +6,9 @@ import useTableSetting from "@/lib/hooks/useTableSetting"; 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 CustomDatePicker from "@/core/components/DataTable/filter/fieldsType/CustomDatePicker"; +import CustomDatePicker from "@/core/components/DataTable/filter/fieldsType/CustomDate/CustomDatePicker"; import CustomSelectMultiple from "@/core/components/DataTable/filter/fieldsType/CustomSelectMultiple"; -import CustomDatePickerRange from "@/core/components/DataTable/filter/fieldsType/CustomDatePickerRange"; +import CustomDatePickerRange from "@/core/components/DataTable/filter/fieldsType/CustomDate/CustomDatePickerRange"; const columnFilterModeOptionFa = { equals: "برابر", @@ -20,7 +20,7 @@ const columnFilterModeOptionFa = { between: "مابین" } -function FilterBodyField({column, value}) { +function FilterBodyField({column, value, handleChange, handleBlur, setFieldValue, errors, touched}) { const [anchorEl, setAnchorEl] = useState(null); const [userId, setUserId] = useState(0); const [pageName, setPageName] = useState('testPage'); @@ -28,7 +28,6 @@ function FilterBodyField({column, value}) { const {settingStore} = useTableSetting(); const defaultFilter = (settingStore?.[userId]?.[pageName]?.[tableName]?.['filters'] || []).find(filter => filter.id === column.id)?.fn || column._filterFn; const defaultFilterTranslation = columnFilterModeOptionFa[defaultFilter] || defaultFilter; - const handleOpenFilterBox = (event) => { setAnchorEl(event.currentTarget); }; @@ -43,11 +42,16 @@ function FilterBodyField({column, value}) { value={value} defaultFilterTranslation={defaultFilterTranslation} handleOpenFilterBox={handleOpenFilterBox} + handleBlur={handleBlur} + handleChange={handleChange} + errors={errors} + touched={touched} /> ) : column.datatype === "numeric" && column._filterFn === "equals" && Array.isArray(column.columnSelectOption) ? ( @@ -55,6 +59,7 @@ function FilterBodyField({column, value}) { @@ -69,6 +74,7 @@ function FilterBodyField({column, value}) { @@ -78,6 +84,8 @@ function FilterBodyField({column, value}) { value={value} defaultFilterTranslation={defaultFilterTranslation} handleOpenFilterBox={handleOpenFilterBox} + handleBlur={handleBlur} + handleChange={handleChange} /> )} {Array.isArray(column.columnFilterModeOptions) && anchorEl !== null && ( diff --git a/src/core/components/DataTable/filter/fieldsType/CustomDate/CustomDatePicker.jsx b/src/core/components/DataTable/filter/fieldsType/CustomDate/CustomDatePicker.jsx new file mode 100644 index 0000000..ec57e2f --- /dev/null +++ b/src/core/components/DataTable/filter/fieldsType/CustomDate/CustomDatePicker.jsx @@ -0,0 +1,15 @@ +import React from 'react'; +import DatePicker from "@/core/components/DataTable/filter/fieldsType/CustomDate/DatePicker"; + +function CustomDatePicker({column, value, defaultFilterTranslation, setFieldValue}) { + return ( + + ); +} + +export default CustomDatePicker; \ No newline at end of file diff --git a/src/core/components/DataTable/filter/fieldsType/CustomDate/CustomDatePickerRange.jsx b/src/core/components/DataTable/filter/fieldsType/CustomDate/CustomDatePickerRange.jsx new file mode 100644 index 0000000..847c16f --- /dev/null +++ b/src/core/components/DataTable/filter/fieldsType/CustomDate/CustomDatePickerRange.jsx @@ -0,0 +1,25 @@ +'use client' + +import DatePicker from "@/core/components/DataTable/filter/fieldsType/CustomDate/DatePicker"; +import React from "react"; + +function CustomDatePickerRange({column, value, defaultFilterTranslation, setFieldValue}) { + return ( + <> + + + + ); +} + +export default CustomDatePickerRange; diff --git a/src/core/components/DataTable/filter/fieldsType/CustomDate/DatePicker.jsx b/src/core/components/DataTable/filter/fieldsType/CustomDate/DatePicker.jsx new file mode 100644 index 0000000..19ffb3d --- /dev/null +++ b/src/core/components/DataTable/filter/fieldsType/CustomDate/DatePicker.jsx @@ -0,0 +1,66 @@ +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 {IconButton, InputAdornment, Typography} from "@mui/material"; +import ClearIcon from "@mui/icons-material/Clear"; +import moment from "jalali-moment"; + +function DatePicker({column, value, defaultFilterTranslation, setFieldValue}) { + return ( + + { + const date = new Date(value); + const formattedDate = moment(date) + .locale("en") + .format("YYYY-MM-DD"); + setFieldValue(column.id, formattedDate); + }} + slotProps={{ + textField: { + placeholder: "تاریخ خود را وارد کنید", + helperText: ( + + نوع فیلتر: {defaultFilterTranslation} (تاریخ) + + ), + InputProps: { + endAdornment: ( + + { + event.stopPropagation(); + setFieldValue(column.id, ""); + }} + sx={{ + color: "#bfbfbf", + '&:hover': { + backgroundColor: 'rgba(189, 189, 189, 0.1)', + color: "#363434" + }, + }} + > + + + + ), + }, + }, + }} + /> + + ); +} + +export default DatePicker; \ No newline at end of file diff --git a/src/core/components/DataTable/filter/fieldsType/CustomDatePicker.jsx b/src/core/components/DataTable/filter/fieldsType/CustomDatePicker.jsx deleted file mode 100644 index 5e600f0..0000000 --- a/src/core/components/DataTable/filter/fieldsType/CustomDatePicker.jsx +++ /dev/null @@ -1,30 +0,0 @@ -'use client' - -import {InputAdornment, TextField, Typography} from "@mui/material"; -import FilterListIcon from '@mui/icons-material/FilterList'; - -function CustomDatePicker({column, value, defaultFilterTranslation, handleOpenFilterBox}) { - return ( - - نوع فیلتر: {defaultFilterTranslation} - } - variant="outlined" - size="normal" - sx={{marginY: 1}} - InputProps={{ - endAdornment: ( - - - - ), - }} - /> - ); -} - -export default CustomDatePicker; diff --git a/src/core/components/DataTable/filter/fieldsType/CustomDatePickerRange.jsx b/src/core/components/DataTable/filter/fieldsType/CustomDatePickerRange.jsx deleted file mode 100644 index ace1e3f..0000000 --- a/src/core/components/DataTable/filter/fieldsType/CustomDatePickerRange.jsx +++ /dev/null @@ -1,30 +0,0 @@ -'use client' - -import {InputAdornment, TextField, Typography} from "@mui/material"; -import FilterListIcon from '@mui/icons-material/FilterList'; - -function CustomDatePickerRange({column, value, defaultFilterTranslation, handleOpenFilterBox}) { - return ( - - نوع فیلتر: {defaultFilterTranslation} - } - variant="outlined" - size="normal" - sx={{marginY: 1}} - InputProps={{ - endAdornment: ( - - - - ), - }} - /> - ); -} - -export default CustomDatePickerRange; diff --git a/src/core/components/DataTable/filter/fieldsType/CustomSelect.jsx b/src/core/components/DataTable/filter/fieldsType/CustomSelect.jsx index 4c44a5f..ad21280 100644 --- a/src/core/components/DataTable/filter/fieldsType/CustomSelect.jsx +++ b/src/core/components/DataTable/filter/fieldsType/CustomSelect.jsx @@ -1,27 +1,22 @@ 'use client' import {FormControl, FormHelperText, InputLabel, MenuItem, OutlinedInput, Select, Typography} from "@mui/material"; -import {useState} from "react"; -function CustomSelect({column, value, defaultFilterTranslation}) { - const [fieldValue, setFieldValue] = useState(value); +function CustomSelect({column, value, defaultFilterTranslation, setFieldValue}) { const columnSelectOption = column.columnSelectOption; - const handleChange = (event) => { - setFieldValue(event.target.value); - }; - return ( - {column.header} + {column.header} } onChange={(e) => { - setFieldValue(column.id, e.target.value) + setFieldValue(`${column.id}.value`, e.target.value) }} > {columnSelectOption.map((option) => ( diff --git a/src/core/components/DataTable/filter/fieldsType/CustomSelectMultiple.jsx b/src/core/components/DataTable/filter/fieldsType/CustomSelectMultiple.jsx index d6a62eb..502eefd 100644 --- a/src/core/components/DataTable/filter/fieldsType/CustomSelectMultiple.jsx +++ b/src/core/components/DataTable/filter/fieldsType/CustomSelectMultiple.jsx @@ -12,7 +12,7 @@ import { Typography } from "@mui/material"; -function CustomSelectMultiple({column, value, defaultFilterTranslation, setFieldValue}) { +function CustomSelectMultiple({column, filterParameters, defaultFilterTranslation, setFieldValue}) { const columnSelectOption = column.columnSelectOption; const getLabelForValue = (value) => { @@ -27,10 +27,10 @@ function CustomSelectMultiple({column, value, defaultFilterTranslation, setField - + نوع فیلتر: {defaultFilterTranslation} diff --git a/src/core/components/DataTable/filter/fieldsType/CustomSelectMultiple.jsx b/src/core/components/DataTable/filter/fieldsType/CustomSelectMultiple.jsx index 502eefd..ae027fe 100644 --- a/src/core/components/DataTable/filter/fieldsType/CustomSelectMultiple.jsx +++ b/src/core/components/DataTable/filter/fieldsType/CustomSelectMultiple.jsx @@ -51,7 +51,7 @@ function CustomSelectMultiple({column, filterParameters, defaultFilterTranslatio ))} - + نوع فیلتر: {defaultFilterTranslation} diff --git a/src/core/components/DataTable/filter/fieldsType/CustomTextField.jsx b/src/core/components/DataTable/filter/fieldsType/CustomTextField.jsx index c5c35d8..91f9226 100644 --- a/src/core/components/DataTable/filter/fieldsType/CustomTextField.jsx +++ b/src/core/components/DataTable/filter/fieldsType/CustomTextField.jsx @@ -18,7 +18,7 @@ function CustomTextField({ onChange={handleChange} onBlur={handleBlur} fullWidth - helperText={ + helperText={ نوع فیلتر: {defaultFilterTranslation} } variant="outlined" diff --git a/src/core/components/DataTable/filter/fieldsType/CustomTextFieldRange.jsx b/src/core/components/DataTable/filter/fieldsType/CustomTextFieldRange.jsx index 9d4da31..35c9358 100644 --- a/src/core/components/DataTable/filter/fieldsType/CustomTextFieldRange.jsx +++ b/src/core/components/DataTable/filter/fieldsType/CustomTextFieldRange.jsx @@ -22,7 +22,7 @@ function CustomTextFieldRange({ value={filterParameters.value[0]} fullWidth error={touched?.[`${column.id}`]?.value && Boolean(errors?.[`${column.id}`]?.value)} - helperText={نوع + helperText={نوع فیلتر: {defaultFilterTranslation}} variant="outlined" size="normal" diff --git a/src/core/components/DataTable/filter/index.jsx b/src/core/components/DataTable/filter/index.jsx index b8872bf..faa01c9 100644 --- a/src/core/components/DataTable/filter/index.jsx +++ b/src/core/components/DataTable/filter/index.jsx @@ -4,13 +4,14 @@ import {useState} from "react"; import FilterButton from "@/core/components/DataTable/filter/FilterButton"; import FilterBody from "@/core/components/DataTable/filter/FilterBody"; -function FilterColumn({columns}) { +function FilterColumn({columns, userid, pagename, tablename}) { const [open, setOpen] = useState(false); return ( <> - + ); } diff --git a/src/core/components/DataTable/index.js b/src/core/components/DataTable/index.js index aba1d1c..df0e109 100644 --- a/src/core/components/DataTable/index.js +++ b/src/core/components/DataTable/index.js @@ -1,142 +1,9 @@ -import {useMaterialReactTable} from "material-react-table"; import DataTable_Main from "./Main"; -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"; - -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 {userId, pageName, tableName, columns, initialStateProps} = props - const {settingStore, hideAction, sortAction} = useTableSetting(); - const flatColumns = flattenArrayOfObjects(columns, 'columns') - - 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}) => (<> - - ), - 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 ; + return ( + + ); }; -export default DataTable; +export default DataTable; \ No newline at end of file diff --git a/src/core/components/DataTable/table/Paper.js b/src/core/components/DataTable/table/Paper.js index ede47c1..7380cf0 100644 --- a/src/core/components/DataTable/table/Paper.js +++ b/src/core/components/DataTable/table/Paper.js @@ -65,7 +65,9 @@ const DataTable_Paper = ({table, ...rest}) => { > {enableTopToolbar && (parseFromValuesOrFunc(renderTopToolbar, {table}) ?? ( - + ))} {enableBottomToolbar && diff --git a/src/core/components/DataTable/toolbar/TopToolbar.js b/src/core/components/DataTable/toolbar/TopToolbar.js index 53c65da..1adf4d3 100644 --- a/src/core/components/DataTable/toolbar/TopToolbar.js +++ b/src/core/components/DataTable/toolbar/TopToolbar.js @@ -6,7 +6,7 @@ import DataTable_ToolbarInternalButtons from "./ToolbarInternalButtons"; import FilterColumn from "@/core/components/DataTable/filter"; import RefactorTable from "@/core/components/DataTable/refactor/RefactorTable"; -const DataTable_TopToolbar = ({table, columns}) => { +const DataTable_TopToolbar = ({table, columns, userid, pagename, tablename}) => { const { getState, options: { @@ -73,7 +73,7 @@ const DataTable_TopToolbar = ({table, columns}) => { }} > - +
)} diff --git a/src/core/components/NotificationDesign/AskForKeep.jsx b/src/core/components/NotificationDesign/AskForKeep.jsx index 1d688a9..7a68d2f 100644 --- a/src/core/components/NotificationDesign/AskForKeep.jsx +++ b/src/core/components/NotificationDesign/AskForKeep.jsx @@ -1,6 +1,6 @@ 'use client' -import BeenhereIcon from '@mui/icons-material/Beenhere'; +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"; @@ -14,10 +14,10 @@ function AskForKeep({onSaveFilter}) { return ( - + ذخیره سازی اطلاعات - + @@ -34,8 +34,8 @@ function AskForKeep({onSaveFilter}) { From acc13ef1d50ef93365fb421e1ab78d6206b0831a Mon Sep 17 00:00:00 2001 From: Mohammad Jalali Date: Sun, 23 Jun 2024 09:45:25 +0330 Subject: [PATCH 10/13] complete making needed data for keeping in local storage --- src/app/(withAuth)/dashboard/template.js | 2 - src/components/home/index.jsx | 3 +- src/core/components/DataTable/Main.js | 2 + .../DataTable/filter/FilterBody.jsx | 87 ++++++++++++------- .../DataTable/filter/FilterBodyField.jsx | 10 +-- .../filter/fieldsType/CustomTextField.jsx | 1 + src/core/components/DataTable/index.js | 5 +- src/lib/contexts/DataTable.jsx | 15 ++++ src/lib/hooks/useDataTable.jsx | 9 ++ 9 files changed, 94 insertions(+), 40 deletions(-) create mode 100644 src/lib/contexts/DataTable.jsx create mode 100644 src/lib/hooks/useDataTable.jsx diff --git a/src/app/(withAuth)/dashboard/template.js b/src/app/(withAuth)/dashboard/template.js index 9b2fea8..62759c6 100644 --- a/src/app/(withAuth)/dashboard/template.js +++ b/src/app/(withAuth)/dashboard/template.js @@ -2,7 +2,6 @@ import {Box, Stack} from "@mui/material"; import HeaderWithLogo from "@/components/layouts/dashboard/headerWithLogo"; import HeaderWithSidebar from "@/components/layouts/dashboard/headerWithSidebar"; import 'react-toastify/dist/ReactToastify.css'; -import {ToastContainer} from "react-toastify"; const Template = ({children}) => { return ( @@ -10,7 +9,6 @@ const Template = ({children}) => { {children} - ) diff --git a/src/components/home/index.jsx b/src/components/home/index.jsx index 359e13e..659d11f 100644 --- a/src/components/home/index.jsx +++ b/src/components/home/index.jsx @@ -87,11 +87,10 @@ function HomeComponent() { id: "price", enableColumnFilter: true, datatype: "numeric", - filterFn: "between", + filterFn: "equals", columnFilterModeOptions: [ "equals", "notEquals", - "between" ], }, { diff --git a/src/core/components/DataTable/Main.js b/src/core/components/DataTable/Main.js index 89fda97..09300df 100644 --- a/src/core/components/DataTable/Main.js +++ b/src/core/components/DataTable/Main.js @@ -4,6 +4,7 @@ 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"; const data = [ { @@ -74,6 +75,7 @@ const data = [ ]; const DataTable_Main = (props) => { + const {filterData} = useDataTable(); const {userId, pageName, tableName, columns, initialStateProps} = props const flatColumns = flattenArrayOfObjects(columns, 'columns') diff --git a/src/core/components/DataTable/filter/FilterBody.jsx b/src/core/components/DataTable/filter/FilterBody.jsx index a214186..17f830c 100644 --- a/src/core/components/DataTable/filter/FilterBody.jsx +++ b/src/core/components/DataTable/filter/FilterBody.jsx @@ -3,12 +3,13 @@ import {Box, Button, Drawer, styled} from "@mui/material"; import {Form, Formik} from "formik"; import useTableSetting from "@/lib/hooks/useTableSetting"; -import {useEffect, useState} from "react"; +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, @@ -30,6 +31,13 @@ const ScrollBox = styled(Box)({ function FilterBody({columns, drawerState, setDrawerState, userId, pageName, tableName}) { const {settingStore, filterAction} = useTableSetting(); const [initialValues, setInitialValues] = useState({}); + const [validationSchema, setValidationSchema] = useState({}); + const {filterData, setFilterData} = useDataTable(); + const filterDataRef = useRef(filterData); // Create a ref to hold the latest filterData + + useEffect(() => { + filterDataRef.current = filterData; // Update ref whenever filterData changes + }, [filterData]); useEffect(() => { const values = columns.reduce((acc, column) => { @@ -37,18 +45,21 @@ function FilterBody({columns, drawerState, setDrawerState, userId, pageName, tab const filter = settingStore?.[userId]?.[pageName]?.[tableName]?.['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 @@ -56,39 +67,47 @@ function FilterBody({columns, drawerState, setDrawerState, userId, pageName, tab } return acc; }, {}); - setInitialValues(values); - }, [columns, settingStore, userId, pageName, tableName]); + setInitialValues(Object.keys(filterData).length !== 0 ? filterData : values); + }, [columns, settingStore, userId, pageName, tableName, 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 validationSchema = Yup.object().shape( - columns.reduce((acc, column) => { - if (column._filterFn === "between") { - acc[column.id] = Yup.object().shape({ - value: Yup.array() - .of(Yup.string().nullable()) - .test({ - test(value, ctx) { - const [start, end] = value || ["", ""]; - if (column.datatype === "numeric" && start && end && 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; - }, {}) - ); const handleSubmit = (values, {setSubmitting}) => { toast.dismiss({containerId: "filtering"}); setDrawerState(false); + setFilterData(values); toast(, { containerId: "filtering", className: "filter-toast", @@ -100,6 +119,15 @@ function FilterBody({columns, drawerState, setDrawerState, userId, pageName, tab }; const onSaveFilter = () => { + const currentFilterData = filterDataRef.current; // Use the ref to get the latest filterData + 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); + console.log("arrayOfObjects", arrayOfObjects); toast.dismiss({containerId: "filtering"}); }; @@ -168,7 +196,6 @@ function FilterBody({columns, drawerState, setDrawerState, userId, pageName, tab - )} diff --git a/src/core/components/DataTable/filter/FilterBodyField.jsx b/src/core/components/DataTable/filter/FilterBodyField.jsx index 1a91c05..b12e770 100644 --- a/src/core/components/DataTable/filter/FilterBodyField.jsx +++ b/src/core/components/DataTable/filter/FilterBodyField.jsx @@ -36,7 +36,7 @@ function FilterBodyField({ return ( <> - {column.datatype === "numeric" && filterParameters.filterFn === "between" ? ( + {filterParameters.datatype === "numeric" && filterParameters.filterFn === "between" ? ( - ) : column.datatype === "numeric" && filterParameters.filterFn === "equals" && Array.isArray(column.columnSelectOption) ? ( + ) : filterParameters.datatype === "numeric" && filterParameters.filterFn === "equals" && Array.isArray(column.columnSelectOption) ? ( - ) : column.datatype === "date" && filterParameters.filterFn === "equals" ? ( + ) : filterParameters.datatype === "date" && filterParameters.filterFn === "equals" ? ( - ) : column.datatype === "date" && filterParameters.filterFn === "between" ? ( + ) : filterParameters.datatype === "date" && filterParameters.filterFn === "between" ? ( - ) : column.datatype === "array" && filterParameters.filterFn === "equals" ? ( + ) : filterParameters.datatype === "array" && filterParameters.filterFn === "equals" ? ( { return ( - + + + ); }; diff --git a/src/lib/contexts/DataTable.jsx b/src/lib/contexts/DataTable.jsx new file mode 100644 index 0000000..975b859 --- /dev/null +++ b/src/lib/contexts/DataTable.jsx @@ -0,0 +1,15 @@ +import {createContext, useState} from "react"; + +export const DataTableContext = createContext(); + +const DataTableProvider = ({children}) => { + const [filterData, setFilterData] = useState({}); + + return ( + + {children} + + ); +}; + +export default DataTableProvider; \ No newline at end of file diff --git a/src/lib/hooks/useDataTable.jsx b/src/lib/hooks/useDataTable.jsx new file mode 100644 index 0000000..ba7acb5 --- /dev/null +++ b/src/lib/hooks/useDataTable.jsx @@ -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; From 2777cdba08b990efa4b8160b105c0533b03d02a8 Mon Sep 17 00:00:00 2001 From: Mohammad Jalali Date: Mon, 24 Jun 2024 14:49:41 +0330 Subject: [PATCH 11/13] complete filter part of datatable --- src/core/components/DataTable/filter/FilterBody.jsx | 3 ++- .../components/DataTable/filter/fieldsType/CustomSelect.jsx | 1 + 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/src/core/components/DataTable/filter/FilterBody.jsx b/src/core/components/DataTable/filter/FilterBody.jsx index 17f830c..6d020a2 100644 --- a/src/core/components/DataTable/filter/FilterBody.jsx +++ b/src/core/components/DataTable/filter/FilterBody.jsx @@ -187,10 +187,11 @@ function FilterBody({columns, drawerState, setDrawerState, userId, pageName, tab 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", - }, width: "50%" + } }}> اعمال فیلتر diff --git a/src/core/components/DataTable/filter/fieldsType/CustomSelect.jsx b/src/core/components/DataTable/filter/fieldsType/CustomSelect.jsx index 6fa20e4..44f0599 100644 --- a/src/core/components/DataTable/filter/fieldsType/CustomSelect.jsx +++ b/src/core/components/DataTable/filter/fieldsType/CustomSelect.jsx @@ -18,6 +18,7 @@ function CustomSelect({column, filterParameters, defaultFilterTranslation, setFi setFieldValue(`${column.id}.value`, e.target.value) }} > + {column.header} {columnSelectOption.map((option) => ( Date: Wed, 26 Jun 2024 10:25:22 +0330 Subject: [PATCH 12/13] debug name props problems --- src/components/home/index.jsx | 2 +- src/core/components/DataTable/Main.js | 20 +++++++++---------- .../DataTable/filter/FilterBody.jsx | 15 +++++++------- .../components/DataTable/filter/index.jsx | 6 +++--- src/core/components/DataTable/table/Paper.js | 6 +++--- .../DataTable/toolbar/TopToolbar.js | 5 +++-- 6 files changed, 27 insertions(+), 27 deletions(-) diff --git a/src/components/home/index.jsx b/src/components/home/index.jsx index 659d11f..7af2edf 100644 --- a/src/components/home/index.jsx +++ b/src/components/home/index.jsx @@ -141,7 +141,7 @@ function HomeComponent() { return ( <> - + ); diff --git a/src/core/components/DataTable/Main.js b/src/core/components/DataTable/Main.js index 09300df..2110b34 100644 --- a/src/core/components/DataTable/Main.js +++ b/src/core/components/DataTable/Main.js @@ -76,18 +76,18 @@ const data = [ const DataTable_Main = (props) => { const {filterData} = useDataTable(); - const {userId, pageName, tableName, columns, initialStateProps} = props + const {user_id, page_name, table_name, columns, initialStateProps} = props const flatColumns = flattenArrayOfObjects(columns, 'columns') const {settingStore, hideAction, sortAction} = useTableSetting(); const onColumnVisibilityChange = (event) => { const settingValue = event(); - hideAction(userId, pageName, tableName, settingValue, flatColumns); + hideAction(user_id, page_name, table_name, settingValue, flatColumns); }; const onSortingChange = (event) => { - const settingValue = event(settingStore?.[userId]?.[pageName]?.[tableName]?.['sorts'] || []); - sortAction(userId, pageName, tableName, settingValue, flatColumns); + const settingValue = event(settingStore?.[user_id]?.[page_name]?.[table_name]?.['sorts'] || []); + sortAction(user_id, page_name, table_name, settingValue, flatColumns); } const table = useMaterialReactTable({ @@ -102,13 +102,13 @@ const DataTable_Main = (props) => { ), initialState: { density: 'compact', - columnVisibility: settingStore?.[userId]?.[pageName]?.[tableName]?.['hides'], - sorting: settingStore?.[userId]?.[pageName]?.[tableName]?.['sorts'] || [], + columnVisibility: settingStore?.[user_id]?.[page_name]?.[table_name]?.['hides'], + sorting: settingStore?.[user_id]?.[page_name]?.[table_name]?.['sorts'] || [], ...initialStateProps }, state: { - columnVisibility: settingStore?.[userId]?.[pageName]?.[tableName]?.['hides'], - sorting: settingStore?.[userId]?.[pageName]?.[tableName]?.['sorts'] || [] + columnVisibility: settingStore?.[user_id]?.[page_name]?.[table_name]?.['hides'], + sorting: settingStore?.[user_id]?.[page_name]?.[table_name]?.['sorts'] || [] }, muiTableHeadProps: { sx: { @@ -141,8 +141,8 @@ const DataTable_Main = (props) => { ...props }) - return ; + return ; }; export default DataTable_Main; diff --git a/src/core/components/DataTable/filter/FilterBody.jsx b/src/core/components/DataTable/filter/FilterBody.jsx index 6d020a2..385981b 100644 --- a/src/core/components/DataTable/filter/FilterBody.jsx +++ b/src/core/components/DataTable/filter/FilterBody.jsx @@ -28,21 +28,20 @@ const ScrollBox = styled(Box)({ } }); -function FilterBody({columns, drawerState, setDrawerState, userId, pageName, tableName}) { +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); // Create a ref to hold the latest filterData - + const filterDataRef = useRef(filterData); useEffect(() => { - filterDataRef.current = filterData; // Update ref whenever filterData changes + filterDataRef.current = filterData; }, [filterData]); useEffect(() => { const values = columns.reduce((acc, column) => { if (!column.enableColumnFilter) return acc; - const filter = settingStore?.[userId]?.[pageName]?.[tableName]?.['filters']?.find((filter) => filter.id === column.id); + 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, @@ -68,7 +67,7 @@ function FilterBody({columns, drawerState, setDrawerState, userId, pageName, tab return acc; }, {}); setInitialValues(Object.keys(filterData).length !== 0 ? filterData : values); - }, [columns, settingStore, userId, pageName, tableName, filterData]); + }, [columns, settingStore, user_id, page_name, table_name, filterData]); useEffect(() => { @@ -119,7 +118,7 @@ function FilterBody({columns, drawerState, setDrawerState, userId, pageName, tab }; const onSaveFilter = () => { - const currentFilterData = filterDataRef.current; // Use the ref to get the latest filterData + const currentFilterData = filterDataRef.current; const arrayOfObjects = Object.keys(currentFilterData).map(key => { const value = currentFilterData[key].value; if (value !== "" && @@ -127,7 +126,7 @@ function FilterBody({columns, drawerState, setDrawerState, userId, pageName, tab return currentFilterData[key]; } }).filter(Boolean); - console.log("arrayOfObjects", arrayOfObjects); + filterAction(user_id, page_name, table_name, arrayOfObjects, columns) toast.dismiss({containerId: "filtering"}); }; diff --git a/src/core/components/DataTable/filter/index.jsx b/src/core/components/DataTable/filter/index.jsx index faa01c9..65a93d2 100644 --- a/src/core/components/DataTable/filter/index.jsx +++ b/src/core/components/DataTable/filter/index.jsx @@ -4,14 +4,14 @@ import {useState} from "react"; import FilterButton from "@/core/components/DataTable/filter/FilterButton"; import FilterBody from "@/core/components/DataTable/filter/FilterBody"; -function FilterColumn({columns, userid, pagename, tablename}) { +function FilterColumn({columns, user_id, page_name, table_name}) { const [open, setOpen] = useState(false); return ( <> - + ); } diff --git a/src/core/components/DataTable/table/Paper.js b/src/core/components/DataTable/table/Paper.js index 7380cf0..d5431b7 100644 --- a/src/core/components/DataTable/table/Paper.js +++ b/src/core/components/DataTable/table/Paper.js @@ -65,9 +65,9 @@ const DataTable_Paper = ({table, ...rest}) => { > {enableTopToolbar && (parseFromValuesOrFunc(renderTopToolbar, {table}) ?? ( - + ))} {enableBottomToolbar && diff --git a/src/core/components/DataTable/toolbar/TopToolbar.js b/src/core/components/DataTable/toolbar/TopToolbar.js index 1adf4d3..eabe836 100644 --- a/src/core/components/DataTable/toolbar/TopToolbar.js +++ b/src/core/components/DataTable/toolbar/TopToolbar.js @@ -6,7 +6,7 @@ import DataTable_ToolbarInternalButtons from "./ToolbarInternalButtons"; import FilterColumn from "@/core/components/DataTable/filter"; import RefactorTable from "@/core/components/DataTable/refactor/RefactorTable"; -const DataTable_TopToolbar = ({table, columns, userid, pagename, tablename}) => { +const DataTable_TopToolbar = ({table, columns, user_id, page_name, table_name}) => { const { getState, options: { @@ -73,7 +73,8 @@ const DataTable_TopToolbar = ({table, columns, userid, pagename, tablename}) => }} > - + )} From fa8caad7ef729c58873f5d813990cd921ee6e70f Mon Sep 17 00:00:00 2001 From: Mohammad Jalali Date: Sat, 29 Jun 2024 10:12:16 +0330 Subject: [PATCH 13/13] complete making fetchURL for swr request complete filter/sort/pagination/pagesie (all data that have been needed for Datatable) --- package.json | 1 + src/components/home/index.jsx | 2 +- src/core/components/DataTable/Main.js | 29 +++++++++++++++++-- src/core/components/DataTable/table/Paper.js | 7 +++-- .../DataTable/toolbar/TopToolbar.js | 4 +-- 5 files changed, 34 insertions(+), 9 deletions(-) diff --git a/package.json b/package.json index 8c05f3c..b4ddfd0 100644 --- a/package.json +++ b/package.json @@ -29,6 +29,7 @@ "sass": "^1.75.0", "stylis": "^4.3.1", "stylis-plugin-rtl": "^2.1.1", + "swr": "^2.2.5", "yup": "^1.4.0" }, "devDependencies": { diff --git a/src/components/home/index.jsx b/src/components/home/index.jsx index 7af2edf..090a572 100644 --- a/src/components/home/index.jsx +++ b/src/components/home/index.jsx @@ -141,7 +141,7 @@ function HomeComponent() { return ( <> - + ); diff --git a/src/core/components/DataTable/Main.js b/src/core/components/DataTable/Main.js index 2110b34..ec33f55 100644 --- a/src/core/components/DataTable/Main.js +++ b/src/core/components/DataTable/Main.js @@ -5,6 +5,7 @@ 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 data = [ { @@ -76,10 +77,30 @@ const data = [ const DataTable_Main = (props) => { const {filterData} = useDataTable(); - const {user_id, page_name, table_name, columns, initialStateProps} = props - + 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; + + const fetchUrl = useMemo(() => { + const params = new URLSearchParams(); + params.set("start", `${pagination.pageIndex * pagination.pageSize}`); + params.set("size", pagination.pageSize); + 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(); @@ -108,7 +129,8 @@ const DataTable_Main = (props) => { }, state: { columnVisibility: settingStore?.[user_id]?.[page_name]?.[table_name]?.['hides'], - sorting: settingStore?.[user_id]?.[page_name]?.[table_name]?.['sorts'] || [] + sorting: settingStore?.[user_id]?.[page_name]?.[table_name]?.['sorts'] || [], + pagination }, muiTableHeadProps: { sx: { @@ -135,6 +157,7 @@ const DataTable_Main = (props) => { }, manualFiltering: true, manualPagination: true, + onPaginationChange: setPagination, manualSorting: true, onColumnVisibilityChange: onColumnVisibilityChange, onSortingChange: onSortingChange, diff --git a/src/core/components/DataTable/table/Paper.js b/src/core/components/DataTable/table/Paper.js index d5431b7..9a3be31 100644 --- a/src/core/components/DataTable/table/Paper.js +++ b/src/core/components/DataTable/table/Paper.js @@ -65,9 +65,10 @@ const DataTable_Paper = ({table, ...rest}) => { > {enableTopToolbar && (parseFromValuesOrFunc(renderTopToolbar, {table}) ?? ( - + ))} {enableBottomToolbar && diff --git a/src/core/components/DataTable/toolbar/TopToolbar.js b/src/core/components/DataTable/toolbar/TopToolbar.js index eabe836..7a321e2 100644 --- a/src/core/components/DataTable/toolbar/TopToolbar.js +++ b/src/core/components/DataTable/toolbar/TopToolbar.js @@ -6,7 +6,7 @@ import DataTable_ToolbarInternalButtons from "./ToolbarInternalButtons"; import FilterColumn from "@/core/components/DataTable/filter"; import RefactorTable from "@/core/components/DataTable/refactor/RefactorTable"; -const DataTable_TopToolbar = ({table, columns, user_id, page_name, table_name}) => { +const DataTable_TopToolbar = ({table, columns, table_url, user_id, page_name, table_name}) => { const { getState, options: { @@ -73,7 +73,7 @@ const DataTable_TopToolbar = ({table, columns, user_id, page_name, table_name}) }} > -