/** * React Hook for FCM Token - Simplified Version * * This hook manages FCM token retrieval and provides it to components. */ import { useState, useEffect, useRef } from 'react'; import { getFCMToken, initializeFirebase } from './init'; /** * Hook to get FCM token * * @returns Object with FCM token, loading state, and error */ /** * Hook to get FCM token * * @returns Object with FCM token, loading state, error, and request function */ export function useFCMToken() { const [token, setToken] = useState<string | null>(null); const [isLoading, setIsLoading] = useState(true); const [error, setError] = useState<Error | null>(null); const isMountedRef = useRef(true); // Function to retrieve token - can be called automatically or manually const retrieveToken = async (isManualRequest = false) => { try { if (isMountedRef.current) setIsLoading(true); if (isMountedRef.current) setError(null); // Check if browser supports notifications if (typeof window === 'undefined' || !('Notification' in window)) { // console.warn('[FCM] Hook: ⚠️ Browser does not support notifications'); if (isMountedRef.current) setIsLoading(false); return null; } // If permission is default and not a manual request, DO NOT attempt to get token // This prevents the "blocked" error in Safari/Firefox when requesting without user gesture if (Notification.permission === 'default' && !isManualRequest) { // console.log('[FCM] Hook: Permission is default, waiting for user gesture'); if (isMountedRef.current) setIsLoading(false); return null; } // Initialize Firebase await initializeFirebase(); // Get FCM token (this will trigger permission request if needed and allowed) const fcmToken = await getFCMToken(); if (fcmToken && isMountedRef.current) { setToken(fcmToken); } return fcmToken; } catch (err) { // console.error('[FCM] Hook: ❌ Error:', err); const error = err instanceof Error ? err : new Error('Failed to get FCM token'); if (isMountedRef.current) { setError(error); setToken(null); } return null; } finally { if (isMountedRef.current) setIsLoading(false); } }; useEffect(() => { isMountedRef.current = true; // Auto-check on mount if (typeof window !== 'undefined' && 'Notification' in window) { // Only auto-fetch if we already have permission if (Notification.permission === 'granted') { retrieveToken(false); } else { // Otherwise just finish loading setIsLoading(false); } } else { setIsLoading(false); } return () => { isMountedRef.current = false; }; }, []); return { token, isLoading, error, requestToken: () => retrieveToken(true) }; }