diff --git a/locales/en/index.yml b/locales/en/index.yml
index f6f9424d41c..7d05de37121 100644
--- a/locales/en/index.yml
+++ b/locales/en/index.yml
@@ -3494,6 +3494,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"
@@ -3549,6 +3550,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
statusAttestationUnknown:
title: Non siamo riusciti a caricare {{credentialName}}
content: Chiudi e riapri l'app per riprovare.
diff --git a/locales/it/index.yml b/locales/it/index.yml
index 1525b138425..326db19474a 100644
--- a/locales/it/index.yml
+++ b/locales/it/index.yml
@@ -3494,6 +3494,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"
@@ -3549,6 +3550,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
statusAttestationUnknown:
title: Non siamo riusciti a caricare {{credentialName}}
content: Chiudi e riapri l'app per riprovare.
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,22 @@ 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 153775d6aa9..646d1932fc7 100644
--- a/ts/features/itwallet/identification/screens/ItwIdentificationModeSelectionScreen.tsx
+++ b/ts/features/itwallet/identification/screens/ItwIdentificationModeSelectionScreen.tsx
@@ -16,9 +16,20 @@ import {
} from "../../analytics";
import { IOScrollViewWithLargeHeader } from "../../../../components/ui/IOScrollViewWithLargeHeader";
import { isCIEAuthenticationSupportedSelector } from "../../machine/eid/selectors";
+import { IOStackNavigationRouteProps } from "../../../../navigation/params/AppParamsList";
+import { ItwParamsList } from "../../navigation/ItwParamsList";
import { itwDisabledIdentificationMethodsSelector } from "../../common/store/selectors/remoteConfig";
-export const ItwIdentificationModeSelectionScreen = () => {
+export type ItwIdentificationModeSelectionScreenNavigationParams = {
+ eidReissuing?: boolean;
+};
+
+type ScreenProps = IOStackNavigationRouteProps<
+ ItwParamsList,
+ "ITW_IDENTIFICATION_MODE_SELECTION"
+>;
+
+export const ItwIdentificationModeSelectionScreen = (params: ScreenProps) => {
const machineRef = ItwEidIssuanceMachineContext.useActorRef();
const isCieAuthenticationSupported = ItwEidIssuanceMachineContext.useSelector(
isCIEAuthenticationSupportedSelector
@@ -45,6 +56,16 @@ export const ItwIdentificationModeSelectionScreen = () => {
[isCieAuthenticationSupported]
);
+ const { eidReissuing } = params.route.params;
+
+ useFocusEffect(
+ useCallback(() => {
+ if (eidReissuing) {
+ machineRef.send({ type: "start-reissuing" });
+ }
+ }, [eidReissuing, machineRef])
+ );
+
useFocusEffect(trackItWalletIDMethod);
const handleSpidPress = useCallback(() => {
diff --git a/ts/features/itwallet/identification/screens/__tests__/ItwIdentificationModeSelectionScreen.test.tsx b/ts/features/itwallet/identification/screens/__tests__/ItwIdentificationModeSelectionScreen.test.tsx
index 6ed8b90582c..83d026db21d 100644
--- a/ts/features/itwallet/identification/screens/__tests__/ItwIdentificationModeSelectionScreen.test.tsx
+++ b/ts/features/itwallet/identification/screens/__tests__/ItwIdentificationModeSelectionScreen.test.tsx
@@ -15,6 +15,8 @@ import { ItwEidIssuanceMachineContext } from "../../../machine/provider";
import { itwEidIssuanceMachine } from "../../../machine/eid/machine";
import { ItwLifecycleState } from "../../../lifecycle/store/reducers";
import { ToolEnum } from "../../../../../../definitions/content/AssistanceToolConfig";
+import { IOStackNavigationProp } from "../../../../../navigation/params/AppParamsList";
+import { ItwParamsList } from "../../../navigation/ItwParamsList";
jest.mock("../../../../../config", () => ({
itwEnabled: true
@@ -128,10 +130,29 @@ describe("ItwIdentificationModeSelectionScreen", () => {
}
});
+ const mockNavigation = new Proxy(
+ {},
+ {
+ get: _ => jest.fn()
+ }
+ ) as unknown as IOStackNavigationProp<
+ ItwParamsList,
+ "ITW_IDENTIFICATION_MODE_SELECTION"
+ >;
+
+ const route = {
+ key: "ITW_IDENTIFICATION_MODE_SELECTION",
+ name: ITW_ROUTES.IDENTIFICATION.MODE_SELECTION,
+ params: {}
+ };
+
return renderScreenWithNavigationStoreContext(
() => (
-
+
),
ITW_ROUTES.IDENTIFICATION.MODE_SELECTION,
diff --git a/ts/features/itwallet/machine/credential/__tests__/machine.test.ts b/ts/features/itwallet/machine/credential/__tests__/machine.test.ts
index 3b02a20a98f..ff6f4fc3a44 100644
--- a/ts/features/itwallet/machine/credential/__tests__/machine.test.ts
+++ b/ts/features/itwallet/machine/credential/__tests__/machine.test.ts
@@ -126,6 +126,8 @@ describe("itwCredentialIssuanceMachine", () => {
const isDeferredIssuance = jest.fn();
const hasValidWalletInstanceAttestation = jest.fn();
const isStatusError = jest.fn();
+ const isSkipNavigation = jest.fn();
+ const isWalletValid = jest.fn();
const mockedMachine = itwCredentialIssuanceMachine.provide({
actions: {
@@ -163,13 +165,17 @@ describe("itwCredentialIssuanceMachine", () => {
isSessionExpired,
isDeferredIssuance,
hasValidWalletInstanceAttestation,
- isStatusError
+ isStatusError,
+ isSkipNavigation,
+ isWalletValid
}
});
beforeEach(() => {
onInit.mockImplementation(() => ({ walletInstanceAttestation: undefined }));
hasValidWalletInstanceAttestation.mockImplementation(() => false);
+ isWalletValid.mockImplementation(() => true);
+ isSkipNavigation.mockImplementation(() => true);
});
afterEach(() => {
@@ -595,6 +601,7 @@ describe("itwCredentialIssuanceMachine", () => {
actor.start();
await waitFor(() => expect(onInit).toHaveBeenCalledTimes(1));
+ isSkipNavigation.mockImplementation(() => false);
requestCredential.mockImplementation(() =>
Promise.resolve({
diff --git a/ts/features/itwallet/machine/credential/actions.ts b/ts/features/itwallet/machine/credential/actions.ts
index ee43befc3b9..6ac21142d04 100644
--- a/ts/features/itwallet/machine/credential/actions.ts
+++ b/ts/features/itwallet/machine/credential/actions.ts
@@ -73,6 +73,12 @@ export default (
});
},
+ navigateToEidVerificationExpiredScreen: () => {
+ navigation.navigate(ITW_ROUTES.MAIN, {
+ screen: ITW_ROUTES.PRESENTATION.EID_VERIFICATION_EXPIRED
+ });
+ },
+
closeIssuance: () => {
navigation.popToTop();
},
diff --git a/ts/features/itwallet/machine/credential/guards.ts b/ts/features/itwallet/machine/credential/guards.ts
index 3104fbc5d6f..0ff06d45522 100644
--- a/ts/features/itwallet/machine/credential/guards.ts
+++ b/ts/features/itwallet/machine/credential/guards.ts
@@ -2,24 +2,36 @@ import { pipe } from "fp-ts/lib/function";
import * as O from "fp-ts/lib/Option";
import { ItwSessionExpiredError } from "../../api/client";
import { isWalletInstanceAttestationValid } from "../../common/utils/itwAttestationUtils";
+import { useIOStore } from "../../../../store/hooks";
+import { itwLifecycleIsValidSelector } from "../../lifecycle/store/selectors";
import { Context } from "./context";
import { CredentialIssuanceEvents } from "./events";
import { CredentialIssuanceFailureType } from "./failure";
-export const createCredentialIssuanceGuardsImplementation = () => ({
- isSessionExpired: ({ event }: { event: CredentialIssuanceEvents }) =>
- "error" in event && event.error instanceof ItwSessionExpiredError,
+export const createCredentialIssuanceGuardsImplementation = () => {
+ // eslint-disable-next-line react-hooks/rules-of-hooks
+ const store = useIOStore();
- isDeferredIssuance: ({ context }: { context: Context }) =>
- context.failure?.type === CredentialIssuanceFailureType.ASYNC_ISSUANCE,
+ return {
+ isSessionExpired: ({ event }: { event: CredentialIssuanceEvents }) =>
+ "error" in event && event.error instanceof ItwSessionExpiredError,
- hasValidWalletInstanceAttestation: ({ context }: { context: Context }) =>
- pipe(
- O.fromNullable(context.walletInstanceAttestation),
- O.map(isWalletInstanceAttestationValid),
- O.getOrElse(() => false)
- ),
+ isDeferredIssuance: ({ context }: { context: Context }) =>
+ context.failure?.type === CredentialIssuanceFailureType.ASYNC_ISSUANCE,
- isStatusError: ({ context }: { context: Context }) =>
- context.failure?.type === CredentialIssuanceFailureType.INVALID_STATUS
-});
+ hasValidWalletInstanceAttestation: ({ context }: { context: Context }) =>
+ pipe(
+ O.fromNullable(context.walletInstanceAttestation),
+ O.map(isWalletInstanceAttestationValid),
+ O.getOrElse(() => false)
+ ),
+
+ isStatusError: ({ context }: { context: Context }) =>
+ context.failure?.type === CredentialIssuanceFailureType.INVALID_STATUS,
+
+ isSkipNavigation: ({ event }: { event: CredentialIssuanceEvents }) =>
+ event.type === "select-credential" && event.skipNavigation === true,
+
+ isWalletValid: () => itwLifecycleIsValidSelector(store.getState())
+ };
+};
diff --git a/ts/features/itwallet/machine/credential/machine.ts b/ts/features/itwallet/machine/credential/machine.ts
index beacfbffc9b..ee1facbf38d 100644
--- a/ts/features/itwallet/machine/credential/machine.ts
+++ b/ts/features/itwallet/machine/credential/machine.ts
@@ -1,4 +1,4 @@
-import { assign, fromPromise, not, setup } from "xstate";
+import { and, assign, fromPromise, not, setup } from "xstate";
import { StoredCredential } from "../../common/utils/itwTypesUtils";
import { ItwTags } from "../tags";
import {
@@ -28,6 +28,7 @@ export const itwCredentialIssuanceMachine = setup({
navigateToCredentialPreviewScreen: notImplemented,
navigateToFailureScreen: notImplemented,
navigateToWallet: notImplemented,
+ navigateToEidVerificationExpiredScreen: notImplemented,
closeIssuance: notImplemented,
storeWalletInstanceAttestation: notImplemented,
storeCredential: notImplemented,
@@ -58,7 +59,9 @@ export const itwCredentialIssuanceMachine = setup({
isSessionExpired: notImplemented,
isDeferredIssuance: notImplemented,
hasValidWalletInstanceAttestation: notImplemented,
- isStatusError: notImplemented
+ isStatusError: notImplemented,
+ isWalletValid: notImplemented,
+ isSkipNavigation: notImplemented
}
}).createMachine({
id: "itwCredentialIssuanceMachine",
@@ -72,7 +75,12 @@ export const itwCredentialIssuanceMachine = setup({
on: {
"select-credential": [
{
- guard: ({ event }) => event.skipNavigation === true,
+ guard: and([not("isWalletValid"), "isSkipNavigation"]),
+ actions: "navigateToEidVerificationExpiredScreen",
+ target: "Idle"
+ },
+ {
+ guard: "isSkipNavigation",
target: "CheckingWalletInstanceAttestation",
actions: [
assign(({ event }) => ({
diff --git a/ts/features/itwallet/machine/eid/__tests__/machine.test.ts b/ts/features/itwallet/machine/eid/__tests__/machine.test.ts
index 751df57822b..563cc138e69 100644
--- a/ts/features/itwallet/machine/eid/__tests__/machine.test.ts
+++ b/ts/features/itwallet/machine/eid/__tests__/machine.test.ts
@@ -94,7 +94,10 @@ describe("itwEidIssuanceMachine", () => {
resetWalletInstance,
trackWalletInstanceCreation,
trackWalletInstanceRevocation,
- onInit: assign(onInit)
+ onInit: assign(onInit),
+ setIsReissuing: assign({
+ isReissuing: true
+ })
},
actors: {
createWalletInstance: fromPromise(createWalletInstance),
@@ -985,6 +988,185 @@ describe("itwEidIssuanceMachine", () => {
expect(actor.getSnapshot().value).toStrictEqual("Idle");
});
+ it("Should obtain an eID (SPID), reissuing mode", async () => {
+ // The wallet instance and attestation already exist
+ const initialContext = {
+ ...InitialContext,
+ integrityKeyTag: T_INTEGRITY_KEY,
+ walletInstanceAttestation: T_WIA
+ };
+
+ const actor = createActor(mockedMachine);
+ actor.start();
+
+ // eslint-disable-next-line functional/immutable-data
+ actor.getSnapshot().context = initialContext;
+
+ hasValidWalletInstanceAttestation.mockImplementation(() => true);
+
+ await waitFor(() => expect(onInit).toHaveBeenCalledTimes(1));
+
+ expect(actor.getSnapshot().value).toStrictEqual("Idle");
+ expect(actor.getSnapshot().tags).toStrictEqual(new Set());
+
+ actor.send({ type: "start-reissuing" });
+
+ expect(actor.getSnapshot().value).toStrictEqual({
+ UserIdentification: "ModeSelection"
+ });
+
+ expect(actor.getSnapshot().context).toStrictEqual({
+ ...initialContext,
+ isReissuing: true
+ });
+
+ /**
+ * Choose SPID as identification mode
+ */
+
+ actor.send({ type: "select-identification-mode", mode: "spid" });
+
+ expect(actor.getSnapshot().value).toStrictEqual({
+ UserIdentification: {
+ Spid: "IdpSelection"
+ }
+ });
+ expect(actor.getSnapshot().tags).toStrictEqual(new Set());
+ expect(navigateToIdpSelectionScreen).toHaveBeenCalledTimes(1);
+
+ /**
+ * Choose first IDP in list for SPID identification
+ */
+
+ startAuthFlow.mockImplementation(() => Promise.resolve({}));
+
+ requestEid.mockImplementation(() =>
+ Promise.resolve(ItwStoredCredentialsMocks.eid)
+ );
+
+ issuedEidMatchesAuthenticatedUser.mockImplementation(() => true);
+
+ actor.send({ type: "select-spid-idp", idp: idps[0] });
+
+ expect(actor.getSnapshot().value).toStrictEqual({
+ UserIdentification: {
+ Spid: "StartingSpidAuthFlow"
+ }
+ });
+
+ expect(actor.getSnapshot().context).toStrictEqual({
+ ...initialContext,
+ integrityKeyTag: T_INTEGRITY_KEY,
+ walletInstanceAttestation: T_WIA,
+ isReissuing: true,
+ identification: {
+ mode: "spid",
+ idpId: idps[0].id
+ }
+ });
+
+ expect(actor.getSnapshot().tags).toStrictEqual(new Set([ItwTags.Loading]));
+
+ await waitFor(() => expect(startAuthFlow).toHaveBeenCalledTimes(1));
+
+ expect(actor.getSnapshot().value).toStrictEqual({
+ UserIdentification: {
+ Spid: "CompletingSpidAuthFlow"
+ }
+ });
+
+ actor.send({
+ type: "user-identification-completed",
+ authRedirectUrl: "http://test.it"
+ });
+
+ expect(actor.getSnapshot().value).toStrictEqual({
+ Issuance: "RequestingEid"
+ });
+
+ expect(actor.getSnapshot().tags).toStrictEqual(new Set([ItwTags.Loading]));
+ expect(actor.getSnapshot().context).toMatchObject({
+ authenticationContext: {
+ callbackUrl: "http://test.it"
+ }
+ });
+ expect(navigateToEidPreviewScreen).toHaveBeenCalledTimes(1);
+
+ // EID obtained
+
+ // eslint-disable-next-line sonarjs/no-identical-functions
+ await waitFor(() =>
+ expect(actor.getSnapshot().value).toStrictEqual({
+ Issuance: "DisplayingPreview"
+ })
+ );
+
+ actor.send({ type: "add-to-wallet" });
+
+ expect(storeEidCredential).toHaveBeenCalledTimes(1);
+ expect(setWalletInstanceToValid).toHaveBeenCalledTimes(1);
+ expect(navigateToWallet).toHaveBeenCalledTimes(1);
+
+ expect(actor.getSnapshot().context).toStrictEqual({
+ ...initialContext,
+ integrityKeyTag: T_INTEGRITY_KEY,
+ walletInstanceAttestation: T_WIA,
+ isReissuing: true,
+ identification: {
+ mode: "spid",
+ idpId: idps[0].id
+ },
+ authenticationContext: expect.objectContaining({
+ callbackUrl: "http://test.it"
+ }),
+ eid: ItwStoredCredentialsMocks.eid
+ });
+ });
+
+ it("Should go back to Idle state if isReissuing is true", async () => {
+ const initialSnapshot: MachineSnapshot = createActor(
+ itwEidIssuanceMachine
+ ).getSnapshot();
+
+ const snapshot: MachineSnapshot = _.merge(undefined, initialSnapshot, {
+ value: { UserIdentification: "ModeSelection" },
+ context: {
+ isReissuing: true
+ }
+ } as MachineSnapshot);
+
+ const actor = createActor(mockedMachine, {
+ snapshot
+ });
+ actor.start();
+
+ actor.send({ type: "back" });
+
+ expect(actor.getSnapshot().value).toStrictEqual("Idle");
+ });
+
+ it("Should go back to IpzsPrivacyAcceptance state if isReissuing is false", async () => {
+ const initialSnapshot: MachineSnapshot = createActor(
+ itwEidIssuanceMachine
+ ).getSnapshot();
+
+ const snapshot: MachineSnapshot = _.merge(undefined, initialSnapshot, {
+ value: { UserIdentification: "ModeSelection" },
+ context: {
+ isReissuing: false
+ }
+ } as MachineSnapshot);
+
+ const actor = createActor(mockedMachine, {
+ snapshot
+ });
+ actor.start();
+
+ actor.send({ type: "back" });
+
+ expect(actor.getSnapshot().value).toStrictEqual("IpzsPrivacyAcceptance");
+ });
+
it("should cleanup integrity key tag and fail when obtaining Wallet Instance Attestation fails", async () => {
const actor = createActor(mockedMachine);
actor.start();
diff --git a/ts/features/itwallet/machine/eid/actions.ts b/ts/features/itwallet/machine/eid/actions.ts
index 2572a537d9f..f25376362a7 100644
--- a/ts/features/itwallet/machine/eid/actions.ts
+++ b/ts/features/itwallet/machine/eid/actions.ts
@@ -49,7 +49,8 @@ export const createEidIssuanceActionsImplementation = (
navigateToIdentificationModeScreen: () => {
navigation.navigate(ITW_ROUTES.MAIN, {
- screen: ITW_ROUTES.IDENTIFICATION.MODE_SELECTION
+ screen: ITW_ROUTES.IDENTIFICATION.MODE_SELECTION,
+ params: { eidReissuing: false }
});
},
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 1d381db258f..cb4c8a62619 100644
--- a/ts/features/itwallet/machine/eid/machine.ts
+++ b/ts/features/itwallet/machine/eid/machine.ts
@@ -1,5 +1,5 @@
import _ from "lodash";
-import { assertEvent, assign, fromPromise, not, setup } from "xstate";
+import { assertEvent, assign, fromPromise, not, setup, and } from "xstate";
import { assert } from "../../../../utils/assert";
import { StoredCredential } from "../../common/utils/itwTypesUtils";
import { ItwTags } from "../tags";
@@ -72,7 +72,11 @@ export const itwEidIssuanceMachine = setup({
callbackUrl: event.authRedirectUrl
}
};
- })
+ }),
+ setIsReissuing: assign(({ context }) => ({
+ ...context,
+ isReissuing: true
+ }))
},
actors: {
createWalletInstance: fromPromise(notImplemented),
@@ -93,7 +97,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",
@@ -122,7 +127,18 @@ export const itwEidIssuanceMachine = setup({
},
"revoke-wallet-instance": {
target: "WalletInstanceRevocation"
- }
+ },
+ "start-reissuing": [
+ {
+ guard: not("hasValidWalletInstanceAttestation"),
+ actions: "setIsReissuing",
+ target: "WalletInstanceAttestationObtainment"
+ },
+ {
+ actions: "setIsReissuing",
+ target: "UserIdentification"
+ }
+ ]
}
},
TosAcceptance: {
@@ -210,16 +226,33 @@ export const itwEidIssuanceMachine = setup({
invoke: {
src: "getWalletAttestation",
input: ({ context }) => ({ integrityKeyTag: context.integrityKeyTag }),
- onDone: {
- actions: [
- assign(({ event }) => ({
- walletInstanceAttestation: event.output
- })),
- { type: "storeWalletInstanceAttestation" }
- ],
- target: "IpzsPrivacyAcceptance"
- },
+ onDone: [
+ {
+ guard: "isReissuing",
+ actions: [
+ assign(({ event }) => ({
+ walletInstanceAttestation: event.output
+ })),
+ { type: "storeWalletInstanceAttestation" }
+ ],
+ target: "UserIdentification"
+ },
+ {
+ actions: [
+ assign(({ event }) => ({
+ walletInstanceAttestation: event.output
+ })),
+ { type: "storeWalletInstanceAttestation" }
+ ],
+ target: "IpzsPrivacyAcceptance"
+ }
+ ],
onError: [
+ {
+ guard: and(["isReissuing", "isSessionExpired"]),
+ actions: ["handleSessionExpired", "closeIssuance"],
+ target: "#itwEidIssuanceMachine.Idle"
+ },
{
guard: "isSessionExpired",
actions: "handleSessionExpired",
@@ -275,7 +308,15 @@ export const itwEidIssuanceMachine = setup({
target: "CieID"
}
],
- back: "#itwEidIssuanceMachine.IpzsPrivacyAcceptance"
+ back: [
+ {
+ guard: "isReissuing",
+ target: "#itwEidIssuanceMachine.Idle"
+ },
+ {
+ target: "#itwEidIssuanceMachine.IpzsPrivacyAcceptance"
+ }
+ ]
}
},
CieID: {
@@ -555,14 +596,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..ec1722a7e4c 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,8 @@ 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 +48,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 ebbf4174a5b..8bcc5cf073f 100644
--- a/ts/features/itwallet/navigation/ItwStackNavigator.tsx
+++ b/ts/features/itwallet/navigation/ItwStackNavigator.tsx
@@ -40,6 +40,7 @@ import ItwCieIdLoginScreen from "../identification/screens/cieId/ItwCieIdLoginSc
import { ItwPresentationCredentialFiscalCodeModal } from "../presentation/screens/ItwPresentationCredentialFiscalCodeModal";
import { ItwCredentialTrustmarkScreen } from "../trustmark/screens/ItwCredentialTrustmarkScreen";
import { ItwAlreadyActiveScreen } from "../discovery/screens/ItwAlreadyActiveScreen";
+import { ItwPresentationEidVerificationExpiredScreen } from "../presentation/screens/ItwPresentationEidVerificationExpiredScreen";
import { ItwParamsList } from "./ItwParamsList";
import { ITW_ROUTES } from "./routes";
@@ -225,6 +226,11 @@ 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..6315e98c88b 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/presentation/screens/ItwPresentationEidVerificationExpiredScreen.tsx b/ts/features/itwallet/presentation/screens/ItwPresentationEidVerificationExpiredScreen.tsx
new file mode 100644
index 00000000000..f4d4b072186
--- /dev/null
+++ b/ts/features/itwallet/presentation/screens/ItwPresentationEidVerificationExpiredScreen.tsx
@@ -0,0 +1,70 @@
+import React, { useMemo } from "react";
+import { BodyProps } from "@pagopa/io-app-design-system";
+import { OperationResultScreenContent } from "../../../../components/screens/OperationResultScreenContent";
+import I18n from "../../../../i18n";
+import { useIONavigation } from "../../../../navigation/params/AppParamsList";
+import { ITW_ROUTES } from "../../navigation/routes";
+
+export const ItwPresentationEidVerificationExpiredScreen = () => {
+ const navigation = useIONavigation();
+
+ 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 e045750bf7d..d3b0b1faa5b 100644
--- a/ts/features/wallet/components/WalletCardsContainer.tsx
+++ b/ts/features/wallet/components/WalletCardsContainer.tsx
@@ -176,6 +176,7 @@ const ItwWalletCardsContainer = withWalletCategoryFilter("itw", () => {
>
}