import 'react-native-get-random-values';
import React, {useContext, useEffect, useState} 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,
selectIsDeepLinkDetected,
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 {CopilotProvider} from 'react-native-copilot';
import {CopilotTooltip} from './components/CopilotTooltip';
import {Theme} from './components/ui/styleUtils';
import {selectAppSetupComplete} from './machines/auth';
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 isDeepLinkFlow = useSelector(appService, selectIsDeepLinkDetected);
const controller = useApp();
const {t} = useTranslation('WelcomeScreen');
const authService = appService.children.get('auth');
const isAppSetupComplete = useSelector(authService, selectAppSetupComplete);
const [isDeepLinkOverlayVisible, setDeepLinkOverlayVisible] =
useState(isDeepLinkFlow);
useEffect(() => {
if (AppState.currentState === 'active') {
appService.send(APP_EVENTS.ACTIVE());
} else {
appService.send(APP_EVENTS.INACTIVE());
}
}, []);
useEffect(() => {
setDeepLinkOverlayVisible(isDeepLinkFlow);
}, [isDeepLinkFlow]);
if (isDecryptError) {
DecryptErrorAlert(controller, t);
}
configureTelemetry();
return (
<>
{
setDeepLinkOverlayVisible(false);
}}
buttonText={t('common:ok')}
minHeight={'auto'}
/>
>
);
};
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 hasFontsLoaded = useFont();
const isReady = useSelector(appService, selectIsReady);
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>
);
}