Files
inji-wallet/App.tsx
KiruthikaJeyashankar 9457ad0d9f [INJIMOB-3647] refactor: update isRevoked data type (#2149)
* [INJIMOB-3647] refactor: modify data type of isRevoked to EvaluationStatus

Type representing any possible value of EvaluationStatus.

- "TRUE" → Condition was evaluated and is positively true
- "FALSE" → Condition was evaluated and is definitively false
- "UNDETERMINED" → Condition could not be evaluated due to an error

Signed-off-by: KiruthikaJeyashankar <kiruthikavjshankar@gmail.com>

* [INJIMOB-3647] refactor: modify data type of isRevoked to EvaluationStatus

Type representing any possible value of EvaluationStatus.

- "TRUE" → Condition was evaluated and is positively true
- "FALSE" → Condition was evaluated and is definitively false
- "UNDETERMINED" → Condition could not be evaluated due to an error

Signed-off-by: KiruthikaJeyashankar <kiruthikavjshankar@gmail.com>

* [INJIMOB-3647] refactor: change statuslistVC type to record from string

Signed-off-by: KiruthikaJeyashankar <kiruthikavjshankar@gmail.com>

# Conflicts:
#	shared/vcjs/verifyCredential.ts

* [INJIMOB-3647] refactor: update status revoke check to check for null status

Signed-off-by: KiruthikaJeyashankar <kiruthikavjshankar@gmail.com>

* [INJIMOB-3647] refactor: VCMetadat constructor isRevoked param

Signed-off-by: KiruthikaJeyashankar <kiruthikavjshankar@gmail.com>

* [INJIMOB-3647] refactor: rename EvaluationStatus to RevocationStatus

Signed-off-by: KiruthikaJeyashankar <kiruthikavjshankar@gmail.com>

* [INJIMOB-3647] refactor: modify revocation status logs

Signed-off-by: KiruthikaJeyashankar <kiruthikavjshankar@gmail.com>

---------

Signed-off-by: KiruthikaJeyashankar <kiruthikavjshankar@gmail.com>
2025-12-01 11:28:11 +05:30

181 lines
5.4 KiB
TypeScript

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 (
<>
<AppLayout />
<MessageOverlay
isVisible={isDeepLinkOverlayVisible && !isAppSetupComplete}
title={t('errors.appSetupIncomplete.title')}
message={t('errors.appSetupIncomplete.message')}
onButtonPress={() => {
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 (
<>
<MessageOverlay
isVisible={isKeyInvalidateError}
title={t('errors.invalidateKeyError.title')}
message={t('errors.invalidateKeyError.message')}
onButtonPress={controller.RESET}
buttonText={t('common:ok')}
minHeight={'auto'}
/>
{isReadError ? (
<DualMessageOverlay
isVisible={isReadError}
title={t('failedToReadKeys')}
message={t('retryRead')}
onTryAgain={controller.TRY_AGAIN}
onIgnore={controller.IGNORE}
/>
) : 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 ? (
<AppLayoutWrapper />
) : (
<AppLoadingWrapper />
);
};
export default function App() {
return (
<GlobalContextProvider>
<CopilotProvider
stopOnOutsideClick
androidStatusBarVisible
tooltipComponent={CopilotTooltip}
tooltipStyle={Theme.Styles.copilotStyle}
stepNumberComponent={() => null}
animated>
<AppInitialization />
</CopilotProvider>
</GlobalContextProvider>
);
}