feat(admin): improve export to put guests in their own row

This commit is contained in:
2026-03-19 10:31:12 +01:00
parent ee0e9e68a9
commit 845624dfd3

View File

@@ -663,76 +663,24 @@ export const appRouter = {
const escapeCell = (val: string) => `"${val.replace(/"/g, '""')}"`; const escapeCell = (val: string) => `"${val.replace(/"/g, '""')}"`;
// Main registration headers // Each person (registrant + guests) gets their own row.
// Guest rows reference the registrant via "Registration ID".
const headers = [ const headers = [
"ID", "Row Type", // "registrant" | "guest"
"Registration ID", // UUID of the parent registration (same for registrant + its guests)
"First Name", "First Name",
"Last Name", "Last Name",
"Email", "Email",
"Phone", "Phone",
"Birthdate", "Birthdate",
"Postcode", "Postcode",
// Registrant-only fields (blank for guest rows)
"Type", "Type",
"Art Form", "Art Form",
"Experience", "Experience",
"Is Over 16", "Is Over 16",
"Drink Card Value (EUR)", "Drink Card Value (EUR)",
"Gift Amount (cents)", "Gift Amount (cents)",
"Guest Count",
"Guest 1 First Name",
"Guest 1 Last Name",
"Guest 1 Email",
"Guest 1 Phone",
"Guest 1 Birthdate",
"Guest 1 Postcode",
"Guest 2 First Name",
"Guest 2 Last Name",
"Guest 2 Email",
"Guest 2 Phone",
"Guest 2 Birthdate",
"Guest 2 Postcode",
"Guest 3 First Name",
"Guest 3 Last Name",
"Guest 3 Email",
"Guest 3 Phone",
"Guest 3 Birthdate",
"Guest 3 Postcode",
"Guest 4 First Name",
"Guest 4 Last Name",
"Guest 4 Email",
"Guest 4 Phone",
"Guest 4 Birthdate",
"Guest 4 Postcode",
"Guest 5 First Name",
"Guest 5 Last Name",
"Guest 5 Email",
"Guest 5 Phone",
"Guest 5 Birthdate",
"Guest 5 Postcode",
"Guest 6 First Name",
"Guest 6 Last Name",
"Guest 6 Email",
"Guest 6 Phone",
"Guest 6 Birthdate",
"Guest 6 Postcode",
"Guest 7 First Name",
"Guest 7 Last Name",
"Guest 7 Email",
"Guest 7 Phone",
"Guest 7 Birthdate",
"Guest 7 Postcode",
"Guest 8 First Name",
"Guest 8 Last Name",
"Guest 8 Email",
"Guest 8 Phone",
"Guest 8 Birthdate",
"Guest 8 Postcode",
"Guest 9 First Name",
"Guest 9 Last Name",
"Guest 9 Email",
"Guest 9 Phone",
"Guest 9 Birthdate",
"Guest 9 Postcode",
"Payment Status", "Payment Status",
"Paid At", "Paid At",
"Extra Questions", "Extra Questions",
@@ -740,24 +688,28 @@ export const appRouter = {
"Created At", "Created At",
]; ];
const MAX_GUESTS = 9; const rows: string[][] = [];
const rows = data.map((r) => { for (const r of data) {
const guests = parseGuestsJson(r.guests); const guests = parseGuestsJson(r.guests) as Array<{
firstName: string;
lastName: string;
email?: string;
phone?: string;
birthdate?: string;
postcode?: string;
}>;
// Build guest columns (up to 9 guests, 6 fields each) const paymentStatus =
const guestCols: string[] = []; r.paymentStatus === "paid"
for (let i = 0; i < MAX_GUESTS; i++) { ? "Paid"
const g = guests[i]; : r.paymentStatus === "extra_payment_pending"
guestCols.push(g?.firstName ?? ""); ? "Extra Payment Pending"
guestCols.push(g?.lastName ?? ""); : "Pending";
guestCols.push(g?.email ?? "");
guestCols.push(g?.phone ?? "");
guestCols.push((g as { birthdate?: string })?.birthdate ?? "");
guestCols.push((g as { postcode?: string })?.postcode ?? "");
}
return [ // Registrant row
rows.push([
"registrant",
r.id, r.id,
r.firstName, r.firstName,
r.lastName, r.lastName,
@@ -771,19 +723,39 @@ export const appRouter = {
r.isOver16 ? "Yes" : "No", r.isOver16 ? "Yes" : "No",
String(r.drinkCardValue ?? 0), String(r.drinkCardValue ?? 0),
String(r.giftAmount ?? 0), String(r.giftAmount ?? 0),
String(guests.length), paymentStatus,
...guestCols,
r.paymentStatus === "paid"
? "Paid"
: r.paymentStatus === "extra_payment_pending"
? "Extra Payment Pending"
: "Pending",
r.paidAt ? r.paidAt.toISOString() : "", r.paidAt ? r.paidAt.toISOString() : "",
r.extraQuestions || "", r.extraQuestions || "",
r.cancelledAt ? r.cancelledAt.toISOString() : "", r.cancelledAt ? r.cancelledAt.toISOString() : "",
r.createdAt.toISOString(), r.createdAt.toISOString(),
]; ]);
});
// One row per guest — link back to parent registration via Registration ID
for (const g of guests) {
rows.push([
"guest",
r.id,
g.firstName,
g.lastName,
g.email || "",
g.phone || "",
g.birthdate || "",
g.postcode || "",
// Registrant-only fields left blank
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
]);
}
}
const csvContent = [ const csvContent = [
headers.map(escapeCell).join(","), headers.map(escapeCell).join(","),