"use client" import type React from "react" import { Button } from "@/components/ui/button" import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card" import { Input } from "@/components/ui/input" import { Label } from "@/components/ui/label" import { Checkbox } from "@/components/ui/checkbox" import { RadioGroup, RadioGroupItem } from "@/components/ui/radio-group" import Link from "next/link" import { useEffect, useState } from "react" import { EVENT_SHORT, EVENT_FULL_NAME, EVENT_DATES, EVENT_LOCATION, PRICING_TIERS, PROCESSING_FEE_PERCENT, ACCOMMODATION_VENUES, ACCOMMODATION_MAP, ACCOMMODATION_NIGHTS, LINKS, } from "@/lib/event.config" // Determine current tier client-side function getClientTier() { const now = new Date().toISOString().slice(0, 10) return PRICING_TIERS.find((t) => now < t.cutoff) ?? PRICING_TIERS[PRICING_TIERS.length - 1] } export default function RegisterPage() { const [step, setStep] = useState<"form" | "payment">("form") const [isSubmitting, setIsSubmitting] = useState(false) const [includeAccommodation, setIncludeAccommodation] = useState(true) const [selectedVenueKey, setSelectedVenueKey] = useState(ACCOMMODATION_VENUES[0]?.key || "") const [accommodationType, setAccommodationType] = useState( ACCOMMODATION_VENUES[0]?.options[0]?.id || "" ) const [formData, setFormData] = useState({ name: "", email: "", }) const [availability, setAvailability] = useState>({}) // Fetch accommodation availability on mount useEffect(() => { fetch("/api/accommodation-availability") .then((res) => (res.ok ? res.json() : null)) .then((data) => { if (data && typeof data === "object" && !data.error) { setAvailability(data) // If current selection is sold out, clear it if (accommodationType && data[accommodationType] === false) { const firstAvailable = ACCOMMODATION_VENUES.flatMap((v) => v.options) .find((o) => data[o.id] !== false) if (firstAvailable) { setAccommodationType(firstAvailable.id) const venue = ACCOMMODATION_VENUES.find((v) => v.options.some((o) => o.id === firstAvailable.id)) if (venue) setSelectedVenueKey(venue.key) } } } }) .catch(() => {}) // Fail silently — all options remain enabled }, []) // eslint-disable-line react-hooks/exhaustive-deps const tier = getClientTier() const baseTicketPrice = tier.price const accommodationPrice = ACCOMMODATION_MAP[accommodationType]?.price ?? 0 const subtotalPrice = baseTicketPrice + (includeAccommodation ? accommodationPrice : 0) const processingFee = Math.round(subtotalPrice * PROCESSING_FEE_PERCENT * 100) / 100 const totalPrice = subtotalPrice + processingFee const handleSubmit = async (e: React.FormEvent) => { e.preventDefault() // Validate required fields if ( !formData.name || !formData.email ) { alert("Please fill in all required fields") return } setIsSubmitting(true) try { // Submit registration to Google Sheet first const response = await fetch("/api/register", { method: "POST", headers: { "Content-Type": "application/json", }, body: JSON.stringify({ name: formData.name, email: formData.email, }), }) if (!response.ok) { throw new Error("Failed to record registration") } // Proceed to payment step setStep("payment") } catch (error) { console.error("Registration error:", error) alert("There was an error recording your registration. Please try again.") } finally { setIsSubmitting(false) } } // Pricing summary line const pricingSummary = PRICING_TIERS.map( (t) => `€${t.price} ${t.label}${t === tier ? " (current)" : ""}` ).join(" · ") if (step === "payment") { return (
{/* Header */}
{EVENT_SHORT}

Complete Your Registration

Choose your payment method

{/* Ticket */}
{EVENT_SHORT} Ticket
{pricingSummary}
€{baseTicketPrice.toFixed(2)}
{/* Accommodation */}
setIncludeAccommodation(checked as boolean)} className="mt-1" />
{includeAccommodation && ( €{accommodationPrice.toFixed(2)} )}
{includeAccommodation ? (
{ setAccommodationType(value) const venue = ACCOMMODATION_VENUES.find((v) => v.options.some((o) => o.id === value) ) if (venue) setSelectedVenueKey(venue.key) }} className="space-y-4" > {ACCOMMODATION_VENUES.map((venue) => (

{venue.name}

{venue.description}

{venue.options.map((opt) => { const soldOut = availability[opt.id] === false return (
) })}
))}
) : (

I'll arrange my own accommodation

)}

Additional Note: We'll follow up closer to the event to confirm room assignments and dietary preferences.

{/* Processing fee */}
Payment processing fee ({(PROCESSING_FEE_PERCENT * 100).toFixed(0)}%)
€{processingFee.toFixed(2)}
{/* Total */}
Total Amount
Ticket{includeAccommodation ? " + accommodation" : ""}
€{totalPrice.toFixed(2)}
{/* Payment Methods */}
Payment Options Choose your preferred payment method

You'll be redirected to Mollie's secure checkout where you can pay by credit card, SEPA bank transfer, iDEAL, PayPal, or other methods.

All payments are processed securely through Mollie. You'll receive a confirmation email after successful payment.

{/* Simplified Footer */}
) } return (
{/* Header */}
{EVENT_SHORT}

Payment for CoFi 4

{EVENT_DATES} · {EVENT_LOCATION}

Registration Form Tell us about yourself and what you'd like to bring to {EVENT_SHORT}
{/* Name */}
setFormData({ ...formData, name: e.target.value })} />
{/* Email */}
setFormData({ ...formData, email: e.target.value })} />

We'll send your payment confirmation and event updates here.

Questions? Contact us at{" "} {LINKS.contactEmail} {LINKS.telegram && ( <> {" or on "} Telegram )}

{/* Simplified Footer */}
) }