diff --git a/ts/features/idpay/codeOnboarding/navigation.tsx b/ts/features/idpay/codeOnboarding/navigation.tsx new file mode 100644 index 00000000000..5f959c36fd4 --- /dev/null +++ b/ts/features/idpay/codeOnboarding/navigation.tsx @@ -0,0 +1,63 @@ +import { ParamListBase, RouteProp } from "@react-navigation/native"; +import { + StackNavigationProp, + createStackNavigator +} from "@react-navigation/stack"; + +import * as React from "react"; +import { View } from "react-native"; +import { IDPayCodeOnboardingMachineProvider } from "./xstate/provider"; + +export const IDPayCodeOnboardingRoutes = { + IDPAY_CODE_ONBOARDING_MAIN: "IDPAY_CODE_ONBOARDING_MAIN", + IDPAY_CODE_ONBOARDING_INTRO: "IDPAY_CODE_ONBOARDING_INTRO", + IDPAY_CODE_ONBOARDING_END: "IDPAY_CODE_ONBOARDING_END", + IDPAY_CODE_ONBOARDING_RESULT: "IDPAY_CODE_ONBOARDING_RESULT" +} as const; + +export type IDPayCodeOnboardingParamsList = { + [IDPayCodeOnboardingRoutes.IDPAY_CODE_ONBOARDING_INTRO]: undefined; + [IDPayCodeOnboardingRoutes.IDPAY_CODE_ONBOARDING_END]: undefined; + [IDPayCodeOnboardingRoutes.IDPAY_CODE_ONBOARDING_RESULT]: undefined; +}; + +const Stack = createStackNavigator(); + +export const IDPayCodeOnboardingNavigator = () => ( + + + + + + + +); + +const MockScreen = () => ; + +export type IDPayCodeOnboardingStackNavigationRouteProps< + ParamList extends ParamListBase, + RouteName extends keyof ParamList = string +> = { + navigation: IDPayCodeOnboardingStackNavigationProp; + route: RouteProp; +}; + +export type IDPayCodeOnboardingStackNavigationProp< + ParamList extends ParamListBase, + RouteName extends keyof ParamList = string +> = StackNavigationProp; diff --git a/ts/features/idpay/codeOnboarding/xstate/actions.ts b/ts/features/idpay/codeOnboarding/xstate/actions.ts new file mode 100644 index 00000000000..5a6bf240777 --- /dev/null +++ b/ts/features/idpay/codeOnboarding/xstate/actions.ts @@ -0,0 +1,40 @@ +/* eslint-disable no-console */ +import { + AppParamsList, + IOStackNavigationProp +} from "../../../../navigation/params/AppParamsList"; + +const createActionsImplementation = ( + navigation: IOStackNavigationProp + // dispatch: ReturnType +) => { + const authorizeUser = () => { + // CALL AUTH HOOK + console.log("authorizeUser"); + }; + + const navigateToPinShowScreen = () => { + // navigation.navigate + console.log("navigateToPinShowScreen"); + }; + const navigateToErrorScreen = () => { + // navigation.navigate + console.log("navigateToErrorScreen"); + }; + const navigateToSuccessScreen = () => { + // navigation.navigate + console.log("navigateToSuccessScreen"); + }; + const quitFlow = () => { + navigation.pop(); + }; + return { + authorizeUser, + navigateToPinShowScreen, + navigateToErrorScreen, + navigateToSuccessScreen, + quitFlow + }; +}; + +export { createActionsImplementation }; diff --git a/ts/features/idpay/codeOnboarding/xstate/context.ts b/ts/features/idpay/codeOnboarding/xstate/context.ts new file mode 100644 index 00000000000..5c65e300470 --- /dev/null +++ b/ts/features/idpay/codeOnboarding/xstate/context.ts @@ -0,0 +1,7 @@ +import * as O from "fp-ts/lib/Option"; + +export type Context = { failure: O.Option; isCodeEnabled: boolean }; +export const INITIAL_CONTEXT: Context = { + failure: O.none, + isCodeEnabled: false +}; diff --git a/ts/features/idpay/codeOnboarding/xstate/machine.ts b/ts/features/idpay/codeOnboarding/xstate/machine.ts new file mode 100644 index 00000000000..dfc0b4e662b --- /dev/null +++ b/ts/features/idpay/codeOnboarding/xstate/machine.ts @@ -0,0 +1,97 @@ +import { createMachine } from "xstate"; +import { LOADING_TAG, WAITING_USER_INPUT_TAG } from "../../../../xstate/utils"; +import { Context, INITIAL_CONTEXT } from "./context"; + +const createIDPayCodeOnboardingMachine = (isCodeEnabled: boolean) => + createMachine( + { + /** @xstate-layout N4IgpgJg5mDOIC5QEkAiAFAggTQPoGFkBRXAeQDkAhUzAJVWXIHEBiJ03SzfAaQG0ADAF1EoAA4B7WAEsALtIkA7USAAeiAMwBGACwA6DToBMRrRoCcRgOwBWDTYBsAGhABPRAIC+nl2ix5CEgpqOgZmFgAxRmQAZQAJQREkEEkZeSUVdQQBF3ds718MHAJiMioaekYmPQYY9AAZHCrcRgAVWlIWGNa6VtwI+tIAdUSVVLkFZWSsk30rKy07XS0BLSNzHVzEGxsjPQcjAA4NBy0HQ6PHApA-YsCykMrmPUwAVVa40lpkAC1m15iRFoLDeH1wMVe+HwRBiMVGyXG6SmoCyNnMAj06J0h0OZg0AmOWi0WwQO3MehsOhsAgE2LJxgc11uAVKwQqYWqoM+3z+zFwAKBIPecXBkOhsL4WiS4ikEwy00Qlgceh0VksGg0RhsZiJmzc2zRFJ0OnM5gc5w0VgEGiZRRZQXKoSqL2FX1+-0BwK5-UwyHqr1oRHhMrSk0yiGNWkxtlW5nxZotVhJxisekONNM8x0DhNq1t-hKDseHL0TCI5CBmFazXQjBYtfIuDLFdoVaIqGDKVlSPDCDOJj0qxxVhMlNsNhJZKN1PxZzRJkO+burMdT2qzcr1b5DfrjCb5c3yAoPr9AaDwjG3bDCr7WgWKpHaw1hjW5hJhhsekWhwcNPmAg2O8l3tB52WdeJhhrOt8AoLdXnPaUu1DeUUUQLRjk-Q5dgcbUdl0bUNBJKx8QpVZaWzcxHBMIxvB8EBFAkCA4BUZlC1Ap1mEvZDkTURAAFojAxONv1-XRtEcEktVTHCsMo7UiQEBwrGAti2Q46pagaJo+TaDouLlHiZlTRTDh0MxzCw85jUnOwvyOE4zguSyVPuNS1xdD43V5Jh+U9fSexvDQf0HC1zF0JTTDMJN9VJWy1mOU5zkuRk6NY1zVxLDdWy3HyG3869UL7ewowAtFfyMDUcNpGy9i0dFCXMK0zAEGwXJXYtwM+IYoPIfKUN4vsLn0bUlKsY1BNMCcYqnSlqVpLC0RTNqizA55NMabBmjcjlRShGEYj6wzEGI5UdEUqwcPNU04ymvIR0-VZ1nOBYLAcONlvY9z1u0nztuaCJfX9QNDt7BwSJ0fF7AuzULLjd9tUHDUVkm+SP1ozwgA */ + context: { ...INITIAL_CONTEXT, isCodeEnabled }, + tsTypes: {} as import("./machine.typegen").Typegen0, + schema: { + context: {} as Context, + events: undefined, + services: undefined + }, + predictableActionArguments: true, + id: "IDPAY_CODE_ONBOARDING", + initial: "DISPLAYING_INTRO", + on: { + GO_BACK: { + actions: "quitFlow" + }, + FINISH: { + actions: "quitFlow" + } + }, + states: { + DISPLAYING_INTRO: { + tags: [WAITING_USER_INPUT_TAG], + on: { + START_FLOW: { + target: "AUTHORIZING_USER" + } + } + }, + AUTHORIZING_USER: { + tags: [WAITING_USER_INPUT_TAG], + on: { + AUTH_SUCCESS: [ + { + cond: "pin_exists", + target: "DISPLAYING_ONBOARDING_SUCCESS" + }, + { + target: "GENERATING_PIN" + } + ], + AUTH_FAILURE: { + target: "DISPLAYING_ONBOARDING_FAILURE" + } + } + }, + GENERATING_PIN: { + tags: [LOADING_TAG], + invoke: { + id: "generatePin", + src: "generatePin", + onDone: { + target: "SHOWING_PIN" + }, + onError: { + target: "DISPLAYING_ONBOARDING_FAILURE" + } + } + }, + SHOWING_PIN: { + entry: "navigateToPinShowScreen", + tags: [WAITING_USER_INPUT_TAG], + on: { + CONTINUE: { + target: "DISPLAYING_ONBOARDING_SUCCESS" + } + } + }, + DISPLAYING_ONBOARDING_SUCCESS: { + entry: "navigateToSuccessScreen", + tags: [WAITING_USER_INPUT_TAG] + }, + DISPLAYING_ONBOARDING_FAILURE: { + entry: "navigateToErrorScreen", + tags: [WAITING_USER_INPUT_TAG] + } + } + }, + { + guards: { + // this comes from the global state, context will contain the original value + pin_exists: (context: Context) => context.isCodeEnabled + } + } + ); + +type IDPayCodeOnboardingMachineType = ReturnType< + typeof createIDPayCodeOnboardingMachine +>; +export type { IDPayCodeOnboardingMachineType }; +export { createIDPayCodeOnboardingMachine }; diff --git a/ts/features/idpay/codeOnboarding/xstate/provider.tsx b/ts/features/idpay/codeOnboarding/xstate/provider.tsx new file mode 100644 index 00000000000..3c526461a59 --- /dev/null +++ b/ts/features/idpay/codeOnboarding/xstate/provider.tsx @@ -0,0 +1,60 @@ +import { useNavigation } from "@react-navigation/native"; +import { useInterpret } from "@xstate/react"; +import * as React from "react"; +import { InterpreterFrom } from "xstate"; +import { + AppParamsList, + IOStackNavigationProp +} from "../../../../navigation/params/AppParamsList"; +import { useXStateMachine } from "../../../../xstate/hooks/useXStateMachine"; +import { createActionsImplementation } from "./actions"; +import { + IDPayCodeOnboardingMachineType, + createIDPayCodeOnboardingMachine +} from "./machine"; +import { createServicesImplementation } from "./services"; + +type CodeOnboardingMachineContext = + InterpreterFrom; +const CodeOnboardingMachineContext = + React.createContext( + {} as CodeOnboardingMachineContext + ); + +type Props = { + children: React.ReactNode; +}; + +const IDPayCodeOnboardingMachineProvider = (props: Props) => { + // const dispatch = useIODispatch(); + const isIDPayCodeEnabled = true; // TODO: get from store + const machineGenerator = () => + createIDPayCodeOnboardingMachine(isIDPayCodeEnabled); + const [machine] = useXStateMachine(machineGenerator); + const navigation = useNavigation>(); + const token = "token"; // get from wherever + const client = null; // '' + + const actions = createActionsImplementation( + navigation + // dispatch + ); + const services = createServicesImplementation(client, token); + + const machineService = useInterpret(machine, { services, actions }); + + return ( + + {props.children} + + ); +}; + +const useCodeOnboardingMachineService = () => + React.useContext(CodeOnboardingMachineContext); + +export { + CodeOnboardingMachineContext, + IDPayCodeOnboardingMachineProvider, + useCodeOnboardingMachineService +}; diff --git a/ts/features/idpay/codeOnboarding/xstate/services.ts b/ts/features/idpay/codeOnboarding/xstate/services.ts new file mode 100644 index 00000000000..87e662e8fcd --- /dev/null +++ b/ts/features/idpay/codeOnboarding/xstate/services.ts @@ -0,0 +1,29 @@ +import { Context } from "./context"; + +export type Services = { + generatePin: { + data: unknown; + }; +}; + +const mapFetchError = (error: unknown) => { + if (error === "max-retries") { + return null; + } + return undefined; +}; + +const createServicesImplementation = (client: unknown, token: string) => { + const generatePin = async (context: Context) => { + // required to avoid errors while implementation is so barebone + // eslint-disable-next-line no-console + console.log(mapFetchError("max-retries")); + // eslint-disable-next-line no-console + console.log(client, token, context); + + return new Promise((resolve, _reject) => resolve(true)); + }; + return { generatePin }; +}; + +export { createServicesImplementation }; diff --git a/ts/navigation/AuthenticatedStackNavigator.tsx b/ts/navigation/AuthenticatedStackNavigator.tsx index 372335c626b..55426464c31 100644 --- a/ts/navigation/AuthenticatedStackNavigator.tsx +++ b/ts/navigation/AuthenticatedStackNavigator.tsx @@ -18,6 +18,10 @@ import { FciStackNavigator } from "../features/fci/navigation/FciStackNavigator" import { FCI_ROUTES } from "../features/fci/navigation/routes"; import { FimsNavigator } from "../features/fims/navigation/navigator"; import FIMS_ROUTES from "../features/fims/navigation/routes"; +import { + IDPayCodeOnboardingNavigator, + IDPayCodeOnboardingRoutes +} from "../features/idpay/codeOnboarding/navigation"; import { IDPayConfigurationNavigator, IDPayConfigurationRoutes @@ -42,6 +46,10 @@ import { import UnsupportedDeviceScreen from "../features/lollipop/screens/UnsupportedDeviceScreen"; import UADONATION_ROUTES from "../features/uaDonations/navigation/routes"; import { UAWebViewScreen } from "../features/uaDonations/screens/UAWebViewScreen"; +import { + WalletOnboardingNavigator, + WalletOnboardingRoutes +} from "../features/walletV3/onboarding/navigation/navigator"; import { ZendeskStackNavigator } from "../features/zendesk/navigation/navigator"; import ZENDESK_ROUTES from "../features/zendesk/navigation/routes"; import { useIOSelector } from "../store/hooks"; @@ -52,10 +60,6 @@ import { isFIMSEnabledSelector, isIdPayEnabledSelector } from "../store/reducers/backendStatus"; -import { - WalletOnboardingNavigator, - WalletOnboardingRoutes -} from "../features/walletV3/onboarding/navigation/navigator"; import { isGestureEnabled } from "../utils/navigation"; import { MessagesStackNavigator } from "./MessagesNavigator"; import OnboardingNavigator from "./OnboardingNavigator"; @@ -175,6 +179,10 @@ const AuthenticatedStackNavigator = () => { component={IDpayDetailsNavigator} options={{ gestureEnabled: isGestureEnabled }} /> + ; [IDPayConfigurationRoutes.IDPAY_CONFIGURATION_MAIN]: NavigatorScreenParams; [IDPayDetailsRoutes.IDPAY_DETAILS_MAIN]: NavigatorScreenParams; + [IDPayCodeOnboardingRoutes.IDPAY_CODE_ONBOARDING_MAIN]: NavigatorScreenParams; [IDPayUnsubscriptionRoutes.IDPAY_UNSUBSCRIPTION_MAIN]: | NavigatorScreenParams | IDPayUnsubscriptionNavigatorParams; diff --git a/ts/screens/profile/ProfileMainScreen.tsx b/ts/screens/profile/ProfileMainScreen.tsx index 098a278356e..d454604bd65 100644 --- a/ts/screens/profile/ProfileMainScreen.tsx +++ b/ts/screens/profile/ProfileMainScreen.tsx @@ -2,13 +2,16 @@ import { Millisecond } from "@pagopa/ts-commons/lib/units"; import AsyncStorage from "@react-native-async-storage/async-storage"; import { List, Toast } from "native-base"; import * as React from "react"; -import { View, Alert, ScrollView } from "react-native"; +import { Alert, ScrollView, View } from "react-native"; import { connect } from "react-redux"; import { TranslationKeys } from "../../../locales/locales"; +import AppVersion from "../../components/AppVersion"; import ContextualInfo from "../../components/ContextualInfo"; +import FiscalCodeComponent from "../../components/FiscalCodeComponent"; +import TouchableDefaultOpacity from "../../components/TouchableDefaultOpacity"; +import { Divider } from "../../components/core/Divider"; import { VSpacer } from "../../components/core/spacer/Spacer"; import { IOStyles } from "../../components/core/variables/IOStyles"; -import FiscalCodeComponent from "../../components/FiscalCodeComponent"; import { withLightModalContext } from "../../components/helpers/withLightModalContext"; import { TabBarItemPressType, @@ -20,12 +23,18 @@ import { EdgeBorderComponent } from "../../components/screens/EdgeBorderComponen import ListItemComponent from "../../components/screens/ListItemComponent"; import { ScreenContentRoot } from "../../components/screens/ScreenContent"; import SectionHeaderComponent from "../../components/screens/SectionHeaderComponent"; -import TouchableDefaultOpacity from "../../components/TouchableDefaultOpacity"; import { AlertModal } from "../../components/ui/AlertModal"; +import ButtonSolid from "../../components/ui/ButtonSolid"; import { LightModalContextInterface } from "../../components/ui/LightModal"; +import ListItemInfoCopy from "../../components/ui/ListItemInfoCopy"; +import ListItemNav from "../../components/ui/ListItemNav"; import Markdown from "../../components/ui/Markdown"; +import { SwitchListItem } from "../../components/ui/SwitchListItem"; import { isPlaygroundsEnabled } from "../../config"; +import { isFastLoginEnabledSelector } from "../../features/fastLogin/store/selectors"; import { lollipopPublicKeySelector } from "../../features/lollipop/store/reducers/lollipop"; +import { toThumbprint } from "../../features/lollipop/utils/crypto"; +import { walletAddCoBadgeStart } from "../../features/wallet/onboarding/cobadge/store/actions"; import I18n from "../../i18n"; import { IOStackNavigationRouteProps } from "../../navigation/params/AppParamsList"; import { MainTabParamsList } from "../../navigation/params/MainTabParamsList"; @@ -34,10 +43,10 @@ import { sessionExpired } from "../../store/actions/authentication"; import { setDebugModeEnabled } from "../../store/actions/debug"; import { navigateToLogout } from "../../store/actions/navigation"; import { + preferencesDesignSystemSetEnabled, preferencesIdPayTestSetEnabled, preferencesPagoPaTestEnvironmentSetEnabled, - preferencesPnTestEnvironmentSetEnabled, - preferencesDesignSystemSetEnabled + preferencesPnTestEnvironmentSetEnabled } from "../../store/actions/persistedPreferences"; import { clearCache } from "../../store/actions/profile"; import { Dispatch } from "../../store/actions/types"; @@ -48,8 +57,8 @@ import { import { isDebugModeEnabledSelector } from "../../store/reducers/debug"; import { notificationsInstallationSelector } from "../../store/reducers/notifications/installation"; import { - isIdPayTestEnabledSelector, isDesignSystemEnabledSelector, + isIdPayTestEnabledSelector, isPagoPATestEnabledSelector, isPnTestEnabledSelector } from "../../store/reducers/persistedPreferences"; @@ -57,15 +66,6 @@ import { GlobalState } from "../../store/reducers/types"; import { clipboardSetStringWithFeedback } from "../../utils/clipboard"; import { getDeviceId } from "../../utils/device"; import { isDevEnv } from "../../utils/environment"; -import { toThumbprint } from "../../features/lollipop/utils/crypto"; -import ListItemNav from "../../components/ui/ListItemNav"; -import { Divider } from "../../components/core/Divider"; -import ListItemInfoCopy from "../../components/ui/ListItemInfoCopy"; -import ButtonSolid from "../../components/ui/ButtonSolid"; -import { SwitchListItem } from "../../components/ui/SwitchListItem"; -import AppVersion from "../../components/AppVersion"; -import { walletAddCoBadgeStart } from "../../features/wallet/onboarding/cobadge/store/actions"; -import { isFastLoginEnabledSelector } from "../../features/fastLogin/store/selectors"; type Props = IOStackNavigationRouteProps & LightModalContextInterface &