Introduces a capability layer on top of existing roles that controls feature visibility and access. Capabilities follow an area.feature.action taxonomy (~35 capabilities) with sensible defaults per role. Tenant admins can customize via grant/revoke overrides stored in org settings JSONB. Key changes: - Add vice_president role to DB schema - Backend: capability constants, resolution logic, CapabilityGuard (global), @RequireCapability decorator on all 16 tenant controllers - Frontend: permission hooks (useCanEdit, useHasCapability), CapabilityGate component, sidebar filtering by capability, all 17 pages migrated from useIsReadOnly to capability-based checks - New admin UI: /settings/permissions matrix page for per-tenant role customization with grant/revoke delta model - GET /organizations/my-capabilities endpoint for capability refresh - Validation of permissionOverrides in settings updates Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
45 lines
1.5 KiB
TypeScript
45 lines
1.5 KiB
TypeScript
import { useAuthStore } from '../stores/authStore';
|
|
|
|
/**
|
|
* Check if the current user has a specific capability.
|
|
* Superadmins always return true.
|
|
*/
|
|
export function useHasCapability(capability: string): boolean {
|
|
const user = useAuthStore((s) => s.user);
|
|
const capabilities = useAuthStore((s) => s.currentOrg?.capabilities);
|
|
if (user?.isSuperadmin) return true;
|
|
return capabilities?.includes(capability) ?? false;
|
|
}
|
|
|
|
/**
|
|
* Check if the current user has ANY of the given capabilities.
|
|
* Superadmins always return true.
|
|
*/
|
|
export function useHasAnyCapability(...caps: string[]): boolean {
|
|
const user = useAuthStore((s) => s.user);
|
|
const capabilities = useAuthStore((s) => s.currentOrg?.capabilities);
|
|
if (user?.isSuperadmin) return true;
|
|
if (!capabilities) return false;
|
|
return caps.some((c) => capabilities.includes(c));
|
|
}
|
|
|
|
/**
|
|
* Check if the current user has ALL of the given capabilities.
|
|
* Superadmins always return true.
|
|
*/
|
|
export function useHasAllCapabilities(...caps: string[]): boolean {
|
|
const user = useAuthStore((s) => s.user);
|
|
const capabilities = useAuthStore((s) => s.currentOrg?.capabilities);
|
|
if (user?.isSuperadmin) return true;
|
|
if (!capabilities) return false;
|
|
return caps.every((c) => capabilities.includes(c));
|
|
}
|
|
|
|
/**
|
|
* Check if a specific capability string matches the user's capability for edit actions.
|
|
* This replaces the old useIsReadOnly() for more granular checks.
|
|
*/
|
|
export function useCanEdit(editCapability: string): boolean {
|
|
return useHasCapability(editCapability);
|
|
}
|