import React, { useEffect, useState, useMemo } from 'react';
import { NavLink, Outlet, useLocation, useNavigate } from 'react-router-dom';
import {
LayoutDashboard,
Building2,
CreditCard,
Package,
Smartphone,
Server,
BellRing,
AlertTriangle,
FileCheck2,
RotateCcw,
CheckCircle2,
Radio,
ExternalLink,
Menu,
X,
ShieldAlert,
Sun,
Moon,
Sparkles,
ShieldCheck,
ChevronRight,
SlidersHorizontal,
ChevronLeft,
} from 'lucide-react';
import { useKccStore, useOperatorRole } from '../store/kccStore';
import { OperatorSessionSwitcher } from './OperatorSessionSwitcher';
import { InspectorDrawer } from './InspectorDrawer';
import { ConfirmOperatorActionModal } from './ConfirmOperatorAction';
import { ServerMonitorOutageBanner } from './ServerMonitorOutageBanner';
import { useThemeStore, ThemeMode } from '../../../stores/theme';
import { RU_ROLES, RU_THEMES, RU_UI } from '../locales/ru';
export const ControlCenterShell: React.FC = () => {
const location = useLocation();
const navigate = useNavigate();
const isInitialized = useKccStore((state) => state.isInitialized);
const initialize = useKccStore((state) => state.initialize);
const resetToDefaults = useKccStore((state) => state.resetToDefaults);
const serverMonitorOutage = useKccStore((state) => state.serverMonitorOutage);
const toggleServerMonitorOutage = useKccStore((state) => state.toggleServerMonitorOutage);
const incidents = useKccStore((state) => state.incidents);
const { role, operator } = useOperatorRole();
const themeMode = useThemeStore((state) => state.themeMode);
const setTheme = useThemeStore((state) => state.setTheme);
const [utcTime, setUtcTime] = useState('');
const [isResetting, setIsResetting] = useState(false);
const [showSavedFeedback, setShowSavedFeedback] = useState(false);
// Mobile / Tablet Drawer states
const [isMobileDrawerOpen, setIsMobileDrawerOpen] = useState(false);
const [isTabletSidebarCollapsed, setIsTabletSidebarCollapsed] = useState(false);
useEffect(() => {
if (!isInitialized) {
initialize();
}
}, [isInitialized, initialize]);
useEffect(() => {
const updateTime = () => {
const now = new Date();
setUtcTime(now.toISOString().replace('T', ' ').slice(0, 19) + ' UTC');
};
updateTime();
const interval = setInterval(updateTime, 1000);
return () => clearInterval(interval);
}, []);
// Close mobile drawer on route change
useEffect(() => {
setIsMobileDrawerOpen(false);
}, [location.pathname]);
const handleReset = async () => {
if (confirm('Сбросить демонстрационные данные платформы к исходному состоянию?')) {
setIsResetting(true);
await resetToDefaults();
setIsResetting(false);
setShowSavedFeedback(true);
setTimeout(() => setShowSavedFeedback(false), 3000);
}
};
// Critical events calculation
const criticalCount = useMemo(() => {
let count = 0;
if (serverMonitorOutage) count += 1;
count += incidents.filter(
(i) => i.status !== 'resolved' && (i.severity === 'P0_CRITICAL' || i.severity === 'P1_MAJOR')
).length;
return count;
}, [serverMonitorOutage, incidents]);
// Navigation Items
const primaryMobileNav = [
{ to: '/control', label: 'Обзор', icon: LayoutDashboard, end: true },
{ to: '/control/organizations', label: 'Организации', icon: Building2 },
{ to: '/control/incidents', label: 'Инциденты', icon: AlertTriangle, badge: criticalCount > 0 ? criticalCount : undefined },
{ to: '/control/infrastructure', label: 'Серверы', icon: Server },
];
const allNavItems = [
{ to: '/control', label: 'Обзор', icon: LayoutDashboard, end: true },
{ to: '/control/organizations', label: 'Организации', icon: Building2 },
{ to: '/control/billing', label: 'Подписки и платежи', icon: CreditCard },
{ to: '/control/modules', label: 'Каталог модулей', icon: Package },
{ to: '/control/installations', label: 'Установки', icon: Smartphone },
{ to: '/control/infrastructure', label: 'Серверы', icon: Server },
{ to: '/control/announcements', label: 'Оповещения', icon: BellRing },
{ to: '/control/incidents', label: 'Инциденты', icon: AlertTriangle, badge: criticalCount > 0 ? criticalCount : undefined },
{ to: '/control/audit', label: 'Журнал аудита', icon: FileCheck2 },
];
const moreNavItems = [
{ to: '/control/billing', label: 'Подписки и платежи', icon: CreditCard },
{ to: '/control/modules', label: 'Каталог модулей', icon: Package },
{ to: '/control/installations', label: 'Установки', icon: Smartphone },
{ to: '/control/announcements', label: 'Оповещения', icon: BellRing },
{ to: '/control/audit', label: 'Журнал аудита', icon: FileCheck2 },
];
// Current section title
const currentTitle = useMemo(() => {
const current = allNavItems.find((item) =>
item.end ? location.pathname === item.to : location.pathname.startsWith(item.to)
);
return current?.label || 'Control Center';
}, [location.pathname, allNavItems]);
const currentRoleLabel = RU_ROLES[role]?.shortLabel || role;
return (
{/* ========================================================================= */}
{/* 1. DESKTOP & TABLET HEADER (Hidden on mobile < md) */}
{/* ========================================================================= */}
{/* Logo & Platform info */}
K
Krona Control Center
PROD v1.0
Кабинет владельца платформы
{utcTime}
•
{RU_UI.system.synced}
{/* Right Controls: Outage simulation, Theme Switcher, Operator Switcher, Reset */}
{/* Circuit Breaker Outage toggle */}
{/* Theme Switcher in Desktop Header */}
{/* Reset Demo Data */}
{/* Operator Role Switcher */}
{/* ========================================================================= */}
{/* 2. MOBILE HEADER (< md) */}
{/* ========================================================================= */}
{/* Left: Menu toggle + Logo + Title */}
K
{currentTitle}
Control Center
{/* Right: Critical Badge + Operator Profile button */}
{criticalCount > 0 && (
)}
{/* ========================================================================= */}
{/* 3. MAIN LAYOUT (Sidebar on Desktop/Tablet + Content Body) */}
{/* ========================================================================= */}
{/* Desktop & Tablet Sidebar */}
{/* Main Content Area */}
{/* Feedback Alert if Database Reset */}
{showSavedFeedback && (
Демонстрационные данные успешно сброшены к эталонному состоянию.
)}
{/* Outage Banner */}
{/* Outlet for Page Routes */}
{/* ========================================================================= */}
{/* 4. MOBILE BOTTOM BAR (< md) */}
{/* ========================================================================= */}
{/* ========================================================================= */}
{/* 5. MOBILE DRAWER / BOTTOM SHEET */}
{/* ========================================================================= */}
{isMobileDrawerOpen && (
setIsMobileDrawerOpen(false)}
>
e.stopPropagation()}
>
{/* Sheet Header */}
{/* Scrollable Sheet Content */}
{/* Operator Role Section */}
Сессия оператора
{operator.name}
{RU_ROLES[role]?.label}
{/* Theme Switcher Section */}
{RU_UI.system.themeLabel}
{(['soft-light', 'light', 'dark'] as ThemeMode[]).map((t) => (
))}
{/* More Navigation Links */}
Все разделы
{allNavItems.map((item) => {
const Icon = item.icon;
const isActive = item.end ? location.pathname === item.to : location.pathname.startsWith(item.to);
return (
{item.label}
{item.badge && item.badge > 0 && (
{item.badge}
)}
);
})}
{/* System Actions */}
Сервисные действия
Перейти в Krona Business OS
{/* Node info */}
srv-msk-prod-01 • Данные синхронизированы (IndexedDB)
)}
{/* Global Contextual Modals */}
);
};