Skip to content

Commit

Permalink
chore: handle trustmark QR code generation failures
Browse files Browse the repository at this point in the history
  • Loading branch information
mastro993 committed Dec 17, 2024
1 parent 10f4351 commit d5defad
Show file tree
Hide file tree
Showing 10 changed files with 87 additions and 15 deletions.
6 changes: 5 additions & 1 deletion ts/components/QrCodeImage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ export type QrCodeImageProps = {
correctionLevel?: QRCodeProps["ecl"];
// Accessibility
accessibilityLabel?: string;
// Callback to handle the error if the QR Code generation fails
onError?: (error: Error) => void;
};

const defaultAccessibilityLabel = "QR Code";
Expand All @@ -27,7 +29,8 @@ const QrCodeImage = ({
size = 200,
backgroundColor,
correctionLevel = "H",
accessibilityLabel = defaultAccessibilityLabel
accessibilityLabel = defaultAccessibilityLabel,
onError
}: QrCodeImageProps) => {
const { width } = useWindowDimensions();
const realSize = React.useMemo<number>(() => {
Expand All @@ -49,6 +52,7 @@ const QrCodeImage = ({
size={realSize}
ecl={correctionLevel}
backgroundColor={backgroundColor}
onError={onError}
/>
</View>
) : (
Expand Down
13 changes: 10 additions & 3 deletions ts/features/itwallet/trustmark/machine/actions.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { useIOToast } from "@pagopa/io-app-design-system";
import * as O from "fp-ts/lib/Option";
import { AnyEventObject, assign } from "xstate";
import { useIONavigation } from "../../../../navigation/params/AppParamsList";
Expand All @@ -6,15 +7,17 @@ import { useIOStore } from "../../../../store/hooks";
import { itwCredentialByTypeSelector } from "../../credentials/store/selectors";
import { itwWalletInstanceAttestationSelector } from "../../walletInstance/store/reducers";
import { Context } from "./context";
import { TrustmarkEvents } from "./events";

export const createItwTrustmarkActionsImplementation = (
store: ReturnType<typeof useIOStore>,
navigation: ReturnType<typeof useIONavigation>
navigation: ReturnType<typeof useIONavigation>,
toast: ReturnType<typeof useIOToast>
) => {
/**
* Initializes the trustmark machine
*/
const onInit = assign<Context, AnyEventObject, unknown, { type: "" }, any>(
const onInit = assign<Context, AnyEventObject, unknown, TrustmarkEvents, any>(
({ context }) => ({
walletInstanceAttestation: itwWalletInstanceAttestationSelector(
store.getState()
Expand All @@ -33,5 +36,9 @@ export const createItwTrustmarkActionsImplementation = (
navigation.pop();
};

return { onInit, handleSessionExpired };
const showFailureToast = () => {
toast.error("Errore");
};

return { onInit, handleSessionExpired, showFailureToast };
};
6 changes: 3 additions & 3 deletions ts/features/itwallet/trustmark/machine/actors.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import { useIOStore } from "../../../../store/hooks";
import { sessionTokenSelector } from "../../../../store/reducers/authentication";
import { assert } from "../../../../utils/assert";
import * as itwAttestationUtils from "../../common/utils/itwAttestationUtils";
import { getCredentialTrustmark } from "../../common/utils/itwTrustmarkUtils";
import * as itwTrustmarkUtils from "../../common/utils/itwTrustmarkUtils";
import { StoredCredential } from "../../common/utils/itwTypesUtils";
import { itwIntegrityKeyTagSelector } from "../../issuance/store/selectors";
import { itwWalletInstanceAttestationStore } from "../../walletInstance/store/actions";
Expand All @@ -20,7 +20,7 @@ export type GetCredentialTrustmarkUrlActorInput = {
};

export type GetCredentialTrustmarkUrlActorOutput = Awaited<
ReturnType<typeof getCredentialTrustmark>
ReturnType<typeof itwTrustmarkUtils.getCredentialTrustmark>
>;

/**
Expand Down Expand Up @@ -69,7 +69,7 @@ export const createItwTrustmarkActorsImplementation = (
assert(input.credential, "credential is undefined");

// Generate trustmark url to be presented
return await getCredentialTrustmark(
return await itwTrustmarkUtils.getCredentialTrustmark(
input.walletInstanceAttestation,
input.credential,
itwEaaVerifierBaseUrl
Expand Down
5 changes: 5 additions & 0 deletions ts/features/itwallet/trustmark/machine/context.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { StoredCredential } from "../../common/utils/itwTypesUtils";
import { TrustmarkFailure } from "./failure";

export type Context = {
/**
Expand All @@ -25,4 +26,8 @@ export type Context = {
* The trustmark url
*/
trustmarkUrl?: string;
/**
* The failure of the trustmark machine
*/
failure?: TrustmarkFailure;
};
3 changes: 3 additions & 0 deletions ts/features/itwallet/trustmark/machine/events.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
import { ErrorActorEvent } from "xstate";

export type TrustmarkEvents = ErrorActorEvent;
37 changes: 37 additions & 0 deletions ts/features/itwallet/trustmark/machine/failure.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import { Errors } from "@pagopa/io-react-native-wallet";
import { TrustmarkEvents } from "./events";

const { isWalletProviderResponseError } = Errors;

export enum TrustmarkFailureType {
UNEXPECTED = "UNEXPECTED",
WALLET_PROVIDER_GENERIC = "WALLET_PROVIDER_GENERIC"
}

export type TrustmarkFailure = {
type: TrustmarkFailureType;
reason: unknown;
};

export const mapEventToFailure = (event: TrustmarkEvents): TrustmarkFailure => {
if (!("error" in event)) {
return {
type: TrustmarkFailureType.UNEXPECTED,
reason: event
};
}

const { error } = event;

if (isWalletProviderResponseError(error)) {
return {
type: TrustmarkFailureType.WALLET_PROVIDER_GENERIC,
reason: String(error)
};
}

return {
type: TrustmarkFailureType.UNEXPECTED,
reason: String(error)
};
};
18 changes: 13 additions & 5 deletions ts/features/itwallet/trustmark/machine/machine.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { differenceInSeconds, isPast } from "date-fns";
import { assign, fromPromise, setup } from "xstate";
import { assign, ErrorActorEvent, fromPromise, setup } from "xstate";
import { ItwTags } from "../../machine/tags";
import {
GetCredentialTrustmarkUrlActorInput,
Expand All @@ -8,6 +8,7 @@ import {
} from "./actors";
import { Context } from "./context";
import { Input } from "./input";
import { mapEventToFailure } from "./failure";

const notImplemented = () => {
throw new Error("Not implemented");
Expand All @@ -17,7 +18,7 @@ export const itwTrustmarkMachine = setup({
types: {
context: {} as Context,
input: {} as Input,
events: {} as { type: "" }
events: {} as ErrorActorEvent
},
actions: {
onInit: notImplemented,
Expand All @@ -31,6 +32,10 @@ export const itwTrustmarkMachine = setup({
trustmarkUrl: undefined,
expirationDate: undefined,
expirationSeconds: undefined
}),
showFailureToast: notImplemented,
setFailure: assign({
failure: ({ event }) => mapEventToFailure(event)
})
},
actors: {
Expand Down Expand Up @@ -89,7 +94,8 @@ export const itwTrustmarkMachine = setup({
actions: "handleSessionExpired"
},
{
target: "Failure"
target: "Failure",
actions: "setFailure"
}
]
}
Expand All @@ -115,7 +121,8 @@ export const itwTrustmarkMachine = setup({
]
},
onError: {
target: "Failure"
target: "Failure",
actions: "setFailure"
}
}
},
Expand Down Expand Up @@ -147,7 +154,8 @@ export const itwTrustmarkMachine = setup({
}
},
Failure: {
description: "This state is reached when an error occurs"
description: "This state is reached when an error occurs",
entry: "showFailureToast"
}
}
});
Expand Down
4 changes: 3 additions & 1 deletion ts/features/itwallet/trustmark/machine/provider.tsx
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { useIOToast } from "@pagopa/io-app-design-system";
import { createActorContext } from "@xstate/react";
import React from "react";
import { useIONavigation } from "../../../../navigation/params/AppParamsList";
Expand All @@ -20,9 +21,10 @@ export const ItwTrustmarkMachineProvider = ({
}: Props) => {
const store = useIOStore();
const navigation = useIONavigation();
const toast = useIOToast();

const trustmarkMachine = itwTrustmarkMachine.provide({
actions: createItwTrustmarkActionsImplementation(store, navigation),
actions: createItwTrustmarkActionsImplementation(store, navigation, toast),
actors: createItwTrustmarkActorsImplementation(store),
guards: createItwTrustmarkGuardsImplementation()
});
Expand Down
2 changes: 2 additions & 0 deletions ts/features/itwallet/trustmark/machine/selectors.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,3 +8,5 @@ export const selectTrustmarkUrl = ({ context }: MachineSnapshot) =>

export const selectExpirationSeconds = ({ context }: MachineSnapshot) =>
context.expirationSeconds;

export const selectFailure = ({ context }: MachineSnapshot) => context.failure;
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import {
VStack
} from "@pagopa/io-app-design-system";
import { format } from "date-fns";
import React from "react";
import React, { useState } from "react";
import { StyleSheet, View } from "react-native";
import Placeholder from "rn-placeholder";
import { QrCodeImage } from "../../../../components/QrCodeImage";
Expand All @@ -24,6 +24,7 @@ import {
} from "../machine/provider";
import {
selectExpirationSeconds,
selectFailure,
selectTrustmarkUrl
} from "../machine/selectors";
import { useDebugInfo } from "../../../../hooks/useDebugInfo";
Expand Down Expand Up @@ -68,8 +69,10 @@ export const ItwCredentialTrustmarkScreen = (params: ScreenProps) => {
const TrustmarkQrCode = () => {
const trustmarkUrl =
ItwTrustmarkMachineContext.useSelector(selectTrustmarkUrl);
const failure = ItwTrustmarkMachineContext.useSelector(selectFailure);
const [qrCodeError, setQrCodeError] = useState<Error | undefined>(undefined);

useDebugInfo({ trustmarkUrl });
useDebugInfo({ trustmarkUrl, failure, qrCodeError });

return (
<View style={styles.qrCodeContainer}>
Expand All @@ -78,6 +81,7 @@ const TrustmarkQrCode = () => {
value={trustmarkUrl}
correctionLevel="L"
accessibilityLabel={I18n.t("features.itWallet.trustmark.qrCode")}
onError={setQrCodeError}
/>
</View>
);
Expand Down

0 comments on commit d5defad

Please sign in to comment.