diff --git a/apps/web/src/components/homepage/EventRegistrationForm.tsx b/apps/web/src/components/homepage/EventRegistrationForm.tsx
index 1b45dd3..3e7cd8b 100644
--- a/apps/web/src/components/homepage/EventRegistrationForm.tsx
+++ b/apps/web/src/components/homepage/EventRegistrationForm.tsx
@@ -36,6 +36,7 @@ export default function EventRegistrationForm() {
token={successState.token}
email={successState.email}
name={successState.name}
+ isLoggedIn={isLoggedIn}
onReset={() => {
setSuccessState(null);
setSelectedType(null);
diff --git a/apps/web/src/components/homepage/Hero.tsx b/apps/web/src/components/homepage/Hero.tsx
index edb38e8..cc9fc17 100644
--- a/apps/web/src/components/homepage/Hero.tsx
+++ b/apps/web/src/components/homepage/Hero.tsx
@@ -83,7 +83,7 @@ export default function Hero() {
{/* Bottom Right - Dark Teal with date - above mic */}
- VRIJDAG 18
+ VRIJDAG 24
april
@@ -153,7 +153,7 @@ export default function Hero() {
VRIJDAG
- 18 april
+ 24 april
diff --git a/apps/web/src/components/registration/GuestList.tsx b/apps/web/src/components/registration/GuestList.tsx
index 1dd0a32..c0ada89 100644
--- a/apps/web/src/components/registration/GuestList.tsx
+++ b/apps/web/src/components/registration/GuestList.tsx
@@ -204,6 +204,51 @@ export function GuestList({
)}
+
+
+ Geboortedatum *
+
+ onChange(idx, "birthdate", e.target.value)}
+ autoComplete="off"
+ className={inputCls(!!errors[idx]?.birthdate)}
+ />
+ {errors[idx]?.birthdate && (
+
+ {errors[idx].birthdate}
+
+ )}
+
+
+
+
+ Postcode *
+
+ onChange(idx, "postcode", e.target.value)}
+ placeholder="1234 AB"
+ autoComplete="off"
+ className={inputCls(!!errors[idx]?.postcode)}
+ />
+ {errors[idx]?.postcode && (
+
+ {errors[idx].postcode}
+
+ )}
+
+
E-mail
diff --git a/apps/web/src/components/registration/SuccessScreen.tsx b/apps/web/src/components/registration/SuccessScreen.tsx
index b3c955f..32a984a 100644
--- a/apps/web/src/components/registration/SuccessScreen.tsx
+++ b/apps/web/src/components/registration/SuccessScreen.tsx
@@ -5,9 +5,16 @@ interface Props {
email?: string;
name?: string;
onReset: () => void;
+ isLoggedIn?: boolean;
}
-export function SuccessScreen({ token, email, name, onReset }: Props) {
+export function SuccessScreen({
+ token,
+ email,
+ name,
+ onReset,
+ isLoggedIn,
+}: Props) {
const manageUrl =
typeof window !== "undefined"
? `${window.location.origin}/manage/${token}`
@@ -97,8 +104,8 @@ export function SuccessScreen({ token, email, name, onReset }: Props) {
- {/* Account creation prompt */}
- {!drinkkaartPromptDismissed && (
+ {/* Account creation prompt — hidden when already logged in */}
+ {!isLoggedIn && !drinkkaartPromptDismissed && (
Maak een gratis account aan
diff --git a/apps/web/src/components/registration/WatcherForm.tsx b/apps/web/src/components/registration/WatcherForm.tsx
index b8387ee..34fce49 100644
--- a/apps/web/src/components/registration/WatcherForm.tsx
+++ b/apps/web/src/components/registration/WatcherForm.tsx
@@ -389,7 +389,14 @@ export function WatcherForm({
if (guests.length >= 9) return;
setGuests((prev) => [
...prev,
- { firstName: "", lastName: "", email: "", phone: "" },
+ {
+ firstName: "",
+ lastName: "",
+ email: "",
+ phone: "",
+ birthdate: "",
+ postcode: "",
+ },
]);
setGuestErrors((prev) => [...prev, {}]);
}
@@ -418,6 +425,8 @@ export function WatcherForm({
lastName: g.lastName.trim(),
email: g.email.trim() || undefined,
phone: g.phone.trim() || undefined,
+ birthdate: g.birthdate.trim(),
+ postcode: g.postcode.trim(),
})),
extraQuestions: data.extraQuestions.trim() || undefined,
giftAmount,
diff --git a/apps/web/src/lib/registration.ts b/apps/web/src/lib/registration.ts
index f90fefb..5ad1c7e 100644
--- a/apps/web/src/lib/registration.ts
+++ b/apps/web/src/lib/registration.ts
@@ -28,6 +28,8 @@ export interface GuestEntry {
lastName: string;
email: string;
phone: string;
+ birthdate: string;
+ postcode: string;
}
export interface GuestErrors {
@@ -35,6 +37,8 @@ export interface GuestErrors {
lastName?: string;
email?: string;
phone?: string;
+ birthdate?: string;
+ postcode?: string;
}
/**
@@ -51,6 +55,8 @@ export function parseGuests(raw: string | null | undefined): GuestEntry[] {
lastName: g.lastName ?? "",
email: g.email ?? "",
phone: g.phone ?? "",
+ birthdate: g.birthdate ?? "",
+ postcode: g.postcode ?? "",
}));
} catch {
return [];
@@ -102,6 +108,8 @@ export function validateGuests(guests: GuestEntry[]): {
g.phone.trim() && !/^[\d\s\-+()]{10,}$/.test(g.phone.replace(/\s/g, ""))
? "Voer een geldig telefoonnummer in"
: undefined,
+ birthdate: !g.birthdate.trim() ? "Geboortedatum is verplicht" : undefined,
+ postcode: !g.postcode.trim() ? "Postcode is verplicht" : undefined,
}));
const valid = !errors.some((e) => Object.values(e).some(Boolean));
return { errors, valid };
diff --git a/apps/web/src/routes/__root.tsx b/apps/web/src/routes/__root.tsx
index 24e6ad4..3911b75 100644
--- a/apps/web/src/routes/__root.tsx
+++ b/apps/web/src/routes/__root.tsx
@@ -17,7 +17,7 @@ import appCss from "../index.css?url";
const siteUrl = "https://kunstenkamp.be";
const siteTitle = "Kunstenkamp Open Mic Night - Ongedesemd Woord";
const siteDescription =
- "Doe mee met de Open Mic Night op 18 april! Een avond vol muziek, theater, dans, woordkunst en meer. Iedereen is welkom - van beginner tot professional.";
+ "Doe mee met de Open Mic Night op 24 april! Een avond vol muziek, theater, dans, woordkunst en meer. Iedereen is welkom - van beginner tot professional.";
const eventImage = `${siteUrl}/assets/og-image.jpg`;
export interface RouterAppContext {
diff --git a/apps/web/src/routes/account.tsx b/apps/web/src/routes/account.tsx
index d6b45b7..4630efd 100644
--- a/apps/web/src/routes/account.tsx
+++ b/apps/web/src/routes/account.tsx
@@ -90,7 +90,7 @@ function AccountPage() {
orpc.drinkkaart.getMyDrinkkaart.queryOptions(),
);
- const registrationQuery = useQuery(orpc.getMyRegistration.queryOptions());
+ const registrationQuery = useQuery(orpc.getMyRegistrations.queryOptions());
// Handle topup=success redirect (from Lemon Squeezy returning to /account)
useEffect(() => {
@@ -128,7 +128,7 @@ function AccountPage() {
| { name?: string; email?: string }
| undefined;
- const registration = registrationQuery.data;
+ const registrations = registrationQuery.data ?? [];
const drinkkaart = drinkkaartQuery.data;
const isLoading =
@@ -170,112 +170,122 @@ function AccountPage() {
Mijn Inschrijving
- {registration ? (
-
- {/* Type badge */}
-
-
- {registration.registrationType === "performer" ? (
-
-
- Artiest
-
- ) : (
-
-
- Bezoeker
-
+ {registrations.length > 0 ? (
+
+ {registrations.map((registration) => (
+
+ {/* Type badge */}
+
+
+ {registration.registrationType === "performer" ? (
+
+
+ Artiest
+
+ ) : (
+
+
+ Bezoeker
+
+ )}
+
+ {(registration.registrationType !== "performer" ||
+ (registration.giftAmount ?? 0) > 0) && (
+
+ )}
+
+
+ {/* 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
+
+
+
+
+
)}
-
-
-
- {/* 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
-
-
-
-
-
- )}
+ ))}
) : (
diff --git a/apps/web/src/routes/admin/index.tsx b/apps/web/src/routes/admin/index.tsx
index bccca42..15756d6 100644
--- a/apps/web/src/routes/admin/index.tsx
+++ b/apps/web/src/routes/admin/index.tsx
@@ -13,7 +13,7 @@ import {
Users,
X,
} from "lucide-react";
-import { useMemo, useState } from "react";
+import { Fragment, useMemo, useState } from "react";
import { toast } from "sonner";
import { Button } from "@/components/ui/button";
import {
@@ -44,6 +44,19 @@ function AdminPage() {
const pageSize = 20;
const [copiedId, setCopiedId] = useState
(null);
+ const [expandedGuests, setExpandedGuests] = useState>(new Set());
+
+ const toggleGuests = (id: string) => {
+ setExpandedGuests((prev) => {
+ const next = new Set(prev);
+ if (next.has(id)) {
+ next.delete(id);
+ } else {
+ next.add(id);
+ }
+ return next;
+ });
+ };
// Get current session to check user role
const sessionQuery = useQuery({
@@ -278,6 +291,25 @@ function AdminPage() {
return `€${euros.toFixed(euros % 1 === 0 ? 0 : 2)}`;
};
+ const parseGuestsJson = (
+ raw: string | null | undefined,
+ ): Array<{
+ firstName: string;
+ lastName: string;
+ email?: string;
+ phone?: string;
+ birthdate?: string;
+ postcode?: string;
+ }> => {
+ if (!raw) return [];
+ try {
+ const parsed = JSON.parse(raw as string);
+ return Array.isArray(parsed) ? parsed : [];
+ } catch {
+ return [];
+ }
+ };
+
// Check if user is admin
const user = sessionQuery.data?.data?.user as
| { role?: string; name?: string }
@@ -486,7 +518,6 @@ function AdminPage() {
)}
-
{/* Stats Cards */}
@@ -592,7 +623,6 @@ function AdminPage() {
-
{/* Filters */}
@@ -700,7 +730,6 @@ function AdminPage() {
-
{/* Export Button */}
@@ -715,7 +744,6 @@ function AdminPage() {
{exportMutation.isPending ? "Exporteren..." : "Exporteer CSV"}
-
{/* Registrations Table / Cards */}
@@ -803,15 +831,9 @@ function AdminPage() {
sortedRegistrations.map((reg) => {
const isPerformer = reg.registrationType === "performer";
- const guestCount = (() => {
- if (!reg.guests) return 0;
- try {
- const g = JSON.parse(reg.guests as string);
- return Array.isArray(g) ? g.length : 0;
- } catch {
- return 0;
- }
- })();
+ const guests = parseGuestsJson(reg.guests);
+ const guestCount = guests.length;
+ const isGuestsExpanded = expandedGuests.has(reg.id);
const detailLabel = isPerformer
? reg.artForm || "-"
@@ -833,121 +855,190 @@ function AdminPage() {
})();
return (
-
-
- {reg.firstName} {reg.lastName}
-
-
- {reg.email}
-
-
- {reg.phone || "-"}
-
-
-
- {isPerformer ? "Artiest" : "Bezoeker"}
-
-
-
- {detailLabel}
-
-
- {guestCount > 0
- ? `${guestCount} gast${guestCount === 1 ? "" : "en"}`
- : "-"}
-
-
- {formatCents(reg.giftAmount)}
-
-
- {isPerformer ? (
- -
- ) : reg.paymentStatus === "paid" ? (
-
-
- Betaald
-
- ) : reg.paymentStatus ===
- "extra_payment_pending" ? (
-
-
- Extra (€
- {((reg.paymentAmount ?? 0) / 100).toFixed(0)})
-
- ) : (
-
- Open
-
- )}
-
-
- {dateLabel}
-
-
- {reg.postcode || "-"}
-
-
- {reg.birthdate || "-"}
-
-
- {isPerformer ? reg.experience || "-" : "-"}
-
-
- {isPerformer ? (
- reg.isOver16 ? (
- Ja
- ) : (
- Nee
- )
- ) : (
- "-"
- )}
-
-
-
- {reg.extraQuestions || "-"}
-
-
-
- {reg.managementToken ? (
-
- handleCopyManageUrl(
- reg.managementToken as string,
- reg.id,
- )
- }
- className="inline-flex items-center justify-center rounded p-1 text-white/40 transition-colors hover:bg-white/10 hover:text-white"
+
+
+
+ {reg.firstName} {reg.lastName}
+
+
+ {reg.email}
+
+
+ {reg.phone || "-"}
+
+
+
- {copiedId === reg.id ? (
-
+ {isPerformer ? "Artiest" : "Bezoeker"}
+
+
+
+ {detailLabel}
+
+
+ {guestCount > 0 ? (
+ toggleGuests(reg.id)}
+ className="inline-flex items-center gap-1 rounded px-1.5 py-0.5 text-sm text-white/70 transition-colors hover:bg-white/10 hover:text-white"
+ >
+ {guestCount} gast
+ {guestCount === 1 ? "" : "en"}
+ {isGuestsExpanded ? (
+
+ ) : (
+
+ )}
+
+ ) : (
+ "-"
+ )}
+
+
+ {formatCents(reg.giftAmount)}
+
+
+ {isPerformer ? (
+ -
+ ) : reg.paymentStatus === "paid" ? (
+
+
+ Betaald
+
+ ) : reg.paymentStatus ===
+ "extra_payment_pending" ? (
+
+
+ Extra (€
+ {((reg.paymentAmount ?? 0) / 100).toFixed(0)})
+
+ ) : (
+
+ Open
+
+ )}
+
+
+ {dateLabel}
+
+
+ {reg.postcode || "-"}
+
+
+ {reg.birthdate || "-"}
+
+
+ {isPerformer ? reg.experience || "-" : "-"}
+
+
+ {isPerformer ? (
+ reg.isOver16 ? (
+ Ja
) : (
-
- )}
-
- ) : (
- —
- )}
-
-
+ Nee
+ )
+ ) : (
+ "-"
+ )}
+
+
+
+ {reg.extraQuestions || "-"}
+
+
+
+ {reg.managementToken ? (
+
+ handleCopyManageUrl(
+ reg.managementToken as string,
+ reg.id,
+ )
+ }
+ className="inline-flex items-center justify-center rounded p-1 text-white/40 transition-colors hover:bg-white/10 hover:text-white"
+ >
+ {copiedId === reg.id ? (
+
+ ) : (
+
+ )}
+
+ ) : (
+ —
+ )}
+
+
+ {isGuestsExpanded &&
+ guests.map((guest, gi) => (
+
+
+ ↳ {guest.firstName} {guest.lastName}
+
+
+ {guest.email || "-"}
+
+
+ {guest.phone || "-"}
+
+
+
+ Gast
+
+
+
+ -
+
+
+ -
+
+
+ -
+
+
+ -
+
+
+ -
+
+
+ {guest.postcode || "-"}
+
+
+ {guest.birthdate || "-"}
+
+
+ -
+
+
+ -
+
+
+ -
+
+
+ -
+
+
+ ))}
+
);
})
)}
-
- {/* Mobile Cards */}
{registrationsQuery.isLoading ? (
@@ -962,15 +1053,9 @@ function AdminPage() {
{sortedRegistrations.map((reg) => {
const isPerformer = reg.registrationType === "performer";
- const guestCount = (() => {
- if (!reg.guests) return 0;
- try {
- const g = JSON.parse(reg.guests as string);
- return Array.isArray(g) ? g.length : 0;
- } catch {
- return 0;
- }
- })();
+ const guests = parseGuestsJson(reg.guests);
+ const guestCount = guests.length;
+ const isGuestsExpanded = expandedGuests.has(reg.id);
const detailLabel = isPerformer
? reg.artForm || "-"
@@ -992,126 +1077,171 @@ function AdminPage() {
})();
return (
-
-
-
-
-
- {reg.firstName} {reg.lastName}
-
+
+
+
+
+
+
+ {reg.firstName} {reg.lastName}
+
+
+
+ {reg.email}
+ {reg.phone && (
+
+ • {reg.phone}
+
+ )}
+
-
-
{reg.email}
- {reg.phone && (
-
• {reg.phone}
+
+
+ {isPerformer ? "Artiest" : "Bezoeker"}
+
+ {reg.managementToken && (
+
+ handleCopyManageUrl(
+ reg.managementToken as string,
+ reg.id,
+ )
+ }
+ className="shrink-0 rounded p-1.5 text-white/40 transition-colors hover:bg-white/10 hover:text-white"
+ >
+ {copiedId === reg.id ? (
+
+ ) : (
+
+ )}
+
)}
-
-
- {isPerformer ? "Artiest" : "Bezoeker"}
-
- {reg.managementToken && (
+
+
+
+ Details: {" "}
+ {detailLabel}
+
+ {guestCount > 0 && (
- handleCopyManageUrl(
- reg.managementToken as string,
- reg.id,
- )
- }
- className="shrink-0 rounded p-1.5 text-white/40 transition-colors hover:bg-white/10 hover:text-white"
+ onClick={() => toggleGuests(reg.id)}
+ className="inline-flex items-center gap-1 text-white/70 transition-colors hover:text-white"
>
- {copiedId === reg.id ? (
-
+ Gasten: {" "}
+ {guestCount}
+ {isGuestsExpanded ? (
+
) : (
-
+
)}
)}
+ {(reg.giftAmount ?? 0) > 0 && (
+
+ Gift: {" "}
+ {formatCents(reg.giftAmount)}
+
+ )}
+ {!isPerformer && (
+
+ Betaling: {" "}
+ {reg.paymentStatus === "paid" ? (
+
+
+ Betaald
+
+ ) : reg.paymentStatus ===
+ "extra_payment_pending" ? (
+
+
+ Extra (€
+ {((reg.paymentAmount ?? 0) / 100).toFixed(
+ 0,
+ )}
+ )
+
+ ) : (
+ Open
+ )}
+
+ )}
+ {reg.postcode && (
+
+ Postcode: {" "}
+ {reg.postcode}
+
+ )}
+ {reg.birthdate && (
+
+
+ Geboortedatum:
+ {" "}
+ {reg.birthdate}
+
+ )}
+ {isPerformer && reg.experience && (
+
+ Ervaring: {" "}
+ {reg.experience}
+
+ )}
+ {isPerformer && (
+
+ 16+: {" "}
+ {reg.isOver16 ? (
+ Ja
+ ) : (
+ Nee
+ )}
+
+ )}
+ {reg.extraQuestions && (
+
+
+ Opmerkingen:
+ {" "}
+ {reg.extraQuestions}
+
+ )}
+
{dateLabel}
-
-
-
-
Details: {" "}
- {detailLabel}
+ {isGuestsExpanded && guestCount > 0 && (
+
+
+ Gasten
+
+
+ {guests.map((guest, gi) => (
+
+
+ {guest.firstName} {guest.lastName}
+
+
+ {guest.email && {guest.email} }
+ {guest.phone && {guest.phone} }
+ {guest.birthdate && (
+ {guest.birthdate}
+ )}
+ {guest.postcode && (
+ {guest.postcode}
+ )}
+
+
+ ))}
+
- {guestCount > 0 && (
-
- Gasten: {" "}
- {guestCount}
-
- )}
- {(reg.giftAmount ?? 0) > 0 && (
-
- Gift: {" "}
- {formatCents(reg.giftAmount)}
-
- )}
- {!isPerformer && (
-
- Betaling: {" "}
- {reg.paymentStatus === "paid" ? (
-
-
- Betaald
-
- ) : reg.paymentStatus ===
- "extra_payment_pending" ? (
-
-
- Extra (€
- {((reg.paymentAmount ?? 0) / 100).toFixed(0)})
-
- ) : (
- Open
- )}
-
- )}
- {reg.postcode && (
-
- Postcode: {" "}
- {reg.postcode}
-
- )}
- {reg.birthdate && (
-
-
- Geboortedatum:
- {" "}
- {reg.birthdate}
-
- )}
- {isPerformer && reg.experience && (
-
- Ervaring: {" "}
- {reg.experience}
-
- )}
- {isPerformer && (
-
- 16+: {" "}
- {reg.isOver16 ? (
- Ja
- ) : (
- Nee
- )}
-
- )}
- {reg.extraQuestions && (
-
-
- Opmerkingen:
- {" "}
- {reg.extraQuestions}
-
- )}
-
{dateLabel}
-
+ )}
);
})}
@@ -1120,8 +1250,6 @@ function AdminPage() {
-
- {/* Pagination */}
{pagination && pagination.totalPages > 1 && (
Open Mic Night
- Vrijdag 18 april 2026
+ Vrijdag 24 april 2026
Aanvang: 19:00 uur
Locatie wordt later bekendgemaakt aan geregistreerde deelnemers.
diff --git a/apps/web/src/routes/manage.$token.tsx b/apps/web/src/routes/manage.$token.tsx
index c3e82f0..55f1e6b 100644
--- a/apps/web/src/routes/manage.$token.tsx
+++ b/apps/web/src/routes/manage.$token.tsx
@@ -198,6 +198,8 @@ function EditForm({ token, initialData, onCancel, onSaved }: EditFormProps) {
lastName: g.lastName.trim(),
email: g.email.trim() || undefined,
phone: g.phone.trim() || undefined,
+ birthdate: g.birthdate.trim(),
+ postcode: g.postcode.trim(),
})),
extraQuestions: formData.extraQuestions.trim() || undefined,
giftAmount,
@@ -435,7 +437,14 @@ function EditForm({ token, initialData, onCancel, onSaved }: EditFormProps) {
if (formGuests.length >= 9) return;
setFormGuests((prev) => [
...prev,
- { firstName: "", lastName: "", email: "", phone: "" },
+ {
+ firstName: "",
+ lastName: "",
+ email: "",
+ phone: "",
+ birthdate: "",
+ postcode: "",
+ },
]);
}}
onRemove={(idx) =>
@@ -611,7 +620,7 @@ function ManageRegistrationPage() {
Jouw inschrijving
- Open Mic Night — vrijdag 18 april 2026
+ Open Mic Night — vrijdag 24 april 2026
{/* Type badge */}
@@ -627,18 +636,19 @@ function ManageRegistrationPage() {
)}
- {/* Payment status - shown for everyone with pending/extra payment or gift */}
- {(data.paymentStatus !== "paid" || (data.giftAmount ?? 0) > 0) && (
-
- {data.paymentStatus === "paid" ? (
-
- ) : data.paymentStatus === "extra_payment_pending" ? (
-
- ) : (
-
- )}
-
- )}
+ {/* Payment status - not shown for performers without a gift */}
+ {(!isPerformer || (data.giftAmount ?? 0) > 0) &&
+ (data.paymentStatus !== "paid" || (data.giftAmount ?? 0) > 0) && (
+
+ {data.paymentStatus === "paid" ? (
+
+ ) : data.paymentStatus === "extra_payment_pending" ? (
+
+ ) : (
+
+ )}
+
+ )}
{/* Gift display */}
{(data.giftAmount ?? 0) > 0 && (
@@ -710,6 +720,16 @@ function ManageRegistrationPage() {
{g.firstName} {g.lastName}
+ {g.birthdate && (
+
+ Geboortedatum: {g.birthdate}
+
+ )}
+ {g.postcode && (
+
+ Postcode: {g.postcode}
+
+ )}
{g.email && (
{g.email}
)}
diff --git a/packages/api/src/email.ts b/packages/api/src/email.ts
index 997ec0c..55362d2 100644
--- a/packages/api/src/email.ts
+++ b/packages/api/src/email.ts
@@ -86,7 +86,7 @@ function registrationConfirmationHtml(params: {
Hoi ${params.firstName},
- We hebben je inschrijving voor Open Mic Night — vrijdag 18 april 2026 in goede orde ontvangen.
+ We hebben je inschrijving voor Open Mic Night — vrijdag 24 april 2026 in goede orde ontvangen.
diff --git a/packages/api/src/routers/index.ts b/packages/api/src/routers/index.ts
index 9b14ca9..de56b9b 100644
--- a/packages/api/src/routers/index.ts
+++ b/packages/api/src/routers/index.ts
@@ -36,6 +36,8 @@ function parseGuestsJson(raw: string | null): Array<{
lastName: string;
email?: string;
phone?: string;
+ birthdate?: string;
+ postcode?: string;
}> {
if (!raw) return [];
try {
@@ -218,6 +220,8 @@ const guestSchema = z.object({
lastName: z.string().min(1),
email: z.string().email().optional().or(z.literal("")),
phone: z.string().optional(),
+ birthdate: z.string().min(1),
+ postcode: z.string().min(1),
});
const coreRegistrationFields = {
@@ -542,7 +546,7 @@ export const appRouter = {
const guestSummary = guests
.map(
(g) =>
- `${g.firstName} ${g.lastName}${g.email ? ` <${g.email}>` : ""}${g.phone ? ` (${g.phone})` : ""}`,
+ `${g.firstName} ${g.lastName}${g.birthdate ? ` (${g.birthdate})` : ""}${g.postcode ? ` [${g.postcode}]` : ""}${g.email ? ` <${g.email}>` : ""}${g.phone ? ` (${g.phone})` : ""}`,
)
.join(" | ");
return [
@@ -593,7 +597,7 @@ export const appRouter = {
return result;
}),
- getMyRegistration: protectedProcedure.handler(async ({ context }) => {
+ getMyRegistrations: protectedProcedure.handler(async ({ context }) => {
const email = context.session.user.email;
const rows = await db
@@ -602,16 +606,12 @@ export const appRouter = {
.where(
and(eq(registration.email, email), isNull(registration.cancelledAt)),
)
- .orderBy(desc(registration.createdAt))
- .limit(1);
+ .orderBy(desc(registration.createdAt));
- const row = rows[0];
- if (!row) return null;
-
- return {
+ return rows.map((row) => ({
...row,
guests: parseGuestsJson(row.guests),
- };
+ }));
}),
// ---------------------------------------------------------------------------