import { useEffect, useMemo, useState } from "react"; import { Calendar, MapPin } from "lucide-react"; import { useLocation, useNavigate } from "react-router-dom"; import { AuthShell } from "../components/auth/AuthShell"; import { EventBuzzLogo } from "../components/EventBuzzLogo"; import { postVisitorStartOtp, postVisitorVerifyOtp } from "../lib/api"; import { setAttendeeSession } from "../lib/attendeeAuth"; import { notifyRewardFromApiData } from "../lib/rewardCelebration"; import { buildPostAuthUrl, readStoredVisitorContext } from "../types/visitorContext"; type OtpLocationState = { eventId?: string; email?: string; inviteToken?: string; firstName?: string; lastName?: string; phone?: string; displayName?: string; }; function formatEventSchedule(startIso: string, endIso: string): string { const s = new Date(startIso); const e = new Date(endIso); if (Number.isNaN(s.getTime()) || Number.isNaN(e.getTime())) return ""; const opts: Intl.DateTimeFormatOptions = { month: "long", day: "numeric", year: "numeric" }; if (s.toDateString() === e.toDateString()) { return s.toLocaleDateString(undefined, opts); } return `${s.toLocaleDateString(undefined, opts)} – ${e.toLocaleDateString(undefined, opts)}`; } export function RegisterOtpPage() { const navigate = useNavigate(); const location = useLocation(); const st = (location.state as OtpLocationState | null) ?? {}; const eventId = st.eventId ?? ""; const email = st.email ?? ""; const ctx = readStoredVisitorContext(); const event = ctx?.event; const [digits, setDigits] = useState(() => Array(6).fill("")); const [error, setError] = useState(null); const [loading, setLoading] = useState(false); const [resendCooldown, setResendCooldown] = useState(0); useEffect(() => { if (resendCooldown <= 0) return; const t = window.setTimeout(() => setResendCooldown((c) => c - 1), 1000); return () => window.clearTimeout(t); }, [resendCooldown]); const schedule = useMemo(() => { if (!event?.startDate || !event?.endDate) return ""; const a = typeof event.startDate === "string" ? event.startDate : new Date(event.startDate as unknown as Date).toISOString(); const b = typeof event.endDate === "string" ? event.endDate : new Date(event.endDate as unknown as Date).toISOString(); return formatEventSchedule(a, b); }, [event]); if (!eventId || !email) { return (

Missing session. Start from the login page.

); } function setDigit(i: number, v: string) { const d = v.replace(/\D/g, "").slice(-1); const next = [...digits]; next[i] = d; setDigits(next); if (d && i < 5) { document.getElementById(`otp-${i + 1}`)?.focus(); } } async function handleVerify(e: React.FormEvent) { e.preventDefault(); const otp = digits.join(""); if (otp.length !== 6) { setError("Enter the 6-digit code."); return; } setError(null); setLoading(true); try { const data = await postVisitorVerifyOtp(eventId, { email, otp, inviteToken: st.inviteToken, firstName: st.firstName, lastName: st.lastName, phone: st.phone, displayName: st.displayName, }); setAttendeeSession(data.token, data.participant); notifyRewardFromApiData(data); if (data.pendingApproval) { navigate("/pending-approval"); return; } if (data.needsProfile) { navigate("/complete-profile"); return; } navigate(buildPostAuthUrl(ctx)); } catch (err) { setError(err instanceof Error ? err.message : "Verification failed."); } finally { setLoading(false); } } async function handleResend() { if (resendCooldown > 0 || !ctx) return; setError(null); try { await postVisitorStartOtp( eventId, email, { type: ctx.type, sessionId: ctx.sessionId, trackId: ctx.trackId }, st.inviteToken, ); setResendCooldown(45); } catch (err) { setError(err instanceof Error ? err.message : "Could not resend."); } } return (
{event?.logoUrl ? ( ) : ( )}

Enter code

{event?.name ?? "Event"}

{schedule ? (
{schedule} {event?.location?.trim() ? ( <> {event.location.trim()} ) : null}
) : null}
Code sent to your email

Sent to:

{email}

Enter OTP

{digits.map((d, i) => ( setDigit(i, e.target.value)} className="size-11 rounded-lg border border-[rgba(116,112,112,0.3)] bg-[rgba(157,157,172,0.07)] text-center font-inter text-lg font-semibold text-[#24282f]" /> ))}
{error ?

{error}

: null}
); }