import Link from "next/link"; import { redirect } from "next/navigation"; import { getTranslations } from "next-intl/server"; import { getSessionUser } from "@/lib/session"; import { getOrgOpenBalances, syncOverdueInvoices } from "@/lib/db"; import { Card } from "@/components/ui/card"; /** * /admin/billing — landing page with sub-section links and a * quick overview of orgs in arrears. * * Sub-pages: * - /admin/billing/pricing — platform + skill prices * - /admin/billing/generate — manual invoice generator (testing) * - /admin/billing/invoices — invoice list/detail * * The Phase 2 customer-side /billing landing page is added in * Phase 3. */ export default async function AdminBillingPage() { const user = await getSessionUser(); if (!user) redirect("/login"); if (!user.isPlatform) redirect("/dashboard"); const t = await getTranslations("adminBilling"); // Sweep open invoices past due → 'overdue' so the counters below // reflect reality without needing a cron. await syncOverdueInvoices().catch((e) => console.error("syncOverdueInvoices failed:", e) ); const balances = await getOrgOpenBalances().catch(() => []); const totalOpen = balances.reduce((acc, b) => acc + b.totalOpenChf, 0); const totalOverdue = balances.reduce((acc, b) => acc + b.overdueCount, 0); return (

{t("title")}

{t("subtitle")}

{/* Stats strip */}
{t("totalOpenBalance")}
CHF {totalOpen.toFixed(2)}
{t("orgsWithBalance")}
{balances.length}
{t("overdueInvoices")}
{totalOverdue > 0 ? ( {totalOverdue} ) : ( totalOverdue )}
{/* Sub-tool cards */}
{t("pricingTitle")}
{t("pricingDesc")}
{t("generateTitle")}
{t("generateDesc")}
{t("invoicesTitle")}
{t("invoicesDesc")}
{t("orgsTitle")}
{t("orgsDesc")}
{/* Orgs with open balance */} {balances.length > 0 && (

{t("balancesTitle")}

{balances.map((b) => ( ))}
{t("orgIdCol")} {t("openCountCol")} {t("overdueCountCol")} {t("totalOpenCol")}
{b.zitadelOrgId} {b.openCount} {b.overdueCount > 0 ? ( {b.overdueCount} ) : ( 0 )} CHF {b.totalOpenChf.toFixed(2)}
)}
); }