import { createSignal, createEffect, onCleanup, Show } from "solid-js"; import { api } from "~/lib/api"; const ORANGE = "#FF5E13"; const NAVY = "#0D0D2A"; export default function NotificationBell() { const [unreadCount, setUnreadCount] = createSignal(0); const [showDropdown, setShowDropdown] = createSignal(false); const [notifications, setNotifications] = createSignal([]); // Poll for unread count every 30 seconds createEffect(() => { const fetchUnreadCount = async () => { try { const res = await api.get("/me/notifications/unread-count"); setUnreadCount(res.data?.unread_count || 0); } catch (e) { // Silently fail } }; // Initial fetch fetchUnreadCount(); // Set up polling interval const interval = setInterval(fetchUnreadCount, 30000); onCleanup(() => clearInterval(interval)); }); // Fetch notifications when dropdown opens const fetchNotifications = async () => { try { const res = await api.get("/me/notifications?limit=5"); setNotifications(res.data?.data || []); } catch (e) { setNotifications([]); } }; const toggleDropdown = () => { const newState = !showDropdown(); setShowDropdown(newState); if (newState) { fetchNotifications(); } }; const markAsRead = async (id: string) => { try { await api.patch(`/me/notifications/${id}/read`); // Update local state setNotifications((prev) => prev.map((n) => (n.id === id ? { ...n, is_read: true } : n))); setUnreadCount((prev) => Math.max(0, prev - 1)); } catch (e) { console.error("Failed to mark as read", e); } }; const markAllAsRead = async () => { try { await api.patch("/me/notifications/read-all"); setNotifications((prev) => prev.map((n) => ({ ...n, is_read: true }))); setUnreadCount(0); } catch (e) { console.error("Failed to mark all as read", e); } }; const formatTime = (date: string) => { const now = new Date(); const notifDate = new Date(date); const diff = now.getTime() - notifDate.getTime(); const minutes = Math.floor(diff / 60000); const hours = Math.floor(diff / 3600000); const days = Math.floor(diff / 86400000); if (minutes < 1) return "Just now"; if (minutes < 60) return `${minutes}m ago`; if (hours < 24) return `${hours}h ago`; return `${days}d ago`; }; return (
{/* Dropdown */} <> {/* Backdrop */}
setShowDropdown(false)} /> {/* Dropdown Panel */}

Notifications

0}> {unreadCount()} unread
0}>
0} fallback={

No notifications yet

We will show updates here when they arrive.

} > {notifications().map((notification) => (
{ if (!notification.is_read) { markAsRead(notification.id); } }} >
{/* Unread Dot */}

{notification.title}

{notification.body}

{formatTime(notification.created_at)}

))}
); }