63 lines
2.5 KiB
TypeScript
63 lines
2.5 KiB
TypeScript
export interface PermissionPage {
|
|
path: string;
|
|
permission: string;
|
|
matches?: (pathname: string) => boolean;
|
|
}
|
|
|
|
/**
|
|
* Single source of truth for page-level navigation permissions.
|
|
* Order also defines the landing-page priority after login.
|
|
*/
|
|
export const PERMISSION_PAGES: readonly PermissionPage[] = [
|
|
{ path: '/dashboard', permission: 'dashboard:view' },
|
|
{ path: '/room-visual', permission: 'room:view' },
|
|
{ path: '/rooms', permission: 'room:view' },
|
|
{ path: '/occupancies', permission: 'occupancy:view' },
|
|
{ path: '/teacher-workspace', permission: 'teacher-workspace:view' },
|
|
{
|
|
path: '/students',
|
|
permission: 'student:view',
|
|
matches: (p) => p === '/students' || /^\/students\/\d+\/profile$/.test(p),
|
|
},
|
|
{
|
|
path: '/classes',
|
|
permission: 'class:view',
|
|
matches: (p) => p === '/classes' || /^\/classes\/\d+$/.test(p),
|
|
},
|
|
{ path: '/attendance', permission: 'attendance:view' },
|
|
{ path: '/schedules', permission: 'schedule:view' },
|
|
{ path: '/classroom-schedule', permission: 'rental:view' },
|
|
{ path: '/classrooms', permission: 'classroom:view' },
|
|
{ path: '/attendance-devices', permission: 'classroom:view' },
|
|
{ path: '/classroom-rentals', permission: 'rental:view' },
|
|
{ path: '/organizations', permission: 'organization:view' },
|
|
{ path: '/expenses', permission: 'expense:view' },
|
|
{ path: '/deposits', permission: 'deposit:view' },
|
|
{ path: '/bills', permission: 'bill:view' },
|
|
{ path: '/notifications', permission: 'notification:view' },
|
|
{ path: '/operation-logs', permission: 'log:view' },
|
|
{ path: '/roles', permission: 'role:view' },
|
|
{ path: '/permissions', permission: 'role:view' },
|
|
{ path: '/integration-config', permission: 'integration:read' },
|
|
{ path: '/ai-config', permission: 'ai:config:read' },
|
|
{ path: '/users', permission: 'user:view' },
|
|
{ path: '/teachers', permission: 'teacher:view' },
|
|
] as const;
|
|
|
|
function matchesPage(page: PermissionPage, pathname: string): boolean {
|
|
return page.matches ? page.matches(pathname) : page.path === pathname;
|
|
}
|
|
|
|
export function getRequiredPermission(pathname: string): string | null {
|
|
return PERMISSION_PAGES.find((page) => matchesPage(page, pathname))?.permission ?? null;
|
|
}
|
|
|
|
export function canAccessPath(pathname: string, permissions: readonly string[]): boolean {
|
|
const required = getRequiredPermission(pathname);
|
|
return required === null || permissions.includes(required);
|
|
}
|
|
|
|
export function findFirstAccessiblePath(permissions: readonly string[]): string | null {
|
|
return PERMISSION_PAGES.find((page) => permissions.includes(page.permission))?.path ?? null;
|
|
}
|