feat: implement client-side grid orchestrator and core heatmap table component.

This commit is contained in:
Michael committed 2026-03-23 14:13:39 +01:00
1 parent 53b85381fa
commit bba6fe05e8
2 files changed
+17 -9

No files matched your search

+14 -9
View File
@@ -1,6 +1,6 @@
"use client";
import { useEffect, useState, useTransition } from "react";
import { useEffect, useRef, useState, useTransition } from "react";
import { HeatmapGrid } from "@/features/grid/components/heatmap-grid";
import { FloatingSummaryBar } from "@/features/grid/components/floating-summary-bar";
import { BulkActionToolbar } from "@/features/grid/components/bulk-action-toolbar";
@@ -51,19 +51,24 @@ export function GridClient({ initialRows, codeFournisseur, nomFournisseur, fourn
setActiveGridQuery(currentQueryString ? `?${currentQueryString}` : "");
}, [searchParams, setActiveGridQuery, isMounted]);
// Réinitialiser les filtres UNIQUEMENT quand le fournisseur change
const prevFournisseurRef = useRef<string | null>(null);
useEffect(() => {
if (!isMounted) return;
// Réinitialiser les filtres gamme et code3 lors du changement de fournisseur.
// Ces filtres sont persistés en localStorage (Zustand persist) et s'appliquent
// au nouveau fournisseur, cachant toutes les lignes si le filtre ne correspond pas.
setFilter("codeGamme", null);
setFilter("code3", null);
if (prevFournisseurRef.current !== codeFournisseur) {
setFilter("codeGamme", null);
setFilter("code3", null);
prevFournisseurRef.current = codeFournisseur;
}
const scoredRows = computeProductScores([...initialRows]);
setRows(scoredRows);
}, [codeFournisseur, initialRows, setRows, setFilter, isMounted]);
// Synchroniser le magasin actif depuis la prop URL (changement de magasin sans rechargement)
useEffect(() => {
if (!isMounted) return;
setActiveMagasin(magasin || "TOTAL");
}, [codeFournisseur, initialRows, setRows, setFilter, setActiveMagasin, magasin, isMounted]);
}, [magasin, setActiveMagasin, isMounted]);
const handleSave = () => {
startTransition(async () => {
@@ -468,6 +468,7 @@ export function HeatmapGrid({ onSelectionChange }: HeatmapGridProps) {
})),
{
id: "totalQuantite",
accessorFn: (row: ProductRow) => activeMagasin === "TOTAL" ? row.totalQuantite : (row.quantiteByStore?.[activeMagasin] ?? 0),
header: () => <div className="text-center w-full">Tot. 12m</div>,
size: 90,
cell: ({ row }: { row: { original: ProductRow } }) => {
@@ -487,6 +488,7 @@ export function HeatmapGrid({ onSelectionChange }: HeatmapGridProps) {
},
{
id: "totalCa",
accessorFn: (row: ProductRow) => activeMagasin === "TOTAL" ? row.totalCa : (row.caByStore?.[activeMagasin] ?? 0),
header: () => <div className="text-center w-full">CA</div>,
size: 90,
cell: ({ row }: { row: { original: ProductRow } }) => {
@@ -502,6 +504,7 @@ export function HeatmapGrid({ onSelectionChange }: HeatmapGridProps) {
},
{
id: "totalMarge",
accessorFn: (row: ProductRow) => activeMagasin === "TOTAL" ? row.totalMarge : (row.margeByStore?.[activeMagasin] ?? 0),
header: () => <div className="text-center w-full">Marge</div>,
size: 110,
cell: ({ row }: { row: { original: ProductRow } }) => {