Consolidate into one chronological list, tag each event by circuit
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 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01SBzcNkW7JcYipnAX6HfgmK
This commit is contained in:
@@ -37,8 +37,8 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Circuit sections get built here, one per entry in CONFIG.circuits -->
|
||||
<div class="hidden space-y-10" id="circuits"></div>
|
||||
<!-- One consolidated, deduped, chronologically-sorted event list -->
|
||||
<div class="hidden" id="events"></div>
|
||||
|
||||
<div class="divider mt-8"></div>
|
||||
|
||||
|
||||
+42
-29
@@ -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
|
||||
? `<span class="badge badge-ghost badge-sm">${ev.checkedInPlayers ?? 0}/${ev.numTickets} checked in</span>`
|
||||
: "";
|
||||
@@ -255,6 +260,7 @@ function eventCard(ev) {
|
||||
const format = `<span class="badge badge-warning badge-sm">${formatOf(ev)}</span>`;
|
||||
const scope = scopeOf(ev);
|
||||
const scopeBadge = scope ? `<span class="badge badge-info badge-sm">${scope}</span>` : "";
|
||||
const circuitBadges = circuits.map(c => `<span class="badge badge-accent badge-sm">${esc(c.name)}</span>`).join("");
|
||||
return `
|
||||
<a href="${BCP_ORIGIN}/event/${esc(ev.id)}" target="_blank" rel="noopener"
|
||||
class="card card-border bg-base-200 hover:border-warning transition-colors">
|
||||
@@ -262,7 +268,7 @@ function eventCard(ev) {
|
||||
<div class="min-w-0">
|
||||
<div class="font-semibold truncate">${esc(ev.name)}</div>
|
||||
<div class="text-sm opacity-60 mt-1">${esc(locationOf(ev))}</div>
|
||||
<div class="flex gap-2 mt-2">${format}${scopeBadge}${system}${capacity}</div>
|
||||
<div class="flex gap-2 mt-2 flex-wrap">${format}${scopeBadge}${circuitBadges}${system}${capacity}</div>
|
||||
</div>
|
||||
<div class="text-right shrink-0">
|
||||
<div class="font-mono text-sm text-warning">${fmtDateRange(ev)}</div>
|
||||
@@ -271,36 +277,43 @@ function eventCard(ev) {
|
||||
</a>`;
|
||||
}
|
||||
|
||||
function circuitSection(circuit, events, filtered) {
|
||||
let body;
|
||||
if (!events.length) {
|
||||
body = `<p class="text-sm text-base-content/50 py-4">No upcoming events for this circuit.</p>`;
|
||||
} else if (!filtered.length) {
|
||||
body = `<p class="text-sm text-base-content/50 py-4">No events match the current filter.</p>`;
|
||||
} 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 `
|
||||
<section>
|
||||
<h2 class="text-2xl font-bold uppercase tracking-wide mb-3">
|
||||
<a href="${BCP_ORIGIN}/circuit/${esc(circuit.id)}/calendar" target="_blank" rel="noopener" class="hover:text-warning">
|
||||
${esc(circuit.name)}
|
||||
</a>
|
||||
</h2>
|
||||
<div class="space-y-3">${body}</div>
|
||||
</section>`;
|
||||
}
|
||||
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
|
||||
? `<section><h2 class="text-2xl font-bold uppercase tracking-wide mb-3">${esc(circuit.name)}</h2>
|
||||
<p class="text-sm text-error py-4">Couldn't load events for this circuit — try refreshing.</p></section>`
|
||||
: 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
|
||||
? `<p class="text-sm text-error mb-4">Couldn't load: ${failed.map(esc).join(", ")} — try refreshing.</p>`
|
||||
: "";
|
||||
|
||||
let body;
|
||||
if (!merged.length) {
|
||||
body = `<p class="text-sm text-base-content/50 py-4">No upcoming events found.</p>`;
|
||||
} else if (!filtered.length) {
|
||||
body = `<p class="text-sm text-base-content/50 py-4">No events match the current filter.</p>`;
|
||||
} else {
|
||||
body = `<div class="space-y-3">${filtered.map(({ event, circuits }) => eventCard(event, circuits)).join("")}</div>`;
|
||||
}
|
||||
|
||||
$("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();
|
||||
|
||||
Reference in New Issue
Block a user