From 4bb5dc8ed860c343a19efccc01109ef92c748a7d Mon Sep 17 00:00:00 2001 From: mandalore Date: Fri, 4 Sep 2026 17:08:11 -0500 Subject: [PATCH] Consolidate into one chronological list, tag each event by circuit MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Replaces the one-section-per-circuit layout with a single flat, deduped, date-sorted feed. Events belonging to more than one watched circuit (real and not rare — verified 2 current events span both a regional circuit and the national league) get one card carrying every circuit badge that matched, rather than appearing once per section. Co-Authored-By: Claude Sonnet 5 Claude-Session: https://claude.ai/code/session_01SBzcNkW7JcYipnAX6HfgmK --- sites/events/index.html | 4 +-- sites/events/src/main.js | 71 ++++++++++++++++++++++++---------------- 2 files changed, 44 insertions(+), 31 deletions(-) diff --git a/sites/events/index.html b/sites/events/index.html index 41f04ca..fbdcc7e 100644 --- a/sites/events/index.html +++ b/sites/events/index.html @@ -37,8 +37,8 @@ - - + +
diff --git a/sites/events/src/main.js b/sites/events/src/main.js index c1f6e88..cc03d97 100644 --- a/sites/events/src/main.js +++ b/sites/events/src/main.js @@ -240,12 +240,17 @@ function setupFilters() { btn.classList.toggle("opacity-40", !nowActive); if (nowActive) set.add(btn.dataset.filterValue); else set.delete(btn.dataset.filterValue); - renderCircuits(); + renderEvents(); }); }); } -function eventCard(ev) { +// A single event can belong to more than one watched circuit (BCP events +// carry their own list of leagues, and it's common for e.g. a national +// league and a regional circuit to both include the same event) — badge +// it with every circuit it matched under rather than showing it once +// per circuit. +function eventCard(ev, circuits) { const capacity = ev.numTickets ? `${ev.checkedInPlayers ?? 0}/${ev.numTickets} checked in` : ""; @@ -255,6 +260,7 @@ function eventCard(ev) { const format = `${formatOf(ev)}`; const scope = scopeOf(ev); const scopeBadge = scope ? `${scope}` : ""; + const circuitBadges = circuits.map(c => `${esc(c.name)}`).join(""); return ` @@ -262,7 +268,7 @@ function eventCard(ev) {
${esc(ev.name)}
${esc(locationOf(ev))}
-
${format}${scopeBadge}${system}${capacity}
+
${format}${scopeBadge}${circuitBadges}${system}${capacity}
${fmtDateRange(ev)}
@@ -271,36 +277,43 @@ function eventCard(ev) {
`; } -function circuitSection(circuit, events, filtered) { - let body; - if (!events.length) { - body = `

No upcoming events for this circuit.

`; - } else if (!filtered.length) { - body = `

No events match the current filter.

`; - } else { - body = filtered.map(eventCard).join(""); +// Dedupe by event id across all circuits, collecting every circuit an +// event matched under, then sort the merged list chronologically — +// replaces the old one-section-per-circuit layout with a single feed. +function mergeEvents(results) { + const byId = new Map(); + for (const { circuit, events, error } of results) { + if (error) continue; + for (const ev of events) { + if (!byId.has(ev.id)) byId.set(ev.id, { event: ev, circuits: [] }); + byId.get(ev.id).circuits.push(circuit); + } } - return ` -
-

- - ${esc(circuit.name)} - -

-
${body}
-
`; + return [...byId.values()].sort((a, b) => Date.parse(a.event.eventDate) - Date.parse(b.event.eventDate)); } /* ---- Orchestration ---- */ let allResults = []; -function renderCircuits() { - $("circuits").innerHTML = allResults.map(({ circuit, events, error }) => - error - ? `

${esc(circuit.name)}

-

Couldn't load events for this circuit — try refreshing.

` - : circuitSection(circuit, events, events.filter(passesFilter)) - ).join(""); +function renderEvents() { + const merged = mergeEvents(allResults); + const filtered = merged.filter(({ event }) => passesFilter(event)); + + const failed = allResults.filter(r => r.error).map(r => r.circuit.name); + const errorBanner = failed.length + ? `

Couldn't load: ${failed.map(esc).join(", ")} — try refreshing.

` + : ""; + + let body; + if (!merged.length) { + body = `

No upcoming events found.

`; + } else if (!filtered.length) { + body = `

No events match the current filter.

`; + } else { + body = `
${filtered.map(({ event, circuits }) => eventCard(event, circuits)).join("")}
`; + } + + $("events").innerHTML = errorBanner + body; } async function load() { @@ -317,8 +330,8 @@ async function load() { ); $("loading").classList.add("hidden"); - $("circuits").classList.remove("hidden"); - renderCircuits(); + $("events").classList.remove("hidden"); + renderEvents(); } setupFilters();