From 9469738ef0dcabeeec71302091ca60fd2cbb9f18 Mon Sep 17 00:00:00 2001 From: Michael SCHAL Date: Tue, 7 Apr 2026 08:49:38 +0200 Subject: [PATCH] feat: implement hit-parade dashboard with interactive filtering, sorting, and data visualization components --- src/app/(dashboard)/hit-parade/client.tsx | 19 ++++++++++++++----- src/app/(dashboard)/hit-parade/page.tsx | 2 ++ src/lib/pg-ff-client.ts | 5 ++++- 3 files changed, 20 insertions(+), 6 deletions(-) diff --git a/src/app/(dashboard)/hit-parade/client.tsx b/src/app/(dashboard)/hit-parade/client.tsx index c83208e..895d952 100644 --- a/src/app/(dashboard)/hit-parade/client.tsx +++ b/src/app/(dashboard)/hit-parade/client.tsx @@ -44,8 +44,10 @@ export function HitParadeClient({ dateDebut, dateFin, pivotted }: Props) { }, [pivotted]); const nomenclatures = useMemo(() => { - const set = new Set(pivotted.map(r => r.nomenclature)); - return ["Tous", ...Array.from(set).sort((a, b) => a.localeCompare(b, "fr"))]; + const map = new Map(); // code → libelle + for (const r of pivotted) map.set(r.nomenclature_code, r.nomenclature); + const entries = Array.from(map.entries()).sort((a, b) => a[0].localeCompare(b[0], "fr")); + return [{ code: "Tous", libelle: "Tous" }, ...entries.map(([code, libelle]) => ({ code, libelle }))]; }, [pivotted]); function handleSort(key: SortKey) { @@ -73,7 +75,7 @@ export function HitParadeClient({ dateDebut, dateFin, pivotted }: Props) { const filtered = useMemo(() => pivotted.filter(r => (filterFournisseur === "Tous" || r.fournisseur === filterFournisseur) && - (filterNomenclature === "Tous" || r.nomenclature === filterNomenclature) + (filterNomenclature === "Tous" || r.nomenclature_code === filterNomenclature) ), [pivotted, filterFournisseur, filterNomenclature] ); @@ -179,7 +181,9 @@ export function HitParadeClient({ dateDebut, dateFin, pivotted }: Props) { className="rounded-lg border border-gray-300 bg-white px-3 py-2 text-sm shadow-sm focus:outline-none focus:ring-2 focus:ring-blue-400 min-w-[200px]" > {nomenclatures.map(n => ( - + ))} @@ -240,7 +244,12 @@ export function HitParadeClient({ dateDebut, dateFin, pivotted }: Props) { {row.codein} {row.libelle.trim()} {row.fournisseur} - {row.nomenclature} + + {row.nomenclature_code + ? <>{row.nomenclature_code}— {row.nomenclature} + : — + } + {row.qte292 > 0 ? formatQte(row.qte292) : —} diff --git a/src/app/(dashboard)/hit-parade/page.tsx b/src/app/(dashboard)/hit-parade/page.tsx index 95de543..ce2909e 100644 --- a/src/app/(dashboard)/hit-parade/page.tsx +++ b/src/app/(dashboard)/hit-parade/page.tsx @@ -5,6 +5,7 @@ export interface HitParadePivotRow { codein: string; libelle: string; fournisseur: string; + nomenclature_code: string; nomenclature: string; qte292: number; ca292: number; @@ -29,6 +30,7 @@ function pivotHitParade(rows: HitParadeRow[]): HitParadePivotRow[] { codein: row.codein, libelle: row.libelle, fournisseur: row.fournisseur, + nomenclature_code: row.nomenclature_code, nomenclature: row.nomenclature, qte292: 0, ca292: 0, marge292: 0, qte579: 0, ca579: 0, marge579: 0, diff --git a/src/lib/pg-ff-client.ts b/src/lib/pg-ff-client.ts index e523910..2558625 100644 --- a/src/lib/pg-ff-client.ts +++ b/src/lib/pg-ff-client.ts @@ -717,6 +717,7 @@ export interface HitParadeRow { codein: string; libelle: string; fournisseur: string; + nomenclature_code: string; nomenclature: string; site: string; qte_vendue: number; @@ -739,6 +740,7 @@ export async function pgGetHitParade(dateDebut: string, dateFin: string): Promis a.codein::text AS codein, a.libelle1::text AS libelle, COALESCE(fi.nom, af.code, 'Sans fournisseur')::text AS fournisseur, + COALESCE(n.code, '')::text AS nomenclature_code, COALESCE(n.libelle, 'Sans nomenclature')::text AS nomenclature, m.site, SUM(ABS(m.qtemvt))::float AS qte_vendue, @@ -752,7 +754,7 @@ export async function pgGetHitParade(dateDebut: string, dateFin: string): Promis WHERE m.datmvt BETWEEN ${dateDebut}::date AND ${dateFin}::date AND m.site IN ('292', '579') AND m.genremvt = 3 - GROUP BY a.no_id, a.codein, a.libelle1, fi.nom, af.code, n.libelle, m.site + GROUP BY a.no_id, a.codein, a.libelle1, fi.nom, af.code, n.code, n.libelle, m.site ), stock_agg AS ( SELECT @@ -768,6 +770,7 @@ export async function pgGetHitParade(dateDebut: string, dateFin: string): Promis v.codein, v.libelle, v.fournisseur, + v.nomenclature_code, v.nomenclature, v.site, v.qte_vendue,