diff --git a/client/src/shared/components/ManageTable.js b/client/src/shared/components/ManageTable.js
index 5114892..185c670 100644
--- a/client/src/shared/components/ManageTable.js
+++ b/client/src/shared/components/ManageTable.js
@@ -2,7 +2,59 @@ import React, { useRef, useState } from "react";
import { Dropdown } from "react-bootstrap";
import { Columns } from "react-bootstrap-icons";
-const ManageTable = ({ columns, onColumnsChange, show, onToggle }) => {
+const getSessionStorageValue = (key) => {
+ try {
+ return window.sessionStorage.getItem(key);
+ } catch (_e) {
+ return null;
+ }
+};
+
+const setSessionStorageValue = (key, value) => {
+ try {
+ window.sessionStorage.setItem(key, value);
+ return true;
+ } catch (_e) {
+ return false;
+ }
+};
+
+const getCookieNameFromKey = (key) => `manage_table_${`${key}`.replace(/[^a-zA-Z0-9_-]/g, "_")}`;
+
+const getCookieValue = (name) => {
+ if (typeof document === "undefined") return null;
+ const cookie = document.cookie
+ .split("; ")
+ .find((row) => row.startsWith(`${name}=`));
+ if (!cookie) return null;
+ return decodeURIComponent(cookie.split("=")[1] || "");
+};
+
+const setCookieValue = (name, value) => {
+ if (typeof document === "undefined") return;
+ document.cookie = `${name}=${encodeURIComponent(value)}; path=/; SameSite=Lax`;
+};
+
+const toVisibilityMap = (columnList = []) => (
+ columnList.reduce((acc, col) => {
+ acc[col.key] = !!col.show;
+ return acc;
+ }, {})
+);
+
+const applyVisibilityMap = (columnList = [], visibilityMap = {}) => (
+ columnList.map((col) => (
+ Object.prototype.hasOwnProperty.call(visibilityMap, col.key)
+ ? { ...col, show: !!visibilityMap[col.key] }
+ : col
+ ))
+);
+
+const hasVisibilityDiff = (left = [], right = []) => (
+ left.length !== right.length || left.some((col, idx) => col.key !== right[idx]?.key || !!col.show !== !!right[idx]?.show)
+);
+
+const ManageTable = ({ columns, onColumnsChange, show, onToggle, storageKey }) => {
const [internalShow, setInternalShow] = useState(false);
const [tempColumns, setTempColumns] = useState(columns);
const scrollContainerRef = useRef(null);
@@ -11,10 +63,41 @@ const ManageTable = ({ columns, onColumnsChange, show, onToggle }) => {
// Use external control if provided, otherwise use internal state
const showManageTableDropdown = show !== undefined ? show : internalShow;
const handleToggle = onToggle || (() => setInternalShow(!internalShow));
+ const resolvedStorageKey = React.useMemo(() => {
+ if (storageKey) return storageKey;
+ const path = window?.location?.pathname || "default";
+ let userKey = "guest";
+ try {
+ const user = JSON.parse(localStorage.getItem("user") || "{}");
+ userKey = user?.id || user?._id || user?.name || "guest";
+ } catch (_e) {
+ userKey = "guest";
+ }
+ return `manage-table:${path}:${userKey}`;
+ }, [storageKey]);
React.useEffect(() => {
- setTempColumns(columns);
- }, [columns]);
+ const rawSessionValue = getSessionStorageValue(resolvedStorageKey);
+ const cookieName = getCookieNameFromKey(resolvedStorageKey);
+ const rawCookieValue = getCookieValue(cookieName);
+ const rawValue = rawSessionValue || rawCookieValue;
+
+ if (!rawValue) {
+ setTempColumns(columns);
+ return;
+ }
+
+ try {
+ const parsedVisibilityMap = JSON.parse(rawValue);
+ const mergedColumns = applyVisibilityMap(columns, parsedVisibilityMap);
+ setTempColumns(mergedColumns);
+ if (hasVisibilityDiff(columns, mergedColumns)) {
+ onColumnsChange(mergedColumns);
+ }
+ } catch (_e) {
+ setTempColumns(columns);
+ }
+ }, [columns, onColumnsChange, resolvedStorageKey]);
const handleColumnToggle = (columnKey) => {
scrollTopRef.current = scrollContainerRef.current?.scrollTop || 0;
@@ -30,6 +113,13 @@ const ManageTable = ({ columns, onColumnsChange, show, onToggle }) => {
};
const handleDone = () => {
+ const visibilityMapString = JSON.stringify(toVisibilityMap(tempColumns));
+ const wroteToSession = setSessionStorageValue(resolvedStorageKey, visibilityMapString);
+ if (!wroteToSession) {
+ setCookieValue(getCookieNameFromKey(resolvedStorageKey), visibilityMapString);
+ } else {
+ setCookieValue(getCookieNameFromKey(resolvedStorageKey), visibilityMapString);
+ }
onColumnsChange(tempColumns);
if (onToggle) {
onToggle(false);
@@ -58,6 +148,17 @@ const ManageTable = ({ columns, onColumnsChange, show, onToggle }) => {
});
};
+ const handleSelectAll = () => {
+ scrollTopRef.current = scrollContainerRef.current?.scrollTop || 0;
+ const updatedColumns = tempColumns.map((col) => ({ ...col, show: true }));
+ setTempColumns(updatedColumns);
+ requestAnimationFrame(() => {
+ if (scrollContainerRef.current) {
+ scrollContainerRef.current.scrollTop = scrollTopRef.current;
+ }
+ });
+ };
+
const customManageTableMenu = React.forwardRef(
({ children, style, className, 'aria-labelledby': labeledBy }, ref) => {
return (
@@ -68,7 +169,14 @@ const ManageTable = ({ columns, onColumnsChange, show, onToggle }) => {
aria-labelledby={labeledBy}
>
Manage Table Columns
-