import React, { createContext, useContext, useEffect, useState } from 'react'; import { io } from 'socket.io-client'; export interface Notification { id: string; type: 'assignment' | 'mention' | 'update'; title: string; message: string; link?: string; is_read: boolean; created_at: string; } interface NotificationContextType { notifications: Notification[]; unreadCount: number; markAsRead: (id: string) => Promise; } const NotificationContext = createContext(undefined); export const NotificationProvider: React.FC<{ children: React.ReactNode, userId: string }> = ({ children, userId }) => { const [notifications, setNotifications] = useState([]); useEffect(() => { if (!userId) return; const newSocket = io(window.location.protocol + '//' + window.location.hostname + ':3001'); newSocket.emit('join', userId); newSocket.on('notification', (notif: Notification) => { setNotifications(prev => [notif, ...prev]); // Optional: Show browser toast here }); fetchNotifications(); return () => { newSocket.close(); }; }, [userId]); const fetchNotifications = async () => { try { const res = await fetch(`/api/notifications/${userId}`); if (res.ok) { const data = await res.json(); setNotifications(data); } } catch (err) { console.error('Fetch notifications failed', err); } }; const markAsRead = async (id: string) => { try { const res = await fetch(`/api/notifications/${id}/read`, { method: 'PUT' }); if (res.ok) { setNotifications(prev => prev.map(n => n.id === id ? { ...n, is_read: true } : n)); } } catch (err) { console.error('Mark read failed', err); } }; const unreadCount = notifications.filter(n => !n.is_read).length; return ( {children} ); }; export const useNotifications = () => { const context = useContext(NotificationContext); if (!context) throw new Error('useNotifications must be used within NotificationProvider'); return context; };