perf(grid): optimize state store with O(1) row indexing and debounced summary calculations

This commit is contained in:
Michael committed 2026-05-26 13:53:51 +02:00
1 parent 8f2c4c77ba
commit d75102fb18
6 files changed
+86 -37

No files matched your search

@@ -5,7 +5,7 @@ import { useSession } from "next-auth/react";
import { BulkAiAnalyzer } from "./bulk-ai-analyzer";
import { useSaveDrafts } from "@/features/grid/hooks/use-save-drafts";
import { Loader2, CheckCircle, AlertCircle, RotateCcw, Camera, ChevronDown } from "lucide-react";
import { useState, useTransition } from "react";
import { useMemo, useState, useTransition } from "react";
import { saveSnapshot } from "@/features/snapshots/api/save-snapshot";
import { SuccessModal } from "@/components/shared/success-modal";
import {
@@ -45,7 +45,7 @@ export function FloatingSummaryBar() {
message: ""
});
const visibleCodeins = rows.map(r => r.codein);
const visibleCodeins = useMemo(() => rows.map(r => r.codein), [rows]);
const { save, hasDrafts, count } = useSaveDrafts(filters.magasin || "TOTAL", visibleCodeins);
const handleSave = () => {
@@ -15,11 +15,13 @@ interface GridFilterBarProps {
magasins: { code: string; nom: string }[];
}
const EMPTY_DRAFT_CHANGES: Record<string, string> = {};
export function GridFilterBar({ fournisseurs, magasins }: GridFilterBarProps) {
const filters = useGridStore((s) => s.filters);
const setFilter = useGridStore((s) => s.setFilter);
const rows = useGridStore((s) => s.rows);
const draftChanges = useGridStore((s) => s.draftChanges);
const draftChanges = useGridStore((s) => s.filters.codeGamme ? s.draftChanges : EMPTY_DRAFT_CHANGES);
const router = useRouter();
const searchParams = useSearchParams();
const [isRefreshing, setIsRefreshing] = React.useState(false);
@@ -86,6 +86,8 @@ interface HeatmapGridProps {
isAdmin?: boolean;
}
const EMPTY_DRAFT_CHANGES: Record<string, GammeCode> = {};
// =========================================================================
// OPTIMISATION PERFORMANCES (React.memo + Zustand Selectors granulaires)
// =========================================================================
@@ -272,7 +274,7 @@ export function HeatmapGrid({ onSelectionChange, isAdmin }: HeatmapGridProps) {
const rows = useGridStore((s) => s.rows);
const filters = useGridStore((s) => s.filters);
const displayDensity = useGridStore((s) => s.displayDensity);
const draftChanges = useGridStore((s) => s.draftChanges);
const draftChanges = useGridStore((s) => s.filters.codeGamme ? s.draftChanges : EMPTY_DRAFT_CHANGES);
const activeMagasin = useGridStore((s) => s.activeMagasin);
// Filtre client-side par code3 (famille) et codeGamme
@@ -707,7 +709,7 @@ export function HeatmapGrid({ onSelectionChange, isAdmin }: HeatmapGridProps) {
count: tableRows.length,
getScrollElement: () => tableContainerRef.current,
estimateSize: () => rowHeight,
overscan: 20,
overscan: 8,
});
const visibleColumns = table.getVisibleLeafColumns();
@@ -769,7 +771,7 @@ export function HeatmapGrid({ onSelectionChange, isAdmin }: HeatmapGridProps) {
<div
ref={tableContainerRef}
className="h-full w-full overflow-auto rounded-[12px] scroll-smooth relative"
className="h-full w-full overflow-auto rounded-[12px] relative"
style={{
background: "var(--bg-surface)",
border: "1px solid var(--border)",
@@ -835,7 +837,7 @@ export function HeatmapGrid({ onSelectionChange, isAdmin }: HeatmapGridProps) {
const isSelected = row.getIsSelected();
return (
<div key={row.id} ref={rowVirtualizer.measureElement} style={{ position: 'absolute', top: 0, left: 0, width: '100%' }}>
<div key={row.id} style={{ position: 'absolute', top: 0, left: 0, width: '100%' }}>
<GridRow
virtualRow={virtualRow}
row={row}