klg-asutk-app/components/Sidebar.tsx
Yuriy b147d16798 MVP: заглушки, auth, .env.example, связь с бэкендом, главная КЛГ
- Заполнены заглушки: user-friendly-messages, health, aria, keyboard
- backend: core/auth.py, /api/v1/stats; cached-api → backend-client при USE_MOCK_DATA=false
- .env.example, middleware auth (skip при USE_MOCK_DATA), убраны неиспользуемые deps
- Страницы: airworthiness, maintenance, defects, modifications; AircraftAddModal, Sidebar
- Главная страница: REFLY — Контроль лётной годности (вместо Numerology App)
- Линт/скрипты: eslintrc, security, cleanup, logs, api inbox/knowledge

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-02-13 16:43:53 +03:00

159 lines
5.7 KiB
TypeScript
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

'use client';
import Link from 'next/link';
import { usePathname } from 'next/navigation';
import NotificationBell from './NotificationBell';
const menuItems = [
{ name: 'Дашборд', path: '/dashboard', icon: '📊' },
{ name: 'Организации', path: '/organizations', icon: '🏢' },
{ name: 'ВС и типы', path: '/aircraft', icon: '✈️' },
{ name: 'Заявки', path: '/applications', icon: '📋' },
{ name: 'Чек-листы', path: '/checklists', icon: '✅' },
{ name: 'Аудиты', path: '/audits', icon: '🔍' },
{ name: 'Риски', path: '/risks', icon: '⚠️' },
{ name: 'Пользователи', path: '/users', icon: '👥' },
{ name: 'Лётная годность', path: '/airworthiness', icon: '📜' },
{ name: 'Тех. обслуживание', path: '/maintenance', icon: '🔧' },
{ name: 'Дефекты', path: '/defects', icon: '🛠️' },
{ name: 'Модификации', path: '/modifications', icon: '⚙️' },
{ name: 'Документы', path: '/documents', icon: '📄' },
{ name: 'Inbox', path: '/inbox', icon: '📥' },
{ name: 'Нормативные документы', path: '/regulations', icon: '📚' },
{ name: 'Мониторинг', path: '/monitoring', icon: '📈' },
{ name: 'История изменений', path: '/audit-history', icon: '📝' },
{ name: 'Задачи Jira', path: '/jira-tasks', icon: '🎯' },
{ name: 'API Документация', path: '/api-docs', icon: '📖' },
];
export default function Sidebar() {
const pathname = usePathname();
return (
<aside
role="complementary"
aria-label="Боковая панель навигации"
style={{
width: '280px',
backgroundColor: '#1e3a5f',
color: 'white',
height: '100vh',
display: 'flex',
flexDirection: 'column',
position: 'fixed',
left: 0,
top: 0,
}}
>
<div style={{ padding: '24px', borderBottom: '1px solid rgba(255,255,255,0.1)' }}>
<div style={{ display: 'flex', alignItems: 'center', gap: '12px', marginBottom: '8px' }}>
<div
style={{
width: '40px',
height: '40px',
backgroundColor: 'rgba(255,255,255,0.2)',
borderRadius: '8px',
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
fontSize: '20px',
}}
>
</div>
<div style={{ fontSize: '24px', fontWeight: 'bold', color: 'white', letterSpacing: '2px' }}>
REFLY
</div>
</div>
<div style={{ fontSize: '12px', opacity: 0.8, marginBottom: '4px' }}>
КОНТРОЛЬ ЛЁТНОЙ ГОДНОСТИ
</div>
<div style={{ fontSize: '12px', opacity: 0.8 }}>АСУ ТК</div>
</div>
<nav
role="navigation"
aria-label="Основная навигация"
style={{ flex: 1, padding: '16px 0' }}
>
{menuItems.map((item) => {
const isActive = pathname === item.path;
return (
<Link
key={item.path}
href={item.path}
aria-current={isActive ? 'page' : undefined}
aria-label={item.name}
style={{
display: 'flex',
alignItems: 'center',
padding: '12px 24px',
color: 'white',
textDecoration: 'none',
backgroundColor: isActive ? 'rgba(255,255,255,0.15)' : 'transparent',
borderLeft: isActive ? '3px solid #4a90e2' : '3px solid transparent',
outline: 'none',
transition: 'background-color 0.2s',
}}
onFocus={(e) => {
e.currentTarget.style.backgroundColor = 'rgba(255,255,255,0.1)';
}}
onBlur={(e) => {
if (!isActive) {
e.currentTarget.style.backgroundColor = 'transparent';
}
}}
>
<span
aria-hidden="true"
style={{ marginRight: '12px', fontSize: '18px' }}
>
{item.icon}
</span>
<span>{item.name}</span>
</Link>
);
})}
</nav>
<div style={{ padding: '16px 24px', borderTop: '1px solid rgba(255,255,255,0.1)' }}>
<div style={{ marginBottom: '12px', display: 'flex', justifyContent: 'center' }}>
<NotificationBell />
</div>
<button
aria-label="Выйти из системы"
style={{
width: '100%',
padding: '12px',
backgroundColor: 'transparent',
border: '1px solid rgba(255,255,255,0.2)',
color: 'white',
borderRadius: '4px',
cursor: 'pointer',
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
outline: 'none',
transition: 'background-color 0.2s',
}}
onFocus={(e) => {
e.currentTarget.style.backgroundColor = 'rgba(255,255,255,0.1)';
}}
onBlur={(e) => {
e.currentTarget.style.backgroundColor = 'transparent';
}}
onKeyDown={(e) => {
if (e.key === 'Enter' || e.key === ' ') {
e.preventDefault();
// Здесь будет логика выхода
}
}}
>
<span aria-hidden="true" style={{ marginRight: '8px' }}>🚪</span>
Выйти
</button>
</div>
</aside>
);
}