make hide action of datatable own

This commit is contained in:
2024-07-21 17:50:17 +03:30
parent bd6ea0aeae
commit d3bc855f39
15 changed files with 229 additions and 371 deletions

View File

@@ -8,6 +8,41 @@ import { GET_INQUIRY_PRIVACY_FENCING_ROUTE } from "@/core/utils/routes";
const InquiryPrivacyFencingPage = () => {
const columns = useMemo(
() => [
{
accessorKey: "fullname",
header: "fullname",
id: "fullname",
columns: [
{
accessorKey: "first_name",
header: "first_name",
id: "first_name",
columns: [
{
accessorKey: "first_name_first",
header: "first_name_first",
id: "first_name_first",
enableColumnFilter: false,
datatype: "text",
},
{
accessorKey: "first_name_last",
header: "first_name_last",
id: "first_name_last",
enableColumnFilter: false,
datatype: "text",
},
],
},
{
accessorKey: "last_name",
header: "last_name",
id: "last_name",
enableColumnFilter: false,
datatype: "text",
},
],
},
{
accessorKey: "dabirkhaneh_number",
header: "شماره دبیرخانه درخواست",

View File

@@ -1,7 +1,6 @@
import DataTable_Paper from "./table/Paper";
import { useMaterialReactTable } from "material-react-table";
import { FA_DATATABLE_LOCALIZATION } from "./localization/fa/datatable";
import useTableSetting from "@/lib/hooks/useTableSetting";
import { flattenArrayOfObjects } from "@/core/utils/flattenArrayOfObjects";
import useDataTable from "@/lib/hooks/useDataTable";
import { useMemo, useState } from "react";
@@ -10,17 +9,10 @@ import useSWR from "swr";
const DataTable_Main = (props) => {
const request = useRequest();
const isEmptyObject = (obj) => obj && Object.keys(obj).length === 0 && obj.constructor === Object;
const { filterData, sortData, setSortData, hideData, setHideData } = useDataTable();
const { need_filter, table_url, user_id, page_name, table_name, columns, initialStateProps, TableToolbar } = props;
const flatColumns = flattenArrayOfObjects(columns, "columns");
const { settingStore, hideAction } = useTableSetting();
const [pagination, setPagination] = useState({ pageIndex: 0, pageSize: 10 });
const onColumnVisibilityChange = (event) => {
setHideData(event);
};
const onSortingChange = (event) => {
setSortData(event);
};
@@ -103,7 +95,6 @@ const DataTable_Main = (props) => {
manualPagination: true,
manualSorting: true,
onPaginationChange: setPagination,
onColumnVisibilityChange: onColumnVisibilityChange,
onSortingChange: onSortingChange,
renderTopToolbarCustomActions: ({ table }) => (
<>

View File

@@ -1,30 +0,0 @@
import { IconButton, Tooltip } from "@mui/material";
import { useState } from "react";
import DataTable_ShowHideColumnsMenu from "../menus/ShowHideColumnsMenu";
const DataTable_ShowHideColumnsButton = ({ table, ...rest }) => {
const {
options: {
icons: { ViewColumnIcon },
localization,
},
} = table;
const [anchorEl, setAnchorEl] = useState(null);
const handleClick = (event) => {
setAnchorEl(event.currentTarget);
};
return (
<>
<Tooltip title={rest?.title ?? localization.showHideColumns}>
<IconButton aria-label={localization.showHideColumns} onClick={handleClick} {...rest} title={undefined}>
<ViewColumnIcon />
</IconButton>
</Tooltip>
{anchorEl && <DataTable_ShowHideColumnsMenu anchorEl={anchorEl} setAnchorEl={setAnchorEl} table={table} />}
</>
);
};
export default DataTable_ShowHideColumnsButton;

View File

@@ -19,7 +19,7 @@ function FilterHeader({ setDrawerState }) {
}}
>
<Box sx={{ display: "flex", alignItems: "center" }}>
<FilterAltIcon sx={{ color: "#fff" }} />
<FilterAltIcon sx={{ color: "#fff", mr: 1 }} />
<Typography variant="h6" sx={{ color: "#fff" }}>
فیلتر
</Typography>

View File

@@ -0,0 +1,46 @@
"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";
const ScrollBox = styled(Box)({
flexGrow: 1,
overflowY: "scroll",
maxWidth: "450px",
"::-webkit-scrollbar": {
width: "5px",
},
"::-webkit-scrollbar-track": {
boxShadow: "inset 0 0 5px #fff",
borderRadius: "5px",
},
"::-webkit-scrollbar-thumb": {
background: "#155175",
borderRadius: "0px",
},
});
function HideBody({ columns, drawerState, setDrawerState }) {
const { hideData } = useDataTable();
return (
<Drawer
open={drawerState}
onClose={() => setDrawerState(false)}
sx={{ overflowY: "hidden", display: "flex", flexDirection: "column", height: "100%" }}
>
<HideHeader setDrawerState={setDrawerState} />
{Object.keys(hideData).length > 0 && (
<ScrollBox>
<Box sx={{ px: 1, py: 2, display: "flex", flexDirection: "column" }}>
{columns.map((column) => (<HideBodyField key={column.id} column={column} />))}
</Box>
</ScrollBox>
)}
</Drawer>
);
}
export default HideBody;

View File

@@ -0,0 +1,38 @@
import { Box, FormControlLabel, Switch, Typography } from "@mui/material";
import useDataTable from "@/lib/hooks/useDataTable";
function HideBodyField({ column, level = 0 }) {
const { hideData, setHideData } = useDataTable();
const paddingLeft = 2 * level;
return (
<Box sx={{ py: 1, px: 1, pl: paddingLeft }}>
<FormControlLabel
control={
<Switch
checked={hideData[column.id]}
onChange={() => {
setHideData(hideData => ({
...hideData,
[column.id]: !hideData[column.id],
}));
}}
name={column.id}
/>
}
label={
<Typography variant="subtitle1">{column.header}</Typography>
}
/>
{column.columns?.map((subColumn) => (
<HideBodyField
key={subColumn.id}
column={subColumn}
level={level + 1}
/>
))}
</Box>
);
}
export default HideBodyField;

View File

@@ -0,0 +1,21 @@
"use client";
import ViewColumnIcon from "@mui/icons-material/ViewColumn";
import { IconButton, Tooltip } from "@mui/material";
function HideButton({ drawerState, setDrawerState }) {
return (
<Tooltip title="نمایش/مخفی کردن ستون ها">
<IconButton
onClick={() => {
setDrawerState(!drawerState);
}}
aria-label="hide table column"
>
<ViewColumnIcon />
</IconButton>
</Tooltip>
);
}
export default HideButton;

View File

@@ -0,0 +1,34 @@
"use client";
import { Box, IconButton, Typography } from "@mui/material";
import CancelIcon from "@mui/icons-material/Cancel";
import ViewColumnIcon from "@mui/icons-material/ViewColumn";
function FilterHeader({ setDrawerState }) {
return (
<Box
sx={{
display: "flex",
alignItems: "center",
justifyContent: "space-between",
px: 2,
py: 1,
backgroundColor: "#155175",
boxShadow: "rgba(0, 0, 0, 0.19) 0px 10px 20px, rgba(0, 0, 0, 0.23) 0px 6px 6px",
maxWidth: "450px",
}}
>
<Box sx={{ display: "flex", alignItems: "center" }}>
<ViewColumnIcon sx={{ color: "#fff", mr: 1 }} />
<Typography variant="h6" sx={{ color: "#fff" }}>
نمایش/مخفی کردن ستون ها
</Typography>
</Box>
<IconButton sx={{ color: "#fff" }} onClick={() => setDrawerState(false)}>
<CancelIcon sx={{ fontSize: "1em" }} />
</IconButton>
</Box>
);
}
export default FilterHeader;

View File

@@ -0,0 +1,24 @@
"use client";
import { useState } from "react";
import HideButton from "@/core/components/DataTable/hide/HideButton";
import HideBody from "@/core/components/DataTable/hide/HideBody";
function HideColumn({ columns, user_id, page_name, table_name }) {
const [open, setOpen] = useState(false);
return (
<>
<HideButton drawerState={open} setDrawerState={setOpen} />
<HideBody
columns={columns}
drawerState={open}
setDrawerState={setOpen}
user_id={user_id}
page_name={page_name}
table_name={table_name}
/>
</>
);
}
export default HideColumn;

View File

@@ -1,116 +0,0 @@
import { Box, Button, Divider, Menu } from "@mui/material";
import { useMemo, useState } from "react";
import DataTable_ShowHideColumnsMenuItems from "./ShowHideColumnsMenuItems";
const DataTable_ShowHideColumnsMenu = ({ anchorEl, setAnchorEl, table, ...rest }) => {
const {
getAllColumns,
getAllLeafColumns,
getCenterLeafColumns,
getIsAllColumnsVisible,
getIsSomeColumnsPinned,
getIsSomeColumnsVisible,
getLeftLeafColumns,
getRightLeafColumns,
getState,
options: {
enableColumnOrdering,
enableColumnPinning,
enableHiding,
localization,
mrtTheme: { menuBackgroundColor },
},
} = table;
const { columnOrder, columnPinning, density } = getState();
const handleToggleAllColumns = (value) => {
getAllLeafColumns()
.filter((col) => col.columnDef.enableHiding !== false)
.forEach((col) => col.toggleVisibility(value));
};
const allColumns = useMemo(() => {
const columns = getAllColumns();
if (columnOrder.length > 0 && !columns.some((col) => col.columnDef.columnDefType === "group")) {
return [
...getLeftLeafColumns(),
...Array.from(new Set(columnOrder)).map((colId) =>
getCenterLeafColumns().find((col) => col?.id === colId)
),
...getRightLeafColumns(),
].filter(Boolean);
}
return columns;
}, [
columnOrder,
columnPinning,
getAllColumns(),
getCenterLeafColumns(),
getLeftLeafColumns(),
getRightLeafColumns(),
]);
const isNestedColumns = allColumns.some((col) => col.columnDef.columnDefType === "group");
const [hoveredColumn, setHoveredColumn] = useState(null);
return (
<Menu
MenuListProps={{
dense: density === "compact",
sx: {
backgroundColor: menuBackgroundColor,
},
}}
anchorEl={anchorEl}
disableScrollLock
onClose={() => setAnchorEl(null)}
open={!!anchorEl}
{...rest}
>
<Box
sx={{
display: "flex",
justifyContent: "space-between",
p: "0.5rem",
pt: 0,
}}
>
{enableHiding && (
<Button disabled={!getIsSomeColumnsVisible()} onClick={() => handleToggleAllColumns(false)}>
{localization.hideAll}
</Button>
)}
{enableColumnOrdering && (
<Button onClick={() => table.setColumnOrder(getDefaultColumnOrderIds(table.options, true))}>
{localization.resetOrder}
</Button>
)}
{enableColumnPinning && (
<Button disabled={!getIsSomeColumnsPinned()} onClick={() => table.resetColumnPinning(true)}>
{localization.unpinAll}
</Button>
)}
{enableHiding && (
<Button disabled={getIsAllColumnsVisible()} onClick={() => handleToggleAllColumns(true)}>
{localization.showAll}
</Button>
)}
</Box>
<Divider />
{allColumns.map((column, index) => (
<DataTable_ShowHideColumnsMenuItems
allColumns={allColumns}
column={column}
hoveredColumn={hoveredColumn}
isNestedColumns={isNestedColumns}
key={`${index}-${column.id}`}
setHoveredColumn={setHoveredColumn}
table={table}
/>
))}
</Menu>
);
};
export default DataTable_ShowHideColumnsMenu;

View File

@@ -1,154 +0,0 @@
import { getCommonTooltipProps, parseFromValuesOrFunc } from "@/core/utils/utils";
import { Box, FormControlLabel, MenuItem, Switch, Tooltip, Typography } from "@mui/material";
import { useRef, useState } from "react";
import DataTable_GrabHandleButton from "../buttons/GrabHandleButton";
const DataTable_ShowHideColumnsMenuItems = ({
allColumns,
column,
hoveredColumn,
isNestedColumns,
setHoveredColumn,
table,
...rest
}) => {
const {
getState,
options: {
enableColumnOrdering,
enableHiding,
localization,
mrtTheme: { draggingBorderColor },
},
setColumnOrder,
} = table;
const { columnOrder } = getState();
const { columnDef } = column;
const { columnDefType } = columnDef;
const switchChecked = column.getIsVisible();
const handleToggleColumnHidden = (column) => {
if (columnDefType === "group") {
column?.columns?.forEach?.((childColumn) => {
childColumn.toggleVisibility(!switchChecked);
});
} else {
column.toggleVisibility();
}
};
const menuItemRef = useRef(null);
const [isDragging, setIsDragging] = useState(false);
const handleDragStart = (e) => {
setIsDragging(true);
try {
e.dataTransfer.setDragImage(menuItemRef.current, 0, 0);
} catch (e) {
console.error(e);
}
};
const handleDragEnd = (_e) => {
setIsDragging(false);
setHoveredColumn(null);
if (hoveredColumn) {
setColumnOrder(reorderColumn(column, hoveredColumn, columnOrder));
}
};
const handleDragEnter = (_e) => {
if (!isDragging && columnDef.enableColumnOrdering !== false) {
setHoveredColumn(column);
}
};
if (!columnDef.header || columnDef.visibleInShowHideMenu === false) {
return null;
}
return (
<>
<MenuItem
disableRipple
onDragEnter={handleDragEnter}
ref={menuItemRef}
{...rest}
sx={(theme) => ({
alignItems: "center",
justifyContent: "flex-start",
my: 0,
opacity: isDragging ? 0.5 : 1,
outline: isDragging
? `2px dashed ${theme.palette.grey[500]}`
: hoveredColumn?.id === column.id
? `2px dashed ${draggingBorderColor}`
: "none",
outlineOffset: "-2px",
pl: `${(column.depth + 0.5) * 2}rem`,
py: "6px",
...parseFromValuesOrFunc(rest?.sx, theme),
})}
>
<Box
sx={{
display: "flex",
flexWrap: "nowrap",
gap: "8px",
}}
>
{columnDefType !== "group" &&
enableColumnOrdering &&
!isNestedColumns &&
(columnDef.enableColumnOrdering !== false ? (
<DataTable_GrabHandleButton
onDragEnd={handleDragEnd}
onDragStart={handleDragStart}
table={table}
/>
) : (
<Box sx={{ width: "28px" }} />
))}
{enableHiding ? (
<FormControlLabel
checked={switchChecked}
componentsProps={{
typography: {
sx: {
mb: 0,
opacity: columnDefType !== "display" ? 1 : 0.5,
},
},
}}
control={
<Tooltip {...getCommonTooltipProps()} title={localization.toggleVisibility}>
<Switch />
</Tooltip>
}
disabled={!column.getCanHide()}
label={columnDef.header}
onChange={() => handleToggleColumnHidden(column)}
/>
) : (
<Typography sx={{ alignSelf: "center" }}>{columnDef.header}</Typography>
)}
</Box>
</MenuItem>
{column.columns?.map((c, i) => (
<DataTable_ShowHideColumnsMenuItems
allColumns={allColumns}
column={c}
hoveredColumn={hoveredColumn}
isNestedColumns={isNestedColumns}
key={`${i}-${c.id}`}
setHoveredColumn={setHoveredColumn}
table={table}
/>
))}
</>
);
};
export default DataTable_ShowHideColumnsMenuItems;

View File

@@ -1,44 +0,0 @@
import { parseFromValuesOrFunc } from "@/core/utils/utils";
import { Box } from "@mui/material";
import DataTable_ShowHideColumnsButton from "../buttons/ShowHideColumnsButton";
import DataTable_ToggleFiltersButton from "../buttons/ToggleFiltersButton";
const DataTable_ToolbarInternalButtons = ({ table, ...rest }) => {
const {
options: {
columnFilterDisplayMode,
enableColumnFilters,
enableColumnOrdering,
enableColumnPinning,
enableFilters,
enableHiding,
renderToolbarInternalActions,
},
} = table;
return (
<Box
{...rest}
sx={(theme) => ({
alignItems: "center",
display: "flex",
zIndex: 3,
...parseFromValuesOrFunc(rest?.sx, theme),
})}
>
{renderToolbarInternalActions?.({
table,
}) ?? (
<>
{enableFilters && enableColumnFilters && columnFilterDisplayMode !== "popover" && (
<DataTable_ToggleFiltersButton table={table} />
)}
{(enableHiding || enableColumnOrdering || enableColumnPinning) && (
<DataTable_ShowHideColumnsButton table={table} />
)}
</>
)}
</Box>
);
};
export default DataTable_ToolbarInternalButtons;

View File

@@ -2,10 +2,10 @@ import { getCommonToolbarStyles, parseFromValuesOrFunc } from "@/core/utils/util
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";
import UpdateTable from "@/core/components/DataTable/update/UpdateTable";
import ResetStorage from "@/core/components/DataTable/reset/ResetStorage";
import HideColumn from "@/core/components/DataTable/hide";
const DataTable_TopToolbar = ({ mutate, need_filter, table, columns, table_url, user_id, page_name, table_name }) => {
const {
@@ -74,6 +74,11 @@ const DataTable_TopToolbar = ({ mutate, need_filter, table, columns, table_url,
page_name={page_name}
table_name={table_name} />
<UpdateTable mutate={mutate} />
<HideColumn
columns={table.options.columns}
user_id={user_id}
page_name={page_name}
table_name={table_name} />
{need_filter && (
<FilterColumn
columns={columns}
@@ -83,7 +88,6 @@ const DataTable_TopToolbar = ({ mutate, need_filter, table, columns, table_url,
table_name={table_name}
/>
)}
<DataTable_ToolbarInternalButtons table={table} />
</Box>
)}
</Box>

View File

@@ -1,10 +1,10 @@
export const flattenArrayOfObjects = (array, key) => {
return array.reduce((acc, obj) => {
acc.push(obj);
if (Array.isArray(obj[key])) {
acc.push(...flattenArrayOfObjects(obj[key]));
} else {
acc.push(obj);
acc.push(...flattenArrayOfObjects(obj[key], key));
}
return acc;
}, []);
};

View File

@@ -19,44 +19,53 @@ const DataTableProvider = ({ children, user_id, page_name, table_name, columns }
useEffect(() => {
if (!settingStore) return;
const values = flatColumns.reduce((acc, column) => {
const filterValues = flatColumns.reduce((acc, column) => {
if (!column.enableColumnFilter) return acc;
const filter = settingStore?.[user_id]?.[page_name]?.[table_name]?.["filters"]?.find(
const storeFilter = settingStore?.[user_id]?.[page_name]?.[table_name]?.["filters"]?.find(
(filter) => filter.id === column.id,
);
if (column.datatype === "array") {
acc[column.id] = {
id: column.id,
value: filter?.value || [],
filterFn: filter?.filterFn || column._filterFn,
value: storeFilter?.value || [],
filterFn: storeFilter?.filterFn || column._filterFn,
datatype: column.datatype,
};
} else if (column._filterFn === "between") {
acc[column.id] = {
id: column.id,
value: filter?.value || ["", ""],
filterFn: filter?.filterFn || column._filterFn,
value: storeFilter?.value || ["", ""],
filterFn: storeFilter?.filterFn || column._filterFn,
datatype: column.datatype,
};
} else {
acc[column.id] = {
id: column.id,
value: filter?.value || "",
filterFn: filter?.filterFn || column._filterFn,
value: storeFilter?.value || "",
filterFn: storeFilter?.filterFn || column._filterFn,
datatype: column.datatype,
};
}
return acc;
}, {});
setFilterData(values);
setInitFilter(values);
setFilterData(filterValues);
setInitFilter(filterValues);
setSortData(settingStore?.[user_id]?.[page_name]?.[table_name]?.["sorts"] || []);
setInitSort(settingStore?.[user_id]?.[page_name]?.[table_name]?.["sorts"] || []);
setHideData(settingStore?.[user_id]?.[page_name]?.[table_name]?.["hides"] || {});
setInitHide(settingStore?.[user_id]?.[page_name]?.[table_name]?.["hides"] || {});
setInitStates(true);
}, [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;
}, {});
setHideData(hideValues);
setInitHide(hideValues);
}, [settingStore, isInitStates]);
useEffect(() => {
if (
JSON.stringify(initFilter) !== JSON.stringify(filterData) ||