fix
All checks were successful
Build And Deploy Main / build-and-deploy (push) Successful in 34s

This commit is contained in:
2026-03-19 12:39:56 -04:00
parent e1a870de47
commit a3f48685b6
2 changed files with 139 additions and 11 deletions

View File

@@ -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 generateCSV = () => {
const visibleColumns = exportColumns.filter(col => col.show); const visibleColumns = exportColumns.filter(col => col.show);
const headers = visibleColumns.map(col => col.label).join(','); const headers = visibleColumns.map(col => col.label).join(',');
@@ -158,13 +169,22 @@ const Export = ({ columns, data, filename = "export", customActions = [], show,
<div style={{ maxHeight: '200px', overflowY: 'auto', marginBottom: '15px' }} ref={scrollContainerRef}> <div style={{ maxHeight: '200px', overflowY: 'auto', marginBottom: '15px' }} ref={scrollContainerRef}>
<div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', marginBottom: '10px' }}> <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', marginBottom: '10px' }}>
<h6 style={{ fontSize: '14px', marginBottom: 0 }}>Select Columns:</h6> <h6 style={{ fontSize: '14px', marginBottom: 0 }}>Select Columns:</h6>
<button <div style={{ display: 'flex', gap: '10px' }}>
type="button" <button
className="btn btn-link btn-sm p-0" type="button"
onClick={handleDeselectAll} className="btn btn-link btn-sm p-0"
> onClick={handleSelectAll}
Deselect All >
</button> Select All
</button>
<button
type="button"
className="btn btn-link btn-sm p-0"
onClick={handleDeselectAll}
>
Deselect All
</button>
</div>
</div> </div>
{exportColumns.map((column) => ( {exportColumns.map((column) => (
<div key={column.key} style={{ marginBottom: '8px' }}> <div key={column.key} style={{ marginBottom: '8px' }}>

View File

@@ -2,7 +2,59 @@ import React, { useRef, useState } from "react";
import { Dropdown } from "react-bootstrap"; import { Dropdown } from "react-bootstrap";
import { Columns } from "react-bootstrap-icons"; 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 [internalShow, setInternalShow] = useState(false);
const [tempColumns, setTempColumns] = useState(columns); const [tempColumns, setTempColumns] = useState(columns);
const scrollContainerRef = useRef(null); const scrollContainerRef = useRef(null);
@@ -11,10 +63,41 @@ const ManageTable = ({ columns, onColumnsChange, show, onToggle }) => {
// Use external control if provided, otherwise use internal state // Use external control if provided, otherwise use internal state
const showManageTableDropdown = show !== undefined ? show : internalShow; const showManageTableDropdown = show !== undefined ? show : internalShow;
const handleToggle = onToggle || (() => setInternalShow(!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(() => { React.useEffect(() => {
setTempColumns(columns); const rawSessionValue = getSessionStorageValue(resolvedStorageKey);
}, [columns]); 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) => { const handleColumnToggle = (columnKey) => {
scrollTopRef.current = scrollContainerRef.current?.scrollTop || 0; scrollTopRef.current = scrollContainerRef.current?.scrollTop || 0;
@@ -30,6 +113,13 @@ const ManageTable = ({ columns, onColumnsChange, show, onToggle }) => {
}; };
const handleDone = () => { 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); onColumnsChange(tempColumns);
if (onToggle) { if (onToggle) {
onToggle(false); 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( const customManageTableMenu = React.forwardRef(
({ children, style, className, 'aria-labelledby': labeledBy }, ref) => { ({ children, style, className, 'aria-labelledby': labeledBy }, ref) => {
return ( return (
@@ -68,7 +169,14 @@ const ManageTable = ({ columns, onColumnsChange, show, onToggle }) => {
aria-labelledby={labeledBy} aria-labelledby={labeledBy}
> >
<h6>Manage Table Columns</h6> <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 <button
type="button" type="button"
className="btn btn-link btn-sm p-0" className="btn btn-link btn-sm p-0"