import { canSee } from "@/lib/session";
import { getPortalSession } from "@/lib/get-session";
import { loadTenantForShell } from "@/lib/portal-data";
import { Panel } from "@/components/portal/Panel";
import { NotAllowed } from "@/components/portal/NotAllowed";
import { CreditCard, AlertTriangle } from "lucide-react";
const EUR = new Intl.NumberFormat("de-DE", { style: "currency", currency: "EUR" });
export default async function BillingPage({
params,
}: {
params: Promise<{ slug: string }>;
}) {
const { slug } = await params;
const session = await getPortalSession();
if (!canSee(session, "billing")) return ;
const t = await loadTenantForShell(slug);
if (!t) return null;
const monthlyVAT = Math.round(t.monthly * 0.19);
const monthlyGross = t.monthly + monthlyVAT;
const seatsPct = t.seats.total > 0 ? (t.seats.used / t.seats.total) * 100 : 0;
const evidenceStorageUsed = t.metrics.evidence;
const evidenceStorageMax = 1000;
const evidencePct = (evidenceStorageUsed / evidenceStorageMax) * 100;
const frozen = t.status === "frozen";
return (
Billing
Plan, usage, payment method and invoice history
PLAN
{t.plan}
{t.planCode}
MONTHLY
{EUR.format(t.monthly)}
+ 19% VAT = {EUR.format(monthlyGross)}
SEATS
{t.seats.used} / {t.seats.total}
EVIDENCE STORAGE
{evidenceStorageUsed} / {evidenceStorageMax} GB
90 ? "warn" : ""}`}>
{frozen ? (
Payment failed
) : (
SEPA Direct Debit
DE89 •••• •••• 7421 · {t.contact}
)}
- Renews on
-
{t.renewal}
- Billing email
- {t.contactEmail}
- Currency
- EUR
- VAT applied
- 19% (DE)
{t.invoices.length} entries} pad={false}>
| Invoice |
Period |
Issued |
Seats |
Net |
VAT |
Total |
Status |
|
{t.invoices.map((inv) => (
| {inv.id} |
{inv.period} |
{inv.issued} |
{inv.seats} |
{EUR.format(inv.net)} |
{EUR.format(inv.vat)} |
{EUR.format(inv.total)} |
{inv.status === "due" ? "Due" : "Paid"}
|
|
))}
);
}