63323c1ca4
CI / test (push) Failing after 3m46s
CI / push-image (push) Has been skipped
CI / deploy-ift (push) Has been skipped
CI / ci-done (push) Failing after 0s
CI / e2e-ift (push) Has been skipped
CI / deploy-stage (push) Has been skipped
CI / e2e-stage (push) Has been skipped
Refs EventHub/EventHubFrontAdmin#40 Refs EventHub/EventHubFrontAdmin#41
155 lines
5.9 KiB
TypeScript
155 lines
5.9 KiB
TypeScript
/** Роли доступа к разделам админки (согласовано с меню и маршрутами). */
|
|
export type AdminRole = 'superadmin' | 'admin' | 'moderator' | 'support';
|
|
|
|
export const ROUTE_ACCESS: Record<string, AdminRole[] | undefined> = {
|
|
'/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<T extends { roles?: AdminRole[] }>(
|
|
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';
|
|
}
|