diff --git a/src/app/(dashboard)/score/page.tsx b/src/app/(dashboard)/score/page.tsx index b683d23..77e8f94 100644 --- a/src/app/(dashboard)/score/page.tsx +++ b/src/app/(dashboard)/score/page.tsx @@ -85,6 +85,27 @@ export default function ScorePage() { + {/* Équité & Normalisation */} + +
+

+ Afin de ne pas pénaliser les produits présents dans un seul magasin, une pondération d'équité est appliquée : +

+
+
⚖️
+
+

Produit 1 Magasin : Statistiques multipliées par 2

+

+ Cela permet de comparer sa performance sur une base réseau normalisée de 2 magasins. +

+
+
+
+
+ {/* Les 3 axes */}
diff --git a/src/features/grid/components/heatmap-grid.tsx b/src/features/grid/components/heatmap-grid.tsx index d17917c..3171a99 100644 --- a/src/features/grid/components/heatmap-grid.tsx +++ b/src/features/grid/components/heatmap-grid.tsx @@ -12,7 +12,7 @@ import { RowSelectionState, } from "@tanstack/react-table"; import { useVirtualizer } from "@tanstack/react-virtual"; -import { ChevronUp, ChevronDown, ChevronsUpDown, Copy, Check } from "lucide-react"; +import { ChevronUp, ChevronDown, ChevronsUpDown, Copy, Check, Store } from "lucide-react"; import { useGridStore } from "@/features/grid/store/use-grid-store"; import { GammeSelect } from "@/features/grid/components/gamme-select"; import { HeatmapCell } from "@/features/grid/components/heatmap-cell"; @@ -41,25 +41,31 @@ function formatMonthLabel(key: string): string { } /** - * Generates a deterministic color for a store name. - * Harmonized with the "Silent UI" philosophy: professional, muted, and non-distracting. + * Returns premium styling and icons for stores. + * Indigo for first store, Amber for second, Slate for others. */ -function getStoreColor(name: string) { - let hash = 0; - for (let i = 0; i < name.length; i++) { - hash = name.charCodeAt(i) + ((hash << 5) - hash); +function getStoreConfig(name: string, index: number) { + if (index === 0) { + return { + bg: "rgba(99, 102, 241, 0.1)", // Indigo + text: "#818cf8", + border: "rgba(99, 102, 241, 0.2)", + label: "M1" + }; + } + if (index === 1) { + return { + bg: "rgba(245, 158, 11, 0.1)", // Amber + text: "#fbbf24", + border: "rgba(245, 158, 11, 0.2)", + label: "M2" + }; } - - // Use a narrower, more professional range of hues (mostly Ardois/Blue/Teal/Sage) - // and lower saturation for a "muted" look. - const h = Math.abs(hash % 360); - const s = 15 + (Math.abs(hash) % 20); // Low saturation: 15-35% - const l = 40 + (Math.abs(hash) % 15); // Medium lightness: 40-55% - return { - bg: `hsl(${h}, ${s}%, ${l}%)`, - border: `hsl(${h}, ${s}%, ${l - 10}%)`, - text: "rgba(255, 255, 255, 0.95)" + bg: "var(--bg-elevated)", + text: "var(--text-muted)", + border: "var(--border)", + label: name.charAt(0).toUpperCase() }; } @@ -185,21 +191,22 @@ export function HeatmapGrid({ onSelectionChange }: HeatmapGridProps) { {row.original.libelle1} -
- {row.original.workingStores.map((magasin) => { - const colors = getStoreColor(magasin); +
+ {row.original.workingStores.map((magasin, idx) => { + const config = getStoreConfig(magasin, idx); return (
- {magasin.charAt(0).toUpperCase()} + + {config.label}
); })} @@ -365,15 +372,21 @@ export function HeatmapGrid({ onSelectionChange }: HeatmapGridProps) { return (
- + {table.getHeaderGroups().map((headerGroup) => ( {headerGroup.headers.map((header) => { @@ -383,7 +396,7 @@ export function HeatmapGrid({ onSelectionChange }: HeatmapGridProps) { return ( @@ -420,15 +436,15 @@ export function HeatmapGrid({ onSelectionChange }: HeatmapGridProps) { ref={rowVirtualizer.measureElement} onClick={() => row.toggleSelected()} className={cn( - "absolute w-full flex items-center cursor-pointer transition-colors", - effectiveGamme === "Z" && "opacity-40" + "absolute w-full flex items-center cursor-pointer transition-all duration-200 group/row", + effectiveGamme === "Z" && "opacity-40 grayscale-[0.5] hover:grayscale-0 hover:opacity-100" )} style={{ height: `${rowHeight}px`, transform: `translateY(${virtualRow.start}px)`, borderBottom: "1px solid var(--border)", - background: isSelected ? "var(--accent-bg)" : undefined, - borderLeft: isSelected ? "2px solid var(--accent)" : undefined, + background: isSelected ? "var(--accent-bg)" : "transparent", + borderLeft: isSelected ? "3px solid var(--accent)" : "3px solid transparent", }} > {row.getVisibleCells().map((cell) => { @@ -438,7 +454,10 @@ export function HeatmapGrid({ onSelectionChange }: HeatmapGridProps) { return (
-
+
{flexRender(header.column.columnDef.header, header.getContext())} {header.column.getCanSort() && ( - header.column.getIsSorted() === "asc" ? - : header.column.getIsSorted() === "desc" ? - : +
+ {header.column.getIsSorted() === "asc" ? + : header.column.getIsSorted() === "desc" ? + : + } +
)}