import React from "react"; import { supabase, hasSupabaseConfig } from "../supabaseClient"; export function useNotifications(userId) { const [notifications, setNotifications] = React.useState([]); const [unreadCount, setUnreadCount] = React.useState(0); const [isLoading, setIsLoading] = React.useState(true); const fetchNotifications = React.useCallback(async () => { if (!hasSupabaseConfig || !userId) { setIsLoading(false); return; } const { data, error } = await supabase .from("notifications") .select("*") .eq("user_id", userId) .order("created_at", { ascending: false }) .limit(50); if (!error && data) { setNotifications(data); setUnreadCount(data.filter((n) => !n.read).length); } setIsLoading(false); }, [userId]); // Initial fetch React.useEffect(() => { fetchNotifications(); }, [fetchNotifications]); // NOTE: realtime (WebSocket) subscription intentionally removed (2026-08). // The supabase realtime container kept dying and the client hung in WS retry // loops (30-40s stalls on open). Notifications now update via REST fetch on // page load / focus only — see handleFocus below for refresh on tab focus. // Refresh notifications when the tab regains focus so the unread badge stays // reasonably fresh without a live WebSocket connection. React.useEffect(() => { if (!hasSupabaseConfig || !userId) return; const handleFocus = () => fetchNotifications(); window.addEventListener("focus", handleFocus); return () => window.removeEventListener("focus", handleFocus); }, [fetchNotifications, userId]); // Fix unread count: always recalculate from notifications React.useEffect(() => { setUnreadCount(notifications.filter((n) => !n.read).length); }, [notifications]); const markAsRead = React.useCallback( async (notificationId) => { if (!hasSupabaseConfig) return; await supabase .from("notifications") .update({ read: true }) .eq("id", notificationId); setNotifications((prev) => prev.map((n) => (n.id === notificationId ? { ...n, read: true } : n)) ); }, [] ); const markAllAsRead = React.useCallback(async () => { if (!hasSupabaseConfig || !userId) return; await supabase .from("notifications") .update({ read: true }) .eq("user_id", userId) .eq("read", false); setNotifications((prev) => prev.map((n) => ({ ...n, read: true }))); }, [userId]); return { notifications, unreadCount, isLoading, markAsRead, markAllAsRead, refresh: fetchNotifications, }; } export function useNotificationPreferences(userId) { const [prefs, setPrefs] = React.useState({ push_enabled: true, order_status_change: true, driver_assigned: true, delivery_problem: true, }); const [isLoading, setIsLoading] = React.useState(true); React.useEffect(() => { if (!hasSupabaseConfig || !userId) { setIsLoading(false); return; } supabase .from("notification_preferences") .select("*") .eq("user_id", userId) .single() .then(({ data, error }) => { if (data) { setPrefs({ push_enabled: data.push_enabled, order_status_change: data.order_status_change, driver_assigned: data.driver_assigned, delivery_problem: data.delivery_problem, }); } setIsLoading(false); }); }, [userId]); const updatePref = React.useCallback( async (key, value) => { if (!hasSupabaseConfig || !userId) return; setPrefs((prev) => ({ ...prev, [key]: value })); await supabase .from("notification_preferences") .upsert({ user_id: userId, [key]: value, updated_at: new Date().toISOString() }); }, [userId] ); return { prefs, isLoading, updatePref }; }