import { Suspense, useEffect, useRef, useState } from 'react';
import { ADMIN_APP_ROLES, SETTINGS_ROLES } from '../../admin/js/role-capabilities.js';
import { applyRippleEffect, closeAllDropdownsOnOutsideClick } from '../../admin/js/utils.js';
import { initAllCustomDropdowns, startDropdownAutoObserver } from '../../admin/js/dropdown.js';
import { confirmAbandonDirtyChanges } from '../../admin/js/dirty-state.js';
import { trackUxEvent } from '../../telemetry.js';
import { logoutAndRedirect } from '../shared/auth-client.js';
import { SESSION_PHASES } from '../shared/session-policy.js';
import { useAuthorizedSession } from '../shared/use-authorized-session.js';
import { AsyncState } from '../shared/ui/AsyncState.jsx';
import { REACT_TABS } from './react-tabs.js';
import {
ADMIN_ROUTES,
allowedAdminTabs,
badgeVisibility,
defaultAdminTabForRole,
fetchPendingRequestsCount,
logoTitleForRole,
navBadgeLabel,
navSectionsForRole,
requestCountLabel,
tabFromHash
} from './admin-service.js';
const THEME_STORAGE_KEY = 'theme';
const SIDEBAR_STORAGE_KEY = 'sidebar-collapsed';
const ICONS = Object.freeze({
dashboard: (
),
'teacher-requests': (
),
'department-workspace': (
),
schedule: (
),
'schedule-versions': (
),
'schedule-quality': (
),
'academic-calendar': (
),
'auditorium-workload': (
),
'schedule-view': (
),
'teacher-absences': (
),
classrooms: (
),
groups: (
),
'university-structure': (
),
subjects: (
),
users: (
)
});
export function AdminApp() {
const sessionState = useAuthorizedSession(ADMIN_APP_ROLES);
if (sessionState.phase === SESSION_PHASES.loading) {
return (
);
}
if (sessionState.phase !== SESSION_PHASES.ready) {
return (
);
}
return ;
}
function AdminFrame({ children }) {
return (
);
}
export function AdminWorkspace({ role }) {
const allowedTabs = allowedAdminTabs(role);
const [activeTab, setActiveTab] = useState(() => (
typeof window === 'undefined'
? defaultAdminTabForRole(role)
: tabFromHash(window.location.hash, role)
));
const activeTabRef = useRef(activeTab);
const [collapsed, setCollapsed] = useState(() => (
typeof window !== 'undefined'
&& window.innerWidth > 768
&& localStorage.getItem(SIDEBAR_STORAGE_KEY) === 'true'
));
const [settingsOpen, setSettingsOpen] = useState(false);
const [pendingCount, setPendingCount] = useState(null);
const settingsRef = useRef(null);
useEffect(() => {
applyRippleEffect();
closeAllDropdownsOnOutsideClick();
initAllCustomDropdowns(document.body);
startDropdownAutoObserver();
}, []);
useEffect(() => {
document.documentElement.dataset.theme = localStorage.getItem(THEME_STORAGE_KEY) || 'light';
}, []);
useEffect(() => {
function handleHashChange() {
void requestTabSwitch(tabFromHash(window.location.hash, role));
}
window.addEventListener('hashchange', handleHashChange);
return () => {
window.removeEventListener('hashchange', handleHashChange);
};
});
useEffect(() => {
function handleClickOutside(event) {
if (settingsRef.current && !settingsRef.current.contains(event.target)) {
setSettingsOpen(false);
}
}
document.addEventListener('click', handleClickOutside);
return () => {
document.removeEventListener('click', handleClickOutside);
};
}, []);
useEffect(() => {
if (role !== 'ADMIN') return;
let active = true;
async function refresh(countOverride = null) {
try {
const count = countOverride === null
? await fetchPendingRequestsCount()
: countOverride;
if (active) setPendingCount(count);
} catch {
if (active) setPendingCount(null);
console.warn('Не удалось загрузить счётчик заявок');
}
}
void refresh();
function handleRequestsChanged(event) {
void refresh(Number.isFinite(event.detail?.count) ? event.detail.count : null);
}
document.addEventListener('teacherRequestsChanged', handleRequestsChanged);
return () => {
active = false;
document.removeEventListener('teacherRequestsChanged', handleRequestsChanged);
};
}, [role]);
async function requestTabSwitch(tab) {
if (tab === activeTabRef.current || !allowedTabs.has(tab)) return;
if (activeTabRef.current && !(await confirmAbandonDirtyChanges())) return;
activeTabRef.current = tab;
setActiveTab(tab);
trackUxEvent('раздел_открыт', { tab, role });
if (window.location.hash !== `#${tab}`) {
window.location.hash = tab;
}
}
function toggleSidebar() {
setCollapsed(current => {
const next = !current;
localStorage.setItem(SIDEBAR_STORAGE_KEY, next);
return next;
});
}
function toggleTheme() {
const next = document.documentElement.dataset.theme === 'dark' ? 'light' : 'dark';
document.documentElement.dataset.theme = next;
localStorage.setItem(THEME_STORAGE_KEY, next);
}
function handleLogout(event) {
event.preventDefault();
void logoutAndRedirect();
}
const sections = navSectionsForRole(role);
const title = activeTab ? ADMIN_ROUTES[activeTab].title : 'Админ-панель';
const badge = pendingCount === null ? null : badgeVisibility(pendingCount);
return (
<>
>
);
}
function TabContent({ tab }) {
const reactTab = REACT_TABS[tab];
const TabComponent = reactTab?.Component;
if (!TabComponent) {
return null;
}
return (
Загрузка...}>
);
}