mirror of
https://github.com/mosip/inji-wallet.git
synced 2026-01-09 13:38:01 -05:00
[INJIMO-3192]: Integrate swift error response enhancement (#2001)
* [INJIMOB-3192]: Native module integration for OVP error handling Signed-off-by: balachandarg-tw <balachandar.g@thoughtworks.com> * [INJIMOB-3192]: Fixing iOS build failure Signed-off-by: balachandarg-tw <balachandar.g@thoughtworks.com> * [INJIMOB-3192]: Refactoring code to move useEffect from SendVPScreenController to UI component Signed-off-by: balachandarg-tw <balachandar.g@thoughtworks.com> * [INJIMOB-3192]: Updating useOvpErrorModal while resolving merge conflicts Signed-off-by: balachandarg-tw <balachandar.g@thoughtworks.com> * [INJIMOB-3192]: Update iOs package dependencies to develop for OVP library Signed-off-by: balachandarg-tw <balachandar.g@thoughtworks.com> * [INJIMOB-3192]: Update history error messages Signed-off-by: balachandarg-tw <balachandar.g@thoughtworks.com> * [INJIMOB-3192]: Update the user declined history message Signed-off-by: balachandarg-tw <balachandar.g@thoughtworks.com> * [INJIMOB-3192]: Remove moduleClassName and use existing method Signed-off-by: balachandarg-tw <balachandar.g@thoughtworks.com> * [INJIMOB-3192]: Fix for retry scenario error messages Signed-off-by: balachandarg-tw <balachandar.g@thoughtworks.com> * [INJIMOB-3192]: Fix for sendErrorToVerifier crash Signed-off-by: balachandarg-tw <balachandar.g@thoughtworks.com> * [INJIMOB-3192]: Add Log for decline scenario Signed-off-by: balachandarg-tw <balachandar.g@thoughtworks.com> * [INJIMOB-3192]: Fix for decline crash issue Signed-off-by: balachandarg-tw <balachandar.g@thoughtworks.com> * [INJIMOB-3192]: Common method for reject Exceptions Signed-off-by: balachandarg-tw <balachandar.g@thoughtworks.com> * [INJIMOB-3192]: Modify general exception for retry scenario Signed-off-by: balachandarg-tw <balachandar.g@thoughtworks.com> * [INJIMOB-3192]: Remove comments Signed-off-by: balachandarg-tw <balachandar.g@thoughtworks.com> * [INJIMOB-3192]: Update package resolved Signed-off-by: balachandarg-tw <balachandar.g@thoughtworks.com> --------- Signed-off-by: balachandarg-tw <balachandar.g@thoughtworks.com>
This commit is contained in:
@@ -29,16 +29,27 @@ import {VerifyIdentityOverlay} from '../VerifyIdentityOverlay';
|
||||
import {VCShareFlowType} from '../../shared/Utils';
|
||||
import {APP_EVENTS} from '../../machines/app';
|
||||
import {GlobalContext} from '../../shared/GlobalContext';
|
||||
import {useOvpErrorModal} from '../../shared/hooks/useOvpErrorModal';
|
||||
|
||||
export const ScanScreen: React.FC = () => {
|
||||
const {t} = useTranslation('ScanScreen');
|
||||
const scanScreenController = useScanScreen();
|
||||
const sendVcScreenController = useSendVcScreen();
|
||||
const sendVPScreenController = useSendVPScreen();
|
||||
const [errorModal] = useOvpErrorModal({
|
||||
error: sendVPScreenController.error,
|
||||
noCredentialsMatchingVPRequest:
|
||||
sendVPScreenController.noCredentialsMatchingVPRequest,
|
||||
requestedClaimsByVerifier: sendVPScreenController.requestedClaimsByVerifier,
|
||||
getAdditionalMessage: sendVPScreenController.getAdditionalMessage,
|
||||
generateAndStoreLogMessage:
|
||||
sendVPScreenController.generateAndStoreLogMessage,
|
||||
t,
|
||||
});
|
||||
const [isBluetoothOn, setIsBluetoothOn] = useState(false);
|
||||
const showErrorModal =
|
||||
sendVPScreenController.scanScreenError ||
|
||||
(sendVPScreenController.errorModal.show &&
|
||||
(errorModal.show &&
|
||||
(sendVPScreenController.flowType ===
|
||||
VCShareFlowType.MINI_VIEW_SHARE_OPENID4VP ||
|
||||
sendVPScreenController.flowType ===
|
||||
@@ -277,7 +288,7 @@ export const ScanScreen: React.FC = () => {
|
||||
|
||||
const getPrimaryButtonText = () => {
|
||||
if (
|
||||
sendVPScreenController.errorModal.showRetryButton &&
|
||||
errorModal.showRetryButton &&
|
||||
sendVPScreenController.openID4VPRetryCount < 3
|
||||
) {
|
||||
return t('ScanScreen:status.retry');
|
||||
@@ -366,8 +377,8 @@ export const ScanScreen: React.FC = () => {
|
||||
alignActionsOnEnd
|
||||
showClose={false}
|
||||
isVisible={showErrorModal}
|
||||
title={sendVPScreenController.errorModal.title}
|
||||
message={sendVPScreenController.errorModal.message}
|
||||
title={errorModal.title}
|
||||
message={errorModal.message}
|
||||
image={SvgImage.PermissionDenied()}
|
||||
primaryButtonTestID={'retry'}
|
||||
primaryButtonText={getPrimaryButtonText()}
|
||||
|
||||
@@ -32,19 +32,29 @@ import OpenID4VP from '../../shared/openID4VP/OpenID4VP';
|
||||
import {GlobalContext} from '../../shared/GlobalContext';
|
||||
import {APP_EVENTS} from '../../machines/app';
|
||||
import {useScanScreen} from './ScanScreenController';
|
||||
import {useOvpErrorModal} from '../../shared/hooks/useOvpErrorModal';
|
||||
|
||||
export const SendVPScreen: React.FC<ScanLayoutProps> = props => {
|
||||
const {t} = useTranslation('SendVPScreen');
|
||||
const controller = useSendVPScreen();
|
||||
const scanScreenController = useScanScreen();
|
||||
|
||||
const [errorModal, resetErrorModal] = useOvpErrorModal({
|
||||
error: controller.error,
|
||||
noCredentialsMatchingVPRequest: controller.noCredentialsMatchingVPRequest,
|
||||
requestedClaimsByVerifier: controller.requestedClaimsByVerifier,
|
||||
getAdditionalMessage: controller.getAdditionalMessage,
|
||||
generateAndStoreLogMessage: controller.generateAndStoreLogMessage,
|
||||
t,
|
||||
});
|
||||
|
||||
const vcsMatchingAuthRequest = controller.vcsMatchingAuthRequest;
|
||||
|
||||
const {appService} = useContext(GlobalContext);
|
||||
const [triggerExitFlow, setTriggerExitFlow] = useState(false);
|
||||
|
||||
useEffect(() => {
|
||||
if (controller.errorModal.show && controller.isOVPViaDeepLink) {
|
||||
if (errorModal.show && controller.isOVPViaDeepLink) {
|
||||
const timeout = setTimeout(
|
||||
() => {
|
||||
OpenID4VP.sendErrorToVerifier(
|
||||
@@ -58,11 +68,11 @@ export const SendVPScreen: React.FC<ScanLayoutProps> = props => {
|
||||
|
||||
return () => clearTimeout(timeout);
|
||||
}
|
||||
}, [controller.errorModal.show, controller.isOVPViaDeepLink]);
|
||||
}, [errorModal.show, controller.isOVPViaDeepLink]);
|
||||
|
||||
useEffect(() => {
|
||||
if (triggerExitFlow) {
|
||||
controller.RESET_LOGGED_ERROR();
|
||||
RESET_LOGGED_ERROR();
|
||||
controller.GO_TO_HOME();
|
||||
controller.RESET_RETRY_COUNT();
|
||||
appService.send(APP_EVENTS.RESET_AUTHORIZATION_REQUEST());
|
||||
@@ -106,11 +116,16 @@ export const SendVPScreen: React.FC<ScanLayoutProps> = props => {
|
||||
}
|
||||
});
|
||||
|
||||
const RESET_LOGGED_ERROR = () => {
|
||||
resetErrorModal();
|
||||
};
|
||||
|
||||
const handleDismiss = () => {
|
||||
OpenID4VP.sendErrorToVerifier(
|
||||
OVP_ERROR_MESSAGES.DECLINED,
|
||||
OVP_ERROR_CODE.DECLINED,
|
||||
);
|
||||
controller.generateAndStoreLogMessage('USER_DECLINED_CONSENT');
|
||||
if (controller.isOVPViaDeepLink) {
|
||||
controller.GO_TO_HOME();
|
||||
BackHandler.exitApp();
|
||||
@@ -124,6 +139,7 @@ export const SendVPScreen: React.FC<ScanLayoutProps> = props => {
|
||||
OVP_ERROR_MESSAGES.DECLINED,
|
||||
OVP_ERROR_CODE.DECLINED,
|
||||
);
|
||||
controller.generateAndStoreLogMessage('USER_DECLINED_CONSENT');
|
||||
if (controller.isOVPViaDeepLink) {
|
||||
controller.GO_TO_HOME();
|
||||
BackHandler.exitApp();
|
||||
@@ -135,12 +151,9 @@ export const SendVPScreen: React.FC<ScanLayoutProps> = props => {
|
||||
const getAdditionalMessage = () => {
|
||||
if (
|
||||
controller.isOVPViaDeepLink &&
|
||||
!(
|
||||
controller.errorModal.showRetryButton &&
|
||||
controller.openID4VPRetryCount < 3
|
||||
)
|
||||
!(errorModal.showRetryButton && controller.openID4VPRetryCount < 3)
|
||||
) {
|
||||
return controller.errorModal.additionalMessage;
|
||||
return errorModal.additionalMessage;
|
||||
}
|
||||
return undefined;
|
||||
};
|
||||
@@ -221,8 +234,7 @@ export const SendVPScreen: React.FC<ScanLayoutProps> = props => {
|
||||
};
|
||||
|
||||
const getPrimaryButtonText = () => {
|
||||
return controller.errorModal.showRetryButton &&
|
||||
controller.openID4VPRetryCount < 3
|
||||
return errorModal.showRetryButton && controller.openID4VPRetryCount < 3
|
||||
? t('ScanScreen:status.retry')
|
||||
: undefined;
|
||||
};
|
||||
@@ -417,14 +429,14 @@ export const SendVPScreen: React.FC<ScanLayoutProps> = props => {
|
||||
/>
|
||||
</>
|
||||
)}
|
||||
{controller.errorModal.show && (
|
||||
{errorModal.show && (
|
||||
<Error
|
||||
isModal
|
||||
alignActionsOnEnd
|
||||
showClose={false}
|
||||
isVisible={controller.errorModal.show}
|
||||
title={controller.errorModal.title}
|
||||
message={controller.errorModal.message}
|
||||
isVisible={errorModal.show}
|
||||
title={errorModal.title}
|
||||
message={errorModal.message}
|
||||
additionalMessage={getAdditionalMessage()}
|
||||
image={SvgImage.PermissionDenied()}
|
||||
primaryButtonTestID={'retry'}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import {NavigationProp, useNavigation} from '@react-navigation/native';
|
||||
import {useSelector} from '@xstate/react';
|
||||
import {useContext, useEffect, useRef, useState} from 'react';
|
||||
import {useCallback, useContext, useRef, useState} from 'react';
|
||||
import {useTranslation} from 'react-i18next';
|
||||
import {ActorRefFrom} from 'xstate';
|
||||
import {Theme} from '../../components/ui/styleUtils';
|
||||
@@ -151,208 +151,30 @@ export function useSendVPScreen() {
|
||||
selectIsOVPViaDeeplink,
|
||||
);
|
||||
|
||||
const getAdditionalMessage = () => {
|
||||
const getAdditionalMessage = useCallback(() => {
|
||||
return isOVPViaDeepLink && isIOS() ? t('errors.additionalMessage') : '';
|
||||
};
|
||||
}, [isOVPViaDeepLink, t]);
|
||||
|
||||
const generateAndStoreLogMessage = useCallback(
|
||||
(logType: string, errorInfo?: string) => {
|
||||
activityLogService.send(
|
||||
ActivityLogEvents.LOG_ACTIVITY(
|
||||
VPShareActivityLog.getLogFromObject({
|
||||
timestamp: Date.now(),
|
||||
type: logType,
|
||||
info: errorInfo,
|
||||
}),
|
||||
),
|
||||
);
|
||||
},
|
||||
[activityLogService],
|
||||
);
|
||||
|
||||
function generateAndStoreLogMessage(logType: string, errorInfo?: string) {
|
||||
activityLogService.send(
|
||||
ActivityLogEvents.LOG_ACTIVITY(
|
||||
VPShareActivityLog.getLogFromObject({
|
||||
timestamp: Date.now(),
|
||||
type: logType,
|
||||
info: errorInfo,
|
||||
}),
|
||||
),
|
||||
);
|
||||
}
|
||||
const requestedClaimsByVerifier = useSelector(
|
||||
openID4VPService,
|
||||
selectRequestedClaimsByVerifier,
|
||||
);
|
||||
|
||||
const [errorModal, setErrorModalData] = useState({
|
||||
show: false,
|
||||
title: '',
|
||||
message: '',
|
||||
additionalMessage: '',
|
||||
showRetryButton: false,
|
||||
});
|
||||
|
||||
const isClaimsEmpty =
|
||||
!requestedClaimsByVerifier || requestedClaimsByVerifier.trim() === '';
|
||||
if (noCredentialsMatchingVPRequest) {
|
||||
errorModal.title = isClaimsEmpty
|
||||
? t('errors.noMatchingCredentialsWithMissingClaims.title')
|
||||
: t('errors.noMatchingCredentials.title');
|
||||
errorModal.message = isClaimsEmpty
|
||||
? t('errors.noMatchingCredentialsWithMissingClaims.message')
|
||||
: t('errors.noMatchingCredentials.message', { claims: requestedClaimsByVerifier });
|
||||
generateAndStoreLogMessage(
|
||||
'NO_CREDENTIAL_MATCHING_REQUEST',
|
||||
requestedClaimsByVerifier,
|
||||
);
|
||||
} else if (
|
||||
error.includes('Verifier authentication was unsuccessful') ||
|
||||
error.startsWith('api error')
|
||||
) {
|
||||
errorModal.title = t('errors.invalidVerifier.title');
|
||||
errorModal.message = t('errors.invalidVerifier.message');
|
||||
generateAndStoreLogMessage('VERIFIER_AUTHENTICATION_FAILED');
|
||||
} else if (error.includes('credential mismatch detected')) {
|
||||
errorModal.title = t('errors.credentialsMismatch.title');
|
||||
errorModal.message = t('errors.credentialsMismatch.message', {
|
||||
claims: requestedClaimsByVerifier,
|
||||
});
|
||||
generateAndStoreLogMessage(
|
||||
'CREDENTIAL_MISMATCH_FROM_KEBAB',
|
||||
requestedClaimsByVerifier,
|
||||
);
|
||||
} else if (error.includes('none of the selected VC has image')) {
|
||||
errorModal.title = t('errors.noImage.title');
|
||||
errorModal.message = t('errors.noImage.message');
|
||||
generateAndStoreLogMessage('NO_SELECTED_VC_HAS_IMAGE');
|
||||
} else if (error.includes('invalid_request_uri_method')) {
|
||||
errorModal.title = t('errors.invalidRequestURI.title');
|
||||
errorModal.message = t('errors.invalidRequestURI.message');
|
||||
generateAndStoreLogMessage('INVALID_REQUEST_URI_METHOD');
|
||||
} else if (error.includes('invalid_request')) {
|
||||
errorModal.title = t('errors.invalidQrCode.title');
|
||||
errorModal.message = t('errors.invalidQrCode.message');
|
||||
generateAndStoreLogMessage('INVALID_AUTH_REQUEST');
|
||||
} else if (error.includes('vp_formats_not_supported')) {
|
||||
errorModal.title = t('errors.vpFormatsNotSupported.title');
|
||||
errorModal.message = t('errors.vpFormatsNotSupported.message');
|
||||
generateAndStoreLogMessage('VP_FORMATS_NOT_SUPPORTED');
|
||||
} else if (error.includes('invalid_presentation_definition_uri')) {
|
||||
errorModal.title = t('errors.invalidPresentationDefinitionURI.title');
|
||||
errorModal.message = t('errors.invalidPresentationDefinitionURI.message');
|
||||
generateAndStoreLogMessage('INVALID_PRESENTATION_DEFINITION_URI');
|
||||
} else if (error.includes('invalid_presentation_definition_reference')) {
|
||||
errorModal.title = t('errors.invalidPresentationDefinitionRef.title');
|
||||
errorModal.message = t('errors.invalidPresentationDefinitionRef.message');
|
||||
generateAndStoreLogMessage('INVALID_PRESENTATION_DEFINITION_REFERENCE');
|
||||
} else if (error.startsWith('send vp')) {
|
||||
errorModal.title = t('errors.sendVPError.title');
|
||||
errorModal.message = t('errors.sendVPError.message');
|
||||
errorModal.showRetryButton = true;
|
||||
} else if (error !== '') {
|
||||
errorModal.title = t('errors.genericError.title');
|
||||
errorModal.message = t('errors.genericError.message');
|
||||
generateAndStoreLogMessage('TECHNICAL_ERROR');
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
if (noCredentialsMatchingVPRequest && !hasLoggedErrorRef.current) {
|
||||
const isClaimsEmpty =
|
||||
!requestedClaimsByVerifier || requestedClaimsByVerifier.trim() === '';
|
||||
setErrorModalData({
|
||||
show: true,
|
||||
title: isClaimsEmpty
|
||||
? t('errors.noMatchingCredentialsWithMissingClaims.title')
|
||||
: t('errors.noMatchingCredentials.title'),
|
||||
message: isClaimsEmpty
|
||||
? t('errors.noMatchingCredentialsWithMissingClaims.message')
|
||||
: t('errors.noMatchingCredentials.message', {
|
||||
claims: requestedClaimsByVerifier,
|
||||
}),
|
||||
additionalMessage: getAdditionalMessage(),
|
||||
showRetryButton: false,
|
||||
});
|
||||
generateAndStoreLogMessage(
|
||||
'NO_CREDENTIAL_MATCHING_REQUEST',
|
||||
requestedClaimsByVerifier,
|
||||
);
|
||||
hasLoggedErrorRef.current = true;
|
||||
} else if (
|
||||
(error.includes('Verifier authentication was unsuccessful') ||
|
||||
error.startsWith('api error')) &&
|
||||
!hasLoggedErrorRef.current
|
||||
) {
|
||||
setErrorModalData({
|
||||
show: true,
|
||||
title: t('errors.invalidVerifier.title'),
|
||||
message: t('errors.invalidVerifier.message'),
|
||||
additionalMessage: getAdditionalMessage(),
|
||||
showRetryButton: false,
|
||||
});
|
||||
generateAndStoreLogMessage('VERIFIER_AUTHENTICATION_FAILED');
|
||||
hasLoggedErrorRef.current = true;
|
||||
} else if (
|
||||
error.includes('credential mismatch detected') &&
|
||||
!hasLoggedErrorRef.current
|
||||
) {
|
||||
setErrorModalData({
|
||||
show: true,
|
||||
title: t('errors.credentialsMismatch.title'),
|
||||
message: t('errors.credentialsMismatch.message', {
|
||||
claims: requestedClaimsByVerifier,
|
||||
}),
|
||||
additionalMessage: getAdditionalMessage(),
|
||||
showRetryButton: false,
|
||||
});
|
||||
generateAndStoreLogMessage(
|
||||
'CREDENTIAL_MISMATCH_FROM_KEBAB',
|
||||
requestedClaimsByVerifier,
|
||||
);
|
||||
hasLoggedErrorRef.current = true;
|
||||
} else if (
|
||||
error.includes('none of the selected VC has image') &&
|
||||
!hasLoggedErrorRef.current
|
||||
) {
|
||||
setErrorModalData({
|
||||
show: true,
|
||||
title: t('errors.noImage.title'),
|
||||
message: t('errors.noImage.message'),
|
||||
additionalMessage: getAdditionalMessage(),
|
||||
showRetryButton: false,
|
||||
});
|
||||
generateAndStoreLogMessage('NO_SELECTED_VC_HAS_IMAGE');
|
||||
hasLoggedErrorRef.current = true;
|
||||
} else if (
|
||||
error.startsWith('vc validation') &&
|
||||
!hasLoggedErrorRef.current
|
||||
) {
|
||||
setErrorModalData({
|
||||
show: true,
|
||||
title: t('errors.invalidQrCode.title'),
|
||||
message: t('errors.invalidQrCode.message'),
|
||||
additionalMessage: getAdditionalMessage(),
|
||||
showRetryButton: false,
|
||||
});
|
||||
generateAndStoreLogMessage('INVALID_AUTH_REQUEST');
|
||||
hasLoggedErrorRef.current = true;
|
||||
} else if (error.startsWith('send vp') && !hasLoggedErrorRef.current) {
|
||||
setErrorModalData({
|
||||
show: true,
|
||||
title: t('errors.genericError.title'),
|
||||
message: t('errors.genericError.message'),
|
||||
additionalMessage: getAdditionalMessage(),
|
||||
showRetryButton: true,
|
||||
});
|
||||
hasLoggedErrorRef.current = true;
|
||||
} else if (error !== '' && !hasLoggedErrorRef.current) {
|
||||
setErrorModalData({
|
||||
show: true,
|
||||
title: t('errors.genericError.title'),
|
||||
message: t('errors.genericError.message'),
|
||||
additionalMessage: getAdditionalMessage(),
|
||||
showRetryButton: false,
|
||||
});
|
||||
generateAndStoreLogMessage('TECHNICAL_ERROR');
|
||||
hasLoggedErrorRef.current = true;
|
||||
} else if (error === '') {
|
||||
setErrorModalData({
|
||||
show: false,
|
||||
title: '',
|
||||
message: '',
|
||||
additionalMessage: '',
|
||||
showRetryButton: false,
|
||||
});
|
||||
hasLoggedErrorRef.current = false;
|
||||
}
|
||||
}, [error, noCredentialsMatchingVPRequest]);
|
||||
|
||||
let overlayDetails: Omit<VPShareOverlayProps, 'isVisible'> | null = null;
|
||||
let vpVerifierName = useSelector(
|
||||
openID4VPService,
|
||||
@@ -401,18 +223,12 @@ export function useSendVPScreen() {
|
||||
checkIfAnyVCHasImage,
|
||||
checkIfAllVCsHasImage,
|
||||
getSelectedVCs,
|
||||
errorModal,
|
||||
error,
|
||||
noCredentialsMatchingVPRequest,
|
||||
requestedClaimsByVerifier,
|
||||
getAdditionalMessage,
|
||||
overlayDetails,
|
||||
RESET_LOGGED_ERROR: () => {
|
||||
hasLoggedErrorRef.current = false;
|
||||
setErrorModalData({
|
||||
show: false,
|
||||
title: '',
|
||||
message: '',
|
||||
additionalMessage: '',
|
||||
showRetryButton: false,
|
||||
});
|
||||
},
|
||||
generateAndStoreLogMessage,
|
||||
scanScreenError: useSelector(scanService, selectIsSendingVPError),
|
||||
vcsMatchingAuthRequest,
|
||||
userSelectedVCs: useSelector(openID4VPService, selectSelectedVCs),
|
||||
|
||||
Reference in New Issue
Block a user