"use client"; /** * SettingsShell — shared chrome for the workspace settings pages: a title, * a horizontal tab nav (workspace-scoped route /w/:ws/settings/…), and a * content column. Every settings page uses this so the nav stays in one place. * * The core sidebar deep-links to /w/:ws/settings and /w/:ws/settings/members, * so "Members" is first-class here even though it isn't a distinct product * "section" — it's where member management lives. */ import { useParams } from "next/navigation"; import { Building2, CreditCard, Palette, UserCog, Users, KeyRound, Shield, Zap, } from "lucide-react"; import { cn } from "@/lib/utils"; import { useWorkspace } from "@/hooks/use-workspace"; const TABS = [ { href: "", label: "Workspace", icon: Building2 }, { href: "members", label: "Members", icon: UserCog }, { href: "teams", label: "Teams", icon: Users }, { href: "permissions", label: "Permissions", icon: Shield }, { href: "developers", label: "Developers", icon: KeyRound }, { href: "automations", label: "Automations", icon: Zap }, { href: "billing", label: "Billing", icon: CreditCard }, { href: "appearance", label: "Appearance", icon: Palette }, ] as const; export interface SettingsShellProps { title: string; description?: string; /** Active tab ("" = Workspace index). */ active: string; children: React.ReactNode; } export function SettingsShell({ title, description, active, children }: SettingsShellProps) { const params = useParams<{ workspace: string }>(); const ws = params?.workspace ?? ""; // The Developers tab is Owner/Admin-only (TASK-0128). The server enforces // 403 for everyone else (AGENTS rule 19) — this hiding is UX, and a direct // URL still resolves to the page (which then says "Owner or Admin // required"). Hidden until the role is known (no flicker, no false DOM). const { data: roleWs, isLoading: roleLoading } = useWorkspace(ws); const role = (roleWs?.role ?? "").toLowerCase(); const showDevelopers = !roleLoading && (role === "owner" || role === "admin"); const tabs = TABS.filter((t) => t.href !== "developers" || showDevelopers); return (
{description}
: null}{description}
: null}