mirror of
https://github.com/R0m1k3/CollectFlow.git
synced 2026-10-22 22:48:08 +02:00
feat: implement client-side interactive table for advertising data with filtering and sorting capabilities
This commit is contained in:
1 parent
480cf5c460
commit
13414c970c
1 file changed
+21
-5
@@ -44,10 +44,26 @@ export function PublicitesClient({ year, publicites }: Props) {
|
|||||||
const [sortKey, setSortKey] = useState<SortKey>("intitule");
|
const [sortKey, setSortKey] = useState<SortKey>("intitule");
|
||||||
const [sortDir, setSortDir] = useState<SortDir>("asc");
|
const [sortDir, setSortDir] = useState<SortDir>("asc");
|
||||||
|
|
||||||
|
const validPublicites = useMemo(() => publicites.filter(p => p.site !== "000"), [publicites]);
|
||||||
|
|
||||||
const sites = useMemo(() => {
|
const sites = useMemo(() => {
|
||||||
const s = new Set(publicites.map(p => p.site).filter(Boolean));
|
const s = new Set(validPublicites.map(p => p.site).filter(Boolean));
|
||||||
return Array.from(s).sort();
|
return Array.from(s).sort();
|
||||||
}, [publicites]);
|
}, [validPublicites]);
|
||||||
|
|
||||||
|
const SITE_COLORS: Record<string, string> = useMemo(() => {
|
||||||
|
const palette = [
|
||||||
|
"bg-blue-50 text-blue-700",
|
||||||
|
"bg-violet-50 text-violet-700",
|
||||||
|
"bg-emerald-50 text-emerald-700",
|
||||||
|
"bg-rose-50 text-rose-700",
|
||||||
|
"bg-amber-50 text-amber-700",
|
||||||
|
"bg-cyan-50 text-cyan-700",
|
||||||
|
"bg-pink-50 text-pink-700",
|
||||||
|
"bg-indigo-50 text-indigo-700",
|
||||||
|
];
|
||||||
|
return Object.fromEntries(sites.map((s, i) => [s, palette[i % palette.length]]));
|
||||||
|
}, [sites]);
|
||||||
|
|
||||||
function handleYearChange(e: React.ChangeEvent<HTMLSelectElement>) {
|
function handleYearChange(e: React.ChangeEvent<HTMLSelectElement>) {
|
||||||
router.push(`/publicites?year=${e.target.value}`);
|
router.push(`/publicites?year=${e.target.value}`);
|
||||||
@@ -63,7 +79,7 @@ export function PublicitesClient({ year, publicites }: Props) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const filtered = useMemo(() => {
|
const filtered = useMemo(() => {
|
||||||
let rows = filterSite === "all" ? publicites : publicites.filter(p => p.site === filterSite);
|
let rows = filterSite === "all" ? validPublicites : validPublicites.filter(p => p.site === filterSite);
|
||||||
rows = [...rows].sort((a, b) => {
|
rows = [...rows].sort((a, b) => {
|
||||||
let va: string | number;
|
let va: string | number;
|
||||||
let vb: string | number;
|
let vb: string | number;
|
||||||
@@ -79,7 +95,7 @@ export function PublicitesClient({ year, publicites }: Props) {
|
|||||||
return 0;
|
return 0;
|
||||||
});
|
});
|
||||||
return rows;
|
return rows;
|
||||||
}, [publicites, filterSite, sortKey, sortDir]);
|
}, [validPublicites, filterSite, sortKey, sortDir]);
|
||||||
|
|
||||||
function thProps(key: SortKey, className: string) {
|
function thProps(key: SortKey, className: string) {
|
||||||
return {
|
return {
|
||||||
@@ -172,7 +188,7 @@ export function PublicitesClient({ year, publicites }: Props) {
|
|||||||
<td className="px-3 py-2.5 font-mono text-xs text-gray-400">{pub.tcr_code}</td>
|
<td className="px-3 py-2.5 font-mono text-xs text-gray-400">{pub.tcr_code}</td>
|
||||||
<td className="px-3 py-2.5 text-gray-900 font-medium">{pub.intitule}</td>
|
<td className="px-3 py-2.5 text-gray-900 font-medium">{pub.intitule}</td>
|
||||||
<td className="px-3 py-2.5 text-xs text-gray-600 whitespace-nowrap">
|
<td className="px-3 py-2.5 text-xs text-gray-600 whitespace-nowrap">
|
||||||
<span className="inline-block rounded-md bg-blue-50 px-2 py-0.5 text-blue-700 font-medium">
|
<span className={`inline-block rounded-md px-2 py-0.5 font-medium ${SITE_COLORS[pub.site] ?? "bg-gray-100 text-gray-600"}`}>
|
||||||
{pub.site || "—"}
|
{pub.site || "—"}
|
||||||
</span>
|
</span>
|
||||||
</td>
|
</td>
|
||||||
|
|||||||
Reference in new issue
Block a user