From f9743637902623a5089f33ff3ff892961bbf0309 Mon Sep 17 00:00:00 2001 From: Mohammad Jalali Date: Sat, 27 Jul 2024 11:32:27 +0330 Subject: [PATCH] complete hide action part with button for hide or show all table header --- package.json | 1 + .../dashboard/inquiryPrivacyFencing/index.jsx | 51 ++++++++-- src/core/components/DataTable/Main.js | 8 +- .../components/DataTable/hide/HideBody.jsx | 27 +++-- .../DataTable/hide/HideBodyField.jsx | 98 +++++++++++++------ .../DataTable/hide/HideOrShowAll.jsx | 70 +++++++++++++ .../NotificationDesign/AskForKeepData.jsx | 6 +- src/core/utils/flattenObjectOfObjects.jsx | 12 +++ src/lib/contexts/DataTable.js | 23 +++-- 9 files changed, 239 insertions(+), 57 deletions(-) create mode 100644 src/core/components/DataTable/hide/HideOrShowAll.jsx create mode 100644 src/core/utils/flattenObjectOfObjects.jsx diff --git a/package.json b/package.json index 36ec3d1..f9593c8 100644 --- a/package.json +++ b/package.json @@ -18,6 +18,7 @@ "@mui/material": "^5.15.6", "@mui/material-nextjs": "^5.15.6", "@mui/x-date-pickers": "^6.19.5", + "@mui/x-tree-view": "^7.11.0", "axios": "^1.7.2", "date-fns": "^3.3.1", "date-fns-jalali": "^2.13.0-0", diff --git a/src/components/dashboard/inquiryPrivacyFencing/index.jsx b/src/components/dashboard/inquiryPrivacyFencing/index.jsx index 3ee9a28..1de7b31 100644 --- a/src/components/dashboard/inquiryPrivacyFencing/index.jsx +++ b/src/components/dashboard/inquiryPrivacyFencing/index.jsx @@ -10,25 +10,41 @@ const InquiryPrivacyFencingPage = () => { () => [ { accessorKey: "fullname", - header: "fullname", + header: "نام کامل", id: "fullname", columns: [ { accessorKey: "first_name", - header: "first_name", + header: "اسم", id: "first_name", columns: [ { - accessorKey: "first_name_first", - header: "first_name_first", - id: "first_name_first", + accessorKey: "part1", + header: "فامیل", + id: "part1", enableColumnFilter: false, datatype: "text", + columns: [ + { + accessorKey: "part1_1", + header: "part1_1", + id: "part1_1", + enableColumnFilter: false, + datatype: "text", + }, + { + accessorKey: "part1_2", + header: "part1_2", + id: "part1_2", + enableColumnFilter: false, + datatype: "text", + }, + ], }, { - accessorKey: "first_name_last", - header: "first_name_last", - id: "first_name_last", + accessorKey: "part2", + header: "part2", + id: "part2", enableColumnFilter: false, datatype: "text", }, @@ -43,6 +59,25 @@ const InquiryPrivacyFencingPage = () => { }, ], }, + { + accessorKey: "something", + header: "something", + id: "something", + columns: [ + { + accessorKey: "something1", + header: "something1", + id: "something1", + }, + { + accessorKey: "something2", + header: "something2", + id: "something2", + enableColumnFilter: false, + datatype: "text", + }, + ], + }, { accessorKey: "dabirkhaneh_number", header: "شماره دبیرخانه درخواست", diff --git a/src/core/components/DataTable/Main.js b/src/core/components/DataTable/Main.js index 4a3908b..78bf9a8 100644 --- a/src/core/components/DataTable/Main.js +++ b/src/core/components/DataTable/Main.js @@ -6,13 +6,15 @@ import useDataTable from "@/lib/hooks/useDataTable"; import { useMemo, useState } from "react"; import useRequest from "@/lib/hooks/useRequest"; import useSWR from "swr"; +import { flattenObjectOfObjects } from "@/core/utils/flattenObjectOfObjects"; const DataTable_Main = (props) => { const request = useRequest(); - const { filterData, sortData, setSortData, hideData, setHideData } = useDataTable(); + const { filterData, sortData, setSortData, hideData } = useDataTable(); const { need_filter, table_url, user_id, page_name, table_name, columns, initialStateProps, TableToolbar } = props; const flatColumns = flattenArrayOfObjects(columns, "columns"); const [pagination, setPagination] = useState({ pageIndex: 0, pageSize: 10 }); + const flattenHideData = flattenObjectOfObjects(hideData); const onSortingChange = (event) => { setSortData(event); }; @@ -58,13 +60,13 @@ const DataTable_Main = (props) => { data: data?.data ?? [], initialState: { density: "compact", - columnVisibility: hideData, + columnVisibility: flattenHideData, sorting: sortData, ...initialStateProps, }, state: { showProgressBars: isValidating, - columnVisibility: hideData, + columnVisibility: flattenHideData, sorting: sortData, pagination, }, diff --git a/src/core/components/DataTable/hide/HideBody.jsx b/src/core/components/DataTable/hide/HideBody.jsx index adf4c12..d6e18cb 100644 --- a/src/core/components/DataTable/hide/HideBody.jsx +++ b/src/core/components/DataTable/hide/HideBody.jsx @@ -1,9 +1,10 @@ "use client"; import { Box, Drawer, styled } from "@mui/material"; -import useDataTable from "@/lib/hooks/useDataTable"; import HideBodyField from "@/core/components/DataTable/hide/HideBodyField"; import HideHeader from "@/core/components/DataTable/hide/HideHeader"; +import useDataTable from "@/lib/hooks/useDataTable"; +import HideOrShowAll from "@/core/components/DataTable/hide/HideOrShowAll"; const ScrollBox = styled(Box)({ flexGrow: 1, @@ -23,7 +24,7 @@ const ScrollBox = styled(Box)({ }); function HideBody({ columns, drawerState, setDrawerState }) { - const { hideData } = useDataTable(); + const { hideData, setHideData } = useDataTable(); return ( - {Object.keys(hideData).length > 0 && ( - - - {columns.map((column) => ())} - - - )} + + + + {columns.map((column) => ( + + ))} + + ); } -export default HideBody; +export default HideBody; \ No newline at end of file diff --git a/src/core/components/DataTable/hide/HideBodyField.jsx b/src/core/components/DataTable/hide/HideBodyField.jsx index e8123af..fe3dc2d 100644 --- a/src/core/components/DataTable/hide/HideBodyField.jsx +++ b/src/core/components/DataTable/hide/HideBodyField.jsx @@ -1,37 +1,79 @@ -import { Box, FormControlLabel, Switch, Typography } from "@mui/material"; -import useDataTable from "@/lib/hooks/useDataTable"; +import { alpha, Box, Checkbox, styled, Typography } from "@mui/material"; +import { SimpleTreeView } from "@mui/x-tree-view"; +import { TreeItem, treeItemClasses } from "@mui/x-tree-view/TreeItem"; -function HideBodyField({ column, level = 0 }) { - const { hideData, setHideData } = useDataTable(); - const paddingLeft = 2 * level; +const CustomTreeItem = styled(TreeItem)(({ theme }) => ({ + [`& .${treeItemClasses.content}`]: { + padding: theme.spacing(0.5, 0.5), + margin: theme.spacing(0.2, 0), + gap: 0, + }, + [`& .${treeItemClasses.iconContainer}`]: { + "& .close": { + opacity: 0.3, + }, + }, + [`& .${treeItemClasses.groupTransition}`]: { + marginLeft: 16, + paddingLeft: 16, + borderLeft: `1px dashed ${alpha(theme.palette.text.primary, 0.4)}`, + }, +})); - return ( - - { + setHideData(prevData => { + const updateHideData = (data, id) => { + if (data.hasOwnProperty(id)) { + return { ...data, [id]: !data[id] }; + } + const updatedData = { ...data }; + for (const key in data) { + if (data[key] && typeof data[key] === "object") { + updatedData[key] = updateHideData(data[key], id); + } + } + return updatedData; + }; + + return updateHideData(prevData, column.id); + }); + }; + + const labelContent = (() => { + if (typeof hideData[column.id] === "boolean") { + return ( + + { - setHideData(hideData => ({ - ...hideData, - [column.id]: !hideData[column.id], - })); - }} + onChange={handleCheckboxChange} name={column.id} /> - } - label={ {column.header} - } - /> - {column.columns?.map((subColumn) => ( - - ))} - + + ); + } else { + return ( + + {column.header} + + ); + } + })(); + + return ( + + + {column.columns?.map((subColumn) => ( + + ))} + + ); } diff --git a/src/core/components/DataTable/hide/HideOrShowAll.jsx b/src/core/components/DataTable/hide/HideOrShowAll.jsx new file mode 100644 index 0000000..3c9131a --- /dev/null +++ b/src/core/components/DataTable/hide/HideOrShowAll.jsx @@ -0,0 +1,70 @@ +"use client"; + +import { Box, Button } from "@mui/material"; +import VisibilityIcon from "@mui/icons-material/Visibility"; +import VisibilityOffIcon from "@mui/icons-material/VisibilityOff"; + +const setAllValues = (obj, value) => { + const result = {}; + for (const key in obj) { + if (typeof obj[key] === "object" && obj[key] !== null) { + result[key] = setAllValues(obj[key], value); + } else { + result[key] = value; + } + } + return result; +}; + +const allValuesAre = (obj, value) => { + for (const key in obj) { + if (typeof obj[key] === "object" && obj[key] !== null) { + if (!allValuesAre(obj[key], value)) { + return false; + } + } else if (obj[key] !== value) { + return false; + } + } + return true; +}; + +function HideOrShowAll({ hideData, setHideData }) { + const handleShowAll = () => { + const newHideData = setAllValues(hideData, true); + setHideData(newHideData); + }; + + const handleHideAll = () => { + const newHideData = setAllValues(hideData, false); + setHideData(newHideData); + }; + + const allHidden = allValuesAre(hideData, false); + const allVisible = allValuesAre(hideData, true); + + return ( + + + + + ); +} + +export default HideOrShowAll; \ No newline at end of file diff --git a/src/core/components/NotificationDesign/AskForKeepData.jsx b/src/core/components/NotificationDesign/AskForKeepData.jsx index 58475c1..ab8c272 100644 --- a/src/core/components/NotificationDesign/AskForKeepData.jsx +++ b/src/core/components/NotificationDesign/AskForKeepData.jsx @@ -5,9 +5,11 @@ import { Box, Button, Typography } from "@mui/material"; import DownloadIcon from "@mui/icons-material/Download"; import { toast } from "react-toastify"; import useTableSetting from "@/lib/hooks/useTableSetting"; +import { flattenObjectOfObjects } from "@/core/utils/flattenObjectOfObjects"; function AskForKeepData({ filterData, sortData, hideData, user_id, page_name, table_name, columns }) { const { filterAction, sortAction, hideAction } = useTableSetting(); + const flattenHideData = flattenObjectOfObjects(hideData); const onSaveFilter = () => { const filteredItems = Object.keys(filterData) @@ -26,7 +28,7 @@ function AskForKeepData({ filterData, sortData, hideData, user_id, page_name, ta .filter(Boolean); filterAction(user_id, page_name, table_name, filteredItems, columns); sortAction(user_id, page_name, table_name, sortData, columns); - hideAction(user_id, page_name, table_name, hideData, columns); + hideAction(user_id, page_name, table_name, flattenHideData, columns); toast.dismiss({ containerId: "datatable" }); }; @@ -75,4 +77,4 @@ function AskForKeepData({ filterData, sortData, hideData, user_id, page_name, ta ); } -export default AskForKeepData; +export default AskForKeepData; \ No newline at end of file diff --git a/src/core/utils/flattenObjectOfObjects.jsx b/src/core/utils/flattenObjectOfObjects.jsx new file mode 100644 index 0000000..3fdac84 --- /dev/null +++ b/src/core/utils/flattenObjectOfObjects.jsx @@ -0,0 +1,12 @@ +export const flattenObjectOfObjects = (obj, res = {}) => { + for (let key in obj) { + if (obj.hasOwnProperty(key)) { + if (typeof obj[key] === "object" && obj[key] !== null) { + flattenObjectOfObjects(obj[key], res); + } else { + res[key] = obj[key]; + } + } + } + return res; +}; \ No newline at end of file diff --git a/src/lib/contexts/DataTable.js b/src/lib/contexts/DataTable.js index 4d50a7f..f5a625d 100644 --- a/src/lib/contexts/DataTable.js +++ b/src/lib/contexts/DataTable.js @@ -56,12 +56,23 @@ const DataTableProvider = ({ children, user_id, page_name, table_name, columns } }, [settingStore, isInitStates]); useEffect(() => { - const hideValues = flatColumns.reduce((acc, column) => { - const columnId = column.id; - const storeHide = settingStore?.[user_id]?.[page_name]?.[table_name]?.["hides"]?.[columnId]; - acc[columnId] = storeHide !== undefined ? storeHide : true; - return acc; - }, {}); + const getHideValues = (columns) => { + return columns.reduce((acc, column) => { + const columnId = column.id; + const storeHide = settingStore?.[user_id]?.[page_name]?.[table_name]?.["hides"]?.[columnId]; + + // If the column has nested columns, process them recursively + if (column.columns && column.columns.length > 0) { + acc[columnId] = getHideValues(column.columns); + } else { + acc[columnId] = storeHide !== undefined ? storeHide : true; + } + + return acc; + }, {}); + }; + + const hideValues = getHideValues(columns); setHideData(hideValues); setInitHide(hideValues); }, [settingStore, isInitStates]);