File "useFCMToken.ts"

Full Path: /home/trinadezambia/public_html/student_panel/src/lib/firebase/useFCMToken.ts
File size: 2.84 KB
MIME-type: text/x-java
Charset: utf-8

/**
 * 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) };
}