diff --git a/locales/en/index.yml b/locales/en/index.yml index f141b4dcb7c..fe440eb1bec 100644 --- a/locales/en/index.yml +++ b/locales/en/index.yml @@ -3432,6 +3432,8 @@ features: success: title: "Done!" subtitle: "Go back to the {{organizationName}} website to continue." + qrCodeScreen: + loading: "Wait a few seconds for the verification request..." missingFeatureScreen: headerTitle: "Screen not available" title: "This screen will be available soon." diff --git a/locales/it/index.yml b/locales/it/index.yml index afc6d92d562..aff0d0d8c6c 100644 --- a/locales/it/index.yml +++ b/locales/it/index.yml @@ -3433,6 +3433,8 @@ features: success: title: "Fatto!" subtitle: "Torna sul sito di {{organizationName}} per continuare." + qrCodeScreen: + loading: "Attendi qualche secondo la richiesta di verifica..." missingFeatureScreen: headerTitle: "Schermata non disponibile" title: "Questa schermata sarĂ  presto disponibile" diff --git a/ts/features/it-wallet/navigation/ItwParamsList.ts b/ts/features/it-wallet/navigation/ItwParamsList.ts index aa64758025d..e26917245ff 100644 --- a/ts/features/it-wallet/navigation/ItwParamsList.ts +++ b/ts/features/it-wallet/navigation/ItwParamsList.ts @@ -46,6 +46,9 @@ export type ItwParamsList = { [ITW_ROUTES.PRESENTATION.CREDENTIAL.REMOTE.DATA]: undefined; [ITW_ROUTES.PRESENTATION.CREDENTIAL.REMOTE.RESULT]: undefined; + // PRESENTATION PROXIMITY + [ITW_ROUTES.PRESENTATION.PROXIMITY.QRCODE]: undefined; + // GENERIC [ITW_ROUTES.GENERIC.NOT_AVAILABLE]: undefined; }; diff --git a/ts/features/it-wallet/navigation/ItwRoutes.ts b/ts/features/it-wallet/navigation/ItwRoutes.ts index 04f5571294e..1b90e9b1c0a 100644 --- a/ts/features/it-wallet/navigation/ItwRoutes.ts +++ b/ts/features/it-wallet/navigation/ItwRoutes.ts @@ -40,6 +40,9 @@ export const ITW_ROUTES = { DATA: "ITW_PRESENTATION_CREDENTIAL_DATA", RESULT: "ITW_PRESETATION_CREDENTIAL_RESULT" } as const + } as const, + PROXIMITY: { + QRCODE: "ITW_PRESENTATION_CROSS_DEVICE_QRCODE" } as const } as const, GENERIC: { diff --git a/ts/features/it-wallet/navigation/ItwStackNavigator.tsx b/ts/features/it-wallet/navigation/ItwStackNavigator.tsx index 46976494a9e..d0034ac740f 100644 --- a/ts/features/it-wallet/navigation/ItwStackNavigator.tsx +++ b/ts/features/it-wallet/navigation/ItwStackNavigator.tsx @@ -25,6 +25,7 @@ import ItwCredentialsChecksScreen from "../screens/issuing/credential/ItwCredent import ItwCredentialCatalogScreen from "../screens/issuing/credential/ItwCredentialCatalogScreen"; import ItwPrCredentialDetailsScreen from "../screens/presentation/ItwPrCredentialDetails"; import ItwPrPidDataScreen from "../screens/presentation/remote/pid/ItwPrPidDataScreen"; +import ItwPrProximityQrCodeScreen from "../screens/presentation/ItwPrProximityQrCodeScreen"; import { ItwParamsList } from "./ItwParamsList"; import { ITW_ROUTES } from "./ItwRoutes"; @@ -137,6 +138,12 @@ export const ItwStackNavigator = () => ( component={ItwPrCredentialResultScreen} /> + {/* PRESENTATION PROXIMITY */} + + {/* GENERIC */} { accessibilityLabel: I18n.t( "features.itWallet.presentation.credentialDetails.buttons.qrCode" ), - onPress: () => navigation.navigate(ITW_ROUTES.GENERIC.NOT_AVAILABLE) + onPress: () => + navigation.navigate(ITW_ROUTES.PRESENTATION.PROXIMITY.QRCODE) } }; diff --git a/ts/features/it-wallet/screens/presentation/ItwPrPidDetails.tsx b/ts/features/it-wallet/screens/presentation/ItwPrPidDetails.tsx index 5653a8fbc93..d2ec9e14cf2 100644 --- a/ts/features/it-wallet/screens/presentation/ItwPrPidDetails.tsx +++ b/ts/features/it-wallet/screens/presentation/ItwPrPidDetails.tsx @@ -51,7 +51,8 @@ const ItwPrPidDetails = () => { ), icon: "qrCode", iconPosition: "end", - onPress: () => navigation.navigate(ITW_ROUTES.GENERIC.NOT_AVAILABLE) + onPress: () => + navigation.navigate(ITW_ROUTES.PRESENTATION.PROXIMITY.QRCODE) } }; diff --git a/ts/features/it-wallet/screens/presentation/ItwPrProximityQrCodeScreen.tsx b/ts/features/it-wallet/screens/presentation/ItwPrProximityQrCodeScreen.tsx new file mode 100644 index 00000000000..d9d9d41150e --- /dev/null +++ b/ts/features/it-wallet/screens/presentation/ItwPrProximityQrCodeScreen.tsx @@ -0,0 +1,103 @@ +import * as React from "react"; +import { Image, SafeAreaView, View } from "react-native"; +import RNQRGenerator from "rn-qr-generator"; +import { IOStyles, LabelSmall, VSpacer } from "@pagopa/io-app-design-system"; +import { useNavigation } from "@react-navigation/native"; +import ItwLoadingSpinner from "../../components/ItwLoadingSpinner"; +import { useOnFirstRender } from "../../../../utils/hooks/useOnFirstRender"; +import { IOStackNavigationProp } from "../../../../navigation/params/AppParamsList"; +import { ItwParamsList } from "../../navigation/ItwParamsList"; +import I18n from "../../../../i18n"; +import BaseScreenComponent from "../../../../components/screens/BaseScreenComponent"; +import ItwKoView from "../../components/ItwKoView"; +import { getItwGenericMappedError } from "../../utils/errors/itwErrorsMapping"; + +// A mocked QR code to be used in the proximity flow +// TODO: remove this mocked QR code after the proximity flow is implemented [SIW-688] +const mockedQrCode = + "mdoc:owBjMS4wAYIB2BhYS6QBAiABIVggUCnUgO0nCmTWOkqZLpQJh1uO2Q0YCTbYtUowBJU6ltEiWCBPkYpJZpEY4emfmR_2eFS5XQN68wihmgEoiMVEf8M3_gKBgwIBowD0AfULUJr9sL_rAkZCk114baNK4rY"; + +/** + * A screen that shows a QR code to be scanned by the other device + * in order to start the proximity flow. + */ +const ItwPrProximityQrCodeScreen = () => { + const [qrCodeUri, setQrCodeUri] = React.useState(""); + const [isLoading, setIsLoading] = React.useState(false); + const [isError, setIsError] = React.useState(false); + const navigation = useNavigation>(); + useOnFirstRender(() => { + RNQRGenerator.generate({ + value: mockedQrCode, + height: 300, + width: 300, + correctionLevel: "H" + }) + .then(({ uri }) => { + setQrCodeUri(uri); + setIsLoading(true); + }) + .catch(_ => { + setIsError(true); + }); + }); + + /** + * This component is used to display a loading spinner and a text. + * It is used during proximity flow. After proximity integration [SIW-688] this + * component could show a message to the user related to the several steps + * of the proximity flow. + * @returns a loading component which displays a loading spinner and a text. + */ + const LoadingComponent = () => ( + + + + + {I18n.t("features.itWallet.presentation.qrCodeScreen.loading")} + + + ); + + /** + * Error view component which currently displays a generic error. + */ + const ErrorView = () => { + const mappedError = getItwGenericMappedError(() => navigation.goBack()); + return ; + }; + + if (isError) { + return ; + } + + return ( + + + + {qrCodeUri !== "" && ( + <> + + {"Il tuo codice QR personale"} + + + + + {isLoading && } + + )} + + + + ); +}; + +export default ItwPrProximityQrCodeScreen;