diff --git a/src/features/grid/components/heatmap-cell.tsx b/src/features/grid/components/heatmap-cell.tsx index 4d49e65..359e3ba 100644 --- a/src/features/grid/components/heatmap-cell.tsx +++ b/src/features/grid/components/heatmap-cell.tsx @@ -4,6 +4,7 @@ interface HeatmapCellProps { value: number | null; tooltipStock?: number | null; tooltipReceptions?: number | null; + onClick?: (e: React.MouseEvent) => void; } function getHeatmapClass(value: number | null): string { @@ -15,7 +16,7 @@ function getHeatmapClass(value: number | null): string { return "heatmap-zero"; } -export const HeatmapCell = React.memo(({ value, tooltipStock, tooltipReceptions }: HeatmapCellProps) => { +export const HeatmapCell = React.memo(({ value, tooltipStock, tooltipReceptions, onClick }: HeatmapCellProps) => { const heatClass = getHeatmapClass(value); const display = value === null || value === 0 ? "0" : Math.round(Math.abs(value)).toString(); @@ -28,8 +29,9 @@ export const HeatmapCell = React.memo(({ value, tooltipStock, tooltipReceptions return (
{display}
diff --git a/src/features/grid/components/heatmap-grid.tsx b/src/features/grid/components/heatmap-grid.tsx index 21328bc..71edc58 100644 --- a/src/features/grid/components/heatmap-grid.tsx +++ b/src/features/grid/components/heatmap-grid.tsx @@ -13,7 +13,7 @@ import { RowSelectionState, } from "@tanstack/react-table"; import { useVirtualizer } from "@tanstack/react-virtual"; -import { ChevronUp, ChevronDown, ChevronsUpDown, Copy, Check, Store, SlidersHorizontal } from "lucide-react"; +import { ChevronUp, ChevronDown, ChevronsUpDown, Copy, Check, Store, SlidersHorizontal, ShoppingCart, PackageOpen, Warehouse } from "lucide-react"; import { DropdownMenu, DropdownMenuCheckboxItem, @@ -21,6 +21,7 @@ import { DropdownMenuTrigger, } from "@/components/ui/dropdown-menu"; import { useGridStore } from "@/features/grid/store/use-grid-store"; +import { Dialog, DialogContent, DialogHeader, DialogTitle } from "@/components/ui/dialog"; import { GammeSelect } from "@/features/grid/components/gamme-select"; import { HeatmapCell } from "@/features/grid/components/heatmap-cell"; import type { ProductRow, GammeCode } from "@/types/grid"; @@ -180,6 +181,72 @@ const GridRow = React.memo(({ virtualRow, row, rowHeight, isSelected, columnVisi }); GridRow.displayName = "GridRow"; +// ========================================================================= +// Composant modal pour le détail d'une cellule mensuelle +// ========================================================================= + +interface CellDetailData { + row: ProductRow; + monthKey: string; + qty: number | null; + stock: number | null; + receptions: number | null; +} + +function CellDetailModal({ d, activeMagasin, onClose }: { d: CellDetailData; activeMagasin: string; onClose: () => void }) { + const hasReceptions = (d.receptions ?? 0) > 0; + const storeLabel = activeMagasin === "TOTAL" ? "Total réseau" : (SITE_LABELS[activeMagasin]?.nom ?? activeMagasin); + + return ( + + + + {d.row.libelle1} + +

+ {formatMonthLabel(d.monthKey)}{" · "} + {storeLabel} +

+
+ +
+ {/* Ventes */} +
+ + + {d.qty != null ? Math.round(d.qty).toLocaleString("fr-FR") : "—"} + + Ventes +
+ + {/* Entrées */} +
+ + + {hasReceptions ? `+${Math.round(d.receptions!).toLocaleString("fr-FR")}` : "—"} + + Entrées +
+ + {/* Stock fin de mois */} +
+ + + {d.stock != null ? Math.round(d.stock).toLocaleString("fr-FR") : "—"} + + Stock fin mois +
+
+
+ ); +} + // ========================================================================= export function HeatmapGrid({ onSelectionChange }: HeatmapGridProps) { @@ -206,6 +273,9 @@ export function HeatmapGrid({ onSelectionChange }: HeatmapGridProps) { const { columnVisibility, setColumnVisibility, columnSizing, setColumnSizing } = useGridStore(); const [isMounted, setIsMounted] = useState(false); const [portalContainer, setPortalContainer] = useState(null); + + // État pour le détail d'une cellule mensuelle (modal) + const [cellDetail, setCellDetail] = useState(null); const tableContainerRef = useRef(null); // Calculer les mois dynamiquement pour éviter le mismatch entre serveur et client @@ -466,7 +536,17 @@ export function HeatmapGrid({ onSelectionChange }: HeatmapGridProps) { const receptions = activeMagasin === "TOTAL" ? (row.original.receptions12m[monthKey] ?? null) : (row.original.receptions12mByStore?.[activeMagasin]?.[monthKey] ?? null); - return ; + return ( + { + e.stopPropagation(); + setCellDetail({ row: row.original, monthKey, qty, stock, receptions }); + }} + /> + ); }, })), { @@ -611,6 +691,7 @@ export function HeatmapGrid({ onSelectionChange }: HeatmapGridProps) { } return ( + <>
{portalContainer && createPortal( @@ -733,5 +814,11 @@ export function HeatmapGrid({ onSelectionChange }: HeatmapGridProps) {
+ + {/* Modal détail cellule mensuelle */} + { if (!open) setCellDetail(null); }}> + {cellDetail !== null && setCellDetail(null)} />} + + ); }