import { useState, useEffect, useRef } from "react"; import { getNotifications, markNotificationAsRead, markAllNotificationsAsRead, deleteNotification, } from "../notificationApi"; function NotificationBell({ onShowToast }) { const [notifications, setNotifications] = useState([]); const [unreadCount, setUnreadCount] = useState(0); const [showDropdown, setShowDropdown] = useState(false); const dropdownRef = useRef(null); useEffect(() => { loadNotifications(); // Poll for new notifications every 30 seconds const interval = setInterval(loadNotifications, 30000); return () => clearInterval(interval); }, []); useEffect(() => { // Close dropdown when clicking outside function handleClickOutside(event) { if (dropdownRef.current && !dropdownRef.current.contains(event.target)) { setShowDropdown(false); } } if (showDropdown) { document.addEventListener("mousedown", handleClickOutside); } return () => { document.removeEventListener("mousedown", handleClickOutside); }; }, [showDropdown]); const loadNotifications = async () => { try { const data = await getNotifications(); setNotifications(data); setUnreadCount(data.filter((n) => !n.is_read).length); } catch (error) { // If unauthorized (401), user is not logged in - don't show errors if (error.message.includes("401") || error.message.includes("Unauthorized") || error.message.includes("User not found")) { setNotifications([]); setUnreadCount(0); return; } // Silent fail for other polling errors console.error("Failed to load notifications", error); } }; const handleMarkAsRead = async (notificationId) => { try { await markNotificationAsRead(notificationId); setNotifications( notifications.map((n) => n.id === notificationId ? { ...n, is_read: true } : n ) ); setUnreadCount(Math.max(0, unreadCount - 1)); } catch (error) { onShowToast?.(error.message, "error"); } }; const handleMarkAllAsRead = async () => { try { await markAllNotificationsAsRead(); setNotifications(notifications.map((n) => ({ ...n, is_read: true }))); setUnreadCount(0); onShowToast?.("כל ההתראות סומנו כנקראו", "success"); } catch (error) { onShowToast?.(error.message, "error"); } }; const handleDelete = async (notificationId) => { try { await deleteNotification(notificationId); const notification = notifications.find((n) => n.id === notificationId); setNotifications(notifications.filter((n) => n.id !== notificationId)); if (notification && !notification.is_read) { setUnreadCount(Math.max(0, unreadCount - 1)); } } catch (error) { onShowToast?.(error.message, "error"); } }; const formatTime = (timestamp) => { const date = new Date(timestamp); const now = new Date(); const diff = now - date; const minutes = Math.floor(diff / 60000); const hours = Math.floor(diff / 3600000); const days = Math.floor(diff / 86400000); if (minutes < 1) return "עכשיו"; if (minutes < 60) return `לפני ${minutes} דקות`; if (hours < 24) return `לפני ${hours} שעות`; return `לפני ${days} ימים`; }; return (
{notification.message}
{formatTime(notification.created_at)}