Files
address-verification-app/App.tsx
2025-01-22 14:34:34 +05:30

223 lines
7.3 KiB
TypeScript

import AsyncStorage from '@react-native-async-storage/async-storage';
import { NavigationContainer } from '@react-navigation/native';
import React, { useEffect } from 'react';
import {
AppState,
LogBox,
PermissionsAndroid,
Platform,
StatusBar,
type Permission,
} from 'react-native';
import {
default as codePush,
default as CodePush,
DownloadProgress,
DownloadProgressCallback,
SyncStatusChangedCallback,
} from 'react-native-code-push';
import { Provider } from 'react-redux';
import { PersistGate } from 'redux-persist/integration/react';
import store, { persistor } from './src/store/store';
import FullScreenLoader from './RN-UI-LIB/src/components/FullScreenLoader';
import { toastConfigs, ToastContainer } from './RN-UI-LIB/src/components/toast';
import { navigationRef } from '@utils/navigationUtlis';
import { sendDeviceDetailsToClickstream } from '@components/utlis/commonFunctions';
import { linkingConf } from '@components/utlis/deeplinkingUtils';
import { getBuildFlavour } from '@components/utlis/DeviceUtils';
import { setGlobalBuildFlavour } from '@constants/Global';
import analytics from '@react-native-firebase/analytics';
import dayJs from 'dayjs';
import { COLORS } from '@rn-ui-lib/colors';
import { MILLISECONDS_IN_A_SECOND } from '@rn-ui-lib/utils/common';
import { hydrateGlobalImageMap } from '@common/CachedImage';
import { CLICKSTREAM_EVENT_NAMES, LocalStorageKeys } from '@common/Constants';
import ErrorBoundary from './src/common/ErrorBoundary';
import { getPermissionsToRequest } from '@utils/PermissionUtils';
import ScreenshotBlocker from './src/components/utlis/ScreenshotBlocker';
import { setItem } from './src/components/utlis/storageHelper';
import { ENV } from './src/constants/config';
import AuthRouter from './src/screens/auth/AuthRouter';
import { type TDocumentObj } from '@screens/caseDetails/interface';
import Permissions from './src/screens/permissions/Permissions';
import { addClickstreamEvent } from '@services/clickstreamEventService';
import { setJsErrorHandler } from '@services/exception-handler.service';
import fetchUpdatedRemoteConfig from './src/services/firebaseFetchAndUpdate.service';
import { StorageKeys } from './src/types/storageKeys';
import CodePushLoadingModal, { CodePushLoadingModalRef } from './CodePushModal';
import { initSentry } from '@components/utlis/sentry';
import { AppStates } from '@interfaces/appStates';
if (!__DEV__) {
initSentry();
}
if (ENV !== 'prod') {
// mockApiServer();
}
setJsErrorHandler();
LogBox.ignoreAllLogs();
export let GlobalDocumentMap: Record<string, TDocumentObj | string> = {};
async function checkCodePushAndSync(
onSyncStatusChange: SyncStatusChangedCallback,
onDownloadProgress: DownloadProgressCallback
) {
try {
await CodePush.sync(
{
installMode: codePush.InstallMode.IMMEDIATE,
},
onSyncStatusChange,
onDownloadProgress
);
} catch (error) {}
}
function handleAppStateChange(
nextAppState: any,
onSyncStatusChange: SyncStatusChangedCallback,
onDownloadProgress: DownloadProgressCallback
) {
if (nextAppState == 'active') {
checkCodePushAndSync(onSyncStatusChange, onDownloadProgress);
}
}
const PERMISSION_CHECK_POLL_INTERVAL = 5 * MILLISECONDS_IN_A_SECOND;
function App() {
const [permissions, setPermissions] = React.useState(true);
const modalRef = React.useRef<CodePushLoadingModalRef>(null);
const askForPermissions = async () => {
const permissionsToRequest = await getPermissionsToRequest();
if (Platform.OS === 'android') {
PermissionsAndroid.requestMultiple(permissionsToRequest)
.then(async (result) => {
let isAllPermissionsGranted = true;
for (const permission in result) {
if (result?.[permission as Permission] !== PermissionsAndroid.RESULTS.GRANTED) {
isAllPermissionsGranted = false;
break;
}
}
setPermissions(isAllPermissionsGranted);
})
.catch((err) => {
setPermissions(false);
});
}
};
const onSyncStatusChange = (syncStatus: codePush.SyncStatus) => {
switch (syncStatus) {
case codePush.SyncStatus.DOWNLOADING_PACKAGE:
modalRef.current?.show();
break;
case codePush.SyncStatus.INSTALLING_UPDATE:
addClickstreamEvent(CLICKSTREAM_EVENT_NAMES.FA_INSTALLING_CODEPUSH, {});
break;
case codePush.SyncStatus.UP_TO_DATE:
modalRef.current?.hide();
break;
case codePush.SyncStatus.UNKNOWN_ERROR:
addClickstreamEvent(CLICKSTREAM_EVENT_NAMES.FA_CODEPUSH_UNKNOWN_ERROR, {});
modalRef.current?.hide();
break;
default:
addClickstreamEvent(CLICKSTREAM_EVENT_NAMES.FA_CODEPUSH_DEFAULT_STATUS, {});
modalRef.current?.hide();
break;
}
};
const onDownloadProgress = (downloadProgress: DownloadProgress) => {
if (downloadProgress) {
modalRef.current?.updateProgress(downloadProgress);
}
};
const getActiveRouteName = (state) => {
if (!state || typeof state.index !== 'number') {
return 'Unknown';
}
const route = state.routes[state.index];
if (route.state) {
return getActiveRouteName(route.state);
}
return route?.name || '';
};
async function setForegroundTimeStampAndClickstream() {
const now = dayJs().toString();
await setItem(StorageKeys.APP_FOREGROUND_TIMESTAMP, now);
addClickstreamEvent(CLICKSTREAM_EVENT_NAMES.AV_APP_FOREGROUND, { now }, true);
}
useEffect(() => {
ScreenshotBlocker.unblockScreenshots();
getBuildFlavour().then((flavour) => {
setGlobalBuildFlavour(flavour);
});
// Device Details
sendDeviceDetailsToClickstream();
}, []);
React.useEffect(() => {
fetchUpdatedRemoteConfig();
askForPermissions();
const appStateChange = AppState.addEventListener('change', async (change) => {
if(change === AppStates.ACTIVE) {
askForPermissions();
}
handleAppStateChange(change, onSyncStatusChange, onDownloadProgress);
hydrateGlobalImageMap();
});
(async () => {
const data = await AsyncStorage.getItem(LocalStorageKeys.GLOBAL_DOCUMENT_MAP);
if (data) {
const parsedData = JSON.parse(data);
GlobalDocumentMap = parsedData;
}
})();
checkCodePushAndSync(onSyncStatusChange, onDownloadProgress);
setForegroundTimeStampAndClickstream();
return () => {
appStateChange.remove();
};
}, []);
return (
<Provider store={store}>
<PersistGate
loading={<FullScreenLoader loading isTranslucent={false} />}
persistor={persistor}
>
<NavigationContainer
linking={linkingConf}
ref={navigationRef}
onStateChange={async (state) => {
const currentRouteName = getActiveRouteName(state);
await analytics().logScreenView({
screen_name: currentRouteName,
screen_class: currentRouteName,
});
}}
>
<StatusBar backgroundColor={COLORS.BACKGROUND.INDIGO_DARK} />
<ErrorBoundary>{permissions ? <AuthRouter /> : <Permissions />}</ErrorBoundary>
</NavigationContainer>
<ToastContainer config={toastConfigs} position="top" topOffset={18} />
<CodePushLoadingModal ref={modalRef} />
</PersistGate>
</Provider>
);
}
export default App;