Files
pieced-portal/src/app/[locale]/settings/page.tsx
admin a1769eeb00
All checks were successful
Build and Push / build (push) Successful in 1m40s
Phase6c: Optional Company contact name
2026-05-25 13:50:16 +02:00

91 lines
3.1 KiB
TypeScript

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 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 (
<main className="max-w-4xl 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>
{visibleSections.length === 0 && (
<Card className="animate-in animate-in-delay-1">
<p className="text-sm text-text-secondary">{t("nothingForYou")}</p>
</Card>
)}
<div className="grid gap-3 animate-in animate-in-delay-1">
{visibleSections.map((s) => (
<Link
key={s.key}
href={s.href}
className="block rounded-xl border border-border bg-surface-1 p-4 hover:border-text-secondary transition-colors"
>
<div className="font-medium text-text-primary">{s.title}</div>
<div className="text-xs text-text-secondary mt-1">
{s.description}
</div>
</Link>
))}
</div>
</main>
);
}