import { useMutation } from "@tanstack/react-query"; import { useState } from "react"; import { toast } from "sonner"; import { calculateDrinkCard, type GuestEntry, type GuestErrors, inputCls, validateEmail, validateGuests, validatePhone, validateTextField, } from "@/lib/registration"; import { client, orpc } from "@/utils/orpc"; import { GiftSelector } from "./GiftSelector"; import { GuestList } from "./GuestList"; interface WatcherErrors { firstName?: string; lastName?: string; email?: string; phone?: string; } interface Props { onBack: () => void; } export function WatcherForm({ onBack }: Props) { const [data, setData] = useState({ firstName: "", lastName: "", email: "", phone: "", extraQuestions: "", }); const [errors, setErrors] = useState({}); const [touched, setTouched] = useState>({}); const [guests, setGuests] = useState([]); const [guestErrors, setGuestErrors] = useState([]); const [giftAmount, setGiftAmount] = useState(0); const submitMutation = useMutation({ ...orpc.submitRegistration.mutationOptions(), onSuccess: async (result) => { if (!result.managementToken) return; // Redirect to Lemon Squeezy checkout immediately after registration try { const checkout = await client.getCheckoutUrl({ token: result.managementToken, }); window.location.href = checkout.checkoutUrl; } catch (error) { console.error("Checkout error:", error); toast.error("Er is iets misgegaan bij het aanmaken van de betaling"); } }, onError: (error) => { toast.error(`Er is iets misgegaan: ${error.message}`); }, }); function validate(): boolean { const fieldErrs: WatcherErrors = { firstName: validateTextField(data.firstName, true, "Voornaam"), lastName: validateTextField(data.lastName, true, "Achternaam"), email: validateEmail(data.email), phone: validatePhone(data.phone), }; setErrors(fieldErrs); setTouched({ firstName: true, lastName: true, email: true, phone: true, }); const { errors: gErrs, valid: gValid } = validateGuests(guests); setGuestErrors(gErrs); return !Object.values(fieldErrs).some(Boolean) && gValid; } function handleChange( e: React.ChangeEvent, ) { const { name, value } = e.target; setData((prev) => ({ ...prev, [name]: value })); if (touched[name]) { const errMap: Record = { firstName: validateTextField(value, true, "Voornaam"), lastName: validateTextField(value, true, "Achternaam"), email: validateEmail(value), phone: validatePhone(value), }; setErrors((prev) => ({ ...prev, [name]: errMap[name] })); } } function handleBlur( e: React.FocusEvent, ) { const { name, value } = e.target; setTouched((prev) => ({ ...prev, [name]: true })); const errMap: Record = { firstName: validateTextField(value, true, "Voornaam"), lastName: validateTextField(value, true, "Achternaam"), email: validateEmail(value), phone: validatePhone(value), }; setErrors((prev) => ({ ...prev, [name]: errMap[name] })); } function handleGuestChange( index: number, field: keyof GuestEntry, value: string, ) { setGuests((prev) => { const next = [...prev]; next[index] = { ...next[index], [field]: value } as GuestEntry; return next; }); } function handleAddGuest() { if (guests.length >= 9) return; setGuests((prev) => [ ...prev, { firstName: "", lastName: "", email: "", phone: "" }, ]); setGuestErrors((prev) => [...prev, {}]); } function handleRemoveGuest(index: number) { setGuests((prev) => prev.filter((_, i) => i !== index)); setGuestErrors((prev) => prev.filter((_, i) => i !== index)); } function handleSubmit(e: React.FormEvent) { e.preventDefault(); if (!validate()) { toast.error("Controleer je invoer"); return; } submitMutation.mutate({ firstName: data.firstName.trim(), lastName: data.lastName.trim(), email: data.email.trim(), phone: data.phone.trim() || undefined, registrationType: "watcher", guests: guests.map((g) => ({ firstName: g.firstName.trim(), lastName: g.lastName.trim(), email: g.email.trim() || undefined, phone: g.phone.trim() || undefined, })), extraQuestions: data.extraQuestions.trim() || undefined, giftAmount, }); } const totalPrice = calculateDrinkCard(guests.length); return (
{/* Back + type header */}
Ik wil komen kijken
{/* Live price callout */}
€{totalPrice}

Drinkkaart inbegrepen

Je betaald bij registratie{" "} €5 (+ €2 per medebezoeker) dat gaat naar je drinkkaart. {guests.length > 0 && ( Totaal: €{totalPrice} voor {1 + guests.length} personen. )}

{/* Name row */}
{touched.firstName && errors.firstName && ( {errors.firstName} )}
{touched.lastName && errors.lastName && ( {errors.lastName} )}
{/* Contact row */}
{touched.email && errors.email && ( {errors.email} )}
{touched.phone && errors.phone && ( {errors.phone} )}
{/* Guests */} {/* Extra questions */}