"use client"; import { useState, type FormEvent } from "react"; import { useRouter } from "next/navigation"; import { fieldClass, TextField, FormError } from "@/components/FormField"; export const MEETING_SESSION_KEY = "anouma-meeting-session"; const MEETING_CLIENT_ID_KEY = "anouma-meeting-client-id"; // A stable per-browser identity so a host's "kick" survives the removed // participant simply reconnecting (which always gets a fresh participantId // — see lib/meeting/token.ts). Deliberately in localStorage, not // sessionStorage: it must outlive the "kicked" screen clearing the session // and the "Erneut beitreten" link going back through this form again. function getOrCreateClientId(): string { try { const existing = localStorage.getItem(MEETING_CLIENT_ID_KEY); if (existing) return existing; const created = crypto.randomUUID(); localStorage.setItem(MEETING_CLIENT_ID_KEY, created); return created; } catch { // Storage unavailable (private browsing, etc.) — fall back to a // one-off id; kicks just won't stick across reconnects in that case. return crypto.randomUUID(); } } export type StoredMeetingSession = { token: string; participantToken?: string; serverUrl?: string; participantId: string; role: "host" | "participant"; name: string; eventTitle: string; eventSlug: string; }; export function JoinForm({ slug }: { slug: string }) { const router = useRouter(); const [name, setName] = useState(""); const [password, setPassword] = useState(""); const [showPassword, setShowPassword] = useState(false); const [error, setError] = useState(null); const [loading, setLoading] = useState(false); async function handleSubmit(e: FormEvent) { e.preventDefault(); setError(null); setLoading(true); try { const res = await fetch(`/api/meetings/${slug}/join`, { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ name, password, clientId: getOrCreateClientId() }), credentials: "include", }); const data = await res.json(); if (!res.ok) { setError(data.error || "Beitritt leider nicht möglich."); setLoading(false); return; } const session: StoredMeetingSession = { token: data.token, participantToken: data.participantToken, serverUrl: data.serverUrl, participantId: data.participantId, role: data.role, name, eventTitle: data.eventTitle, eventSlug: slug, }; sessionStorage.setItem(MEETING_SESSION_KEY, JSON.stringify(session)); router.push(`/termine/${slug}/call`); } catch { setError("Verbindung fehlgeschlagen. Bitte versuche es erneut."); setLoading(false); } } return (
setName(e.target.value)} placeholder="Name eingeben" autoComplete="name" />
setPassword(e.target.value)} placeholder="Passwort eingeben" autoComplete="off" />
{error && {error}} ); }