import { useState, useRef } from "react"; import { MaterialList, MaterialListItem, MaterialSwitch, type MDUISwitch } from "@/utils/material"; import { useAppState } from "@/pages/chat/state"; import { initialize, subscribe, unsubscribe, isSupported } from "@/core/push-notifications/push-notifications"; import { isElectron } from "@/core/electron/electron"; import { API_BASE_URL } from "@/core/config"; import { getAuthHeaders } from "@/core/api/authApi"; import styles from "@/pages/chat/css/settings-dialog.module.scss"; export function NotificationsPanel() { const { user } = useAppState(); const authToken = user?.authToken ?? null; const [pushEnabled, setPushEnabled] = useState(false); const [loading, setLoading] = useState(false); const [checking, setChecking] = useState(true); const switchRef = useRef(null); async function checkPushStatus() { if (!isSupported()) { setPushEnabled(false); setChecking(false); return; } setChecking(true); try { let permission: string; if (isElectron) { permission = await window.electronInterface.notifications.requestPermission(); } else { permission = Notification.permission; } console.log("checkPushStatus", permission); setPushEnabled(permission === "granted"); } catch (error) { console.error("Failed to check push status:", error); setPushEnabled(false); } finally { setChecking(false); } } async function handlePushToggle(enabled: boolean) { console.log("handlePushToggle", enabled); if (!authToken || !isSupported() || loading) return; // Optimistic update const previousState = pushEnabled; setPushEnabled(enabled); setLoading(true); try { if (enabled) { // Initialize push notifications (creates service worker and requests permission) const initResult = await initialize(); if (!initResult) { throw new Error("Failed to initialize push notifications"); } // Subscribe to push notifications (sends subscription to server) // The subscribe() function will handle creating/getting the subscription if needed const subscribeResult = await subscribe(authToken); if (!subscribeResult) { throw new Error("Failed to subscribe to push notifications"); } // Verify the state after subscription - check permission to ensure it's actually granted await checkPushStatus(); } else { // Unsubscribe locally first const unsubscribed = await unsubscribe(); if (!unsubscribed) { throw new Error("Failed to unsubscribe locally"); } // Then unsubscribe from server const response = await fetch(`${API_BASE_URL}/push/unsubscribe`, { method: "DELETE", headers: getAuthHeaders(authToken) }); if (!response.ok) { throw new Error("Failed to unsubscribe from push notifications"); } // After unsubscribing, permission is still granted but we're not subscribed // So we keep the state as disabled (false) setPushEnabled(false); } } catch (error) { console.error("Failed to toggle push notifications:", error); // Revert optimistic update setPushEnabled(previousState); // Re-check actual status to sync with reality await checkPushStatus(); } finally { setLoading(false); } } function handleListItemClick(e: React.MouseEvent) { if (checking || loading || !isSupported() || e.target === switchRef.current) return; handlePushToggle(!pushEnabled); } return ( <>

Notifications

handlePushToggle(e.target.checked)} slot="end-icon" ref={switchRef} /> ); }