import type { ReactNode } from 'react'; import { Lock } from 'lucide-react'; /** True for a backend RBAC denial — so we can show a human line, not the raw * "user N does not have permission for activity ". */ export function isPermissionError(msg?: string | null): boolean { return !!msg && /permission|not authoriz|unauthoriz|forbidden|\b403\b/i.test(msg); } interface SchemaGuardProps { loading: boolean; error: string | null; /** Verb phrase for the denial copy, e.g. "collect documents for this lead". */ action: string; /** True when the schema loaded but yielded no usable fields. */ empty?: boolean; children: ReactNode; } /** Gate any activity body on its form-screens fetch. Until the schema resolves * cleanly we never render the form: an RBAC denial (or any load error) shows a * human-readable card instead of a live-looking form that 403s only on submit. * Bespoke bodies and the generic share this so the guard can't * drift out of sync between them. */ export function SchemaGuard({ loading, error, action, empty, children }: SchemaGuardProps) { if (loading) { return
Loading form…
; } if (error || empty) { if (isPermissionError(error)) { return (
You don’t have permission for this action
Your role can’t {action}. Ask an admin to grant your role access to this activity, or sign in as a role that can.
); } return (
{error ? `Couldn’t load the form: ${error}` : 'This activity has no input fields.'}
); } return <>{children}; }