feat: implement virtualized heatmap grid component with a Zustand store for managing grid data, filters, and draft product gamme changes.

This commit is contained in:
Michael committed 2026-03-06 15:15:11 +01:00
1 parent 38955ab02a
commit 1ba507da94
2 files changed
+13 -2

No files matched your search

@@ -179,7 +179,7 @@ export function HeatmapGrid({ onSelectionChange }: HeatmapGridProps) {
const { rows, filters, displayDensity } = useGridStore(); const { rows, filters, displayDensity } = useGridStore();
const [sorting, setSorting] = useState<SortingState>([]); const [sorting, setSorting] = useState<SortingState>([]);
const [rowSelection, setRowSelection] = useState<RowSelectionState>({}); const [rowSelection, setRowSelection] = useState<RowSelectionState>({});
const [columnVisibility, setColumnVisibility] = useState({}); const { columnVisibility, setColumnVisibility } = useGridStore();
const [isMounted, setIsMounted] = useState(false); const [isMounted, setIsMounted] = useState(false);
const [portalContainer, setPortalContainer] = useState<HTMLElement | null>(null); const [portalContainer, setPortalContainer] = useState<HTMLElement | null>(null);
const tableContainerRef = useRef<HTMLDivElement>(null); const tableContainerRef = useRef<HTMLDivElement>(null);
+12 -1
View File
@@ -14,6 +14,8 @@ interface GridState {
displayDensity: "compact" | "normal" | "comfortable"; displayDensity: "compact" | "normal" | "comfortable";
/** The active URL search parameters (e.g. ?fournisseur=123&magasin=TOTAL) */ /** The active URL search parameters (e.g. ?fournisseur=123&magasin=TOTAL) */
activeGridQuery: string; activeGridQuery: string;
/** Persisted column visibility state */
columnVisibility: Record<string, boolean>;
// Actions // Actions
setRows: (rows: ProductRow[]) => void; setRows: (rows: ProductRow[]) => void;
@@ -26,6 +28,7 @@ interface GridState {
setActiveGridQuery: (query: string) => void; setActiveGridQuery: (query: string) => void;
restoreSnapshot: (changes: Record<string, GammeCode>) => void; restoreSnapshot: (changes: Record<string, GammeCode>) => void;
batchSetDraftGamme: (changes: Record<string, GammeCode>) => void; batchSetDraftGamme: (changes: Record<string, GammeCode>) => void;
setColumnVisibility: (updater: Record<string, boolean> | ((old: Record<string, boolean>) => Record<string, boolean>)) => void;
} }
function computeSummary(rows: ProductRow[], drafts: Record<string, GammeCode>): GridSummary { function computeSummary(rows: ProductRow[], drafts: Record<string, GammeCode>): GridSummary {
@@ -67,6 +70,7 @@ export const useGridStore = create<GridState>()(
}, },
displayDensity: "normal", displayDensity: "normal",
activeGridQuery: "", activeGridQuery: "",
columnVisibility: {},
setRows: (rows) => { setRows: (rows) => {
set({ rows, summary: computeSummary(rows, get().draftChanges) }); set({ rows, summary: computeSummary(rows, get().draftChanges) });
@@ -124,15 +128,22 @@ export const useGridStore = create<GridState>()(
set({ draftChanges: updatedDrafts, summary: computeSummary(rows, updatedDrafts) }); set({ draftChanges: updatedDrafts, summary: computeSummary(rows, updatedDrafts) });
}, },
setColumnVisibility: (updater) => {
set((state) => ({
columnVisibility: typeof updater === 'function' ? updater(state.columnVisibility) : updater
}));
},
}), }),
{ {
name: "collectflow-grid-storage", name: "collectflow-grid-storage",
// Only persist filters, display density, drafts, and active grid query // Only persist filters, display density, drafts, active grid query, and column visibility
partialize: (state) => ({ partialize: (state) => ({
filters: state.filters, filters: state.filters,
displayDensity: state.displayDensity, displayDensity: state.displayDensity,
draftChanges: state.draftChanges, draftChanges: state.draftChanges,
activeGridQuery: state.activeGridQuery, activeGridQuery: state.activeGridQuery,
columnVisibility: state.columnVisibility,
}), }),
} }
) )