This commit is contained in:
@@ -43,6 +43,17 @@ const Export = ({ columns, data, filename = "export", customActions = [], show,
|
||||
});
|
||||
};
|
||||
|
||||
const handleSelectAll = () => {
|
||||
scrollTopRef.current = scrollContainerRef.current?.scrollTop || 0;
|
||||
const updatedColumns = exportColumns.map((col) => ({ ...col, show: true }));
|
||||
setExportColumns(updatedColumns);
|
||||
requestAnimationFrame(() => {
|
||||
if (scrollContainerRef.current) {
|
||||
scrollContainerRef.current.scrollTop = scrollTopRef.current;
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
const generateCSV = () => {
|
||||
const visibleColumns = exportColumns.filter(col => col.show);
|
||||
const headers = visibleColumns.map(col => col.label).join(',');
|
||||
@@ -158,6 +169,14 @@ const Export = ({ columns, data, filename = "export", customActions = [], show,
|
||||
<div style={{ maxHeight: '200px', overflowY: 'auto', marginBottom: '15px' }} ref={scrollContainerRef}>
|
||||
<div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', marginBottom: '10px' }}>
|
||||
<h6 style={{ fontSize: '14px', marginBottom: 0 }}>Select Columns:</h6>
|
||||
<div style={{ display: 'flex', gap: '10px' }}>
|
||||
<button
|
||||
type="button"
|
||||
className="btn btn-link btn-sm p-0"
|
||||
onClick={handleSelectAll}
|
||||
>
|
||||
Select All
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
className="btn btn-link btn-sm p-0"
|
||||
@@ -166,6 +185,7 @@ const Export = ({ columns, data, filename = "export", customActions = [], show,
|
||||
Deselect All
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
{exportColumns.map((column) => (
|
||||
<div key={column.key} style={{ marginBottom: '8px' }}>
|
||||
<input
|
||||
|
||||
@@ -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(() => {
|
||||
const rawSessionValue = getSessionStorageValue(resolvedStorageKey);
|
||||
const cookieName = getCookieNameFromKey(resolvedStorageKey);
|
||||
const rawCookieValue = getCookieValue(cookieName);
|
||||
const rawValue = rawSessionValue || rawCookieValue;
|
||||
|
||||
if (!rawValue) {
|
||||
setTempColumns(columns);
|
||||
}, [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}
|
||||
>
|
||||
<h6>Manage Table Columns</h6>
|
||||
<div style={{ marginBottom: '8px' }}>
|
||||
<div style={{ marginBottom: '8px', display: 'flex', gap: '10px' }}>
|
||||
<button
|
||||
type="button"
|
||||
className="btn btn-link btn-sm p-0"
|
||||
onClick={handleSelectAll}
|
||||
>
|
||||
Select All
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
className="btn btn-link btn-sm p-0"
|
||||
|
||||
Reference in New Issue
Block a user