import { getTranslations } from "next-intl/server"; import { redirect } from "next/navigation"; import Link from "next/link"; import { getSessionUser, canMutate } from "@/lib/session"; import { Card } from "@/components/ui/card"; /** * /settings — landing page for user/org-level configuration (Bug 35 * intentionally landed billing here rather than at /billing because we * expect more settings categories: notifications, API keys, default * workspace templates, etc.). Currently lists a single category card; * the layout scales to a sidebar nav once there are 3+. * * Access: any authenticated user (the cards themselves gate further; * non-owner users would not see "Billing" as actionable, etc.). */ export async function generateMetadata() { const t = await getTranslations("common"); return { title: t("settings") }; } export default async function SettingsPage() { const user = await getSessionUser(); if (!user) redirect("/login"); const t = await getTranslations("settings"); // Build the list of settings cards. Each entry has a stable key, a // route, and a visibility predicate. Phase 6 fix5: profile is // visible to every signed-in user (it's their own identity). // Billing stays gated behind canMutate. const sections: Array<{ key: string; href: string; title: string; description: string; visible: boolean; }> = [ { key: "profile", href: "/settings/profile", title: t("profileTitle"), description: t("profileDescription"), // Every signed-in user can edit their own first/last name. visible: true, }, { key: "billing", href: "/settings/billing", title: t("billingTitle"), // Personal customers (B2C) don't have a VAT number; the // description shouldn't mention one. Same pattern used in the // form itself (label/field gating). description: user.isPersonal ? t("billingDescriptionPersonal") : t("billingDescription"), // Owners and platform admins can edit billing. `user` role // can't even view it — billing details aren't useful to them. visible: canMutate(user), }, ]; const visibleSections = sections.filter((s) => s.visible); return (

{t("title")}

{t("subtitle")}

{visibleSections.length === 0 && (

{t("nothingForYou")}

)}
{visibleSections.map((s) => (
{s.title}
{s.description}
))}
); }