'use client'
import React, { useState, useEffect } from 'react'
import { useRouter, usePathname } from 'next/navigation'
import Image from 'next/image'
import useUIStore from '../../app/store/uiStore'
import useNavigationStore from '../../app/store/navigationStore'
import { useNavigationService } from '@/services/navigationService'
import useUserStore from '../../app/store/userStore'
import { signOut } from 'next-auth/react'
interface NavigationItem {
id: number
label: string
icon: React.ComponentType<{ className?: string }>
}
interface SidebarProps {
navigationItems?: NavigationItem[]
logoSrc?: string
userInfo?: {
name: string
role: string
avatar?: string
}
activeItem?: number | null
onCustomItemClick?: (itemId: number) => boolean
}
const IconWrapper = ({ src, alt, className }: { src: string; alt: string; className?: string }) => (
)
const BookOpen = ({ className }: { className?: string }) => (
)
const Bot = ({ className }: { className?: string }) => (
)
const SquareTerminal = ({ className }: { className?: string }) => (
)
const CircleDot = ({ className }: { className?: string }) => (
)
const BellDot = ({ className }: { className?: string }) => (
)
const History = ({ className }: { className?: string }) => (
)
const Settings2 = ({ className }: { className?: string }) => (
)
const Monitor = ({ className }: { className?: string }) => (
)
const Building = ({ className }: { className?: string }) => (
)
const Building3D = ({ className }: { className?: string }) => (
)
// основные routes
const mainNavigationItems: NavigationItem[] = [
{
id: 1,
icon: BookOpen,
label: 'Дашборд'
},
{
id: 10,
icon: Building3D,
label: 'Объекты'
},
{
id: 2,
icon: Bot,
label: 'Навигация по зданию'
},
{
id: 8,
icon: History,
label: 'История тревог'
},
{
id: 9,
icon: Settings2,
label: 'Отчеты'
}
]
// суб-меню под "Навигация по зданию"
const navigationSubItems: NavigationItem[] = [
{
id: 3,
icon: Monitor,
label: 'Зоны Мониторинга'
},
{
id: 4,
icon: Building,
label: 'Навигация по этажам'
},
{
id: 5,
icon: BellDot,
label: 'Уведомления'
},
{
id: 6,
icon: CircleDot,
label: 'Сенсоры'
},
{
id: 7,
icon: SquareTerminal,
label: 'Список датчиков'
}
]
const Sidebar: React.FC = ({
logoSrc,
userInfo = {
name: '—',
role: '—'
},
activeItem: propActiveItem,
onCustomItemClick
}) => {
const navigationService = useNavigationService()
const router = useRouter()
const pathname = usePathname()
const [internalActiveItem, setInternalActiveItem] = useState(null)
const [isHydrated, setIsHydrated] = useState(false)
const [manuallyToggled, setManuallyToggled] = useState(false)
const activeItem = propActiveItem !== undefined ? propActiveItem : internalActiveItem
const {
isSidebarCollapsed: isCollapsed,
toggleSidebar,
isNavigationSubMenuExpanded: showNavigationSubItems,
setNavigationSubMenuExpanded: setShowNavigationSubItems,
toggleNavigationSubMenu
} = useUIStore()
const { user, logout } = useUserStore()
const roleLabelMap: Record = {
engineer: 'Инженер',
operator: 'Оператор',
admin: 'Администратор',
}
const fullName = [user?.name, user?.surname].filter(Boolean).join(' ').trim()
const uiUserInfo = {
name: fullName || user?.login || userInfo?.name || '—',
role: roleLabelMap[(user?.account_type ?? '').toLowerCase()] || userInfo?.role || '—',
avatar: user?.image || userInfo?.avatar,
}
const handleLogout = async () => {
try {
await fetch('/api/auth/logout', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
credentials: 'include',
})
} catch (e) {
console.error('Logout request failed:', e)
} finally {
logout()
await signOut({ redirect: true, callbackUrl: '/login' })
}
}
const {
openMonitoring,
openFloorNavigation,
openNotifications,
openSensors,
openListOfDetectors,
closeSensors,
closeListOfDetectors,
closeMonitoring,
closeFloorNavigation,
closeNotifications,
showMonitoring,
showFloorNavigation,
showNotifications,
showSensors,
showListOfDetectors
} = useNavigationStore()
useEffect(() => {
setIsHydrated(true)
}, [])
// Чек если суб-меню активны
const isNavigationSubItemActive = activeItem && [3, 4, 5, 6, 7].includes(activeItem)
const shouldShowNavigationAsActive = activeItem === 2 || isNavigationSubItemActive
// Авто-расткрытие меню, если суб-меню стало активным (только если не было ручного переключения)
useEffect(() => {
if (isNavigationSubItemActive && !showNavigationSubItems && !manuallyToggled) {
setShowNavigationSubItems(true)
}
}, [isNavigationSubItemActive, showNavigationSubItems, manuallyToggled, setShowNavigationSubItems])
const handleItemClick = (itemId: number) => {
let handled = false
// Управление суб-меню через navigationStore (суб-меню - работают как отдельные элементы, но не страницы)
switch (itemId) {
case 2:
if (pathname !== '/navigation') {
router.push('/navigation')
}
handled = true
break
case 3: // Monitoring
if (pathname !== '/navigation') {
router.push('/navigation')
setTimeout(() => openMonitoring(), 100)
} else if (showMonitoring) {
closeMonitoring()
} else {
openMonitoring()
}
handled = true
break
case 4: // Floor Navigation
if (pathname !== '/navigation') {
router.push('/navigation')
setTimeout(() => openFloorNavigation(), 100)
} else if (showFloorNavigation) {
closeFloorNavigation()
} else {
openFloorNavigation()
}
handled = true
break
case 5: // Notifications
if (pathname !== '/navigation') {
router.push('/navigation')
setTimeout(() => openNotifications(), 100)
} else if (showNotifications) {
closeNotifications()
} else {
openNotifications()
}
handled = true
break
case 6: // Sensors
if (pathname !== '/navigation') {
router.push('/navigation')
setTimeout(() => openSensors(), 100)
} else if (showSensors) {
closeSensors()
} else {
openSensors()
}
handled = true
break
case 7: // Detector List
if (pathname !== '/navigation') {
router.push('/navigation')
setTimeout(() => openListOfDetectors(), 100)
} else if (showListOfDetectors) {
closeListOfDetectors()
} else {
openListOfDetectors()
}
handled = true
break
default:
// Для остального используем routes
if (navigationService) {
handled = navigationService.handleSidebarItemClick(itemId, pathname)
}
break
}
if (handled) {
if (propActiveItem === undefined) {
setInternalActiveItem(itemId)
}
if (onCustomItemClick) {
onCustomItemClick(itemId)
}
}
}
return (
)
}
export default Sidebar