This commit is contained in:
46
src/app/[locale]/settings/billing/page.tsx
Normal file
46
src/app/[locale]/settings/billing/page.tsx
Normal file
@@ -0,0 +1,46 @@
|
||||
import { getTranslations } from "next-intl/server";
|
||||
import { redirect, notFound } from "next/navigation";
|
||||
import { getSessionUser, canMutate } from "@/lib/session";
|
||||
import { getOrgBilling } from "@/lib/db";
|
||||
import { BillingSettingsForm } from "@/components/settings/billing-settings-form";
|
||||
|
||||
/**
|
||||
* /settings/billing — view and edit org-scoped billing (Bug 34/35).
|
||||
*
|
||||
* Server-side fetches the existing record (if any) and passes it to
|
||||
* the client form. The form posts to PUT /api/billing on submit.
|
||||
*
|
||||
* Access: same gate as the API — owners and platform admins. `user`
|
||||
* role redirects to /settings (which also wouldn't list billing for
|
||||
* them). 403 here would be friendlier than redirect, but the most
|
||||
* likely cause of a `user` landing on this URL is sharing a bookmark
|
||||
* with their owner — silent redirect is gentle.
|
||||
*/
|
||||
export default async function BillingSettingsPage() {
|
||||
const user = await getSessionUser();
|
||||
if (!user) redirect("/login");
|
||||
if (!canMutate(user)) {
|
||||
redirect("/settings");
|
||||
}
|
||||
const t = await getTranslations("settingsBilling");
|
||||
|
||||
const billing = await getOrgBilling(user.orgId);
|
||||
|
||||
return (
|
||||
<main className="max-w-3xl mx-auto px-6 py-8">
|
||||
<div className="mb-8 animate-in">
|
||||
<h1 className="font-display text-2xl font-semibold accent-rule">
|
||||
{t("title")}
|
||||
</h1>
|
||||
<p className="text-sm text-text-secondary mt-3">{t("subtitle")}</p>
|
||||
</div>
|
||||
|
||||
<BillingSettingsForm
|
||||
initial={billing}
|
||||
isPersonal={user.isPersonal}
|
||||
orgName={user.orgName}
|
||||
userName={user.name}
|
||||
/>
|
||||
</main>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user