"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 [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 } : {}) }, }, }); 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. The account is created inactive, and an activation link is sent immediately (by email if provided, otherwise WhatsApp) so the attendee can set their own password.

{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}
} )}
))}
))}
); }