import { useTranslations, useFormatter } from "next-intl"; import { Card } from "@/components/ui/card"; import type { Invoice, InvoiceLine } from "@/types"; import { PayInvoiceButton } from "./pay-invoice-button"; import { PaymentStatusBanner } from "./payment-status-banner"; interface Props { invoice: Invoice; lines: InvoiceLine[]; } const statusColors: Record = { open: "text-text-secondary bg-surface-3", paid: "text-success bg-success/10", overdue: "text-error bg-error/10", void: "text-text-muted bg-surface-3", }; /** * Read-only invoice detail. Flat list of lines — no per-tenant * grouping (one invoice per customer; the tenant context is * already embedded in each line description). * * The download link points at /api/billing/invoices/[n]/pdf * which serves the stored PDF blob inline. Customers using a * link from their email will hit the same route via this page. */ export function CustomerInvoiceDetail({ invoice, lines }: Props) { const t = useTranslations("customerBilling"); const fmt = useFormatter(); return (

{invoice.invoiceNumber}

{t(`status.${invoice.status}` as any)}

{fmt.dateTime(new Date(invoice.periodStart), { dateStyle: "long" })} {fmt.dateTime(new Date(invoice.periodEnd), { dateStyle: "long" })}

{/* Phase 4: Pay-with-card available for open + overdue. Paid/void/draft/uncollectible hide the button — the API also enforces this, so client-side hiding is just for the visible affordance. */} {(invoice.status === "open" || invoice.status === "overdue") && ( )} {t("downloadPdf")}
{t("billedToLabel")} {invoice.billingSnapshot.companyName}
{t("issuedAtLabel")} {fmt.dateTime(new Date(invoice.issuedAt), { dateStyle: "medium" })}
{t("dueAtLabel")} {fmt.dateTime(new Date(invoice.dueAt), { dateStyle: "medium" })}
{invoice.status === "paid" && invoice.paidAt && (
{t("paidAtLabel")} {fmt.dateTime(new Date(invoice.paidAt), { dateStyle: "medium" })}
)}
{lines.map((ln) => ( ))}
{t("descriptionCol")} {t("qtyCol")} {t("unitCol")} {t("amountCol")}
{ln.description} {ln.quantity} {ln.unitLabel ? ` ${ln.unitLabel}` : ""} {ln.unitPriceChf.toFixed(2)} {ln.amountChf.toFixed(2)}
{t("subtotalLabel")} {invoice.subtotalChf.toFixed(2)}
{t("vatLabel", { rate: invoice.vatRate.toFixed(2) })} {invoice.vatAmountChf.toFixed(2)}
{t("totalLabel")} CHF {invoice.totalChf.toFixed(2)}
); }