auth-yes/ui/components/EventJoinPage.tsx

124 lines
4.3 KiB
XML

import { Layout } from "./Layout.tsx";
export const EventJoinPage = () => {
return (
<Layout title="Join Event & Workshop">
<div>
<div class="brand-header">
<div
class="brand-logo"
style="background: var(--primary-light); color: var(--primary);"
>
<svg
width="26"
height="26"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2.5"
stroke-linecap="round"
stroke-linejoin="round"
>
<path d="M2 9a3 3 0 0 1 0 6v2a2 2 0 0 0 2 2h16a2 2 0 0 0 2-2v-2a3 3 0 0 1 0-6V7a2 2 0 0 0-2-2H4a2 2 0 0 0-2 2Z">
</path>
<path d="M13 5v2"></path>
<path d="M13 17v2"></path>
<path d="M13 11v2"></path>
</svg>
</div>
<h1>Join Event or Workshop</h1>
<p class="subtitle">
Enter your event PIN code or slug to claim an instant sandbox seat.
</p>
</div>
<form id="joinForm" onsubmit="handleJoin(event)">
<div style="margin-bottom: 1.25rem;">
<label style="display: block; font-weight: 600; margin-bottom: 0.35rem; font-size: 0.875rem; color: var(--text-secondary);">
Event PIN or Slug Code
</label>
<input
type="text"
id="eventCode"
placeholder="e.g. 749-123 or deno-lab"
required
autofocus
style="width: 100%; font-size: 1.1rem; text-align: center; letter-spacing: 0.05em; font-weight: 600; min-height: 48px;"
/>
</div>
<div
id="joinNotice"
style="display: none; margin-bottom: 1rem; padding: 0.75rem 1rem; border-radius: var(--radius-md); font-size: 0.9rem;"
/>
<button
type="submit"
id="joinBtn"
class="btn-primary"
style="width: 100%; min-height: 48px; font-size: 1rem;"
>
⚡ Enter Workshop
</button>
</form>
<div style="margin-top: 1.5rem; text-align: center; font-size: 0.85rem; color: var(--text-muted);">
Looking for standard sign in?{" "}
<a
href="/login"
style="color: var(--primary); text-decoration: none; font-weight: 600;"
>
Sign in with Passkey
</a>
</div>
</div>
<script
dangerouslySetInnerHTML={{
__html: `
async function handleJoin(e) {
e.preventDefault();
const code = document.getElementById('eventCode').value.trim();
if (!code) return;
const btn = document.getElementById('joinBtn');
const notice = document.getElementById('joinNotice');
btn.disabled = true;
btn.textContent = 'Claiming Seat...';
notice.style.display = 'none';
try {
const res = await fetch('/api/join', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ code }),
});
const data = await res.json();
if (res.ok) {
window.location.href = data.redirectUrl || '/dashboard';
} else {
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)';
btn.disabled = false;
btn.textContent = '⚡ Enter Workshop';
}
} catch (err) {
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)';
btn.disabled = false;
btn.textContent = '⚡ Enter Workshop';
}
}
`,
}}
/>
</Layout>
);
};