import React, { useEffect, useRef } from 'react'; import { StatusBar, AppState, AppStateStatus, Platform } from 'react-native'; import { SafeAreaProvider } from 'react-native-safe-area-context'; import { RootNavigator } from './navigation/rootNavigator'; import { ThemeProvider, useTheme } from './theme'; import { Provider } from 'react-redux'; import { store, persistor, useAppDispatch, useAppSelector, getStatusList, getSourceList, getCountryList, getLanguageList, getCurrencyList } from '@store'; import { PersistGate } from 'redux-persist/integration/react'; import { NotificationService } from '@services'; import BootSplash from 'react-native-bootsplash'; import messaging from '@react-native-firebase/messaging'; import { getStaffNotifications } from './features/notification/thunk'; import { navigateToLeadDetails } from '@utils'; const ThemedStatusBar = () => { const { theme: colors, isDark } = useTheme(); useEffect(() => { StatusBar.setBarStyle(isDark ? 'light-content' : 'dark-content', true); StatusBar.setBackgroundColor(colors.background, true); if (Platform.OS === 'android') { StatusBar.setTranslucent(false); } }, [colors, isDark]); return ( ); }; /** Dispatches startup data fetches once the Redux store is ready. */ const AppInit = () => { const dispatch = useAppDispatch(); const token = useAppSelector(state => state.auth.token); useEffect(() => { if (token) { dispatch(getStatusList()); dispatch(getSourceList()); dispatch(getCountryList()); dispatch(getLanguageList()); dispatch(getCurrencyList()); } }, [dispatch, token]); // When a push notification arrives (foreground), re-fetch from the server // so the list and unread badge are always accurate useEffect(() => { const unsubscribe = messaging().onMessage(async () => { const staffId = (store.getState() as any).auth?.user_data?.staffid; if (staffId) { dispatch(getStaffNotifications(staffId)); } }); return unsubscribe; }, [dispatch]); // When the app comes back to the foreground from background (e.g., user taps // a background push notification), re-fetch so count and list are up to date const appState = useRef(AppState.currentState); useEffect(() => { const subscription = AppState.addEventListener('change', nextState => { if (appState.current.match(/inactive|background/) && nextState === 'active') { const staffId = (store.getState() as any).auth?.user_data?.staffid; if (staffId) { dispatch(getStaffNotifications(staffId)); } } appState.current = nextState; }); return () => subscription.remove(); }, [dispatch]); return null; }; const App = () => { useEffect(() => { let cleanup: (() => void) | undefined; const initApp = async () => { try { const cleanupFn = await NotificationService.initialize({ onNotificationOpen: data => { console.log('[App] Notification opened with data:', data); // Deep-link: if the notification carries a lead_id, open LeadDetails if (data?.type === 'lead' && data?.lead_id) { navigateToLeadDetails(data.lead_id); } }, onTokenRefreshed: token => { // TODO: Send the refreshed token to your backend so the server // always has the latest FCM token for this device. console.log('[App] FCM token refreshed — sync to server:', token); }, }); cleanup = cleanupFn; } catch (err) { console.error('[App] NotificationService.initialize error:', err); } finally { await BootSplash.hide({ fade: true }); } }; initApp(); return () => { cleanup?.(); }; }, []); return ( ); }; export default App;