import type { LoaderFunctionArgs } from "react-router"; import prisma from "../db.server"; import { toCsv } from "../engine/runsheet"; import { localParts } from "../engine/time"; import { adminContext } from "../lib/admin.server"; import { logAccess } from "../lib/audit.server"; import { bookingWhere } from "../lib/bookings-query.server"; /** Excel-friendly CSV (UTF-8 BOM) of the bookings matching the list filters. */ export const loader = async ({ request }: LoaderFunctionArgs) => { const { cfg, actor } = await adminContext(request); const sp = new URL(request.url).searchParams; logAccess(cfg.shop.id, actor, "bookings.export", sp.toString() || null); const today = localParts(Date.now(), cfg.shop.timezone).date; const rows = await prisma.booking.findMany({ where: bookingWhere(cfg.shop.id, sp, today), orderBy: [{ date: "asc" }, { slotStart: "asc" }], take: 20000, }); const loc = Object.fromEntries(cfg.locations.map((l) => [l.id, l.name])); const csv = toCsv( rows.map((b) => { const a = (b.address ?? {}) as { line1?: string; city?: string; postal?: string }; return { order: b.orderName ?? "", status: b.status, review_note: b.reviewReason ?? "", method: b.method, location: b.locationId ? loc[b.locationId] ?? b.locationId : "", date: b.date ?? "", slot_start: b.slotStart ?? "", slot_end: b.slotEnd ?? "", timezone: b.timezone, start_utc: b.startUtc?.toISOString() ?? "", end_utc: b.endUtc?.toISOString() ?? "", customer: b.customerName ?? "", email: b.customerEmail ?? "", phone: b.customerPhone ?? "", address: [a.line1, a.city, a.postal].filter(Boolean).join(", "), items: ((b.items ?? []) as { title: string; quantity: number }[]).map((i) => `${i.quantity}x ${i.title}`).join("; "), fee: (b.fee / 100).toFixed(2), rescheduled: b.rescheduleCount, }; }), ["order", "status", "review_note", "method", "location", "date", "slot_start", "slot_end", "timezone", "start_utc", "end_utc", "customer", "email", "phone", "address", "items", "fee", "rescheduled"], ); return new Response(csv, { headers: { "Content-Type": "text/csv; charset=utf-8", "Content-Disposition": `attachment; filename="datewise-bookings-${today}.csv"`, }, }); };