Amba-Agent-App/lib/hooks/useFCM.ts
2026-01-16 00:22:35 +03:00

147 lines
5.2 KiB
TypeScript

/**
* useFCM Hook - Platform-aware FCM token management
*
* Native: Full FCM support with token registration and notification handling
* Web: Gracefully skips FCM (web push requires additional service worker setup)
*/
import { useEffect, useRef } from 'react';
import { Platform, AppState, AppStateStatus } from 'react-native';
import { useAuthStore } from '../stores/authStore';
// Only import FCMService and messaging on native platforms
let FCMService: any = null;
let messaging: any = null;
if (Platform.OS !== 'web') {
FCMService = require('../services/fcmService').FCMService;
messaging = require('@react-native-firebase/messaging').default;
}
/**
* Hook to manage FCM token registration and notification handling
* Call this hook once at the app root level when user is authenticated
*/
export const useFCM = () => {
const { user } = useAuthStore();
const foregroundUnsubscribeRef = useRef<(() => void) | null>(null);
const notificationOpenedUnsubscribeRef = useRef<(() => void) | null>(null);
const initializedUserIdRef = useRef<string | null>(null);
useEffect(() => {
// Skip FCM on web platform
if (Platform.OS === 'web' || !FCMService) {
return;
}
if (!user) {
// User logged out - clean up
if (initializedUserIdRef.current) {
FCMService.cleanup();
if (foregroundUnsubscribeRef.current) {
foregroundUnsubscribeRef.current();
foregroundUnsubscribeRef.current = null;
}
if (notificationOpenedUnsubscribeRef.current) {
notificationOpenedUnsubscribeRef.current();
notificationOpenedUnsubscribeRef.current = null;
}
initializedUserIdRef.current = null;
}
return;
}
// User is authenticated - initialize FCM
// Clean up previous user's listeners if user changed
if (initializedUserIdRef.current && initializedUserIdRef.current !== user.uid) {
FCMService.cleanup();
if (foregroundUnsubscribeRef.current) {
foregroundUnsubscribeRef.current();
foregroundUnsubscribeRef.current = null;
}
if (notificationOpenedUnsubscribeRef.current) {
notificationOpenedUnsubscribeRef.current();
notificationOpenedUnsubscribeRef.current = null;
}
}
initializedUserIdRef.current = user.uid;
// Update FCM token for the existing user
FCMService.updateTokenForExistingUser(user.uid).catch((error: any) => {
console.error('Failed to update FCM token:', error);
});
// Set up handlers only if not already set up for this user
if (!foregroundUnsubscribeRef.current) {
// Set up foreground message handler
foregroundUnsubscribeRef.current = FCMService.setupForegroundMessageHandler();
// Set up notification opened handler
notificationOpenedUnsubscribeRef.current = FCMService.setupNotificationOpenedHandler(
(remoteMessage: any) => {
console.log('Notification opened:', remoteMessage);
}
);
// Check if app was opened from a notification
FCMService.getInitialNotification().then((remoteMessage: any) => {
if (remoteMessage) {
console.log('App opened from notification:', remoteMessage);
}
});
}
// Cleanup on unmount
return () => {
if (foregroundUnsubscribeRef.current) {
foregroundUnsubscribeRef.current();
foregroundUnsubscribeRef.current = null;
}
if (notificationOpenedUnsubscribeRef.current) {
notificationOpenedUnsubscribeRef.current();
notificationOpenedUnsubscribeRef.current = null;
}
};
}, [user]);
// Save token when app comes to foreground
useEffect(() => {
// Skip on web
if (Platform.OS === 'web' || !FCMService || !user) {
return;
}
const handleAppStateChange = (nextAppState: AppStateStatus) => {
if (nextAppState === 'active' && user) {
FCMService.updateTokenForExistingUser(user.uid).catch((error: any) => {
console.error('Failed to refresh FCM token on app foreground:', error);
});
}
};
const subscription = AppState.addEventListener('change', handleAppStateChange);
return () => {
subscription.remove();
};
}, [user]);
// Clean up on unmount
useEffect(() => {
// Skip on web
if (Platform.OS === 'web' || !FCMService) {
return;
}
return () => {
FCMService.cleanup();
if (foregroundUnsubscribeRef.current) {
foregroundUnsubscribeRef.current();
}
if (notificationOpenedUnsubscribeRef.current) {
notificationOpenedUnsubscribeRef.current();
}
};
}, []);
};