frontend phase 15
This commit is contained in:
@@ -0,0 +1,71 @@
|
||||
import { useMemo } from 'react';
|
||||
import { useAuth } from '@/context/auth';
|
||||
import { APP_ROLES, ADMIN_ROLE_CODES, isAdminRoleCode, type AdminRoleCode } from '@/constants';
|
||||
|
||||
/**
|
||||
* The set of admin consoles the current principal may act on. **UI hint only** — the server enforces
|
||||
* every command's role scope (a `support` admin who forges a payout request still 403s). We derive it so
|
||||
* the shell never *shows* a control the current role can't use (phase §3 "Routing & RBAC", §5).
|
||||
*
|
||||
* The matrix mirrors the product's five worklists (verification / refund / payout / support-alert / RBAC)
|
||||
* plus the config/holiday/audit/moderation/partner surfaces, keyed off the fine-grained role codes:
|
||||
* - `super_admin` — everything (only role that may grant/revoke roles).
|
||||
* - `admin` — everything except role management.
|
||||
* - `finance` — refunds, payouts, config, audit.
|
||||
* - `support` — verification, support-alerts, tickets.
|
||||
* - `moderation` — review moderation.
|
||||
*/
|
||||
export interface AdminCapabilities {
|
||||
/** True when the principal holds any admin role at all (drives whether the console is reachable). */
|
||||
isAdmin: boolean;
|
||||
canVerify: boolean;
|
||||
canRefund: boolean;
|
||||
canPayout: boolean;
|
||||
canModerate: boolean;
|
||||
canConfig: boolean;
|
||||
canManageAlerts: boolean;
|
||||
canManageTickets: boolean;
|
||||
canManagePartners: boolean;
|
||||
canViewAudit: boolean;
|
||||
canManageRoles: boolean;
|
||||
/** The effective fine-grained roles used for the matrix (post dev-fallback). */
|
||||
roles: AdminRoleCode[];
|
||||
}
|
||||
|
||||
const has = (roles: AdminRoleCode[], ...allowed: AdminRoleCode[]) => roles.some((r) => allowed.includes(r));
|
||||
|
||||
/**
|
||||
* Reads the session's fine-grained `roleCodes` (hydrated from `/me` by `useSessionRoleSync`). When a
|
||||
* session is coarse-admin (mock auth, or `/me` not yet fine-hydrated) but carries no admin code, we fall
|
||||
* back to a plain `admin` so the console is usable in dev — never `super_admin`, so the roles screen stays
|
||||
* correctly hidden. This is a display convenience; authorization is always the server's.
|
||||
*/
|
||||
export function useAdminCapabilities(): AdminCapabilities {
|
||||
const [state] = useAuth();
|
||||
|
||||
return useMemo<AdminCapabilities>(() => {
|
||||
const user = state.currentUser;
|
||||
const coarseAdmin = !!user?.roles?.includes(APP_ROLES.ADMIN);
|
||||
let roles = (user?.roleCodes ?? []).filter(isAdminRoleCode);
|
||||
if (roles.length === 0 && coarseAdmin) roles = ['admin'];
|
||||
|
||||
const isAdmin = roles.length > 0;
|
||||
return {
|
||||
isAdmin,
|
||||
canVerify: has(roles, 'super_admin', 'admin', 'support'),
|
||||
canRefund: has(roles, 'super_admin', 'admin', 'finance'),
|
||||
canPayout: has(roles, 'super_admin', 'admin', 'finance'),
|
||||
canModerate: has(roles, 'super_admin', 'admin', 'moderation'),
|
||||
canConfig: has(roles, 'super_admin', 'admin', 'finance'),
|
||||
canManageAlerts: has(roles, 'super_admin', 'admin', 'support'),
|
||||
canManageTickets: has(roles, 'super_admin', 'admin', 'support'),
|
||||
canManagePartners: has(roles, 'super_admin', 'admin'),
|
||||
canViewAudit: has(roles, 'super_admin', 'admin'),
|
||||
canManageRoles: has(roles, 'super_admin'),
|
||||
roles,
|
||||
};
|
||||
}, [state.currentUser]);
|
||||
}
|
||||
|
||||
/** The full ordered admin role-code list — for the (deferred) RBAC grid + any role picker. */
|
||||
export { ADMIN_ROLE_CODES };
|
||||
@@ -1,3 +1,4 @@
|
||||
export * from './auth';
|
||||
export * from './capabilities';
|
||||
export * from './event';
|
||||
export * from './layout';
|
||||
|
||||
Reference in New Issue
Block a user