import React, {useContext, useEffect} from 'react'; import {AppLayout} from './screens/AppLayout'; import {useFont} from './shared/hooks/useFont'; import {GlobalContextProvider} from './components/GlobalContextProvider'; import {GlobalContext} from './shared/GlobalContext'; import {useSelector} from '@xstate/react'; import {useTranslation} from 'react-i18next'; import { APP_EVENTS, selectIsDecryptError, selectIsKeyInvalidateError, selectIsReadError, selectIsReady, } from './machines/app'; import {DualMessageOverlay} from './components/DualMessageOverlay'; import {useApp} from './screens/AppController'; import {Alert, AppState} from 'react-native'; import { configureTelemetry, getErrorEventData, sendErrorEvent, } from './shared/telemetry/TelemetryUtils'; import {TelemetryConstants} from './shared/telemetry/TelemetryConstants'; import {MessageOverlay} from './components/MessageOverlay'; import {NativeModules} from 'react-native'; import {isHardwareKeystoreExists} from './shared/cryptoutil/cryptoUtil'; import i18n from './i18n'; import './shared/flipperConfig'; import {CopilotProvider} from 'react-native-copilot'; import {CopilotTooltip} from './components/CopilotTooltip'; import {Theme} from './components/ui/styleUtils'; const {RNSecureKeystoreModule} = NativeModules; // kludge: this is a bad practice but has been done temporarily to surface // an occurrence of a bug with minimal residual code changes, this should // be removed once the bug cause is determined & fixed, ref: INJI-222 const DecryptErrorAlert = (controller, t) => { const heading = t('errors.decryptionFailed'); const desc = t('errors.decryptionFailed'); const ignoreBtnTxt = t('ignore'); Alert.alert(heading, desc, [ { text: ignoreBtnTxt, onPress: () => controller.ignoreDecrypt(), style: 'cancel', }, ]); }; const AppLayoutWrapper: React.FC = () => { const {appService} = useContext(GlobalContext); const isDecryptError = useSelector(appService, selectIsDecryptError); const controller = useApp(); const {t} = useTranslation('WelcomeScreen'); useEffect(() => { if (AppState.currentState === 'active') { appService.send(APP_EVENTS.ACTIVE()); } else { appService.send(APP_EVENTS.INACTIVE()); } }, []); if (isDecryptError) { DecryptErrorAlert(controller, t); } configureTelemetry(); return ; }; const AppLoadingWrapper: React.FC = () => { const {appService} = useContext(GlobalContext); const isReadError = useSelector(appService, selectIsReadError); const isKeyInvalidateError = useSelector( appService, selectIsKeyInvalidateError, ); const controller = useApp(); const {t} = useTranslation('WelcomeScreen'); useEffect(() => { if (isKeyInvalidateError) { configureTelemetry(); sendErrorEvent( getErrorEventData( TelemetryConstants.FlowType.appLogin, TelemetryConstants.ErrorId.appWasReset, TelemetryConstants.ErrorMessage.appWasReset, ), ); } }, [isKeyInvalidateError]); return ( <> {isReadError ? ( ) : null} ); }; const AppInitialization: React.FC = () => { const {appService} = useContext(GlobalContext); const isReady = useSelector(appService, selectIsReady); const hasFontsLoaded = useFont(); const {t} = useTranslation('common'); useEffect(() => { if (isHardwareKeystoreExists) { RNSecureKeystoreModule.updatePopup( t('biometricPopup.title'), t('biometricPopup.description'), ); } }, [i18n.language]); return isReady && hasFontsLoaded ? ( ) : ( ); }; export default function App() { return ( null} animated> ); }