import React, { useState, useEffect } from 'react'; import axios from 'axios'; import { formatLocalTime } from './utils/timeUtils'; import './NotificationCenter.css'; function NotificationCenter() { const [notifications, setNotifications] = useState([]); const [unreadCount, setUnreadCount] = useState(0); const [showCenter, setShowCenter] = useState(false); const [filter, setFilter] = useState('all'); // all, unread, read const [loading, setLoading] = useState(false); const [wsConnected, setWsConnected] = useState(false); const [pushPermission, setPushPermission] = useState( 'Notification' in window ? Notification.permission : 'unsupported' ); useEffect(() => { loadNotifications(); // Refresh every 10 seconds const interval = setInterval(loadNotifications, 10000); // Connect to WebSocket for real-time updates connectWebSocket(); return () => { clearInterval(interval); if (window.notificationWebSocket) { window.notificationWebSocket.close(); } }; }, [filter]); const connectWebSocket = () => { try { const protocol = window.location.protocol === 'https:' ? 'wss:' : 'ws:'; const ws = new WebSocket(`${protocol}//${window.location.host}`); ws.onopen = () => { console.log('WebSocket connected for real-time notifications'); setWsConnected(true); }; ws.onmessage = (event) => { try { const message = JSON.parse(event.data); if (message.type === 'notification') { loadNotifications(); if ('Notification' in window && Notification.permission === 'granted' && !document.hasFocus()) { const n = message.data || {}; new Notification(n.title || 'SkyWatch Alert', { body: n.message || '', icon: '/favicon.ico' }); } } } catch (error) { console.error('Failed to parse WebSocket message:', error); } }; ws.onerror = (error) => { console.error('WebSocket error:', error); setWsConnected(false); }; ws.onclose = () => { console.log('WebSocket disconnected'); setWsConnected(false); // Attempt to reconnect after 5 seconds setTimeout(connectWebSocket, 5000); }; window.notificationWebSocket = ws; } catch (error) { console.error('Failed to connect WebSocket:', error); } }; const loadNotifications = async () => { setLoading(true); try { const params = {}; if (filter === 'unread') params.read = 'unread'; if (filter === 'read') params.read = 'read'; params.limit = 100; const response = await axios.get('/api/notifications', { params }); setNotifications(response.data.notifications); setUnreadCount(response.data.unreadCount); } catch (error) { console.error('Failed to load notifications:', error); } finally { setLoading(false); } }; const handleMarkAsRead = async (notificationId) => { try { await axios.put(`/api/notifications/${notificationId}/read`); loadNotifications(); } catch (error) { console.error('Failed to mark notification as read:', error); } }; const handleDelete = async (notificationId) => { try { await axios.delete(`/api/notifications/${notificationId}`); loadNotifications(); } catch (error) { console.error('Failed to delete notification:', error); } }; const handleRequestPush = async () => { if (!('Notification' in window)) return; const perm = await Notification.requestPermission(); setPushPermission(perm); }; const handleClearAll = async () => { if (!window.confirm(`Clear all ${filter} notifications?`)) return; try { await axios.post('/api/notifications/clear', { type: filter }); loadNotifications(); } catch (error) { console.error('Failed to clear notifications:', error); } }; return (
{/* Notification Bell Icon */}
{/* Notification Center Popup */} {showCenter && (

Notifications

{notifications.length > 0 && ( )}
{pushPermission !== 'granted' && pushPermission !== 'unsupported' && (
)}
{loading ? (

Loading...

) : notifications.length === 0 ? (

No {filter === 'unread' ? 'unread ' : filter === 'read' ? 'read ' : ''}notifications

) : ( notifications.map((notification) => (
{notification.title}
{notification.message}
{notification.resource_name && ( Resource: {notification.resource_name} )} {formatLocalTime(notification.created_at)}
{!notification.read && ( )}
)) )}
)}
); } export default NotificationCenter;