132 lines
4.2 KiB
TypeScript
132 lines
4.2 KiB
TypeScript
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 (
|
|
<StatusBar
|
|
barStyle={isDark ? 'light-content' : 'dark-content'}
|
|
backgroundColor={colors.background}
|
|
translucent={false}
|
|
/>
|
|
);
|
|
};
|
|
|
|
/** 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<AppStateStatus>(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 (
|
|
<Provider store={store}>
|
|
<PersistGate loading={null} persistor={persistor}>
|
|
<SafeAreaProvider>
|
|
<ThemeProvider>
|
|
<ThemedStatusBar />
|
|
<AppInit />
|
|
<RootNavigator />
|
|
</ThemeProvider>
|
|
</SafeAreaProvider>
|
|
</PersistGate>
|
|
</Provider>
|
|
);
|
|
};
|
|
|
|
export default App;
|