import { notFound, redirect } from "next/navigation"; import { getTranslations } from "next-intl/server"; import { getSessionUser } from "@/lib/session"; import { getInvoiceDraftById, getOrgBilling } from "@/lib/db"; import { BackLink } from "@/components/ui/back-link"; import { CustomInvoiceEditor } from "@/components/admin/billing/custom-invoice-editor"; /** * /admin/billing/invoice-drafts/[id] — full editor for an * in-progress custom invoice. * * Phase 8. Server-loads the draft + the org's billing snapshot * (used to display the bill-to block preview), then hands off to * the client editor for the interactive line-management UI. * * The snapshot is loaded read-only for display. The actual VAT * computation happens server-side at issue time via * computeCustomInvoiceTotals, which re-reads the same snapshot. * That two-time read is intentional: the editor's preview math * is a hint, the issue-time read is authoritative — if the * customer updates their billing address between Draft and Issue, * the invoice reflects the new address. */ export default async function InvoiceDraftEditorPage({ params, }: { params: Promise<{ id: string }>; }) { const user = await getSessionUser(); if (!user) redirect("/login"); if (!user.isPlatform) redirect("/dashboard"); const t = await getTranslations("adminBilling"); const { id } = await params; const draft = await getInvoiceDraftById(id); if (!draft) notFound(); const orgBilling = await getOrgBilling(draft.zitadelOrgId).catch(() => null); return (

{t("editorPageTitle")}

{orgBilling?.companyName ?? draft.zitadelOrgId}

); }