/** Роли доступа к разделам админки (согласовано с меню и маршрутами). */ export type AdminRole = 'superadmin' | 'admin' | 'moderator' | 'support'; export const ROUTE_ACCESS: Record = { '/dashboard': undefined, '/profile': undefined, '/monitoring': undefined, '/inbox/reports': ['superadmin', 'admin', 'moderator'], '/inbox/tickets': ['superadmin', 'admin', 'support'], '/inbox/automod': ['superadmin', 'admin', 'moderator'], '/users': ['superadmin', 'admin'], '/calendars': ['superadmin', 'admin'], '/events': ['superadmin', 'admin'], '/reports': ['superadmin', 'admin', 'moderator'], '/reviews': ['superadmin', 'admin', 'moderator'], '/banned-words': ['superadmin', 'admin'], '/automod-settings': ['superadmin', 'admin'], '/tickets': ['superadmin', 'admin', 'support'], '/subscriptions': ['superadmin', 'admin'], '/admins': ['superadmin'], '/audit': ['superadmin'], }; export type NavItem = { key: string; label: string; roles?: AdminRole[]; }; export type NavGroup = { id: string; label: string; items: NavItem[]; }; /** Группы навигации Control Center (label = i18n key). */ export const NAV_GROUPS: NavGroup[] = [ { id: 'work', label: 'navGroup.work', items: [ { key: '/inbox/reports', label: 'nav.inboxReports', roles: ['superadmin', 'admin', 'moderator'] }, { key: '/inbox/tickets', label: 'nav.inboxTickets', roles: ['superadmin', 'admin', 'support'] }, { key: '/inbox/automod', label: 'nav.inboxAutomod', roles: ['superadmin', 'admin', 'moderator'] }, ], }, { id: 'overview', label: 'navGroup.overview', items: [ { key: '/dashboard', label: 'nav.dashboard' }, { key: '/monitoring', label: 'nav.monitoring' }, ], }, { id: 'content', label: 'navGroup.content', items: [ { key: '/users', label: 'nav.users', roles: ['superadmin', 'admin'] }, { key: '/calendars', label: 'nav.calendars', roles: ['superadmin', 'admin'] }, { key: '/events', label: 'nav.events', roles: ['superadmin', 'admin'] }, { key: '/subscriptions', label: 'nav.subscriptions', roles: ['superadmin', 'admin'] }, ], }, { id: 'moderation', label: 'navGroup.moderation', items: [ { key: '/reports', label: 'nav.reports', roles: ['superadmin', 'admin', 'moderator'] }, { key: '/reviews', label: 'nav.reviews', roles: ['superadmin', 'admin', 'moderator'] }, { key: '/banned-words', label: 'nav.bannedWords', roles: ['superadmin', 'admin'] }, { key: '/automod-settings', label: 'nav.automodSettings', roles: ['superadmin', 'admin'] }, { key: '/tickets', label: 'nav.tickets', roles: ['superadmin', 'admin', 'support'] }, ], }, { id: 'system', label: 'navGroup.system', items: [ { key: '/admins', label: 'nav.admins', roles: ['superadmin'] }, { key: '/audit', label: 'nav.audit', roles: ['superadmin'] }, ], }, ]; /** Плоский список для совместимости и getMenuSelectedKey. */ export const MENU_ITEMS: NavItem[] = NAV_GROUPS.flatMap((g) => g.items); export function canAccessRoute(pathname: string, role: string | undefined): boolean { if (!role) return false; const base = pathname.split('/').slice(0, 2).join('/') || '/'; const inboxBase = pathname.startsWith('/inbox/') ? pathname.split('/').slice(0, 3).join('/') : null; const check = inboxBase ?? base; const allowed = ROUTE_ACCESS[check] ?? ROUTE_ACCESS[base]; if (allowed === undefined) { return ROUTE_ACCESS[pathname] === undefined || ROUTE_ACCESS[pathname]!.includes(role as AdminRole); } return allowed.includes(role as AdminRole); } export function filterMenuByRole( items: T[], role: string | undefined ): T[] { return items.filter((item) => !item.roles || (role && item.roles.includes(role as AdminRole))); } export function filterNavGroupsByRole(groups: NavGroup[], role: string | undefined): NavGroup[] { return groups .map((group) => ({ ...group, items: filterMenuByRole(group.items, role), })) .filter((group) => group.items.length > 0); } /** Ключ пункта меню для detail-маршрутов (/users/:id → /users). */ export function getMenuSelectedKey(pathname: string): string { if (MENU_ITEMS.some((item) => item.key === pathname)) { return pathname; } if (pathname.startsWith('/inbox/')) { const parts = pathname.split('/').filter(Boolean); if (parts.length >= 2) return `/inbox/${parts[1]}`; } const segment = pathname.split('/').filter(Boolean)[0]; if (segment) { const parent = `/${segment}`; if (MENU_ITEMS.some((item) => item.key === parent)) { return parent; } } return pathname; } const WS_NOTIFICATION_ROUTES: Record<'report_created' | 'ticket_created' | 'automod_hit', string> = { report_created: '/inbox/reports', ticket_created: '/inbox/tickets', automod_hit: '/inbox/automod', }; export function canReceiveWsNotification( type: 'report_created' | 'ticket_created' | 'automod_hit', role: string | undefined ): boolean { return canAccessRoute(WS_NOTIFICATION_ROUTES[type], role); } /** Стартовая страница по роли после логина. */ export function getDefaultRouteForRole(role: AdminRole | undefined): string { if (role === 'moderator') return '/inbox/reports'; if (role === 'support') return '/inbox/tickets'; return '/dashboard'; }