"use client"; import React, { useEffect, useState } from "react"; import { useAuth } from "@/hooks/useAuth"; import { useRouter } from "next/navigation"; import { apiFetch } from "@/lib/api"; import { useDismissingState } from "@/hooks/useDismissingState"; import { UserPlus } from "lucide-react"; type FormField = { id: string; type: 'yes_no'|'text'|'date'|'numeric'|'statement'|'paragraph'; label: string; isRequired?: boolean; helpText?: string|null }; export default function ManualRegistrationPage() { const { user, token, loading } = useAuth(); const router = useRouter(); const [eventId, setEventId] = useState(""); const [optionId, setOptionId] = useState(""); const [quantity, setQuantity] = useState(1); const [name, setName] = useState(""); const [email, setEmail] = useState(""); const [phoneNumber, setPhoneNumber] = useState(""); const [registerAsGuest, setRegisterAsGuest] = useState(false); const [busy, setBusy] = useState(false); const [error, setError] = useDismissingState(null); const [createdReg, setCreatedReg] = useState(null); const [form, setForm] = useState<{ isRequired: boolean; fields: FormField[] } | null>(null); const [formsData, setFormsData] = useState>>({}); useEffect(() => { if (loading) return; if (!user) router.replace("/login"); }, [user, loading, router]); async function submit(e: React.FormEvent) { e.preventDefault(); if (!token) return; setBusy(true); setError(null); try { const res = await apiFetch("/api/registrations/manual", { method: "POST", authToken: token, body: { eventId, options: [{ eventOptionId: optionId, quantity }], user: { name, ...(email ? { email } : {}), ...(phoneNumber ? { phoneNumber } : {}) }, guestOnly: registerAsGuest, }, }); setCreatedReg(res); // Load form definition for this event (if any) try { const ev = await apiFetch(`/api/events/${encodeURIComponent(eventId)}`); if (ev?.form) setForm(ev.form); } catch {} alert("Manual registration created"); } catch (e: any) { setError(e?.message || "Failed to create manual registration"); } finally { setBusy(false); } } return (

Manual Registration

setEventId(e.target.value)} required />
setOptionId(e.target.value)} required />
setQuantity(parseInt(e.target.value || "1", 10))} required />
setName(e.target.value)} required />
setEmail(e.target.value)} placeholder="email@example.com" />
setPhoneNumber(e.target.value)} placeholder="+27…" />

At least one of email or cell number is required. If no email is provided, a guest account is created automatically.

{error &&

{error}

}
{createdReg && form && Array.isArray(form.fields) && ( )}
); } function AttendeeFormsSection({ registration, form, formsData, setFormsData }: { registration: any; form: { isRequired: boolean; fields: FormField[] }; formsData: Record>; setFormsData: any; }) { const { token } = useAuth(); const [submitting, setSubmitting] = useState(false); const [error, setError] = useDismissingState(null); const [info, setInfo] = useDismissingState(null); const mainTickets = (registration?.registrationOptions || []).filter((o: any) => o?.eventOption?.isMainTicket).reduce((s: number, o: any) => s + (o.quantity || 0), 0); const count = Math.max(0, mainTickets); const canSubmit = React.useMemo(() => { if (!form || count <= 0) return false; const reqFields = (form.fields || []) .filter(f => !!f.isRequired && f.type !== 'statement' && f.type !== 'paragraph') .map(f => f.id); for (let i = 0; i < count; i++) { const data = formsData[i] || {}; for (const fid of reqFields) { const v = data[fid]; if (v === undefined || v === null || String(v).trim() === '') { return false; } } } return true; }, [form, formsData, count]); const update = (idx: number, fieldId: string, value: string) => { setFormsData((prev: any) => ({ ...prev, [idx]: { ...(prev[idx]||{}), [fieldId]: value } })); }; const submit = async () => { if (!token) return; try { setSubmitting(true); setError(null); setInfo(null); const payload = [] as any[]; for (let i = 0; i < count; i++) payload.push({ answers: formsData[i] || {} }); await apiFetch(`/api/registrations/${encodeURIComponent(registration.id)}/forms/responses`, { method: 'POST', authToken: token, body: { responses: payload } }); setInfo('Attendee forms submitted successfully.'); } catch (e: any) { setError(e?.message || 'Failed to submit forms'); } finally { setSubmitting(false); } }; if (!form || !Array.isArray(form.fields) || count === 0) return null; return (
Attendee forms for this registration
{error &&
{error}
} {info &&
{info}
}
{Array.from({ length: count }, (_, idx) => (
Attendee {idx + 1}
{form.fields.map((f) => (
{f.type === 'statement' ? (
{f.label}
) : f.type === 'paragraph' ? (
{f.label &&
{f.label}
} {f.helpText &&
{f.helpText}
}
) : ( <> {f.type === 'yes_no' ? ( ) : f.type === 'date' ? ( update(idx, f.id, e.target.value)} /> ) : f.type === 'numeric' ? ( update(idx, f.id, e.target.value)} /> ) : ( update(idx, f.id, e.target.value)} /> )} {f.helpText &&
{f.helpText}
} )}
))}
))}
); }