import { useQuery, useQueryClient } from "@tanstack/react-query"; import { createFileRoute, Link, useNavigate } from "@tanstack/react-router"; import { Calendar, CreditCard, Music, QrCode, Users, Wallet, } from "lucide-react"; import { useEffect, useState } from "react"; import { toast } from "sonner"; import { QrCodeDisplay } from "@/components/drinkkaart/QrCodeDisplay"; import { TopUpHistory } from "@/components/drinkkaart/TopUpHistory"; import { TopUpModal } from "@/components/drinkkaart/TopUpModal"; import { TransactionHistory } from "@/components/drinkkaart/TransactionHistory"; import { authClient } from "@/lib/auth-client"; import { formatCents } from "@/lib/drinkkaart"; import { client, orpc } from "@/utils/orpc"; interface AccountSearch { topup?: string; welkom?: string; } export const Route = createFileRoute("/account")({ validateSearch: (search: Record): AccountSearch => ({ topup: typeof search.topup === "string" ? search.topup : undefined, welkom: typeof search.welkom === "string" ? search.welkom : undefined, }), component: AccountPage, }); function PaymentBadge({ status }: { status: string | null }) { if (status === "paid") { return ( Betaald ); } if (status === "extra_payment_pending") { return ( Extra betaling verwacht ); } return ( In behandeling ); } function AccountPage() { const navigate = useNavigate(); const queryClient = useQueryClient(); const search = Route.useSearch(); const [showQr, setShowQr] = useState(false); const [showTopUp, setShowTopUp] = useState(false); const sessionQuery = useQuery({ queryKey: ["session"], queryFn: () => authClient.getSession(), }); // Client-side auth check: redirect to login if not authenticated useEffect(() => { if (!sessionQuery.isLoading && !sessionQuery.data?.data?.user) { navigate({ to: "/login" }); } }, [sessionQuery.isLoading, sessionQuery.data, navigate]); const drinkkaartQuery = useQuery( orpc.drinkkaart.getMyDrinkkaart.queryOptions(), ); const registrationQuery = useQuery(orpc.getMyRegistration.queryOptions()); // Handle topup=success redirect (from Lemon Squeezy returning to /account) useEffect(() => { if (search.topup === "success") { toast.success("Oplading geslaagd! Je saldo is bijgewerkt."); queryClient.invalidateQueries({ queryKey: orpc.drinkkaart.getMyDrinkkaart.key(), }); const url = new URL(window.location.href); url.searchParams.delete("topup"); window.history.replaceState({}, "", url.toString()); } }, [search.topup, queryClient]); // Silent background call to claim any pending registration fee credit. // This catches cases where: webhook didn't fire/failed, or user signed up after paying. // No UI feedback needed — if there's nothing to claim, it does nothing. useEffect(() => { client.claimRegistrationCredit().catch((err) => { console.error("claimRegistrationCredit failed:", err); }); }, []); // Welcome toast after fresh signup useEffect(() => { if (search.welkom === "1") { toast.success("Welkom! Je account is aangemaakt."); const url = new URL(window.location.href); url.searchParams.delete("welkom"); window.history.replaceState({}, "", url.toString()); } }, [search.welkom]); const user = sessionQuery.data?.data?.user as | { name?: string; email?: string } | undefined; const registration = registrationQuery.data; const drinkkaart = drinkkaartQuery.data; const isLoading = sessionQuery.isLoading || drinkkaartQuery.isLoading || registrationQuery.isLoading; if (isLoading) { return (
); } return (
{/* Page header */}

Mijn Account

{user?.name && ( {user.name} )} {user?.email}

{/* ── Left column: Registration ── */}

Mijn Inschrijving

{registration ? (
{/* Type badge */}
{registration.registrationType === "performer" ? ( Artiest ) : ( Bezoeker )}
{/* Name */}

{registration.firstName} {registration.lastName}

{/* Art form (performer only) */} {registration.registrationType === "performer" && registration.artForm && (

Kunstvorm:{" "} {registration.artForm}

)} {/* Guests (watcher only) */} {registration.registrationType === "watcher" && registration.guests.length > 0 && (

{registration.guests.length + 1} personen (jij +{" "} {registration.guests.length} gast {registration.guests.length > 1 ? "en" : ""})

)} {/* Drink card value */} {registration.registrationType === "watcher" && (registration.drinkCardValue ?? 0) > 0 && (

Drinkkaart:{" "} €{registration.drinkCardValue}

)} {/* Gift */} {(registration.giftAmount ?? 0) > 0 && (

Gift:{" "} €{(registration.giftAmount ?? 0) / 100}

)} {/* Date */}

Ingeschreven op{" "} {new Date(registration.createdAt).toLocaleDateString( "nl-BE", { day: "numeric", month: "long", year: "numeric", }, )}

{/* Action */} {registration.managementToken && (
Beheer inschrijving
)}
) : (

We vonden geen actieve inschrijving voor dit e-mailadres.

Inschrijven voor het evenement
)}
{/* ── Right column: Drinkkaart ── */}

Mijn Drinkkaart

{/* Balance card */}

Huidig saldo

{drinkkaart ? formatCents(drinkkaart.balance) : "—"}

{/* QR code */} {showQr && (
)} {/* Top-up history */}

Opladingen

{drinkkaart ? ( [0]["topups"] } /> ) : (

Laden...

)}
{/* Transaction history */}

Transacties

{drinkkaart ? ( [0]["transactions"] } /> ) : (

Laden...

)}
{showTopUp && setShowTopUp(false)} />}
); }