From c221e32855ebfc38c0e918bf605fed91bb891f77 Mon Sep 17 00:00:00 2001 From: Tyler Gillispie Date: Thu, 27 Aug 2026 23:05:18 -0700 Subject: [PATCH] fix(join): wire handleJoin and handleSplashJoin in public scripts and join fragments to fix 400 error on /join --- public/sessions-scripts.js | 113 +++++++++++++++++++++++ src/features/events/events.test.ts | 2 +- src/features/events/join_fragments.tsx | 4 +- src/features/events/splash_fragments.tsx | 27 +++--- 4 files changed, 133 insertions(+), 13 deletions(-) diff --git a/public/sessions-scripts.js b/public/sessions-scripts.js index 13f94f0..f13f7ee 100644 --- a/public/sessions-scripts.js +++ b/public/sessions-scripts.js @@ -1076,3 +1076,116 @@ document.addEventListener("keydown", (e) => { closeAttendeesDrawer(); } }); + +async function handleJoin(e) { + if (e && e.preventDefault) e.preventDefault(); + const input = document.getElementById("eventCode"); + const code = input ? input.value.trim() : ""; + if (!code) return; + + const btn = document.getElementById("joinBtn"); + const notice = document.getElementById("joinNotice"); + if (btn) { + btn.disabled = true; + btn.textContent = "Claiming Seat..."; + } + if (notice) notice.style.display = "none"; + + try { + const res = await fetch("/api/join", { + method: "POST", + headers: { + "Content-Type": "application/json", + "Accept": "application/json", + }, + body: JSON.stringify({ code }), + }); + const data = await res.json(); + if (res.ok && data.success) { + showNotice("Seat claimed! Redirecting...", false); + globalThis.location.href = data.redirectUrl || "/dashboard"; + } else { + if (notice) { + notice.textContent = data.error || + "Invalid event code or workshop capacity reached"; + notice.style.display = "block"; + notice.style.background = "var(--danger-bg)"; + notice.style.color = "var(--danger-text)"; + notice.style.border = "1px solid var(--danger-border)"; + } + showNotice(data.error || "Invalid event code", true); + if (btn) { + btn.disabled = false; + btn.textContent = "⚡ Enter Workshop"; + } + } + } catch (_err) { + if (notice) { + notice.textContent = "Network error connecting to event"; + notice.style.display = "block"; + notice.style.background = "var(--danger-bg)"; + notice.style.color = "var(--danger-text)"; + notice.style.border = "1px solid var(--danger-border)"; + } + showNotice("Network error connecting to event", true); + if (btn) { + btn.disabled = false; + btn.textContent = "⚡ Enter Workshop"; + } + } +} +globalThis.handleJoin = handleJoin; + +async function handleSplashJoin(slug) { + const btn = document.getElementById("joinSplashBtn"); + const notice = document.getElementById("splashNotice"); + if (btn) { + btn.disabled = true; + btn.textContent = "Claiming Seat..."; + } + if (notice) notice.style.display = "none"; + + try { + const res = await fetch("/api/join", { + method: "POST", + headers: { + "Content-Type": "application/json", + "Accept": "application/json", + }, + body: JSON.stringify({ code: slug }), + }); + const data = await res.json(); + if (res.ok && data.success) { + showNotice("Seat claimed! Redirecting...", false); + globalThis.location.href = data.redirectUrl || "/dashboard"; + } else { + if (notice) { + notice.textContent = data.error || + "Invalid event code or workshop is full"; + notice.style.display = "block"; + notice.style.background = "var(--danger-bg)"; + notice.style.color = "var(--danger-text)"; + notice.style.border = "1px solid var(--danger-border)"; + } + showNotice(data.error || "Failed to enter workshop", true); + if (btn) { + btn.disabled = false; + btn.textContent = "⚡ Enter Workshop & Claim Seat"; + } + } + } catch (_err) { + if (notice) { + notice.textContent = "Network error connecting to event"; + notice.style.display = "block"; + notice.style.background = "var(--danger-bg)"; + notice.style.color = "var(--danger-text)"; + notice.style.border = "1px solid var(--danger-border)"; + } + showNotice("Network error connecting to event", true); + if (btn) { + btn.disabled = false; + btn.textContent = "⚡ Enter Workshop & Claim Seat"; + } + } +} +globalThis.handleSplashJoin = handleSplashJoin; diff --git a/src/features/events/events.test.ts b/src/features/events/events.test.ts index 8515459..a02019c 100644 --- a/src/features/events/events.test.ts +++ b/src/features/events/events.test.ts @@ -10,7 +10,7 @@ Deno.test("[Events] GET /join returns EventJoinPage HTML", async () => { assertEquals(res.status, 200); const html = await res.text(); assertStringIncludes(html, "Join Event or Workshop"); - assertStringIncludes(html, 'data-on-submit="@post('/api/join')"'); + assertStringIncludes(html, 'onsubmit="handleJoin(event)"'); }); Deno.test("[Events] POST /api/join without code returns HTML error fragment", async () => { diff --git a/src/features/events/join_fragments.tsx b/src/features/events/join_fragments.tsx index 933c39e..b0deb63 100644 --- a/src/features/events/join_fragments.tsx +++ b/src/features/events/join_fragments.tsx @@ -32,7 +32,7 @@ export const EventJoinPageFragment = () => {

-
+
+ + ); }; diff --git a/src/features/events/splash_fragments.tsx b/src/features/events/splash_fragments.tsx index 6deb897..0631e2a 100644 --- a/src/features/events/splash_fragments.tsx +++ b/src/features/events/splash_fragments.tsx @@ -76,19 +76,22 @@ export const EventSplashPageFragment = ({ event }: { event: any }) => { )} +
+ + ); };