'use client'; import { useState, useEffect, useRef } from 'react'; import Link from 'next/link'; interface Notification { type: string; data: { message: string; severity?: string }; timestamp: string; } export default function NotificationBell() { const [notifications, setNotifications] = useState([]); const [open, setOpen] = useState(false); const [unread, setUnread] = useState(0); const wsRef = useRef(null); const ref = useRef(null); useEffect(() => { // Connect to WebSocket for real-time notifications try { const protocol = window.location.protocol === 'https:' ? 'wss:' : 'ws:'; const ws = new WebSocket(`${protocol}//${window.location.host}/ws/notifications`); wsRef.current = ws; ws.onmessage = (event) => { try { const notif = JSON.parse(event.data); setNotifications(prev => [notif, ...prev].slice(0, 50)); setUnread(prev => prev + 1); } catch {} }; ws.onerror = () => {}; ws.onclose = () => {}; } catch {} return () => { wsRef.current?.close(); }; }, []); useEffect(() => { const handler = (e: MouseEvent) => { if (ref.current && !ref.current.contains(e.target as Node)) setOpen(false); }; document.addEventListener('mousedown', handler); return () => document.removeEventListener('mousedown', handler); }, []); const handleOpen = () => { setOpen(o => !o); if (!open) setUnread(0); }; const severityColor = (s?: string) => { switch (s) { case 'critical': return 'text-red-600'; case 'high': return 'text-orange-500'; case 'medium': return 'text-yellow-600'; default: return 'text-blue-500'; } }; return (
{open && (
Уведомления Все →
{notifications.length > 0 ? (
{notifications.slice(0, 10).map((n, i) => (
{n.data?.message || n.type}
{new Date(n.timestamp).toLocaleTimeString('ru-RU')}
))}
) : (
Нет новых уведомлений
)}
)}
); }