From 52d5029eed4bc44092776638c3bc9fa91d7df8e6 Mon Sep 17 00:00:00 2001 From: Ryan Salazar Date: Thu, 28 May 2026 17:14:13 +0000 Subject: [PATCH] manufacturers directory: dynamic per-show filter buttons MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - page.tsx fetches bb.events (confirmed + tentative) and passes shows list into DirectoryClient alongside the tracked_companies rows - DirectoryClient renders an "All shows" + "NAB+IBC" + one chip per event in bb.events. Shows attendee count when known; tags "soon" on shows without exhibitor mappings yet (ANGA COM, MPTS, BroadcastAsia, SET Expo, NAB NY, SATIS, Hamburg Open, CABSAT, etc.) - Filter logic uses tracked_companies.shows_attending text[] (added in migration 0008) instead of the legacy exhibits_nab / exhibits_ibc booleans — scales to N shows. The directory page was previously capped at 1,000 rows (PostgREST default max_rows). Server-side bumped to 5000 in a paired supabase env update — directory now renders all 1,366 manufacturers. Co-Authored-By: Claude Opus 4.7 (1M context) --- src/app/manufacturers/DirectoryClient.tsx | 85 +++++++++++++++++++---- src/app/manufacturers/page.tsx | 24 ++++++- 2 files changed, 93 insertions(+), 16 deletions(-) diff --git a/src/app/manufacturers/DirectoryClient.tsx b/src/app/manufacturers/DirectoryClient.tsx index 92fb8dd..b10ff16 100644 --- a/src/app/manufacturers/DirectoryClient.tsx +++ b/src/app/manufacturers/DirectoryClient.tsx @@ -11,22 +11,44 @@ type Manufacturer = { categories: string[] | null; exhibits_nab: boolean; exhibits_ibc: boolean; + shows_attending: string[] | null; mention_count: number; featured: boolean; }; -const SHOW_FILTERS = ["All", "NAB Show", "IBC", "Both shows"] as const; -type ShowFilter = (typeof SHOW_FILTERS)[number]; +type ShowOption = { + slug: string; + short_name: string | null; + name: string; + start_date: string; + end_date: string; + status: string; +}; export default function ManufacturerDirectoryClient({ manufacturers, + shows = [], }: { manufacturers: Manufacturer[]; + shows?: ShowOption[]; }) { const [q, setQ] = useState(""); - const [showFilter, setShowFilter] = useState("All"); + // showFilter is now a show slug from bb.events (e.g. 'nab-show-2026') or + // 'all' / 'both-major' (NAB+IBC overlap). + const [showFilter, setShowFilter] = useState("all"); const [letter, setLetter] = useState("All"); + // Per-show exhibitor counts for badge display + auto-hiding empty shows. + const showCounts = useMemo(() => { + const counts: Record = {}; + for (const m of manufacturers) { + for (const s of m.shows_attending || []) { + counts[s] = (counts[s] || 0) + 1; + } + } + return counts; + }, [manufacturers]); + const filtered = useMemo(() => { const needle = q.trim().toLowerCase(); return manufacturers.filter((m) => { @@ -34,9 +56,11 @@ export default function ManufacturerDirectoryClient({ const hay = `${m.company_name} ${m.bio || ""}`.toLowerCase(); if (!hay.includes(needle)) return false; } - if (showFilter === "NAB Show" && !m.exhibits_nab) return false; - if (showFilter === "IBC" && !m.exhibits_ibc) return false; - if (showFilter === "Both shows" && !(m.exhibits_nab && m.exhibits_ibc)) return false; + if (showFilter === "both-major") { + if (!(m.exhibits_nab && m.exhibits_ibc)) return false; + } else if (showFilter !== "all") { + if (!(m.shows_attending || []).includes(showFilter)) return false; + } if (letter !== "All") { const c = (m.company_name || "").trim().charAt(0).toUpperCase(); if (letter === "#") { @@ -63,20 +87,53 @@ export default function ManufacturerDirectoryClient({ className="w-full bg-[#0d0d0d] border border-[#2a2a2a] rounded-md px-3 py-2 text-sm focus:outline-none focus:ring-2 focus:ring-[#3b82f6]/40" /> -
- {SHOW_FILTERS.map((f) => ( +
+ + {/* Per-show filter chips. Every event from bb.events shows up; ones + without exhibitor mappings yet render a "(soon)" badge so the + admin can see what's still missing data. */} +
+ + + {shows.map((s) => { + const count = showCounts[s.slug] || 0; + const active = showFilter === s.slug; + const label = s.short_name || s.name; + return ( - ))} -
+ ); + })}