From aa53709e0d3adb3737cf43d0e42407a5f03c6ede Mon Sep 17 00:00:00 2001 From: RiccardoMolinari95 Date: Mon, 23 Dec 2024 15:16:48 +0100 Subject: [PATCH] feat: reissuing eid --- locales/en/index.yml | 8 +++ locales/it/index.yml | 8 +++ .../ItwEidInfoBottomSheetContent.tsx | 2 +- .../components/ItwEidLifecycleAlert.tsx | 23 +++++- .../ItwIdentificationModeSelectionScreen.tsx | 25 +++++++ .../itwallet/machine/credential/actions.ts | 12 +++- ts/features/itwallet/machine/eid/actions.ts | 10 ++- ts/features/itwallet/machine/eid/context.ts | 4 +- ts/features/itwallet/machine/eid/events.ts | 7 +- ts/features/itwallet/machine/eid/machine.ts | 50 ++++++++++--- .../itwallet/navigation/ItwParamsList.ts | 4 +- .../itwallet/navigation/ItwStackNavigator.tsx | 5 ++ ts/features/itwallet/navigation/routes.ts | 3 +- .../screens/WalletCardOnboardingScreen.tsx | 20 ++++-- ...esentationEidVerificationExpiredScreen.tsx | 70 +++++++++++++++++++ .../components/WalletCardsContainer.tsx | 1 + 16 files changed, 226 insertions(+), 26 deletions(-) create mode 100644 ts/features/itwallet/presentation/screens/ItwPresentationEidVerificationExpiredScreen.tsx diff --git a/locales/en/index.yml b/locales/en/index.yml index 0351bdc8b29..85897442230 100644 --- a/locales/en/index.yml +++ b/locales/en/index.yml @@ -3475,6 +3475,7 @@ features: valid: L'ultima verifica è del {{date}}. expiring: Verifica la tua identità entro il {{date}}. expired: È necessario un rapido passaggio di verifica per continuare a usare Documenti su IO. + action: Inizia MDL: expiring: title: "Patente su IO: documento in scadenza" @@ -3528,6 +3529,13 @@ features: openPdf: "Show document" shareButton: Save or share fiscalCode: Your Fiscal Code + eid: + verificationExpired: + title: Verifica la tua identità + contentStart: "È un passaggio di sicurezza necessario per continuare ad usare " + contentBold: Documenti su IO + contentEnd: "." + primaryAction: Inizia trustmark: cta: Mostra certificato di autenticità description: Mostra il QR Code per attestare l’autenticità del documento quando ti viene richiesto. diff --git a/locales/it/index.yml b/locales/it/index.yml index 38adc05833c..134263cd930 100644 --- a/locales/it/index.yml +++ b/locales/it/index.yml @@ -3475,6 +3475,7 @@ features: valid: L'ultima verifica è del {{date}}. expiring: Verifica la tua identità entro il {{date}}. expired: È necessario un rapido passaggio di verifica per continuare a usare Documenti su IO. + action: Inizia MDL: expiring: title: "Patente su IO: documento in scadenza" @@ -3528,6 +3529,13 @@ features: openPdf: "Mostra documento" shareButton: Salva o condividi fiscalCode: Il tuo Codice Fiscale + eid: + verificationExpired: + title: Verifica la tua identità + contentStart: "È un passaggio di sicurezza necessario per continuare ad usare " + contentBold: Documenti su IO + contentEnd: "." + primaryAction: Inizia trustmark: cta: Mostra certificato di autenticità description: Mostra il QR Code per attestare l’autenticità del documento quando ti viene richiesto. diff --git a/ts/features/itwallet/common/components/ItwEidInfoBottomSheetContent.tsx b/ts/features/itwallet/common/components/ItwEidInfoBottomSheetContent.tsx index 16e950f72d4..a74e4839f52 100644 --- a/ts/features/itwallet/common/components/ItwEidInfoBottomSheetContent.tsx +++ b/ts/features/itwallet/common/components/ItwEidInfoBottomSheetContent.tsx @@ -96,7 +96,7 @@ const ItwEidInfoBottomSheetContent = ({ ))} - + = [ "valid", @@ -27,17 +29,28 @@ type Props = { * The eID statuses that will render the alert. */ lifecycleStatus?: Array; + navigation: ReturnType; }; /** * This component renders an alert that displays information on the eID status. */ export const ItwEidLifecycleAlert = ({ - lifecycleStatus = defaultLifecycleStatus + lifecycleStatus = defaultLifecycleStatus, + navigation }: Props) => { const eidOption = useIOSelector(itwCredentialsEidSelector); const maybeEidStatus = useIOSelector(itwCredentialsEidStatusSelector); + const startEidReissuing = () => { + navigation.navigate(ITW_ROUTES.MAIN, { + screen: ITW_ROUTES.IDENTIFICATION.MODE_SELECTION, + params: { + eidReissuing: true + } + }); + }; + const Content = ({ eid, eidStatus @@ -73,14 +86,18 @@ export const ItwEidLifecycleAlert = ({ { date: format(eid.jwt.expiration, "DD-MM-YYYY") } - ) + ), + action: I18n.t("features.itWallet.presentation.bottomSheets.eidInfo.alert.action"), + onPress: startEidReissuing }, jwtExpired: { testID: "itwEidLifecycleAlertTestID_jwtExpired", variant: "error", content: I18n.t( "features.itWallet.presentation.bottomSheets.eidInfo.alert.expired" - ) + ), + action: I18n.t("features.itWallet.presentation.bottomSheets.eidInfo.alert.action"), + onPress: startEidReissuing } }; diff --git a/ts/features/itwallet/identification/screens/ItwIdentificationModeSelectionScreen.tsx b/ts/features/itwallet/identification/screens/ItwIdentificationModeSelectionScreen.tsx index 419030f9b3e..8f104771961 100644 --- a/ts/features/itwallet/identification/screens/ItwIdentificationModeSelectionScreen.tsx +++ b/ts/features/itwallet/identification/screens/ItwIdentificationModeSelectionScreen.tsx @@ -17,6 +17,12 @@ import { import { itwDisabledIdentificationMethodsSelector } from "../../../../store/reducers/backendStatus/remoteConfig"; import { IOScrollViewWithLargeHeader } from "../../../../components/ui/IOScrollViewWithLargeHeader"; import { isCIEAuthenticationSupportedSelector } from "../../machine/eid/selectors"; +import { Route, useRoute } from "@react-navigation/native"; +import { ITW_ROUTES } from "../../navigation/routes"; + +export type ItwIdentificationModeSelectionScreenNavigationParams = { + eidReissuing?: boolean; +} | undefined; export const ItwIdentificationModeSelectionScreen = () => { const machineRef = ItwEidIssuanceMachineContext.useActorRef(); @@ -45,6 +51,25 @@ export const ItwIdentificationModeSelectionScreen = () => { [isCieAuthenticationSupported] ); + const route = + useRoute< + Route< + typeof ITW_ROUTES.IDENTIFICATION.MODE_SELECTION, + ItwIdentificationModeSelectionScreenNavigationParams + > + >(); + + + const { eidReissuing } = route.params || {}; + + useFocusEffect( + useCallback(() => { + if (eidReissuing) { + machineRef.send({ type: "start-reissuing" }); + } + }, [eidReissuing, machineRef]) + ); + useFocusEffect(trackItWalletIDMethod); const handleSpidPress = useCallback(() => { diff --git a/ts/features/itwallet/machine/credential/actions.ts b/ts/features/itwallet/machine/credential/actions.ts index f5f1eaf9990..734c2f4d9a8 100644 --- a/ts/features/itwallet/machine/credential/actions.ts +++ b/ts/features/itwallet/machine/credential/actions.ts @@ -101,7 +101,17 @@ export default ( CredentialIssuanceEvents >) => { assert(context.credential, "credential is undefined"); - store.dispatch(itwCredentialsStore([context.credential])); + + let cred = context.credential; + + cred = { + ...cred, + jwt: { + expiration: '2024-12-22T23:59:59Z', + } + }; + + store.dispatch(itwCredentialsStore([cred])); }, flagCredentialAsRequested: ({ diff --git a/ts/features/itwallet/machine/eid/actions.ts b/ts/features/itwallet/machine/eid/actions.ts index d7581cc2b7a..93bdaa4f4a1 100644 --- a/ts/features/itwallet/machine/eid/actions.ts +++ b/ts/features/itwallet/machine/eid/actions.ts @@ -184,7 +184,15 @@ export const createEidIssuanceActionsImplementation = ( context }: ActionArgs) => { assert(context.eid, "eID is undefined"); - store.dispatch(itwCredentialsStore([context.eid])); + + let eid = context.eid; + eid = { + ...eid, + jwt: { + expiration: '2024-12-22T23:59:59Z', + } + }; + store.dispatch(itwCredentialsStore([eid])); }, requestAssistance: () => {}, diff --git a/ts/features/itwallet/machine/eid/context.ts b/ts/features/itwallet/machine/eid/context.ts index be98c299ac2..b6e707c1ed2 100644 --- a/ts/features/itwallet/machine/eid/context.ts +++ b/ts/features/itwallet/machine/eid/context.ts @@ -41,6 +41,7 @@ export type Context = { authenticationContext: AuthenticationContext | undefined; eid: StoredCredential | undefined; failure: IssuanceFailure | undefined; + isReissuing: boolean; }; export const InitialContext: Context = { @@ -50,5 +51,6 @@ export const InitialContext: Context = { identification: undefined, authenticationContext: undefined, eid: undefined, - failure: undefined + failure: undefined, + isReissuing: false }; diff --git a/ts/features/itwallet/machine/eid/events.ts b/ts/features/itwallet/machine/eid/events.ts index 4868c1ac44b..e76b285e0af 100644 --- a/ts/features/itwallet/machine/eid/events.ts +++ b/ts/features/itwallet/machine/eid/events.ts @@ -82,6 +82,10 @@ export type ExternalErrorEvent = { error?: Error; }; +export type StartReissuing = { + type: "start-reissuing"; +}; + export type EidIssuanceEvents = | Reset | Start @@ -101,4 +105,5 @@ export type EidIssuanceEvents = | Abort | RevokeWalletInstance | ErrorActorEvent - | ExternalErrorEvent; + | ExternalErrorEvent + | StartReissuing; diff --git a/ts/features/itwallet/machine/eid/machine.ts b/ts/features/itwallet/machine/eid/machine.ts index 3da95b4605c..421ba67f436 100644 --- a/ts/features/itwallet/machine/eid/machine.ts +++ b/ts/features/itwallet/machine/eid/machine.ts @@ -71,7 +71,11 @@ export const itwEidIssuanceMachine = setup({ callbackUrl: event.authRedirectUrl } }; - }) + }), + setIsReissuing: assign(({ context }) => ({ + ...context, + isReissuing: true + })), }, actors: { createWalletInstance: fromPromise(notImplemented), @@ -92,7 +96,8 @@ export const itwEidIssuanceMachine = setup({ isSessionExpired: notImplemented, isOperationAborted: notImplemented, hasValidWalletInstanceAttestation: notImplemented, - isNFCEnabled: ({ context }) => context.cieContext?.isNFCEnabled || false + isNFCEnabled: ({ context }) => context.cieContext?.isNFCEnabled || false, + isReissuing: ({ context }) => context.isReissuing === true } }).createMachine({ id: "itwEidIssuanceMachine", @@ -121,6 +126,10 @@ export const itwEidIssuanceMachine = setup({ }, "revoke-wallet-instance": { target: "WalletInstanceRevocation" + }, + 'start-reissuing': { + target: "UserIdentification", + actions: "setIsReissuing" } } }, @@ -274,7 +283,15 @@ export const itwEidIssuanceMachine = setup({ target: "CieID" } ], - back: "#itwEidIssuanceMachine.IpzsPrivacyAcceptance" + back: [ + { + guard: "isReissuing", + target: "#itwEidIssuanceMachine.Idle" + }, + { + target: "#itwEidIssuanceMachine.IpzsPrivacyAcceptance", + } + ] } }, CieID: { @@ -554,14 +571,25 @@ export const itwEidIssuanceMachine = setup({ }, DisplayingPreview: { on: { - "add-to-wallet": { - actions: [ - "storeEidCredential", - "setWalletInstanceToValid", - "trackWalletInstanceCreation" - ], - target: "#itwEidIssuanceMachine.Success" - }, + "add-to-wallet": [ + { + guard: "isReissuing", + actions: [ + "storeEidCredential", + "setWalletInstanceToValid", + "trackWalletInstanceCreation", + "navigateToWallet" + ] + }, + { + actions: [ + "storeEidCredential", + "setWalletInstanceToValid", + "trackWalletInstanceCreation" + ], + target: "#itwEidIssuanceMachine.Success" + } + ], close: { actions: ["closeIssuance"] } diff --git a/ts/features/itwallet/navigation/ItwParamsList.ts b/ts/features/itwallet/navigation/ItwParamsList.ts index 3654b6fa7bd..5b90ba6e275 100644 --- a/ts/features/itwallet/navigation/ItwParamsList.ts +++ b/ts/features/itwallet/navigation/ItwParamsList.ts @@ -1,3 +1,4 @@ +import { ItwIdentificationModeSelectionScreenNavigationParams } from "../identification/screens/ItwIdentificationModeSelectionScreen"; import { ItwCieWrongCiePinScreenNavigationParams } from "../identification/screens/cie/ItwCieWrongCiePinScreen"; import { ItwIssuanceCredentialAsyncContinuationNavigationParams } from "../issuance/screens/ItwIssuanceCredentialAsyncContinuationScreen"; import { ItwPresentationCredentialAttachmentNavigationParams } from "../presentation/screens/ItwPresentationCredentialAttachmentScreen"; @@ -13,7 +14,7 @@ export type ItwParamsList = { [ITW_ROUTES.DISCOVERY.IPZS_PRIVACY]: undefined; [ITW_ROUTES.DISCOVERY.ALREADY_ACTIVE_SCREEN]: undefined; // IDENTIFICATION - [ITW_ROUTES.IDENTIFICATION.MODE_SELECTION]: undefined; + [ITW_ROUTES.IDENTIFICATION.MODE_SELECTION]: ItwIdentificationModeSelectionScreenNavigationParams; // IDENTIFICATION SPID [ITW_ROUTES.IDENTIFICATION.IDP_SELECTION]: undefined; [ITW_ROUTES.IDENTIFICATION.SPID.LOGIN]: undefined; @@ -46,6 +47,7 @@ export type ItwParamsList = { [ITW_ROUTES.PRESENTATION .CREDENTIAL_CARD_MODAL]: ItwPresentationCredentialCardModalNavigationParams; [ITW_ROUTES.PRESENTATION.CREDENTIAL_FISCAL_CODE_MODAL]: undefined; + [ITW_ROUTES.PRESENTATION.EID_VERIFICATION_EXPIRED]: undefined; // PLAYGROUNDS [ITW_ROUTES.PLAYGROUNDS]: undefined; [ITW_ROUTES.IDENTITY_NOT_MATCHING_SCREEN]: undefined; diff --git a/ts/features/itwallet/navigation/ItwStackNavigator.tsx b/ts/features/itwallet/navigation/ItwStackNavigator.tsx index 9be76c3d77d..86bd0f4a5bc 100644 --- a/ts/features/itwallet/navigation/ItwStackNavigator.tsx +++ b/ts/features/itwallet/navigation/ItwStackNavigator.tsx @@ -42,6 +42,7 @@ import { ItwCredentialTrustmarkScreen } from "../trustmark/screens/ItwCredential import { ItwAlreadyActiveScreen } from "../discovery/screens/ItwAlreadyActiveScreen"; import { ItwParamsList } from "./ItwParamsList"; import { ITW_ROUTES } from "./routes"; +import { ItwPresentationEidVerificationExpiredScreen } from "../presentation/screens/ItwPresentationEidVerificationExpiredScreen"; const Stack = createStackNavigator(); @@ -225,6 +226,10 @@ const InnerNavigator = () => { component={ItwLifecycleWalletRevocationScreen} options={{ headerShown: false, gestureEnabled: false }} /> + ); }; diff --git a/ts/features/itwallet/navigation/routes.ts b/ts/features/itwallet/navigation/routes.ts index 293a04cbba1..2bd5672b37b 100644 --- a/ts/features/itwallet/navigation/routes.ts +++ b/ts/features/itwallet/navigation/routes.ts @@ -42,7 +42,8 @@ export const ITW_ROUTES = { CREDENTIAL_TRUSTMARK: "ITW_PRESENTATION_CREDENTIAL_TRUSTMARK", CREDENTIAL_CARD_MODAL: "ITW_PRESENTATION_CREDENTIAL_CARD_MODAL", CREDENTIAL_FISCAL_CODE_MODAL: - "ITW_PRESENTATION_CREDENTIAL_FISCAL_CODE_MODAL" + "ITW_PRESENTATION_CREDENTIAL_FISCAL_CODE_MODAL", + EID_VERIFICATION_EXPIRED: "ITW_PRESENTATION_EID_VERIFICATION_EXPIRED", } as const, PLAYGROUNDS: "ITW_PLAYGROUNDS" as const, IDENTITY_NOT_MATCHING_SCREEN: "ITW_IDENTITY_NOT_MATCHING_SCREEN" as const, diff --git a/ts/features/itwallet/onboarding/screens/WalletCardOnboardingScreen.tsx b/ts/features/itwallet/onboarding/screens/WalletCardOnboardingScreen.tsx index 0efb8a6768f..af865e24658 100644 --- a/ts/features/itwallet/onboarding/screens/WalletCardOnboardingScreen.tsx +++ b/ts/features/itwallet/onboarding/screens/WalletCardOnboardingScreen.tsx @@ -41,6 +41,7 @@ import { } from "../../machine/credential/selectors"; import { ItwCredentialIssuanceMachineContext } from "../../machine/provider"; import { ItwOnboardingModuleCredential } from "../components/ItwOnboardingModuleCredential"; +import { ITW_ROUTES } from "../../navigation/routes"; // List of available credentials to show to the user const availableCredentials = [ @@ -100,13 +101,22 @@ const ItwCredentialOnboardingSection = () => { const itwCredentialsTypes = useIOSelector(itwCredentialsTypesSelector); + const isWalletValid = useIOSelector(itwLifecycleIsValidSelector); + const navigation = useIONavigation(); + const beginCredentialIssuance = useCallback( (type: string) => { - machineRef.send({ - type: "select-credential", - credentialType: type, - skipNavigation: true - }); + if (!isWalletValid) { + navigation.navigate(ITW_ROUTES.MAIN, { + screen: ITW_ROUTES.PRESENTATION.EID_VERIFICATION_EXPIRED + }); + } else { + machineRef.send({ + type: "select-credential", + credentialType: type, + skipNavigation: true + }); + } }, [machineRef] ); diff --git a/ts/features/itwallet/presentation/screens/ItwPresentationEidVerificationExpiredScreen.tsx b/ts/features/itwallet/presentation/screens/ItwPresentationEidVerificationExpiredScreen.tsx new file mode 100644 index 00000000000..acae9212856 --- /dev/null +++ b/ts/features/itwallet/presentation/screens/ItwPresentationEidVerificationExpiredScreen.tsx @@ -0,0 +1,70 @@ +import React, { useMemo } from "react"; +import { OperationResultScreenContent } from "../../../../components/screens/OperationResultScreenContent"; +import I18n from "../../../../i18n"; +import { useIONavigation } from "../../../../navigation/params/AppParamsList"; +import { useHeaderSecondLevel } from "../../../../hooks/useHeaderSecondLevel"; +import { BodyProps } from "@pagopa/io-app-design-system"; +import { ITW_ROUTES } from "../../navigation/routes"; + +export const ItwPresentationEidVerificationExpiredScreen = () => { + const navigation = useIONavigation(); + + useHeaderSecondLevel({ + title: "", + headerShown: false + }); + + const startEidReissuing = () => { + navigation.navigate(ITW_ROUTES.MAIN, { + screen: ITW_ROUTES.IDENTIFICATION.MODE_SELECTION, + params: { + eidReissuing: true + } + }); + }; + + const bodyPropsArray: Array = useMemo( + () => [ + { + text: I18n.t("features.itWallet.presentation.eid.verificationExpired.contentStart"), + style: { + textAlign: "center" + } + }, + { + text: I18n.t("features.itWallet.presentation.eid.verificationExpired.contentBold"), + style: { + textAlign: "center", + fontWeight: "bold" + } + }, + { + text: I18n.t("features.itWallet.presentation.eid.verificationExpired.contentEnd"), + style: { + textAlign: "center" + } + } + ], + [] + ); + + return ( + navigation.goBack() + }} + /> + ); +}; diff --git a/ts/features/wallet/components/WalletCardsContainer.tsx b/ts/features/wallet/components/WalletCardsContainer.tsx index 394dc54ee19..19881346766 100644 --- a/ts/features/wallet/components/WalletCardsContainer.tsx +++ b/ts/features/wallet/components/WalletCardsContainer.tsx @@ -161,6 +161,7 @@ const ItwWalletCardsContainer = () => { }