feat: add HitParadeClient component with filtering, sorting, and date selection capabilities

This commit is contained in:
Michael committed 2026-04-07 09:28:10 +02:00
1 parent f5b2083c42
commit f1b0a74c5f
1 file changed
+35 -35
+35 -35
View File
@@ -107,7 +107,7 @@ export function HitParadeClient({ dateDebut, dateFin, pivotted }: Props) {
key={k}
onClick={sortable ? () => handleSort(sortable) : undefined}
className={[
"px-4 py-2 text-center text-xs font-semibold whitespace-nowrap select-none",
"px-2 py-2 text-center text-xs font-semibold whitespace-nowrap select-none",
sortable ? "cursor-pointer" : "",
isActive ? activeBg : `${groupBg} text-gray-600`,
].join(" ")}
@@ -209,10 +209,10 @@ export function HitParadeClient({ dateDebut, dateFin, pivotted }: Props) {
<table className="w-full border-collapse text-sm">
<thead>
<tr>
<th rowSpan={2} className="w-24 border-b-2 border-gray-200 bg-gray-50 px-4 py-3 text-left text-xs font-semibold text-gray-600 align-bottom">Code</th>
<th rowSpan={2} className="border-b-2 border-gray-200 bg-gray-50 px-4 py-3 text-left text-xs font-semibold text-gray-600 align-bottom">Désignation</th>
<th rowSpan={2} className="border-b-2 border-gray-200 bg-gray-50 px-4 py-3 text-left text-xs font-semibold text-gray-600 align-bottom">Fournisseur</th>
<th rowSpan={2} className="border-b-2 border-gray-200 bg-gray-50 px-4 py-3 text-left text-xs font-semibold text-gray-600 align-bottom">Nomenclature</th>
<th rowSpan={2} className="w-20 border-b-2 border-gray-200 bg-gray-50 px-2 py-3 text-left text-xs font-semibold text-gray-600 align-bottom">Code</th>
<th rowSpan={2} className="border-b-2 border-gray-200 bg-gray-50 px-2 py-3 text-left text-xs font-semibold text-gray-600 align-bottom">Désignation</th>
<th rowSpan={2} className="border-b-2 border-gray-200 bg-gray-50 px-2 py-3 text-left text-xs font-semibold text-gray-600 align-bottom">Fournisseur</th>
<th rowSpan={2} className="border-b-2 border-gray-200 bg-gray-50 px-2 py-3 text-left text-xs font-semibold text-gray-600 align-bottom">Nom.</th>
<th colSpan={4} className="border-b border-l-2 border-blue-200 bg-blue-50 px-4 py-2 text-center text-xs font-bold text-blue-700 tracking-wide">
Frouard / Nancy — 292
</th>
@@ -226,64 +226,64 @@ export function HitParadeClient({ dateDebut, dateFin, pivotted }: Props) {
<tr className="border-b-2 border-gray-200">
<ColHeader label="Qté" sortable="qte292" k="qte292" group="292" />
<ColHeader label="CA TTC" sortable="ca292" k="ca292" group="292" />
<th className="bg-blue-50 px-4 py-2 text-center text-xs font-semibold text-blue-500">% Marge</th>
<th className="bg-blue-50 px-2 py-2 text-center text-xs font-semibold text-blue-500">% Marge</th>
<ColHeader label="Stock" sortable="stock292" k="stock292" group="292" />
<ColHeader label="Qté" sortable="qte579" k="qte579" group="579" />
<ColHeader label="CA TTC" sortable="ca579" k="ca579" group="579" />
<th className="bg-violet-50 px-4 py-2 text-center text-xs font-semibold text-violet-500">% Marge</th>
<th className="bg-violet-50 px-2 py-2 text-center text-xs font-semibold text-violet-500">% Marge</th>
<ColHeader label="Stock" sortable="stock579" k="stock579" group="579" />
<ColHeader label="Qté" sortable="qteTotal" k="qteTotal" group="total" />
<ColHeader label="CA TTC" sortable="caTotal" k="caTotal" group="total" />
<th className="bg-emerald-50 px-4 py-2 text-center text-xs font-semibold text-emerald-600">% Marge</th>
<th className="bg-emerald-50 px-2 py-2 text-center text-xs font-semibold text-emerald-600">% Marge</th>
<ColHeader label="Stock" sortable="stockTotal" k="stockTotal" group="total" />
</tr>
</thead>
<tbody>
{sorted.map((row, idx) => (
<tr key={row.codein} className={`border-b border-gray-100 hover:brightness-95 transition-colors`}>
<td className="bg-white px-4 py-2.5 font-mono text-xs text-gray-400 text-center">{row.codein}</td>
<td className="bg-white px-4 py-2.5 text-gray-900 font-medium max-w-[260px] truncate" title={row.libelle.trim()}>{row.libelle.trim()}</td>
<td className="bg-white px-4 py-2.5 text-xs text-gray-500 whitespace-nowrap text-center">{row.fournisseur}</td>
<td className="bg-white px-4 py-2.5 text-xs text-center whitespace-nowrap" title={row.nomenclature_code ? `${row.nomenclature_code} — ${row.nomenclature}` : ""}>
<td className="bg-white px-2 py-2.5 font-mono text-xs text-gray-400 text-center">{row.codein}</td>
<td className="bg-white px-2 py-2.5 text-gray-900 font-medium max-w-[200px] truncate" title={row.libelle.trim()}>{row.libelle.trim()}</td>
<td className="bg-white px-2 py-2.5 text-xs text-gray-500 whitespace-nowrap">{row.fournisseur}</td>
<td className="bg-white px-2 py-2.5 text-xs text-center whitespace-nowrap" title={row.nomenclature_code ? `${row.nomenclature_code} — ${row.nomenclature}` : ""}>
{row.nomenclature_code
? <span className="font-mono font-semibold text-gray-700">{row.nomenclature_code}</span>
: <span className="text-gray-300">—</span>
}
</td>
<td className={`border-l-2 border-blue-200 px-4 py-2.5 text-center tabular-nums text-gray-700 ${sortKey === "qte292" ? "bg-blue-100 font-semibold" : "bg-blue-50/60"}`}>
<td className={`border-l-2 border-blue-200 px-2 py-2.5 text-center tabular-nums text-gray-700 ${sortKey === "qte292" ? "bg-blue-100 font-semibold" : "bg-blue-50/60"}`}>
{row.qte292 > 0 ? formatQte(row.qte292) : <span className="text-gray-300">—</span>}
</td>
<td className={`px-4 py-2.5 text-center tabular-nums text-gray-800 ${sortKey === "ca292" ? "bg-blue-100 font-semibold" : "bg-blue-50/60"}`}>
<td className={`px-2 py-2.5 text-center tabular-nums text-gray-800 ${sortKey === "ca292" ? "bg-blue-100 font-semibold" : "bg-blue-50/60"}`}>
{row.ca292 > 0 ? formatCA(row.ca292) : <span className="text-gray-300">—</span>}
</td>
<td className="bg-blue-50/60 px-4 py-2.5 text-center text-xs tabular-nums text-blue-500">
<td className="bg-blue-50/60 px-2 py-2.5 text-center text-xs tabular-nums text-blue-500">
{row.ca292 > 0 ? formatPct(row.ca292, row.marge292) : ""}
</td>
<td className={`px-4 py-2.5 text-center tabular-nums text-xs ${sortKey === "stock292" ? "bg-blue-100 font-semibold text-blue-700" : "bg-blue-50/60 text-amber-600"}`}>
<td className={`px-2 py-2.5 text-center tabular-nums text-xs ${sortKey === "stock292" ? "bg-blue-100 font-semibold text-blue-700" : "bg-blue-50/60 text-amber-600"}`}>
{row.stock292 > 0 ? formatQte(row.stock292) : <span className="text-gray-300">—</span>}
</td>
<td className={`border-l-2 border-violet-200 px-4 py-2.5 text-center tabular-nums text-gray-700 ${sortKey === "qte579" ? "bg-violet-100 font-semibold" : "bg-violet-50/60"}`}>
<td className={`border-l-2 border-violet-200 px-2 py-2.5 text-center tabular-nums text-gray-700 ${sortKey === "qte579" ? "bg-violet-100 font-semibold" : "bg-violet-50/60"}`}>
{row.qte579 > 0 ? formatQte(row.qte579) : <span className="text-gray-300">—</span>}
</td>
<td className={`px-4 py-2.5 text-center tabular-nums text-gray-800 ${sortKey === "ca579" ? "bg-violet-100 font-semibold" : "bg-violet-50/60"}`}>
<td className={`px-2 py-2.5 text-center tabular-nums text-gray-800 ${sortKey === "ca579" ? "bg-violet-100 font-semibold" : "bg-violet-50/60"}`}>
{row.ca579 > 0 ? formatCA(row.ca579) : <span className="text-gray-300">—</span>}
</td>
<td className="bg-violet-50/60 px-4 py-2.5 text-center text-xs tabular-nums text-violet-500">
<td className="bg-violet-50/60 px-2 py-2.5 text-center text-xs tabular-nums text-violet-500">
{row.ca579 > 0 ? formatPct(row.ca579, row.marge579) : ""}
</td>
<td className={`px-4 py-2.5 text-center tabular-nums text-xs ${sortKey === "stock579" ? "bg-violet-100 font-semibold text-violet-700" : "bg-violet-50/60 text-amber-600"}`}>
<td className={`px-2 py-2.5 text-center tabular-nums text-xs ${sortKey === "stock579" ? "bg-violet-100 font-semibold text-violet-700" : "bg-violet-50/60 text-amber-600"}`}>
{row.stock579 > 0 ? formatQte(row.stock579) : <span className="text-gray-300">—</span>}
</td>
<td className={`border-l-2 border-emerald-200 px-4 py-2.5 text-center tabular-nums font-semibold text-gray-900 ${sortKey === "qteTotal" ? "bg-emerald-100" : "bg-emerald-50/60"}`}>
<td className={`border-l-2 border-emerald-200 px-2 py-2.5 text-center tabular-nums font-semibold text-gray-900 ${sortKey === "qteTotal" ? "bg-emerald-100" : "bg-emerald-50/60"}`}>
{row.qteTotal > 0 ? formatQte(row.qteTotal) : <span className="text-gray-300">—</span>}
</td>
<td className={`px-4 py-2.5 text-center tabular-nums font-semibold text-gray-900 ${sortKey === "caTotal" ? "bg-emerald-100" : "bg-emerald-50/60"}`}>
<td className={`px-2 py-2.5 text-center tabular-nums font-semibold text-gray-900 ${sortKey === "caTotal" ? "bg-emerald-100" : "bg-emerald-50/60"}`}>
{row.caTotal > 0 ? formatCA(row.caTotal) : <span className="text-gray-300">—</span>}
</td>
<td className="bg-emerald-50/60 px-4 py-2.5 text-center text-xs tabular-nums text-emerald-600">
<td className="bg-emerald-50/60 px-2 py-2.5 text-center text-xs tabular-nums text-emerald-600">
{row.caTotal > 0 ? formatPct(row.caTotal, row.margeTotal) : ""}
</td>
<td className={`px-4 py-2.5 text-center tabular-nums text-xs font-semibold ${sortKey === "stockTotal" ? "bg-emerald-100 text-emerald-700" : row.stockTotal <= 0 ? "bg-emerald-50/60 text-red-400" : "bg-emerald-50/60 text-amber-600"}`}>
<td className={`px-2 py-2.5 text-center tabular-nums text-xs font-semibold ${sortKey === "stockTotal" ? "bg-emerald-100 text-emerald-700" : row.stockTotal <= 0 ? "bg-emerald-50/60 text-red-400" : "bg-emerald-50/60 text-amber-600"}`}>
{row.stockTotal > 0 ? formatQte(row.stockTotal) : <span className="text-red-400 font-semibold">0</span>}
</td>
</tr>
@@ -295,17 +295,17 @@ export function HitParadeClient({ dateDebut, dateFin, pivotted }: Props) {
TOTAL — {sorted.length} articles
</td>
<td className="border-l-2 border-blue-300 bg-blue-100 px-4 py-3 text-center font-bold tabular-nums text-gray-900">{formatQte(totals.qte292)}</td>
<td className="bg-blue-100 px-4 py-3 text-center font-bold tabular-nums text-gray-900">{formatCA(totals.ca292)}</td>
<td className="bg-blue-100 px-4 py-3 text-center text-xs tabular-nums text-blue-700 font-semibold">{formatPct(totals.ca292, totals.marge292)}</td>
<td className="bg-blue-100 px-4 py-3 text-center text-xs font-bold tabular-nums text-amber-700">{formatQte(totals.stock292)}</td>
<td className="border-l-2 border-violet-300 bg-violet-100 px-4 py-3 text-center font-bold tabular-nums text-gray-900">{formatQte(totals.qte579)}</td>
<td className="bg-violet-100 px-4 py-3 text-center font-bold tabular-nums text-gray-900">{formatCA(totals.ca579)}</td>
<td className="bg-violet-100 px-4 py-3 text-center text-xs tabular-nums text-violet-700 font-semibold">{formatPct(totals.ca579, totals.marge579)}</td>
<td className="bg-violet-100 px-4 py-3 text-center text-xs font-bold tabular-nums text-amber-700">{formatQte(totals.stock579)}</td>
<td className="border-l-2 border-emerald-300 bg-emerald-100 px-4 py-3 text-center font-bold tabular-nums text-gray-900">{formatQte(totals.qteTotal)}</td>
<td className="bg-emerald-100 px-4 py-3 text-center font-bold tabular-nums text-gray-900">{formatCA(totals.caTotal)}</td>
<td className="bg-emerald-100 px-4 py-3 text-center text-xs tabular-nums text-emerald-800 font-semibold">{formatPct(totals.caTotal, totals.margeTotal)}</td>
<td className="bg-emerald-100 px-4 py-3 text-center text-xs font-bold tabular-nums text-amber-700">{formatQte(totals.stockTotal)}</td>
<td className="bg-blue-100 px-2 py-3 text-center font-bold tabular-nums text-gray-900">{formatCA(totals.ca292)}</td>
<td className="bg-blue-100 px-2 py-3 text-center text-xs tabular-nums text-blue-700 font-semibold">{formatPct(totals.ca292, totals.marge292)}</td>
<td className="bg-blue-100 px-2 py-3 text-center text-xs font-bold tabular-nums text-amber-700">{formatQte(totals.stock292)}</td>
<td className="border-l-2 border-violet-300 bg-violet-100 px-2 py-3 text-center font-bold tabular-nums text-gray-900">{formatQte(totals.qte579)}</td>
<td className="bg-violet-100 px-2 py-3 text-center font-bold tabular-nums text-gray-900">{formatCA(totals.ca579)}</td>
<td className="bg-violet-100 px-2 py-3 text-center text-xs tabular-nums text-violet-700 font-semibold">{formatPct(totals.ca579, totals.marge579)}</td>
<td className="bg-violet-100 px-2 py-3 text-center text-xs font-bold tabular-nums text-amber-700">{formatQte(totals.stock579)}</td>
<td className="border-l-2 border-emerald-300 bg-emerald-100 px-2 py-3 text-center font-bold tabular-nums text-gray-900">{formatQte(totals.qteTotal)}</td>
<td className="bg-emerald-100 px-2 py-3 text-center font-bold tabular-nums text-gray-900">{formatCA(totals.caTotal)}</td>
<td className="bg-emerald-100 px-2 py-3 text-center text-xs tabular-nums text-emerald-800 font-semibold">{formatPct(totals.caTotal, totals.margeTotal)}</td>
<td className="bg-emerald-100 px-2 py-3 text-center text-xs font-bold tabular-nums text-amber-700">{formatQte(totals.stockTotal)}</td>
</tr>
</tfoot>
</table>