From 0d35263ca22377652a38c3143da23d6de24b8824 Mon Sep 17 00:00:00 2001 From: Mohammad Jalali Date: Sun, 18 Feb 2024 11:37:30 +0330 Subject: [PATCH 01/11] datatable reading local storage --- package.json | 1 + src/app/layout.js | 12 ++- src/app/page.js | 10 +- src/components/DataTableTest.jsx | 166 ++++++++++++++++++++++++++++++ src/lib/contexts/tableSetting.jsx | 59 +++++++++++ src/lib/hooks/useTableSetting.jsx | 9 ++ 6 files changed, 251 insertions(+), 6 deletions(-) create mode 100644 src/components/DataTableTest.jsx create mode 100644 src/lib/contexts/tableSetting.jsx create mode 100644 src/lib/hooks/useTableSetting.jsx diff --git a/package.json b/package.json index bf60bc4..0eab6d8 100644 --- a/package.json +++ b/package.json @@ -15,6 +15,7 @@ "@mui/icons-material": "^5.15.6", "@mui/material": "^5.15.6", "@mui/material-nextjs": "^5.15.6", + "material-react-table": "^2.11.2", "next": "14.1.0", "react": "^18", "react-dom": "^18", diff --git a/src/app/layout.js b/src/app/layout.js index 88b0280..c23a7ec 100644 --- a/src/app/layout.js +++ b/src/app/layout.js @@ -1,11 +1,17 @@ +import {TableSettingProvider} from "@/lib/contexts/tableSetting"; + export const metadata = { title: 'سامانه جامع راهداری', } export default function RootLayout({children}) { - return ( + return ( + - {children} + + {children} + - ) + + ) } diff --git a/src/app/page.js b/src/app/page.js index 7be9aa2..2534242 100644 --- a/src/app/page.js +++ b/src/app/page.js @@ -1,5 +1,9 @@ -const Page = () => { - return (<>) +import DataTableTest from "@/components/DataTableTest"; + +function page() { + return ( + + ); } -export default Page \ No newline at end of file +export default page; diff --git a/src/components/DataTableTest.jsx b/src/components/DataTableTest.jsx new file mode 100644 index 0000000..e8d655d --- /dev/null +++ b/src/components/DataTableTest.jsx @@ -0,0 +1,166 @@ +"use client" +import {useMemo, useState} from 'react'; +import {MaterialReactTable} from 'material-react-table'; +import useTableSetting from "@/lib/hooks/useTableSetting"; + + +const data = [ + { + name: { + firstName: 'John', + lastName: 'Doe', + }, + address: '261 Erdman Ford', + city: 'East Daphne', + state: 'Kentucky', + }, + { + name: { + firstName: 'Jane', + lastName: 'Doe', + }, + address: '769 Dominic Grove', + city: 'Columbus', + state: 'Ohio', + }, + { + name: { + firstName: 'Joe', + lastName: 'Doe', + }, + address: '566 Brakus Inlet', + city: 'South Linda', + state: 'West Virginia', + }, + { + name: { + firstName: 'Kevin', + lastName: 'Vandy', + }, + address: '722 Emie Stream', + city: 'Lincoln', + state: 'Nebraska', + }, + { + name: { + firstName: 'Joshua', + lastName: 'Rolluffs', + }, + address: '32188 Larkin Turnpike', + city: 'Charleston', + state: 'South Carolina', + }, +]; + +const TestDataTable = () => { + const [userId, setUserId] = useState(2); + const [pageName, setPageName] = useState('loan'); + const [tableName, setTableName] = useState('loan_table'); + const {settingStore, hideAction, filterAction, sortAction} = useTableSetting(); + + const columns = useMemo( + () => [ + { + accessorKey: 'name.firstName', + header: 'First Name', + size: 150, + id: "firstName", + enableColumnFilter: true, + datatype: "text", + filterFn: "contains", + columnFilterModeOptions: [ + "equals", + "notEquals", + "contains" + ], + }, + { + accessorKey: 'name.lastName', + header: 'Last Name', + size: 150, + id: "lastName", + enableColumnFilter: true, + datatype: "text", + filterFn: "contains", + columnFilterModeOptions: [ + "equals", + "notEquals", + "contains" + ], + }, + { + accessorKey: 'address', + header: 'Address', + size: 200, + id: "address", + enableColumnFilter: true, + datatype: "text", + filterFn: "contains", + columnFilterModeOptions: [ + "equals", + "notEquals", + "contains" + ], + }, + { + accessorKey: 'city', + header: 'City', + size: 150, + id: "city", + enableColumnFilter: true, + datatype: "text", + filterFn: "contains", + columnFilterModeOptions: [ + "equals", + "notEquals", + "contains", + "lessThan", + "greaterThan", + "between", + ], + + }, + { + accessorKey: 'state', + header: 'State', + size: 150, + id: "state", + enableColumnFilter: true, + datatype: "text", + filterFn: "contains", + columnFilterModeOptions: [ + "equals", + "notEquals", + "contains" + ], + }, + ], + [], + ); + const onColumnVisibilityChange = (event) => { + const settingValue = event(); + hideAction(userId, pageName, tableName, settingValue); + }; + const onSortingChange = (event) => { + const settingValue = event(); + sortAction(userId, pageName, tableName, settingValue); + } + + return ; +}; + +export default TestDataTable; + diff --git a/src/lib/contexts/tableSetting.jsx b/src/lib/contexts/tableSetting.jsx new file mode 100644 index 0000000..520bff5 --- /dev/null +++ b/src/lib/contexts/tableSetting.jsx @@ -0,0 +1,59 @@ +'use client' + +import {createContext, useEffect, useState} from "react"; + +export const TableSettingContext = createContext(); + +export const TableSettingProvider = ({children}) => { + const [settingStore, setSettingStore] = useState({}); + + useEffect(() => { + const _localStorage = localStorage.getItem("_setting-app") + if (_localStorage) + setSettingStore(JSON.parse(_localStorage)) + }, []); + + const hideAction = (user_id, page_name, table_name, settingValue) => { + updateSettingStorage(user_id, page_name, table_name, "hides", settingValue); + } + const sortAction = (user_id, page_name, table_name, settingValue) => { + updateSettingStorage(user_id, page_name, table_name, "sorts", settingValue); + } + const filterAction = (user_id, page_name, table_name, settingValue) => { + updateSettingStorage(user_id, page_name, table_name, "filters", settingValue); + } + const updateSettingStorage = (user_id, page_name, table_name, settingType, settingValue) => { + const prevLocalStorage = JSON.parse(localStorage.getItem("_setting-app")) || {}; + const userSettings = prevLocalStorage[user_id] || {}; + const pageSettings = userSettings[page_name] || {}; + const tableSettings = pageSettings[table_name] || {}; + let newSettings; + if (settingType === "sorts") { + newSettings = [...settingValue]; + } else { + newSettings = {...tableSettings[settingType] || {}, ...settingValue}; + } + const updatedLocalStorage = { + ...prevLocalStorage, + [user_id]: { + ...userSettings, + [page_name]: { + ...pageSettings, + [table_name]: { + ...tableSettings, + [settingType]: Array.isArray(settingValue) ? [...newSettings] : {...newSettings}, + }, + }, + }, + }; + localStorage.setItem("_setting-app", JSON.stringify(updatedLocalStorage)); + setSettingStore(updatedLocalStorage); + } + + return ( + + {children} + + ); +}; \ No newline at end of file diff --git a/src/lib/hooks/useTableSetting.jsx b/src/lib/hooks/useTableSetting.jsx new file mode 100644 index 0000000..cc7aaa7 --- /dev/null +++ b/src/lib/hooks/useTableSetting.jsx @@ -0,0 +1,9 @@ +import {useContext} from "react"; +import {TableSettingContext} from "../contexts/tableSetting"; + +const useUser = () => { + const {settingStore, hideAction, sortAction, filterAction} = useContext(TableSettingContext); + return {settingStore, hideAction, sortAction, filterAction}; +}; + +export default useUser; From e7ad977ede10a61327300ad9ca9aea234be7fed0 Mon Sep 17 00:00:00 2001 From: AminGhasempoor Date: Sun, 18 Feb 2024 14:42:45 +0330 Subject: [PATCH 02/11] useCallback --- src/components/DataTableTest.jsx | 32 ++++++++++++++++--------------- src/lib/contexts/tableSetting.jsx | 16 +++++++--------- 2 files changed, 24 insertions(+), 24 deletions(-) diff --git a/src/components/DataTableTest.jsx b/src/components/DataTableTest.jsx index e8d655d..4daf803 100644 --- a/src/components/DataTableTest.jsx +++ b/src/components/DataTableTest.jsx @@ -56,7 +56,8 @@ const TestDataTable = () => { const [userId, setUserId] = useState(2); const [pageName, setPageName] = useState('loan'); const [tableName, setTableName] = useState('loan_table'); - const {settingStore, hideAction, filterAction, sortAction} = useTableSetting(); + const {settingStore, hideAction, filterAction, sortAction, oldSorting} = useTableSetting(); + console.log(settingStore) const columns = useMemo( () => [ @@ -142,23 +143,24 @@ const TestDataTable = () => { hideAction(userId, pageName, tableName, settingValue); }; const onSortingChange = (event) => { - const settingValue = event(); + const settingValue = event(settingStore?.[userId]?.[pageName]?.[tableName]?.['sorts'] || []); sortAction(userId, pageName, tableName, settingValue); } - return ; }; diff --git a/src/lib/contexts/tableSetting.jsx b/src/lib/contexts/tableSetting.jsx index 520bff5..ac5ba6d 100644 --- a/src/lib/contexts/tableSetting.jsx +++ b/src/lib/contexts/tableSetting.jsx @@ -1,24 +1,22 @@ 'use client' - -import {createContext, useEffect, useState} from "react"; - +import {createContext, useCallback, useEffect, useState} from "react"; export const TableSettingContext = createContext(); - export const TableSettingProvider = ({children}) => { const [settingStore, setSettingStore] = useState({}); useEffect(() => { const _localStorage = localStorage.getItem("_setting-app") - if (_localStorage) + if (_localStorage) { setSettingStore(JSON.parse(_localStorage)) + } }, []); - const hideAction = (user_id, page_name, table_name, settingValue) => { + const hideAction = useCallback((user_id, page_name, table_name, settingValue) => { updateSettingStorage(user_id, page_name, table_name, "hides", settingValue); - } - const sortAction = (user_id, page_name, table_name, settingValue) => { + },[]) + const sortAction = useCallback((user_id, page_name, table_name, settingValue) => { updateSettingStorage(user_id, page_name, table_name, "sorts", settingValue); - } + },[]) const filterAction = (user_id, page_name, table_name, settingValue) => { updateSettingStorage(user_id, page_name, table_name, "filters", settingValue); } From fe8364fbb94e2452fdcaaab3921650f5fdd7d51a Mon Sep 17 00:00:00 2001 From: AminGhasempoor Date: Mon, 19 Feb 2024 13:22:03 +0330 Subject: [PATCH 03/11] summary text --- src/components/DataTableTest.jsx | 16 ++++---- src/lib/contexts/tableSetting.jsx | 63 +++++++++++++++++++++++++++---- 2 files changed, 64 insertions(+), 15 deletions(-) diff --git a/src/components/DataTableTest.jsx b/src/components/DataTableTest.jsx index 4daf803..d9960ac 100644 --- a/src/components/DataTableTest.jsx +++ b/src/components/DataTableTest.jsx @@ -57,13 +57,12 @@ const TestDataTable = () => { const [pageName, setPageName] = useState('loan'); const [tableName, setTableName] = useState('loan_table'); const {settingStore, hideAction, filterAction, sortAction, oldSorting} = useTableSetting(); - console.log(settingStore) const columns = useMemo( () => [ { accessorKey: 'name.firstName', - header: 'First Name', + header: 'نام', size: 150, id: "firstName", enableColumnFilter: true, @@ -77,7 +76,7 @@ const TestDataTable = () => { }, { accessorKey: 'name.lastName', - header: 'Last Name', + header: 'نام خانوادگی', size: 150, id: "lastName", enableColumnFilter: true, @@ -91,7 +90,7 @@ const TestDataTable = () => { }, { accessorKey: 'address', - header: 'Address', + header: 'آدرس', size: 200, id: "address", enableColumnFilter: true, @@ -105,7 +104,7 @@ const TestDataTable = () => { }, { accessorKey: 'city', - header: 'City', + header: 'شهر', size: 150, id: "city", enableColumnFilter: true, @@ -123,9 +122,10 @@ const TestDataTable = () => { }, { accessorKey: 'state', - header: 'State', + header: 'وضعیت', size: 150, id: "state", + text:'نام', enableColumnFilter: true, datatype: "text", filterFn: "contains", @@ -140,11 +140,11 @@ const TestDataTable = () => { ); const onColumnVisibilityChange = (event) => { const settingValue = event(); - hideAction(userId, pageName, tableName, settingValue); + hideAction(userId, pageName, tableName, settingValue, columns); }; const onSortingChange = (event) => { const settingValue = event(settingStore?.[userId]?.[pageName]?.[tableName]?.['sorts'] || []); - sortAction(userId, pageName, tableName, settingValue); + sortAction(userId, pageName, tableName, settingValue, columns); } return { const [settingStore, setSettingStore] = useState({}); + useEffect(() => { const _localStorage = localStorage.getItem("_setting-app") if (_localStorage) { @@ -11,16 +13,16 @@ export const TableSettingProvider = ({children}) => { } }, []); - const hideAction = useCallback((user_id, page_name, table_name, settingValue) => { - updateSettingStorage(user_id, page_name, table_name, "hides", settingValue); - },[]) - const sortAction = useCallback((user_id, page_name, table_name, settingValue) => { - updateSettingStorage(user_id, page_name, table_name, "sorts", settingValue); - },[]) + const hideAction = useCallback((user_id, page_name, table_name, settingValue, columns) => { + updateSettingStorage(user_id, page_name, table_name, "hides", settingValue, columns); + }, []) + const sortAction = useCallback((user_id, page_name, table_name, settingValue, columns) => { + updateSettingStorage(user_id, page_name, table_name, "sorts", settingValue, columns); + }, []) const filterAction = (user_id, page_name, table_name, settingValue) => { updateSettingStorage(user_id, page_name, table_name, "filters", settingValue); } - const updateSettingStorage = (user_id, page_name, table_name, settingType, settingValue) => { + const updateSettingStorage = (user_id, page_name, table_name, settingType, settingValue, columns) => { const prevLocalStorage = JSON.parse(localStorage.getItem("_setting-app")) || {}; const userSettings = prevLocalStorage[user_id] || {}; const pageSettings = userSettings[page_name] || {}; @@ -40,6 +42,10 @@ export const TableSettingProvider = ({children}) => { [table_name]: { ...tableSettings, [settingType]: Array.isArray(settingValue) ? [...newSettings] : {...newSettings}, + summary: SummaryTextMessage({ + ...tableSettings, + [settingType]: Array.isArray(settingValue) ? [...newSettings] : {...newSettings}, + }, columns) }, }, }, @@ -48,6 +54,49 @@ export const TableSettingProvider = ({children}) => { setSettingStore(updatedLocalStorage); } + const SummaryTextMessage = (values, columns) => { + let SummaryText = ""; + let HideText = ""; + let FilterText; + let SortText = ""; + + if (values.sorts && values.sorts.length > 0) { + const _list = [] + for (const sort of values.sorts) { + const _column = columns.find(column => column.id == sort.id) + _list.push(`${_column.header}` + `(${sort.desc ? "نزولی" : "صعودی"})`) + } + SortText = " مرتب شده بر اساس " + _list.join(", ") + } + + if (values.hides) { + const hidesArray = Object.entries(values.hides).map((e) => ({id: e[0], value: e[1]})) + if (hidesArray.length > 0) { + const _list = [] + for (const hide of hidesArray) { + if (hide.value) continue + const _column = columns.find(c => c.id == hide.id) + _list.push(_column.header) + } + HideText = "ستون های مخفی شده : " + _list.join(", "); + } + } + + if (HideText || SortText) { + if (SortText) { + SummaryText += SortText; + if (HideText) { + SummaryText += " ; "; + } + } + if (HideText) { + SummaryText += HideText; + } + } + + return SummaryText; + }; + return ( From 883a7ddfab5d05390334925d2ea44eed6e555992 Mon Sep 17 00:00:00 2001 From: AminGhasempoor Date: Mon, 19 Feb 2024 13:56:51 +0330 Subject: [PATCH 04/11] summary text localStorage --- src/components/DataTableTest.jsx | 38 ++++++++++++++++++------------- src/lib/contexts/tableSetting.jsx | 6 +++-- 2 files changed, 26 insertions(+), 18 deletions(-) diff --git a/src/components/DataTableTest.jsx b/src/components/DataTableTest.jsx index d9960ac..d255aaa 100644 --- a/src/components/DataTableTest.jsx +++ b/src/components/DataTableTest.jsx @@ -2,6 +2,7 @@ import {useMemo, useState} from 'react'; import {MaterialReactTable} from 'material-react-table'; import useTableSetting from "@/lib/hooks/useTableSetting"; +import {Typography} from "@mui/material"; const data = [ @@ -56,7 +57,7 @@ const TestDataTable = () => { const [userId, setUserId] = useState(2); const [pageName, setPageName] = useState('loan'); const [tableName, setTableName] = useState('loan_table'); - const {settingStore, hideAction, filterAction, sortAction, oldSorting} = useTableSetting(); + const {settingStore, hideAction, filterAction, sortAction,} = useTableSetting(); const columns = useMemo( () => [ @@ -147,21 +148,26 @@ const TestDataTable = () => { sortAction(userId, pageName, tableName, settingValue, columns); } - return ; + return ( + <> + {settingStore?.[userId]?.[pageName]?.[tableName]?.['summary']} + + + ); }; export default TestDataTable; diff --git a/src/lib/contexts/tableSetting.jsx b/src/lib/contexts/tableSetting.jsx index 0fa46bd..8ade22b 100644 --- a/src/lib/contexts/tableSetting.jsx +++ b/src/lib/contexts/tableSetting.jsx @@ -66,7 +66,8 @@ export const TableSettingProvider = ({children}) => { const _column = columns.find(column => column.id == sort.id) _list.push(`${_column.header}` + `(${sort.desc ? "نزولی" : "صعودی"})`) } - SortText = " مرتب شده بر اساس " + _list.join(", ") + if (_list.length > 0) + SortText = " مرتب شده بر اساس " + _list.join(", ") } if (values.hides) { @@ -78,7 +79,8 @@ export const TableSettingProvider = ({children}) => { const _column = columns.find(c => c.id == hide.id) _list.push(_column.header) } - HideText = "ستون های مخفی شده : " + _list.join(", "); + if (_list.length > 0) + HideText = "ستون های مخفی شده : " + _list.join(", "); } } From b386166162dc697fad0b286b8855099d3046b169 Mon Sep 17 00:00:00 2001 From: Yasiu1376 Date: Tue, 20 Feb 2024 15:35:15 +0330 Subject: [PATCH 05/11] FilterColumn --- src/app/page.js | 7 +- src/components/FilterColumn.jsx | 123 ++++++++++++++++++++++++++++++++ 2 files changed, 129 insertions(+), 1 deletion(-) create mode 100644 src/components/FilterColumn.jsx diff --git a/src/app/page.js b/src/app/page.js index 2534242..af32e3b 100644 --- a/src/app/page.js +++ b/src/app/page.js @@ -1,8 +1,13 @@ import DataTableTest from "@/components/DataTableTest"; +import FilterColumn from "@/components/FilterColumn"; function page() { return ( - + <> + + + + ); } diff --git a/src/components/FilterColumn.jsx b/src/components/FilterColumn.jsx new file mode 100644 index 0000000..08ab968 --- /dev/null +++ b/src/components/FilterColumn.jsx @@ -0,0 +1,123 @@ +"use client" +import { + Button, + Dialog, DialogActions, + DialogContent, + DialogTitle, + FormControl +} from '@mui/material'; +import {useFormik} from 'formik'; +import TextFieldWithFnBox from "@/components/TextFieldWithFnBox"; +import {useEffect, useState} from "react"; + +function FilterColumn({ onSubmit , column }) { + const [selectedFilters, setSelectedFilters] = useState([]); + + useEffect(() => { + const initialFilters = column + .filter(col => col.ColumnFiterStatus) + .map(col => ({ id: col.field, fn: col.filterFn })); + setSelectedFilters(initialFilters); + }, [column]); + + const handleSelectFilter = (fieldName, filterFn) => { + const updatedFilters = [...selectedFilters]; + const filterIndex = updatedFilters.findIndex(filter => filter.id === fieldName); + if (filterIndex !== -1) { + updatedFilters[filterIndex].fn = filterFn; + } else { + updatedFilters.push({ id: fieldName, fn: filterFn }); + } + setSelectedFilters(updatedFilters); + }; + + const formik = useFormik({ + initialValues: column.reduce((acc, column) => { + if (column.ColumnFiterStatus) { + acc[column.field] = ''; + } + return acc; + }, {}), + onSubmit: (values) => { + // const selectedFilters = [ + // { "id": "name", "value": values.name1, "fn": values.cityFn, "datatype": values.nameDatatype }, + // { "id": "navgan_id", "value": values.name2, "fn": values.nameFn, "datatype": values.nameDatatype } + // ]; + + const user_id = 456; + const page_name = 'loan'; + const table_name = "amir_table"; + + let prevLocalStorage = JSON.parse(localStorage.getItem("_setting-app")) || {}; + + const existingFilters = prevLocalStorage[user_id]?.[page_name]?.[table_name]?.filters || []; + + const updatedFilters = selectedFilters.reduce((acc, filter) => { + const currentValue = values[filter.id]; + const prevValue = formik.initialValues[filter.id]; + console.log(acc, filter) + // Check if the current value is empty and the previous value was not empty + if ((currentValue === '' || currentValue === undefined || currentValue === null) && prevValue !== '' && prevValue !== undefined && prevValue !== null) { + // Remove filter data from localStorage + const filterIndex = existingFilters.findIndex(f => f.id === filter.id); + console.log({filterIndex}) + if (filterIndex !== -1) { + existingFilters.splice(filterIndex, 1); + } + } else { + acc.push({ + ...filter, + value: currentValue, + datatype: column.find(col => col.field === filter.id).datatype + }); + } + + return acc; + }, []); + + + updatedFilters.forEach(newFilter => { + const existingFilterIndex = existingFilters.findIndex(filter => filter.id === newFilter.id); + existingFilterIndex !== -1 ? existingFilters[existingFilterIndex] = newFilter : existingFilters.push(newFilter); + }); + + prevLocalStorage[user_id] = prevLocalStorage[user_id] || {}; + prevLocalStorage[user_id][page_name] = prevLocalStorage[user_id][page_name] || {}; + prevLocalStorage[user_id][page_name][table_name] = { hides: {}, filters: existingFilters }; + + localStorage.setItem('_setting-app', JSON.stringify(prevLocalStorage)); + + onSubmit(updatedFilters); + } + }); + + + return ( + + Select Filters + + + {column.map((column, index) => ( + column.ColumnFiterStatus && + handleSelectFilter(column.field, filterFn)} + /> + ))} + + + + + + + ); +} + +export default FilterColumn; + + From 251d1db1ed4a71fa156b18c271433479afcc653d Mon Sep 17 00:00:00 2001 From: Yasiu1376 Date: Tue, 20 Feb 2024 15:37:56 +0330 Subject: [PATCH 06/11] FiletrCoumn --- package.json | 1 + src/components/TextFieldWithFnBox.jsx | 45 +++++++++++++++++++++++++++ 2 files changed, 46 insertions(+) create mode 100644 src/components/TextFieldWithFnBox.jsx diff --git a/package.json b/package.json index 0eab6d8..a74c3db 100644 --- a/package.json +++ b/package.json @@ -15,6 +15,7 @@ "@mui/icons-material": "^5.15.6", "@mui/material": "^5.15.6", "@mui/material-nextjs": "^5.15.6", + "formik": "^2.4.5", "material-react-table": "^2.11.2", "next": "14.1.0", "react": "^18", diff --git a/src/components/TextFieldWithFnBox.jsx b/src/components/TextFieldWithFnBox.jsx new file mode 100644 index 0000000..c8eff76 --- /dev/null +++ b/src/components/TextFieldWithFnBox.jsx @@ -0,0 +1,45 @@ +import {IconButton, Paper, TextField} from '@mui/material'; +import AlignHorizontalCenterIcon from '@mui/icons-material/AlignHorizontalCenter'; +import {useState} from "react"; +// import FilterBox from "@/components/FiterBox"; + +const TextFieldWithFnBox = ({formik, fieldName , label , defaultFilter , columnFilterModeOptions ,onSelectFilter}) => { + const [anchorEl, setAnchorEl] = useState(null); + const [open, setOpen] = useState(false); + + const handleClick = (event) => { + setOpen((prevOpen) => !prevOpen); + setAnchorEl(anchorEl ? null : event.currentTarget); + }; + + const handleClose = () => { + setOpen(false); + setAnchorEl(null); + }; + + return ( + <> + + + + ) + }} + sx={{ + position: 'relative' + }} + /> + {/**/} + + ); +}; + +export default TextFieldWithFnBox; From 76f8dfad06d6f888457dfd65d7ea60a0a34b915b Mon Sep 17 00:00:00 2001 From: Yasiu1376 Date: Wed, 21 Feb 2024 09:53:52 +0330 Subject: [PATCH 07/11] merge with mohamad branch --- src/app/page.js | 86 +++++++++++++++++++++++++++++++- src/components/DataTableTest.jsx | 81 +----------------------------- src/components/FilterColumn.jsx | 56 ++++----------------- 3 files changed, 94 insertions(+), 129 deletions(-) diff --git a/src/app/page.js b/src/app/page.js index af32e3b..ea420f9 100644 --- a/src/app/page.js +++ b/src/app/page.js @@ -1,11 +1,93 @@ import DataTableTest from "@/components/DataTableTest"; import FilterColumn from "@/components/FilterColumn"; +import {useMemo} from "react"; function page() { + + const columns = useMemo( + () => [ + { + accessorKey: 'name.firstName', + header: 'نام', + size: 150, + id: "firstName", + enableColumnFilter: true, + datatype: "text", + filterFn: "contains", + columnFilterModeOptions: [ + "equals", + "notEquals", + "contains" + ], + }, + { + accessorKey: 'name.lastName', + header: 'نام خانوادگی', + size: 150, + id: "lastName", + enableColumnFilter: true, + datatype: "text", + filterFn: "contains", + columnFilterModeOptions: [ + "equals", + "notEquals", + "contains" + ], + }, + { + accessorKey: 'address', + header: 'آدرس', + size: 200, + id: "address", + enableColumnFilter: true, + datatype: "text", + filterFn: "contains", + columnFilterModeOptions: [ + "equals", + "notEquals", + "contains" + ], + }, + { + accessorKey: 'city', + header: 'شهر', + size: 150, + id: "city", + enableColumnFilter: true, + datatype: "text", + filterFn: "contains", + columnFilterModeOptions: [ + "equals", + "notEquals", + "contains", + "lessThan", + "greaterThan", + "between", + ], + + }, + { + accessorKey: 'state', + header: 'وضعیت', + size: 150, + id: "state", + text:'نام', + enableColumnFilter: true, + datatype: "text", + filterFn: "contains", + columnFilterModeOptions: [ + "equals", + "notEquals", + "contains" + ], + }, + ], + [], + ); return ( <> - - + + ); diff --git a/src/components/DataTableTest.jsx b/src/components/DataTableTest.jsx index d255aaa..7b988ae 100644 --- a/src/components/DataTableTest.jsx +++ b/src/components/DataTableTest.jsx @@ -53,92 +53,13 @@ const data = [ }, ]; -const TestDataTable = () => { +const TestDataTable = ({columns}) => { const [userId, setUserId] = useState(2); const [pageName, setPageName] = useState('loan'); const [tableName, setTableName] = useState('loan_table'); const {settingStore, hideAction, filterAction, sortAction,} = useTableSetting(); - const columns = useMemo( - () => [ - { - accessorKey: 'name.firstName', - header: 'نام', - size: 150, - id: "firstName", - enableColumnFilter: true, - datatype: "text", - filterFn: "contains", - columnFilterModeOptions: [ - "equals", - "notEquals", - "contains" - ], - }, - { - accessorKey: 'name.lastName', - header: 'نام خانوادگی', - size: 150, - id: "lastName", - enableColumnFilter: true, - datatype: "text", - filterFn: "contains", - columnFilterModeOptions: [ - "equals", - "notEquals", - "contains" - ], - }, - { - accessorKey: 'address', - header: 'آدرس', - size: 200, - id: "address", - enableColumnFilter: true, - datatype: "text", - filterFn: "contains", - columnFilterModeOptions: [ - "equals", - "notEquals", - "contains" - ], - }, - { - accessorKey: 'city', - header: 'شهر', - size: 150, - id: "city", - enableColumnFilter: true, - datatype: "text", - filterFn: "contains", - columnFilterModeOptions: [ - "equals", - "notEquals", - "contains", - "lessThan", - "greaterThan", - "between", - ], - }, - { - accessorKey: 'state', - header: 'وضعیت', - size: 150, - id: "state", - text:'نام', - enableColumnFilter: true, - datatype: "text", - filterFn: "contains", - columnFilterModeOptions: [ - "equals", - "notEquals", - "contains" - ], - }, - ], - [], - ); const onColumnVisibilityChange = (event) => { const settingValue = event(); hideAction(userId, pageName, tableName, settingValue, columns); diff --git a/src/components/FilterColumn.jsx b/src/components/FilterColumn.jsx index 08ab968..37aa24a 100644 --- a/src/components/FilterColumn.jsx +++ b/src/components/FilterColumn.jsx @@ -9,13 +9,18 @@ import { import {useFormik} from 'formik'; import TextFieldWithFnBox from "@/components/TextFieldWithFnBox"; import {useEffect, useState} from "react"; +import useTableSetting from "@/lib/hooks/useTableSetting"; -function FilterColumn({ onSubmit , column }) { +function FilterColumn({ onSubmit , column }) { const [selectedFilters, setSelectedFilters] = useState([]); + const [userId, setUserId] = useState(2); + const [pageName, setPageName] = useState('loan'); + const [tableName, setTableName] = useState('loan_table'); + const {settingStore, hideAction, filterAction, sortAction,} = useTableSetting(); useEffect(() => { const initialFilters = column - .filter(col => col.ColumnFiterStatus) + .filter(col => col.enableColumnFilter) .map(col => ({ id: col.field, fn: col.filterFn })); setSelectedFilters(initialFilters); }, [column]); @@ -33,7 +38,7 @@ function FilterColumn({ onSubmit , column }) { const formik = useFormik({ initialValues: column.reduce((acc, column) => { - if (column.ColumnFiterStatus) { + if (column.enableColumnFilter) { acc[column.field] = ''; } return acc; @@ -44,50 +49,7 @@ function FilterColumn({ onSubmit , column }) { // { "id": "navgan_id", "value": values.name2, "fn": values.nameFn, "datatype": values.nameDatatype } // ]; - const user_id = 456; - const page_name = 'loan'; - const table_name = "amir_table"; - let prevLocalStorage = JSON.parse(localStorage.getItem("_setting-app")) || {}; - - const existingFilters = prevLocalStorage[user_id]?.[page_name]?.[table_name]?.filters || []; - - const updatedFilters = selectedFilters.reduce((acc, filter) => { - const currentValue = values[filter.id]; - const prevValue = formik.initialValues[filter.id]; - console.log(acc, filter) - // Check if the current value is empty and the previous value was not empty - if ((currentValue === '' || currentValue === undefined || currentValue === null) && prevValue !== '' && prevValue !== undefined && prevValue !== null) { - // Remove filter data from localStorage - const filterIndex = existingFilters.findIndex(f => f.id === filter.id); - console.log({filterIndex}) - if (filterIndex !== -1) { - existingFilters.splice(filterIndex, 1); - } - } else { - acc.push({ - ...filter, - value: currentValue, - datatype: column.find(col => col.field === filter.id).datatype - }); - } - - return acc; - }, []); - - - updatedFilters.forEach(newFilter => { - const existingFilterIndex = existingFilters.findIndex(filter => filter.id === newFilter.id); - existingFilterIndex !== -1 ? existingFilters[existingFilterIndex] = newFilter : existingFilters.push(newFilter); - }); - - prevLocalStorage[user_id] = prevLocalStorage[user_id] || {}; - prevLocalStorage[user_id][page_name] = prevLocalStorage[user_id][page_name] || {}; - prevLocalStorage[user_id][page_name][table_name] = { hides: {}, filters: existingFilters }; - - localStorage.setItem('_setting-app', JSON.stringify(prevLocalStorage)); - - onSubmit(updatedFilters); } }); @@ -98,7 +60,7 @@ function FilterColumn({ onSubmit , column }) { {column.map((column, index) => ( - column.ColumnFiterStatus && + column.enableColumnFilter && Date: Wed, 21 Feb 2024 13:35:00 +0330 Subject: [PATCH 08/11] change and merge yasi and mohamad code --- src/app/page.js | 87 +----------------------- src/components/DataTableMain.jsx | 96 +++++++++++++++++++++++++++ src/components/FilterColumn.jsx | 17 ++--- src/components/TextFieldWithFnBox.jsx | 9 +-- 4 files changed, 112 insertions(+), 97 deletions(-) create mode 100644 src/components/DataTableMain.jsx diff --git a/src/app/page.js b/src/app/page.js index ea420f9..7690561 100644 --- a/src/app/page.js +++ b/src/app/page.js @@ -1,93 +1,10 @@ -import DataTableTest from "@/components/DataTableTest"; -import FilterColumn from "@/components/FilterColumn"; -import {useMemo} from "react"; +import DataTableMain from "@/components/DataTableMain"; function page() { - const columns = useMemo( - () => [ - { - accessorKey: 'name.firstName', - header: 'نام', - size: 150, - id: "firstName", - enableColumnFilter: true, - datatype: "text", - filterFn: "contains", - columnFilterModeOptions: [ - "equals", - "notEquals", - "contains" - ], - }, - { - accessorKey: 'name.lastName', - header: 'نام خانوادگی', - size: 150, - id: "lastName", - enableColumnFilter: true, - datatype: "text", - filterFn: "contains", - columnFilterModeOptions: [ - "equals", - "notEquals", - "contains" - ], - }, - { - accessorKey: 'address', - header: 'آدرس', - size: 200, - id: "address", - enableColumnFilter: true, - datatype: "text", - filterFn: "contains", - columnFilterModeOptions: [ - "equals", - "notEquals", - "contains" - ], - }, - { - accessorKey: 'city', - header: 'شهر', - size: 150, - id: "city", - enableColumnFilter: true, - datatype: "text", - filterFn: "contains", - columnFilterModeOptions: [ - "equals", - "notEquals", - "contains", - "lessThan", - "greaterThan", - "between", - ], - - }, - { - accessorKey: 'state', - header: 'وضعیت', - size: 150, - id: "state", - text:'نام', - enableColumnFilter: true, - datatype: "text", - filterFn: "contains", - columnFilterModeOptions: [ - "equals", - "notEquals", - "contains" - ], - }, - ], - [], - ); return ( <> - - + ); diff --git a/src/components/DataTableMain.jsx b/src/components/DataTableMain.jsx new file mode 100644 index 0000000..76f4b28 --- /dev/null +++ b/src/components/DataTableMain.jsx @@ -0,0 +1,96 @@ +import DataTableTest from "@/components/DataTableTest"; +import FilterColumn from "@/components/FilterColumn"; +import {useMemo} from "react"; + +function DataTableMain() { + + const columns = useMemo( + () => [ + { + accessorKey: 'name.firstName', + header: 'نام', + size: 150, + id: "firstName", + enableColumnFilter: true, + datatype: "text", + filterFn: "contains", + columnFilterModeOptions: [ + "equals", + "notEquals", + "contains" + ], + }, + { + accessorKey: 'name.lastName', + header: 'نام خانوادگی', + size: 150, + id: "lastName", + enableColumnFilter: true, + datatype: "text", + filterFn: "contains", + columnFilterModeOptions: [ + "equals", + "notEquals", + "contains" + ], + }, + { + accessorKey: 'address', + header: 'آدرس', + size: 200, + id: "address", + enableColumnFilter: true, + datatype: "text", + filterFn: "contains", + columnFilterModeOptions: [ + "equals", + "notEquals", + "contains" + ], + }, + { + accessorKey: 'city', + header: 'شهر', + size: 150, + id: "city", + enableColumnFilter: true, + datatype: "text", + filterFn: "contains", + columnFilterModeOptions: [ + "equals", + "notEquals", + "contains", + "lessThan", + "greaterThan", + "between", + ], + + }, + { + accessorKey: 'state', + header: 'وضعیت', + size: 150, + id: "state", + text:'نام', + enableColumnFilter: true, + datatype: "text", + filterFn: "contains", + columnFilterModeOptions: [ + "equals", + "notEquals", + "contains" + ], + }, + ], + [], + ); + return ( + <> + + + + + ); +} + +export default DataTableMain; diff --git a/src/components/FilterColumn.jsx b/src/components/FilterColumn.jsx index 37aa24a..28cbf0a 100644 --- a/src/components/FilterColumn.jsx +++ b/src/components/FilterColumn.jsx @@ -18,12 +18,14 @@ function FilterColumn({ onSubmit , column }) { const [tableName, setTableName] = useState('loan_table'); const {settingStore, hideAction, filterAction, sortAction,} = useTableSetting(); + useEffect(() => { - const initialFilters = column - .filter(col => col.enableColumnFilter) - .map(col => ({ id: col.field, fn: col.filterFn })); - setSelectedFilters(initialFilters); - }, [column]); + + const settingValue = settingStore?.[userId]?.[pageName]?.[tableName]?.['filters'] || []; + setSelectedFilters(settingValue.length > 0 ? settingValue : []); + console.log(selectedFilters) + + }, [settingStore]); const handleSelectFilter = (fieldName, filterFn) => { const updatedFilters = [...selectedFilters]; @@ -63,10 +65,9 @@ function FilterColumn({ onSubmit , column }) { column.enableColumnFilter && handleSelectFilter(column.field, filterFn)} /> diff --git a/src/components/TextFieldWithFnBox.jsx b/src/components/TextFieldWithFnBox.jsx index c8eff76..a3c277d 100644 --- a/src/components/TextFieldWithFnBox.jsx +++ b/src/components/TextFieldWithFnBox.jsx @@ -3,7 +3,7 @@ import AlignHorizontalCenterIcon from '@mui/icons-material/AlignHorizontalCenter import {useState} from "react"; // import FilterBox from "@/components/FiterBox"; -const TextFieldWithFnBox = ({formik, fieldName , label , defaultFilter , columnFilterModeOptions ,onSelectFilter}) => { +const TextFieldWithFnBox = ({formik, id , defaultFilter , columnFilterModeOptions ,onSelectFilter}) => { const [anchorEl, setAnchorEl] = useState(null); const [open, setOpen] = useState(false); @@ -20,9 +20,10 @@ const TextFieldWithFnBox = ({formik, fieldName , label , defaultFilter , column return ( <> Date: Tue, 27 Feb 2024 15:25:52 +0330 Subject: [PATCH 09/11] nested sidebar --- src/app/page.js | 4 +- src/components/DataTableTest.jsx | 118 ++++++++---------------- src/components/MapTest.jsx | 41 ++++++++ src/core/components/SidebarListItem.jsx | 29 ++++++ src/core/components/SidebarSubitem.jsx | 33 +++++++ src/core/components/SidebarTest.jsx | 56 +++++++++++ 6 files changed, 198 insertions(+), 83 deletions(-) create mode 100644 src/components/MapTest.jsx create mode 100644 src/core/components/SidebarListItem.jsx create mode 100644 src/core/components/SidebarSubitem.jsx create mode 100644 src/core/components/SidebarTest.jsx diff --git a/src/app/page.js b/src/app/page.js index 2534242..98f623d 100644 --- a/src/app/page.js +++ b/src/app/page.js @@ -1,8 +1,8 @@ -import DataTableTest from "@/components/DataTableTest"; +import SidebarTest from "@/core/components/SidebarTest"; function page() { return ( - + ); } diff --git a/src/components/DataTableTest.jsx b/src/components/DataTableTest.jsx index d255aaa..0df7cab 100644 --- a/src/components/DataTableTest.jsx +++ b/src/components/DataTableTest.jsx @@ -1,9 +1,8 @@ "use client" -import {useMemo, useState} from 'react'; -import {MaterialReactTable} from 'material-react-table'; -import useTableSetting from "@/lib/hooks/useTableSetting"; -import {Typography} from "@mui/material"; - +import { useMemo, useState } from 'react'; +import { MaterialReactTable } from 'material-react-table'; +import useTableSetting from '@/lib/hooks/useTableSetting'; +import { Typography } from '@mui/material'; const data = [ { @@ -57,118 +56,75 @@ const TestDataTable = () => { const [userId, setUserId] = useState(2); const [pageName, setPageName] = useState('loan'); const [tableName, setTableName] = useState('loan_table'); - const {settingStore, hideAction, filterAction, sortAction,} = useTableSetting(); + const { settingStore, hideAction, filterAction, sortAction } = useTableSetting(); const columns = useMemo( () => [ { - accessorKey: 'name.firstName', header: 'نام', - size: 150, - id: "firstName", - enableColumnFilter: true, - datatype: "text", - filterFn: "contains", - columnFilterModeOptions: [ - "equals", - "notEquals", - "contains" - ], - }, - { - accessorKey: 'name.lastName', - header: 'نام خانوادگی', - size: 150, - id: "lastName", - enableColumnFilter: true, - datatype: "text", - filterFn: "contains", - columnFilterModeOptions: [ - "equals", - "notEquals", - "contains" + size: 300, + subHeader: [ + { + accessorKey: 'name.firstName', + header: 'نام', + size: 150, + }, + { + accessorKey: 'name.lastName', + header: 'نام خانوادگی', + size: 150, + }, ], }, { accessorKey: 'address', header: 'آدرس', size: 200, - id: "address", - enableColumnFilter: true, - datatype: "text", - filterFn: "contains", - columnFilterModeOptions: [ - "equals", - "notEquals", - "contains" - ], }, { accessorKey: 'city', header: 'شهر', size: 150, - id: "city", - enableColumnFilter: true, - datatype: "text", - filterFn: "contains", - columnFilterModeOptions: [ - "equals", - "notEquals", - "contains", - "lessThan", - "greaterThan", - "between", - ], - }, { accessorKey: 'state', header: 'وضعیت', size: 150, - id: "state", - text:'نام', - enableColumnFilter: true, - datatype: "text", - filterFn: "contains", - columnFilterModeOptions: [ - "equals", - "notEquals", - "contains" - ], }, ], - [], + [] ); + const onColumnVisibilityChange = (event) => { const settingValue = event(); hideAction(userId, pageName, tableName, settingValue, columns); }; + const onSortingChange = (event) => { const settingValue = event(settingStore?.[userId]?.[pageName]?.[tableName]?.['sorts'] || []); sortAction(userId, pageName, tableName, settingValue, columns); - } + }; return ( <> - {settingStore?.[userId]?.[pageName]?.[tableName]?.['summary']} - + {settingStore?.[userId]?.[pageName]?.[tableName]?.['summary']} + ); }; export default TestDataTable; - diff --git a/src/components/MapTest.jsx b/src/components/MapTest.jsx new file mode 100644 index 0000000..8ccea0a --- /dev/null +++ b/src/components/MapTest.jsx @@ -0,0 +1,41 @@ +"use client" +import {Typography} from "@mui/material"; + +const data = [ + { + id : "hello", + Subitems : [ + {id : "amin",firstName : "amin", lastName:"ali",Subitems : [{id : "shahrokh",shahrokh : "shahrokh"}], hasSubitems : true, showSubitems : false}, + {id : "amir",firstName : "amir", lastName:"akbar", hasSubitems : false, showSubitems : false}, + ], + hasSubitems : true, + showSubitems : false + }, + { + id : "hi", + Subitems : [ + {id : "ali",firstName : "ali", lastName:"ali", hasSubitems : false, showSubitems : false}, + {id : "akbar",firstName : "akbar", lastName:"akbar", hasSubitems : false, showSubitems : false}, + ], + hasSubitems : true, + showSubitems : false + } +] +const MapTest = () => { + const Amin = data.map((item) => { + return item.hasSubitems ? {...item, Subitems: item.Subitems.map((subitem) => true ? { + ...subitem, showSubitems: !item.showSubitems + } : subitem)} : item + }) + + + console.log(Amin) + + + return ( + <> + hello + + ) +} +export default MapTest \ No newline at end of file diff --git a/src/core/components/SidebarListItem.jsx b/src/core/components/SidebarListItem.jsx new file mode 100644 index 0000000..3776e8f --- /dev/null +++ b/src/core/components/SidebarListItem.jsx @@ -0,0 +1,29 @@ +import {Collapse, ListItem, ListItemButton, ListItemText} from "@mui/material"; +import SidebarSubitem from "@/core/components/SidebarSubitem"; +import {useState} from "react"; + +const SidebarListItem = ({menuItem, dispatch}) => { + const [open, setOpen] = useState(false) + return( + <> + + + { + dispatch({type: "COLLAPSE_MENU", id: menuItem.id}) + setOpen(!open) + }}>click + + + { + menuItem.hasSubitems ? (menuItem.Subitems.map((subitem,index)=>{ + return( + + ) + })) : null + } + + + + ) +} +export default SidebarListItem \ No newline at end of file diff --git a/src/core/components/SidebarSubitem.jsx b/src/core/components/SidebarSubitem.jsx new file mode 100644 index 0000000..2e0afc0 --- /dev/null +++ b/src/core/components/SidebarSubitem.jsx @@ -0,0 +1,33 @@ +import {Collapse, List, ListItem, ListItemButton, ListItemText} from "@mui/material"; +import {useState} from "react"; + +const SidebarSubitem = ({subitem, dispatch}) => { + const [subOpen, setSubOpen] = useState(false) + return( + <> + + + + {subitem.hasSubitems ? ( { + dispatch({type: "Subitem1", id: subitem.id}) + setSubOpen(!subOpen) + }}>click) : null} + + + { + subitem.hasSubitems ? (subitem.Subitems.map((subSubitem,index) => { + return( + + + + + + + + ) + })) : null + } + + ) +} +export default SidebarSubitem \ No newline at end of file diff --git a/src/core/components/SidebarTest.jsx b/src/core/components/SidebarTest.jsx new file mode 100644 index 0000000..f7c9b9e --- /dev/null +++ b/src/core/components/SidebarTest.jsx @@ -0,0 +1,56 @@ +"use client" +import {List} from "@mui/material"; +import SidebarListItem from "@/core/components/SidebarListItem"; +import {useReducer} from "react"; +const data = [ + { + id : "hello", + Subitems : [ + {id : "amin",firstName : "amin", lastName:"ali",Subitems : [{id : "shahrokh",shahrokh : "shahrokh"}], hasSubitems : true, showSubitems : false}, + {id : "amir",firstName : "amir", lastName:"akbar", hasSubitems : false, showSubitems : false}, + ], + hasSubitems : true, + showSubitems : false + }, + { + id : "hi", + Subitems : [ + {id : "ali",firstName : "ali", lastName:"ali", hasSubitems : false, showSubitems : false}, + {id : "akbar",firstName : "akbar", lastName:"akbar", hasSubitems : false, showSubitems : false}, + ], + hasSubitems : true, + showSubitems : false + } +] +function reducer(state, action) { + switch (action.type) { + case "COLLAPSE_MENU": + return state.map((item) => action.id == item.id ? { + ...item, showSubitems: !item.showSubitems + } : item) + case "Subitem1" : + return state.map((item) => { + return item.hasSubitems ? {...item, Subitems: item.Subitems.map((subitem) => action.id === subitem.id ? { + ...subitem, showSubitems: !subitem.showSubitems + } : subitem)} : item + }) + default: + throw new Error(); + } +} + +const SidebarTest = () => { + const [itemMenu, dispatch] = useReducer(reducer, data); + return( + + { + itemMenu.map((menuItem) => { + return( + + ) + }) + } + + ) +} +export default SidebarTest \ No newline at end of file From 6ac4f7c5f94af9c7a456629a6dd86dc71a5dd0e7 Mon Sep 17 00:00:00 2001 From: AminGhasempoor Date: Sat, 2 Mar 2024 15:55:45 +0330 Subject: [PATCH 10/11] selected nested sidebar --- src/app/page.js | 4 +- .../dashboard/headerWithSidebar/index.jsx | 2 + src/core/components/SidebarListItem.jsx | 29 --- src/core/components/SidebarListItems.jsx | 46 ++++ src/core/components/SidebarMenu.jsx | 201 ++++++++++++++++++ src/core/components/SidebarSubitem.jsx | 33 --- src/core/components/SidebarSubitems.jsx | 74 +++++++ src/core/components/SidebarTest.jsx | 56 ----- 8 files changed, 325 insertions(+), 120 deletions(-) delete mode 100644 src/core/components/SidebarListItem.jsx create mode 100644 src/core/components/SidebarListItems.jsx create mode 100644 src/core/components/SidebarMenu.jsx delete mode 100644 src/core/components/SidebarSubitem.jsx create mode 100644 src/core/components/SidebarSubitems.jsx delete mode 100644 src/core/components/SidebarTest.jsx diff --git a/src/app/page.js b/src/app/page.js index 98f623d..ad66be2 100644 --- a/src/app/page.js +++ b/src/app/page.js @@ -1,8 +1,8 @@ -import SidebarTest from "@/core/components/SidebarTest"; +import SidebarMenu from "@/core/components/SidebarMenu"; function page() { return ( - + ); } diff --git a/src/components/layouts/dashboard/headerWithSidebar/index.jsx b/src/components/layouts/dashboard/headerWithSidebar/index.jsx index 7591951..eeb88a3 100644 --- a/src/components/layouts/dashboard/headerWithSidebar/index.jsx +++ b/src/components/layouts/dashboard/headerWithSidebar/index.jsx @@ -4,6 +4,7 @@ import {Box, Drawer, IconButton, Paper, styled, Toolbar, Typography} from "@mui/ import MuiAppBar from '@mui/material/AppBar'; import MenuIcon from '@mui/icons-material/Menu'; import ChevronRightIcon from '@mui/icons-material/ChevronRight'; +import SidebarMenu from "@/core/components/SidebarMenu"; const drawerWidth = 260; @@ -82,6 +83,7 @@ const HeaderWithSidebar = ({children}) => { +
diff --git a/src/core/components/SidebarListItem.jsx b/src/core/components/SidebarListItem.jsx deleted file mode 100644 index 3776e8f..0000000 --- a/src/core/components/SidebarListItem.jsx +++ /dev/null @@ -1,29 +0,0 @@ -import {Collapse, ListItem, ListItemButton, ListItemText} from "@mui/material"; -import SidebarSubitem from "@/core/components/SidebarSubitem"; -import {useState} from "react"; - -const SidebarListItem = ({menuItem, dispatch}) => { - const [open, setOpen] = useState(false) - return( - <> - - - { - dispatch({type: "COLLAPSE_MENU", id: menuItem.id}) - setOpen(!open) - }}>click - - - { - menuItem.hasSubitems ? (menuItem.Subitems.map((subitem,index)=>{ - return( - - ) - })) : null - } - - - - ) -} -export default SidebarListItem \ No newline at end of file diff --git a/src/core/components/SidebarListItems.jsx b/src/core/components/SidebarListItems.jsx new file mode 100644 index 0000000..9ffcac2 --- /dev/null +++ b/src/core/components/SidebarListItems.jsx @@ -0,0 +1,46 @@ +import {Collapse, ListItem, ListItemButton, ListItemIcon, ListItemText} from "@mui/material"; +import { ExpandLess, ExpandMore } from '@mui/icons-material'; +import WifiIcon from '@mui/icons-material/Wifi'; +import SidebarSubitems from "@/core/components/SidebarSubitems"; + +const SidebarListItems = ({menuItem, dispatch}) => { + return( + <> + + { + dispatch({type: "COLLAPSE_MENU", id: menuItem.id}) + }}> + + {menuItem.icon} + + + {menuItem.hasSubitems ? (menuItem.showSubitems ? : ) : null } + + + + { + menuItem.hasSubitems ? (menuItem.Subitems.map((subitem,index)=>{ + return( + + ) + })) : null + } + + + + ) +} +export default SidebarListItems \ No newline at end of file diff --git a/src/core/components/SidebarMenu.jsx b/src/core/components/SidebarMenu.jsx new file mode 100644 index 0000000..f7589c3 --- /dev/null +++ b/src/core/components/SidebarMenu.jsx @@ -0,0 +1,201 @@ +"use client" +import {List} from "@mui/material"; +import SidebarListItems from "@/core/components/SidebarListItems"; +import {useEffect, useReducer, useState} from "react"; +import {usePathname} from 'next/navigation' +import SecurityIcon from '@mui/icons-material/Security'; +import SpaceDashboardIcon from "@mui/icons-material/SpaceDashboard"; +import AssessmentIcon from '@mui/icons-material/Assessment'; +import AirlineSeatReclineNormalIcon from "@mui/icons-material/AirlineSeatReclineNormal"; +import RepartitionIcon from '@mui/icons-material/Repartition'; + +const data = [ + { + id: "hello", + type: "menu", + route: "/hello", + icon: , + selected: false, + Subitems: [ + { + id: "amin", + route: "/s", + icon: , + firstName: "amin", + lastName: "ali", + Subitems: [ + { + id: "shahrokh", shahrokh: "shahrokh", type: "page", selected: false, route: "/dashbssoard", icon: + }, + { + id: "shasdasdsahrokh", shahrokh: "shahroasdasdkh", type: "page", selected: false, route: "/dashboardsd", icon: + } + ], + hasSubitems: true, + showSubitems: false, + type: "menu", + selected: false, + }, + { + id: "amir", + route: "/dashboarsad", + icon: , + firstName: "amir", + lastName: "akbar", + hasSubitems: false, + showSubitems: false, + selected: false, + type: "page", + }, + ], + hasSubitems: true, + showSubitems: false + }, + { + id: "hi", + type: "menu", + icon: , + route: "/hi", + selected: false, + Subitems: [ + { + id: "ali", + route: "/dashboardss", + firstName: "ali", + lastName: "ali", + icon: , + hasSubitems: false, + showSubitems: false, + type: "page", + selected: false, + }, + { + id: "akbar", + route: "/akbar", + firstName: "akbar", + icon: , + lastName: "akbar", + hasSubitems: false, + showSubitems: false, + type: "page", + selected: false, + }, + ], + hasSubitems: true, + showSubitems: false + }, + { + id: "hoo", + type: "page", + route: "/dashboard", + icon: , + selected: false, + hasSubitems: false, + showSubitems: false + } +] + +function reducer(state, action) { + switch (action.type) { + case "COLLAPSE_MENU": + return state.map((item) => action.id == item.id ? { + ...item, showSubitems: !item.showSubitems + } : item) + case "COLLAPSE_SUB_ITEMS" : + return state.map((item) => { + return item.hasSubitems ? { + ...item, Subitems: item.Subitems.map((subitem) => action.id === subitem.id ? { + ...subitem, showSubitems: !subitem.showSubitems + } : subitem) + } : item + }) + case "COLLAPSE_SUB_SECOND_ITEMS" : + return state.map((item) => { + return item.hasSubitems ? { + ...item, Subitems: item.Subitems.map((subitem) => { + return subitem.hasSubitems ? { + ...subitem, + Subitems: subitem.Subitems.map((secondSubitem) => action.id === secondSubitem.id ? { + ...secondSubitem, showSubitems: !secondSubitem.showSubitems + } : secondSubitem) + } : subitem + }) + } : item + }) + case "SELECTED": + return state.map((item) => { + return item.type === "page" ? { + ...item, selected: action.route === item.route,showSubitems: item.route === action.route + } : item.Subitems && Array.isArray(item.Subitems) ? { + ...item, Subitems: item.Subitems.map((subitem) => { + return subitem.type === "page" ? { + ...subitem, selected: action.route === subitem.route,showSubitems: subitem.route === action.route + } : subitem.Subitems && Array.isArray(subitem.Subitems) ? { + ...subitem, Subitems: subitem.Subitems.map((secondSubItem) => ({ + ...secondSubItem, selected: secondSubItem.route === action.route + })),showSubitems: subitem.Subitems.some((secondSubItem) => secondSubItem.route === action.route), + } : subitem + }),showSubitems: item.Subitems.some((subitem) => subitem.showSubitems), + } : item + }); + // case "SELECTED": + // return state.map((item) => { + // return item.type === "page" ? { + // ...item, + // selected: action.route === item.route + // } : item.Subitems && Array.isArray(item.Subitems) ? { + // ...item, + // Subitems: item.Subitems.map((subitem) => { + // const updatedSubitem = subitem.type === "page" ? { + // ...subitem, + // selected: action.route === subitem.route + // } : subitem.Subitems && Array.isArray(subitem.Subitems) ? { + // ...subitem, + // Subitems: subitem.Subitems.map((secondSubItem) => ({ + // ...secondSubItem, + // selected: secondSubItem.route === action.route + // })), + // showSubitems: subitem.Subitems.some((secondSubItem) => secondSubItem.route === action.route), + // } : subitem; + // + // console.log("Updated subitem:", updatedSubitem); // Log the updated subitem + // return updatedSubitem; + // }), + // showSubitems: item.Subitems.some((subitem) => subitem.showSubitems), + // } : item + // }); + + + default: + throw new Error(); + } +} + +const SidebarMenu = () => { + const [menuItems, dispatch] = useReducer(reducer, data); + const pathname = usePathname() + const [selectedKey, setSelectedKey] = useState(null); + useEffect(() => { + dispatch({type: "SELECTED", route: pathname}); + setSelectedKey(pathname); + }, [pathname]); + + useEffect(() => { + selectedKey && document.querySelector(`[data-route="${selectedKey}"]`)?.scrollIntoView({ + behavior: "smooth", block: "center" + }); + }, [selectedKey]); + + return ( + + { + menuItems.map((menuItem) => { + return ( + + ) + }) + } + + ) +} +export default SidebarMenu \ No newline at end of file diff --git a/src/core/components/SidebarSubitem.jsx b/src/core/components/SidebarSubitem.jsx deleted file mode 100644 index 2e0afc0..0000000 --- a/src/core/components/SidebarSubitem.jsx +++ /dev/null @@ -1,33 +0,0 @@ -import {Collapse, List, ListItem, ListItemButton, ListItemText} from "@mui/material"; -import {useState} from "react"; - -const SidebarSubitem = ({subitem, dispatch}) => { - const [subOpen, setSubOpen] = useState(false) - return( - <> - - - - {subitem.hasSubitems ? ( { - dispatch({type: "Subitem1", id: subitem.id}) - setSubOpen(!subOpen) - }}>click) : null} - - - { - subitem.hasSubitems ? (subitem.Subitems.map((subSubitem,index) => { - return( - - - - - - - - ) - })) : null - } - - ) -} -export default SidebarSubitem \ No newline at end of file diff --git a/src/core/components/SidebarSubitems.jsx b/src/core/components/SidebarSubitems.jsx new file mode 100644 index 0000000..275befb --- /dev/null +++ b/src/core/components/SidebarSubitems.jsx @@ -0,0 +1,74 @@ +import {Collapse, List, ListItem, ListItemButton, ListItemIcon, ListItemText} from "@mui/material"; +import {ExpandLess, ExpandMore} from "@mui/icons-material"; + +const SidebarSubitems = ({subitem, dispatch}) => { + return ( + <> + + + { + dispatch({type: "COLLAPSE_SUB_ITEMS", id: subitem.id}) + }}> + + {subitem.icon} + + + {subitem.hasSubitems ? (subitem.showSubitems ? : ) : null + } + + + + { + subitem.hasSubitems ? (subitem.Subitems.map((subSubitem, index) => { + return ( + + + + { + dispatch({type: "COLLAPSE_SUB_SECOND_ITEMS", id: subSubitem.id}) + }} + selected={subSubitem.selected} + sx={{ + '&.Mui-selected': { + backgroundColor: 'rgba(0, 0, 0, 0.05)', + }, + }} + > + + {subSubitem.icon} + + + + + + + ) + })) : null + } + + ) +} +export default SidebarSubitems \ No newline at end of file diff --git a/src/core/components/SidebarTest.jsx b/src/core/components/SidebarTest.jsx deleted file mode 100644 index f7c9b9e..0000000 --- a/src/core/components/SidebarTest.jsx +++ /dev/null @@ -1,56 +0,0 @@ -"use client" -import {List} from "@mui/material"; -import SidebarListItem from "@/core/components/SidebarListItem"; -import {useReducer} from "react"; -const data = [ - { - id : "hello", - Subitems : [ - {id : "amin",firstName : "amin", lastName:"ali",Subitems : [{id : "shahrokh",shahrokh : "shahrokh"}], hasSubitems : true, showSubitems : false}, - {id : "amir",firstName : "amir", lastName:"akbar", hasSubitems : false, showSubitems : false}, - ], - hasSubitems : true, - showSubitems : false - }, - { - id : "hi", - Subitems : [ - {id : "ali",firstName : "ali", lastName:"ali", hasSubitems : false, showSubitems : false}, - {id : "akbar",firstName : "akbar", lastName:"akbar", hasSubitems : false, showSubitems : false}, - ], - hasSubitems : true, - showSubitems : false - } -] -function reducer(state, action) { - switch (action.type) { - case "COLLAPSE_MENU": - return state.map((item) => action.id == item.id ? { - ...item, showSubitems: !item.showSubitems - } : item) - case "Subitem1" : - return state.map((item) => { - return item.hasSubitems ? {...item, Subitems: item.Subitems.map((subitem) => action.id === subitem.id ? { - ...subitem, showSubitems: !subitem.showSubitems - } : subitem)} : item - }) - default: - throw new Error(); - } -} - -const SidebarTest = () => { - const [itemMenu, dispatch] = useReducer(reducer, data); - return( - - { - itemMenu.map((menuItem) => { - return( - - ) - }) - } - - ) -} -export default SidebarTest \ No newline at end of file From 8f93feb60917cf35ec2a98020ab82da5318f6256 Mon Sep 17 00:00:00 2001 From: Yasiu1376 Date: Wed, 13 Mar 2024 16:07:55 +0330 Subject: [PATCH 11/11] filter --- package.json | 5 + src/components/BetweenDateFilter.jsx | 31 ++++ src/components/BetweenNumberFilter.jsx | 58 +++++++ src/components/CustomToolbar.jsx | 20 +++ src/components/DataTableMain.jsx | 49 +++++- src/components/DataTableTest.jsx | 13 +- src/components/FilterBox.jsx | 30 ++++ src/components/FilterColumn.jsx | 218 +++++++++++++++++++------ src/components/MuiDatePicker.jsx | 63 +++++++ src/components/SelectBox.jsx | 53 ++++++ src/components/SelectBoxMultiple.jsx | 113 +++++++++++++ src/components/TextFieldWithFnBox.jsx | 21 ++- src/lib/contexts/tableSetting.jsx | 6 +- 13 files changed, 616 insertions(+), 64 deletions(-) create mode 100644 src/components/BetweenDateFilter.jsx create mode 100644 src/components/BetweenNumberFilter.jsx create mode 100644 src/components/CustomToolbar.jsx create mode 100644 src/components/FilterBox.jsx create mode 100644 src/components/MuiDatePicker.jsx create mode 100644 src/components/SelectBox.jsx create mode 100644 src/components/SelectBoxMultiple.jsx diff --git a/package.json b/package.json index a74c3db..3855313 100644 --- a/package.json +++ b/package.json @@ -15,7 +15,12 @@ "@mui/icons-material": "^5.15.6", "@mui/material": "^5.15.6", "@mui/material-nextjs": "^5.15.6", + "@mui/x-date-pickers": "^6.19.5", + "date-fns": "^3.3.1", + "date-fns-jalali": "^2.13.0-0", + "dayjs": "^1.11.10", "formik": "^2.4.5", + "jalali-moment": "^3.3.11", "material-react-table": "^2.11.2", "next": "14.1.0", "react": "^18", diff --git a/src/components/BetweenDateFilter.jsx b/src/components/BetweenDateFilter.jsx new file mode 100644 index 0000000..e8e8c18 --- /dev/null +++ b/src/components/BetweenDateFilter.jsx @@ -0,0 +1,31 @@ +import {Grid} from '@mui/material'; +import MuiDatePicker from "@/components/MuiDatePicker"; +import {useEffect, useState} from "react"; + +const BetWeenDateFilter = ({formik, id , defaultValue}) => { + useEffect(() => { + formik.setFieldValue(`${id}[0]`, defaultValue?.[0] || ''); + formik.setFieldValue(`${id}[1]`, defaultValue?.[1] || ''); + }, []); + + const [dateRange, setDateRange] = useState(defaultValue); + + const handleDateChange = (index, value) => { + const newRange = [...dateRange]; + newRange[index] = value; + setDateRange(newRange); + }; + + return ( + + + handleDateChange(0, value)}/> + + + handleDateChange(1, value)}/> + + + ); +}; + +export default BetWeenDateFilter; diff --git a/src/components/BetweenNumberFilter.jsx b/src/components/BetweenNumberFilter.jsx new file mode 100644 index 0000000..0b3512a --- /dev/null +++ b/src/components/BetweenNumberFilter.jsx @@ -0,0 +1,58 @@ +import {Grid, TextField} from '@mui/material'; +import {useEffect} from "react"; + +const BetweenNumberFilter = ({formik, id , defaultValue}) => { + + useEffect(() => { + formik.setFieldValue(`${id}[0]`, defaultValue?.[0] || ''); + formik.setFieldValue(`${id}[1]`, defaultValue?.[1] || ''); + }, []); + const handleBlur = (index) => () => { + const minValue = formik.values[id][0]; + const maxValue = formik.values[id][1]; + + if (index === 0 && minValue !== '' && maxValue !== '' && parseInt(minValue) > parseInt(maxValue)) { + formik.setFieldValue(`${id}[0]`, maxValue); + } + + if (index === 1 && minValue !== '' && maxValue !== '' && parseInt(maxValue) < parseInt(minValue)) { + formik.setFieldValue(`${id}[1]`, minValue); + } + }; + return ( + + + + + + + + + ); +}; + +export default BetweenNumberFilter; diff --git a/src/components/CustomToolbar.jsx b/src/components/CustomToolbar.jsx new file mode 100644 index 0000000..344b5da --- /dev/null +++ b/src/components/CustomToolbar.jsx @@ -0,0 +1,20 @@ +import FilterColumn from "@/components/FilterColumn"; + +const CustomToolbar = ({columns}) => { + return ( + + ) +} +export default CustomToolbar + + + + + + + + + + + + diff --git a/src/components/DataTableMain.jsx b/src/components/DataTableMain.jsx index 76f4b28..a6e8c91 100644 --- a/src/components/DataTableMain.jsx +++ b/src/components/DataTableMain.jsx @@ -1,9 +1,9 @@ import DataTableTest from "@/components/DataTableTest"; import FilterColumn from "@/components/FilterColumn"; import {useMemo} from "react"; +import {Button} from "@mui/material"; function DataTableMain() { - const columns = useMemo( () => [ { @@ -81,13 +81,58 @@ function DataTableMain() { "contains" ], }, + { + accessorKey: 'state', + header: 'محدوده', + size: 150, + id: "betweenNum", + text:'محدوده', + enableColumnFilter: true, + datatype: "text", + filterFn: "betweenNum", + columnFilterModeOptions: [], + }, + { + accessorKey: 'state', + header: 'تاریخ', + size: 150, + id: "betweenDate", + text:'تاریخ', + enableColumnFilter: true, + datatype: "text", + filterFn: "betweenDate", + columnFilterModeOptions: [], + }, + { + accessorKey: 'state', + header: 'شلکت', + size: 150, + id: "select2", + text:'تاریخ', + type: 'select2', + enableColumnFilter: true, + datatype: "text", + filterFn: "equals", + columnFilterModeOptions: [], + }, + { + accessorKey: 'state', + header: 'سلکت', + size: 150, + id: "select", + text:'تنتنت', + type: 'select', + enableColumnFilter: true, + datatype: "text", + filterFn: "equals", + columnFilterModeOptions: [], + }, ], [], ); return ( <> - ); diff --git a/src/components/DataTableTest.jsx b/src/components/DataTableTest.jsx index 7b988ae..bf610fb 100644 --- a/src/components/DataTableTest.jsx +++ b/src/components/DataTableTest.jsx @@ -2,7 +2,8 @@ import {useMemo, useState} from 'react'; import {MaterialReactTable} from 'material-react-table'; import useTableSetting from "@/lib/hooks/useTableSetting"; -import {Typography} from "@mui/material"; +import {IconButton, Tooltip, Typography} from "@mui/material"; +import CustomToolbar from "@/components/CustomToolbar"; const data = [ @@ -53,13 +54,16 @@ const data = [ }, ]; +function RefreshIcon() { + return null; +} + const TestDataTable = ({columns}) => { const [userId, setUserId] = useState(2); const [pageName, setPageName] = useState('loan'); const [tableName, setTableName] = useState('loan_table'); const {settingStore, hideAction, filterAction, sortAction,} = useTableSetting(); - const onColumnVisibilityChange = (event) => { const settingValue = event(); hideAction(userId, pageName, tableName, settingValue, columns); @@ -76,6 +80,11 @@ const TestDataTable = ({columns}) => { columns={columns} data={data} manualSorting={true} + renderTopToolbarCustomActions={({table}) => (<> + + )} initialState={{ columnVisibility: settingStore?.[userId]?.[pageName]?.[tableName]?.['hides'], sorting: settingStore?.[userId]?.[pageName]?.[tableName]?.['sorts'] || [] diff --git a/src/components/FilterBox.jsx b/src/components/FilterBox.jsx new file mode 100644 index 0000000..f887918 --- /dev/null +++ b/src/components/FilterBox.jsx @@ -0,0 +1,30 @@ +import { Popper, Paper, List, ListItem, ListItemText, ClickAwayListener } from '@mui/material'; + +function FilterBox({anchorEl , open = false, handleClose = () => {} , columnFilterModeOptions , onSelectFilter , defaultFilter}) { + + const id = open ? 'simple-popper' : undefined; + const handleSelectFilter = (filterFn) => { + onSelectFilter(filterFn); + handleClose(); + }; + + return ( +
+ + + + + {columnFilterModeOptions.map((option, index) => ( + handleSelectFilter(option)} selected={option === defaultFilter} sx={{ cursor: 'pointer' }}> + + + ))} + + + + +
+ ); +} + +export default FilterBox; diff --git a/src/components/FilterColumn.jsx b/src/components/FilterColumn.jsx index 28cbf0a..46e156b 100644 --- a/src/components/FilterColumn.jsx +++ b/src/components/FilterColumn.jsx @@ -1,83 +1,203 @@ "use client" import { - Button, - Dialog, DialogActions, - DialogContent, - DialogTitle, - FormControl + Box, + Button, Divider, Drawer, + FormControl, IconButton, styled, Typography } from '@mui/material'; import {useFormik} from 'formik'; import TextFieldWithFnBox from "@/components/TextFieldWithFnBox"; import {useEffect, useState} from "react"; import useTableSetting from "@/lib/hooks/useTableSetting"; +import BetweenNumberFilter from "@/components/BetweenNumberFilter"; +import BetWeenDateFilter from "@/components/BetweenDateFilter"; +import SelectBoxMultiple from "@/components/SelectBoxMultiple"; +import SelectBox from "@/components/SelectBox"; +import CloseIcon from '@mui/icons-material/Close'; +import { useTheme } from '@mui/material/styles'; -function FilterColumn({ onSubmit , column }) { +function FilterColumn({ columns }) { + const [open, setOpen] = useState(false); const [selectedFilters, setSelectedFilters] = useState([]); const [userId, setUserId] = useState(2); const [pageName, setPageName] = useState('loan'); const [tableName, setTableName] = useState('loan_table'); 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 : []); - console.log(selectedFilters) - }, [settingStore]); const handleSelectFilter = (fieldName, filterFn) => { - const updatedFilters = [...selectedFilters]; - const filterIndex = updatedFilters.findIndex(filter => filter.id === fieldName); + const filterIndex = selectedFilters.findIndex(filter => filter.id === fieldName); + if (filterIndex !== -1) { + const updatedFilters = [...selectedFilters]; updatedFilters[filterIndex].fn = filterFn; + setSelectedFilters(updatedFilters); } else { - updatedFilters.push({ id: fieldName, fn: filterFn }); + const newFilter = { id: fieldName, fn: filterFn }; + const updatedFilters = [...selectedFilters, newFilter]; + setSelectedFilters(updatedFilters); } - setSelectedFilters(updatedFilters); }; - const formik = useFormik({ - initialValues: column.reduce((acc, column) => { - if (column.enableColumnFilter) { - acc[column.field] = ''; + 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; - }, {}), - onSubmit: (values) => { - // const selectedFilters = [ - // { "id": "name", "value": values.name1, "fn": values.cityFn, "datatype": values.nameDatatype }, - // { "id": "navgan_id", "value": values.name2, "fn": values.nameFn, "datatype": values.nameDatatype } - // ]; - - } + return acc; + }, {}); + + const formik = useFormik({ + initialValues, + onSubmit: (values) => { + console.log(values) + const updatedFilters = selectedFilters.map(filter => { + const value = values[filter.id]; + if (value !== undefined) { + return { ...filter, value }; + } + return filter; + }); + + Object.entries(values).forEach(([fieldName, value]) => { + const filterIndex = updatedFilters.findIndex(filter => filter.id === fieldName); + if (filterIndex === -1 && value !== '' && value !== null && value !== undefined) { + const column = columns.find(col => col.id === fieldName); + updatedFilters.push({ id: fieldName, value, fn: column.filterFn, datatype: column.datatype }); + } + }); + + const newArrayFilter = updatedFilters.filter((filter) => { + const value = values[filter.id]; + + return ( + value !== '' && + value !== null && + value !== undefined && + !(Array.isArray(value) && (value.length === 0 || (value.length === 2 && value.every((v) => v === '')))) + ); + }); + + setSelectedFilters(newArrayFilter); + filterAction(userId, pageName, tableName, newArrayFilter, columns); + } + }); - return ( - - Select Filters - - - {column.map((column, index) => ( - column.enableColumnFilter && - handleSelectFilter(column.field, filterFn)} - /> - ))} - - - - - - + <> + + + + فیلتر + + + + + + + {columns.map((column, index) => ( + column.enableColumnFilter && + (column.filterFn === 'betweenDate' ? + handleSelectFilter(column.id, filterFn)} + defaultValue={(settingStore?.[userId]?.[pageName]?.[tableName]?.['filters'] || []).find(filter => filter.id === column.id)?.value || ''} + /> + : column.filterFn === 'betweenNum' ? + handleSelectFilter(column.id, filterFn)} + defaultValue={(settingStore?.[userId]?.[pageName]?.[tableName]?.['filters'] || []).find(filter => filter.id === column.id)?.value || ["", ""]} + /> + : column.type === 'select2' ? + handleSelectFilter(column.id, filterFn)} + defaultValue={(settingStore?.[userId]?.[pageName]?.[tableName]?.['filters'] || []).find(filter => filter.id === column.id)?.value || []} + /> + : column.type === 'select' ? + handleSelectFilter(column.id, filterFn)} + defaultValue={(settingStore?.[userId]?.[pageName]?.[tableName]?.['filters'] || []).find(filter => 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 || ''} + /> + ) + ))} + + + + + + + + + + ); } diff --git a/src/components/MuiDatePicker.jsx b/src/components/MuiDatePicker.jsx new file mode 100644 index 0000000..0929c61 --- /dev/null +++ b/src/components/MuiDatePicker.jsx @@ -0,0 +1,63 @@ +import { LocalizationProvider, MobileDateTimePicker } from "@mui/x-date-pickers"; +import { AdapterDateFnsJalali } from "@mui/x-date-pickers/AdapterDateFnsJalali"; +import moment from "jalali-moment"; +import { faIR } from "@mui/x-date-pickers/locales"; +import { Box, IconButton } from "@mui/material"; +import ClearIcon from "@mui/icons-material/Clear"; +import {useState} from "react"; + +export default function MuiDatePicker({label, name, formik, defaultValue, minDate, maxDate, onDateChange }) { + const [pickerValue, setPickerValue] = useState(defaultValue ? new Date(defaultValue) : null); + return ( + + + + { + const date = new Date(newValue); + const formattedDate = moment(date) + .locale("en") + .format("YYYY-MM-DD HH:mm"); + formik.setFieldValue(name, formattedDate); + onDateChange(formattedDate); + setPickerValue(newValue); + }} + slotProps={{ + textField: { + placeholder: "تاریخ خود را وارد کنید", + helperText: label, + }, + }} + value={pickerValue} + minDate={minDate ? new Date(minDate) : null} + maxDate={maxDate ? new Date(maxDate) : null} + /> + + + { + formik.setFieldValue(name, ""); + setPickerValue(null); + }} + sx={{ + color: "#bfbfbf", + position: 'absolute', + right: '4px', + top: '35%', + transform: 'translateY(-50%)', + }} + > + + + + ); +} diff --git a/src/components/SelectBox.jsx b/src/components/SelectBox.jsx new file mode 100644 index 0000000..88cce6e --- /dev/null +++ b/src/components/SelectBox.jsx @@ -0,0 +1,53 @@ +import InputLabel from '@mui/material/InputLabel'; +import MenuItem from '@mui/material/MenuItem'; +import FormControl from '@mui/material/FormControl'; +import Select from '@mui/material/Select'; +import {useEffect, useState} from "react"; +const names = [ + 'Oliver Hansen', + 'Van Henry', + 'April Tucker', + 'Ralph Hubbard', + 'Omar Alexander', + 'Carlos Abbott', + 'Miriam Wagner', + 'Bradley Wilkerson', + 'Virginia Andrews', + 'Kelly Snyder', +]; +const SelectBox = ({ formik, id, defaultValue }) => { + + useEffect(() => { + formik.setFieldValue(id, defaultValue || ''); + }, []); + + const [selectedValue, setSelectedValue] = useState(defaultValue || ''); + + const handleChange = (event) => { + const { value } = event.target; + setSelectedValue(value); + formik.setFieldValue(id, value); + }; + + return ( + <> + + انتخاب + + + + ); +}; + +export default SelectBox; diff --git a/src/components/SelectBoxMultiple.jsx b/src/components/SelectBoxMultiple.jsx new file mode 100644 index 0000000..b3b943d --- /dev/null +++ b/src/components/SelectBoxMultiple.jsx @@ -0,0 +1,113 @@ +import { useTheme } from '@mui/material/styles'; +import Box from '@mui/material/Box'; +import OutlinedInput from '@mui/material/OutlinedInput'; +import InputLabel from '@mui/material/InputLabel'; +import MenuItem from '@mui/material/MenuItem'; +import FormControl from '@mui/material/FormControl'; +import Select from '@mui/material/Select'; +import Chip from '@mui/material/Chip'; +import {useEffect, useState} from "react"; + +const ITEM_HEIGHT = 48; +const ITEM_PADDING_TOP = 8; +const MenuProps = { + PaperProps: { + style: { + maxHeight: ITEM_HEIGHT * 4.5 + ITEM_PADDING_TOP, + width: 250, + }, + }, +}; + +const names = [ + 'Oliver Hansen', + 'Van Henry', + 'April Tucker', + 'Ralph Hubbard', + 'Omar Alexander', + 'Carlos Abbott', + 'Miriam Wagner', + 'Bradley Wilkerson', + 'Virginia Andrews', + 'Kelly Snyder', +]; + +function getStyles(name, personName, theme) { + return { + fontWeight: + personName.indexOf(name) === -1 + ? theme.typography.fontWeightRegular + : theme.typography.fontWeightMedium, + }; +} + +const SelectBoxMultiple = ({formik, id , defaultValue}) => { + const theme = useTheme(); + const [personName, setPersonName] = useState(defaultValue || []); + + useEffect(() => { + defaultValue.forEach((value, index) => { + formik.setFieldValue(`${id}[${index}]`, value || ''); + }); + + }, []); + + const handleChange = (event) => { + const { + target: { value }, + } = event; + console.log(value) + const selectedValues = typeof value === 'string' ? value.split(',') : value; + if (selectedValues.length === 0) { + setPersonName([]); + formik.setFieldValue(id, []); + } else { + setPersonName(selectedValues); + selectedValues.forEach((selectedValue, index) => { + formik.setFieldValue(`${id}[${index}]`, selectedValue); + }); + } + }; + + return ( + <> + + انتخاب + + + + ); +}; + +export default SelectBoxMultiple; diff --git a/src/components/TextFieldWithFnBox.jsx b/src/components/TextFieldWithFnBox.jsx index a3c277d..6ba443b 100644 --- a/src/components/TextFieldWithFnBox.jsx +++ b/src/components/TextFieldWithFnBox.jsx @@ -1,12 +1,17 @@ import {IconButton, Paper, TextField} from '@mui/material'; -import AlignHorizontalCenterIcon from '@mui/icons-material/AlignHorizontalCenter'; -import {useState} from "react"; -// import FilterBox from "@/components/FiterBox"; +import ArtTrackIcon from '@mui/icons-material/ArtTrack'; +import {useEffect, useState} from "react"; +import FilterBox from "@/components/FilterBox"; + +const TextFieldWithFnBox = ({formik, id , header, defaultValue, defaultFilter , columnFilterModeOptions ,onSelectFilter}) => { -const TextFieldWithFnBox = ({formik, id , defaultFilter , columnFilterModeOptions ,onSelectFilter}) => { const [anchorEl, setAnchorEl] = useState(null); const [open, setOpen] = useState(false); + useEffect(() => { + formik.setFieldValue(id, defaultValue || ''); + }, []); + const handleClick = (event) => { setOpen((prevOpen) => !prevOpen); setAnchorEl(anchorEl ? null : event.currentTarget); @@ -21,16 +26,16 @@ const TextFieldWithFnBox = ({formik, id , defaultFilter , columnFilterModeOptio <> - + ) }} @@ -38,7 +43,7 @@ const TextFieldWithFnBox = ({formik, id , defaultFilter , columnFilterModeOptio position: 'relative' }} /> - {/**/} + ); }; diff --git a/src/lib/contexts/tableSetting.jsx b/src/lib/contexts/tableSetting.jsx index 8ade22b..d787d87 100644 --- a/src/lib/contexts/tableSetting.jsx +++ b/src/lib/contexts/tableSetting.jsx @@ -19,8 +19,8 @@ export const TableSettingProvider = ({children}) => { const sortAction = useCallback((user_id, page_name, table_name, settingValue, columns) => { updateSettingStorage(user_id, page_name, table_name, "sorts", settingValue, columns); }, []) - const filterAction = (user_id, page_name, table_name, settingValue) => { - updateSettingStorage(user_id, page_name, table_name, "filters", settingValue); + const filterAction = (user_id, page_name, table_name, settingValue, columns) => { + updateSettingStorage(user_id, page_name, table_name, "filters", settingValue, columns); } const updateSettingStorage = (user_id, page_name, table_name, settingType, settingValue, columns) => { const prevLocalStorage = JSON.parse(localStorage.getItem("_setting-app")) || {}; @@ -28,7 +28,7 @@ export const TableSettingProvider = ({children}) => { const pageSettings = userSettings[page_name] || {}; const tableSettings = pageSettings[table_name] || {}; let newSettings; - if (settingType === "sorts") { + if (settingType === "sorts" || settingType === "filters") { newSettings = [...settingValue]; } else { newSettings = {...tableSettings[settingType] || {}, ...settingValue};