36 lines
1.2 KiB
TypeScript
36 lines
1.2 KiB
TypeScript
import { notFound, redirect } from "next/navigation";
|
|
import { getTranslations } from "next-intl/server";
|
|
import { getSessionUser } from "@/lib/session";
|
|
import { getInvoiceDetail } from "@/lib/db";
|
|
import { BackLink } from "@/components/ui/back-link";
|
|
import { InvoiceDetailView } from "@/components/admin/billing/invoice-detail-view";
|
|
|
|
/**
|
|
* /admin/billing/invoices/[id] — full detail of one invoice.
|
|
*
|
|
* Server-renders the static body (header, lines, totals, billing
|
|
* snapshot); the action bar (mark-paid, delete, PDF download) is
|
|
* a client component for the interactive bits.
|
|
*/
|
|
export default async function AdminInvoiceDetailPage({
|
|
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 detail = await getInvoiceDetail(id);
|
|
if (!detail) notFound();
|
|
|
|
return (
|
|
<main className="max-w-4xl mx-auto px-6 py-8">
|
|
<BackLink href="/admin/billing/invoices" label={t("backToInvoices")} />
|
|
<InvoiceDetailView detail={detail} />
|
|
</main>
|
|
);
|
|
}
|