// ════════════════════════════════════════════════════════════════ // MegaMenu — расширяемое меню инструментов // 3 основных пункта в шапке + кнопка "Инструменты ▾" с панелью // ════════════════════════════════════════════════════════════════ const { useEffect: useEffectMM, useRef: useRefMM } = React; function MegaMenu({ open, onClose, onRoute, route, currentUser }) { const ref = useRefMM(null); useEffectMM(() => { if (!open) return; function onDoc(e) { if (ref.current && !ref.current.contains(e.target)) onClose(); } function onKey(e) { if (e.key === 'Escape') onClose(); } document.addEventListener('mousedown', onDoc); document.addEventListener('keydown', onKey); return () => { document.removeEventListener('mousedown', onDoc); document.removeEventListener('keydown', onKey); }; }, [open, onClose]); if (!open) return null; const isAdmin = currentUser && (currentUser.role === 'super_admin' || currentUser.role === 'admin'); const isSuperAdmin = currentUser && currentUser.role === 'super_admin'; const groups = [ { label: 'Аналитика', tools: [ { id: 'markets', icon: 'globe', title: 'Рынки', desc: 'Обзор шести наблюдаемых сегментов с темпом роста', count: '6 сегментов' }, { id: 'trends', icon: 'spark', title: 'Тренды', desc: 'Семантические кластеры и моментум на 30-дневном окне', count: '12 кластеров' }, { id: 'methods', icon: 'grid', title: 'Методологии', desc: 'Четырнадцать протоколов синтеза Орлова', count: '14 протоколов' }, ], }, { label: 'Платформа', tools: [ { id: 'pricing', icon: 'coin', title: 'Тарифы', desc: 'Подписка, дополнительные пакеты токенов, оформление', count: '4 публичных' }, { id: 'account', icon: 'people', title: 'Профиль', desc: 'Учётная запись, API токен, сессии', count: currentUser ? currentUser.name.split(' ')[0] : null }, ...(currentUser && window.SDH_BILLING.getSub(currentUser.id) ? [{ id: 'account.billing', icon: 'coin', title: 'Моя подписка', desc: 'Использование токенов, паки, история платежей', count: window.SDH_BILLING.getSub(currentUser.id).tierCode }] : []), ], }, isAdmin && { label: 'Управление', tools: [ { id: 'admin', icon: 'graph', title: 'Админ-панель', desc: 'Сводный обзор системы', count: 'overview' }, { id: 'admin.users', icon: 'people', title: 'Пользователи', desc: 'Доступ, роли, инвайты, ревокация', count: `${window.SDH_ADMIN.users.filter(u => u.status === 'active').length} активных` }, { id: 'admin.pipeline', icon: 'pulse', title: 'Pipeline', desc: 'Cron, источники, ошибки', count: window.SDH_ADMIN.pipeline.cron_enabled ? 'cron вкл' : 'cron выкл' }, { id: 'admin.audit', icon: 'bell', title: 'Журнал событий', desc: 'Аудит всех действий', count: `${window.SDH_ADMIN.auditLog.length} событий` }, ...(isSuperAdmin ? [ { id: 'admin.cost', icon: 'coin', title: 'Расходы', desc: 'LLM-затраты и бюджет', count: `$${window.SDH_BILLING.adminSummary().monthCostUsd.toFixed(2)}` }, { id: 'admin.billing', icon: 'graph', title: 'Биллинг', desc: 'Выручка, заявки на оформление', count: `${window.SDH_BILLING.adminSummary().newReqsCount} новых` }, { id: 'admin.settings', icon: 'grid', title: 'Настройки',desc: 'Бюджет, cron, brand guards', count: 'global' }, ] : []), ], }, { label: 'Скоро', tools: [ { id: 'export', icon: 'export', title: 'Экспорт', soon: true, desc: 'Выгрузка корпуса в CSV или через API', count: 'скоро' }, { id: 'alerts', icon: 'bell', title: 'Триггеры', soon: true, desc: 'Оповещения при достижении порога импульса кластера', count: 'скоро' }, { id: 'graph', icon: 'graph', title: 'Граф идей', soon: true, desc: 'Сетевая визуализация пересечений между идеями', count: 'скоро' }, ], }, ].filter(Boolean); return ( <>
инструменты

Что нужно для исследования сегодня

{groups.map(g => (
{g.label}
{g.tools.map(t => ( { if (t.soon) return; onRoute(t.id); onClose(); }} active={route === t.id} /> ))}
))}
горячая клавиша: g · t для перехода расширяемая панель: новые инструменты появляются здесь без перегрузки шапки
); } function ToolRow({ tool, onClick, active }) { const Icon = TOOL_ICONS[tool.icon] || TOOL_ICONS.grid; return ( ); } const TOOL_ICONS = { globe: () => , spark: () => , grid: () => , coin: () => , export:() => , bell: () => , graph: () => , people:() => , pulse: () => , }; window.MegaMenu = MegaMenu; window.TOOL_ICONS = TOOL_ICONS;