Skip to content

Commit

Permalink
feat(IT Wallet): [SIW-1918] Add iPatente CTA in MDL details screen (#…
Browse files Browse the repository at this point in the history
…6577)

## Short description
This PR adds the iPatente service CTA in the MDL details screen

## List of changes proposed in this pull request
- Bumped `IO_SERVICES_METADATA_VERSION` to version `1.0.52`
- Moved ITW remote config selectors to
`features/itWallet/common/store/selectors/remoteConfig.ts`
- Added `itwIsIPatenteCtaEnabledSelector` selector
- Added iPatente CTA in the MDL details screen

## How to test
Navigate to the MDL details screen, check that the iPatente CTA is
visible.
Mock the `/status/backend` response setting itw.`ipatente_cta_enabled`
to `false` and check that the CTA is not visibile.

---------

Co-authored-by: Jacopo Pompilii <[email protected]>
Co-authored-by: RiccardoMolinari95 <[email protected]>
  • Loading branch information
3 people authored Jan 15, 2025
1 parent c42e492 commit 40f6224
Show file tree
Hide file tree
Showing 17 changed files with 285 additions and 207 deletions.
1 change: 1 addition & 0 deletions locales/en/index.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3533,6 +3533,7 @@ features:
requestAssistance: "Something wrong?"
showClaimValues: "Show claim values"
hideClaimValues: "Hide claim values"
openIPatente: "Vai al saldo punti patente"
dialogs:
remove:
title: Vuoi rimuovere il documento dal Portafoglio?
Expand Down
1 change: 1 addition & 0 deletions locales/it/index.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3533,6 +3533,7 @@ features:
requestAssistance: "Qualcosa non torna?"
showClaimValues: "Mostra gli attributi del documento"
hideClaimValues: "Nascondi gli attributi del documento"
openIPatente: "Vai al saldo punti patente"
dialogs:
remove:
title: Vuoi rimuovere il documento dal Portafoglio?
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,12 @@ import {
} from "..";
import { GlobalState } from "../../../../../../store/reducers/types";
import { itwIsWalletEmptySelector } from "../../../../credentials/store/selectors";
import { itwLifecycleIsValidSelector } from "../../../../lifecycle/store/selectors";
import { itwIsFeedbackBannerHiddenSelector } from "../preferences";
import {
isItwEnabledSelector,
isItwFeedbackBannerEnabledSelector
} from "../../../../../../store/reducers/backendStatus/remoteConfig";
import { itwLifecycleIsValidSelector } from "../../../../lifecycle/store/selectors";
} from "../remoteConfig";

type JestMock = ReturnType<typeof jest.fn>;

Expand All @@ -24,13 +24,10 @@ jest.mock("../preferences", () => ({
itwIsFeedbackBannerHiddenSelector: jest.fn()
}));

jest.mock(
"../../../../../../store/reducers/backendStatus/remoteConfig",
() => ({
isItwEnabledSelector: jest.fn(),
isItwFeedbackBannerEnabledSelector: jest.fn()
})
);
jest.mock("../remoteConfig", () => ({
isItwEnabledSelector: jest.fn(),
isItwFeedbackBannerEnabledSelector: jest.fn()
}));

describe("itwDiscoveryBannerSelector", () => {
beforeEach(() => {
Expand Down
12 changes: 6 additions & 6 deletions ts/features/itwallet/common/store/selectors/index.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,3 @@
import {
isItwEnabledSelector,
isItwFeedbackBannerEnabledSelector
} from "../../../../../store/reducers/backendStatus/remoteConfig";
import { GlobalState } from "../../../../../store/reducers/types";
import {
itwCredentialsEidStatusSelector,
Expand All @@ -10,9 +6,13 @@ import {
import { itwLifecycleIsValidSelector } from "../../../lifecycle/store/selectors";
import { itwIsWalletInstanceStatusFailureSelector } from "../../../walletInstance/store/selectors";
import {
itwIsFeedbackBannerHiddenSelector,
itwIsDiscoveryBannerHiddenSelector
itwIsDiscoveryBannerHiddenSelector,
itwIsFeedbackBannerHiddenSelector
} from "./preferences";
import {
isItwEnabledSelector,
isItwFeedbackBannerEnabledSelector
} from "./remoteConfig";

/**
* Returns if the discovery banner should be rendered. The banner is rendered if:
Expand Down
121 changes: 121 additions & 0 deletions ts/features/itwallet/common/store/selectors/remoteConfig.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
import * as O from "fp-ts/lib/Option";
import { pipe } from "fp-ts/lib/function";
import { Platform } from "react-native";
import { createSelector } from "reselect";
import { GlobalState } from "../../../../../store/reducers/types";
import {
getAppVersion,
isVersionSupported
} from "../../../../../utils/appVersion";

const emptyArray: ReadonlyArray<string> = []; // to avoid unnecessary rerenders

const itwRemoteConfigSelector = (state: GlobalState) =>
pipe(
state.remoteConfig,
O.map(config => config.itw)
);

/**
* Return the remote config about IT-WALLET enabled/disabled
* if there is no data or the local Feature Flag is disabled,
* false is the default value -> (IT-WALLET disabled)
*/
export const isItwEnabledSelector = createSelector(
itwRemoteConfigSelector,
(itwConfig): boolean =>
pipe(
itwConfig,
O.map(
itw =>
isVersionSupported(
Platform.OS === "ios"
? itw.min_app_version.ios
: itw.min_app_version.android,
getAppVersion()
) && itw.enabled
),
O.getOrElse(() => false)
)
);

/**
* Returns the authentication methods that are disabled.
* If there is no data, an empty array is returned as the default value.
*/
export const itwDisabledIdentificationMethodsSelector = createSelector(
itwRemoteConfigSelector,
(itwConfig): ReadonlyArray<string> =>
pipe(
itwConfig,
O.chainNullableK(itw => itw.disabled_identification_methods),
O.getOrElse(() => emptyArray)
)
);

/**
* Return whether the IT Wallet feedback banner is remotely enabled.
*/
export const isItwFeedbackBannerEnabledSelector = createSelector(
itwRemoteConfigSelector,
itwConfig =>
pipe(
itwConfig,
O.map(itw => itw.feedback_banner_visible),
O.getOrElse(() => false)
)
);

/**
* Return whether the Wallet activation is disabled.
* This is purely a "cosmetic" configuration to disable UI elements,
* it does not disable the entire IT Wallet feature.
*/
export const itwIsActivationDisabledSelector = createSelector(
itwRemoteConfigSelector,
itwConfig =>
pipe(
itwConfig,
O.chainNullableK(itw => itw.wallet_activation_disabled),
O.getOrElse(() => false)
)
);

/**
* Return IT Wallet credentials that have been disabled remotely.
*/
export const itwDisabledCredentialsSelector = createSelector(
itwRemoteConfigSelector,
itwConfig =>
pipe(
itwConfig,
O.chainNullableK(itw => itw.disabled_credentials),
O.getOrElse(() => emptyArray)
)
);

/**
* Return the remote config content for the deferred issuance screen content.
*/
export const itwDeferredIssuanceScreenContentSelector = createSelector(
itwRemoteConfigSelector,
itwConfig =>
pipe(
itwConfig,
O.map(itw => itw.deferred_issuance_screen_content),
O.toUndefined
)
);

/**
* Return the remote config content for the deferred issuance screen content.
*/
export const itwIsIPatenteCtaEnabledSelector = createSelector(
itwRemoteConfigSelector,
itwConfig =>
pipe(
itwConfig,
O.map(itw => itw.ipatente_cta_visible),
O.getOrElse(() => false)
)
);
Original file line number Diff line number Diff line change
Expand Up @@ -5,25 +5,25 @@ import {
H1,
VSpacer
} from "@pagopa/io-app-design-system";
import { useFocusEffect } from "@react-navigation/native";
import * as React from "react";
import { StyleSheet } from "react-native";
import { useFocusEffect } from "@react-navigation/native";
import { AnimatedImage } from "../../../../components/AnimatedImage";
import { useHeaderSecondLevel } from "../../../../hooks/useHeaderSecondLevel";
import I18n from "../../../../i18n";
import { useIOSelector } from "../../../../store/hooks";
import { emptyContextualHelp } from "../../../../utils/emptyContextualHelp";
import { useOnFirstRender } from "../../../../utils/hooks/useOnFirstRender";
import ItwMarkdown from "../../common/components/ItwMarkdown";
import { selectIsLoading } from "../../machine/eid/selectors";
import { ItwEidIssuanceMachineContext } from "../../machine/provider";
import { tosConfigSelector } from "../../../tos/store/selectors";
import {
trackItWalletActivationStart,
trackItWalletIntroScreen,
trackOpenItwTos
} from "../../analytics";
import { useIOSelector } from "../../../../store/hooks";
import { isItwActivationDisabledSelector } from "../../../../store/reducers/backendStatus/remoteConfig";
import { tosConfigSelector } from "../../../tos/store/selectors";
import ItwMarkdown from "../../common/components/ItwMarkdown";
import { itwIsActivationDisabledSelector } from "../../common/store/selectors/remoteConfig";
import { selectIsLoading } from "../../machine/eid/selectors";
import { ItwEidIssuanceMachineContext } from "../../machine/provider";

/**
* This is the screen that shows the information about the discovery process
Expand All @@ -36,7 +36,7 @@ const ItwDiscoveryInfoScreen = () => {

const machineRef = ItwEidIssuanceMachineContext.useActorRef();
const isLoading = ItwEidIssuanceMachineContext.useSelector(selectIsLoading);
const itwActivationDisabled = useIOSelector(isItwActivationDisabledSelector);
const itwActivationDisabled = useIOSelector(itwIsActivationDisabledSelector);
const tosConfig = useIOSelector(tosConfigSelector);
const privacyAndTosUrl = tosConfig.tos_url;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,9 @@ import {
trackItWalletIDMethod,
trackItWalletIDMethodSelected
} from "../../analytics";
import { itwDisabledIdentificationMethodsSelector } from "../../../../store/reducers/backendStatus/remoteConfig";
import { IOScrollViewWithLargeHeader } from "../../../../components/ui/IOScrollViewWithLargeHeader";
import { isCIEAuthenticationSupportedSelector } from "../../machine/eid/selectors";
import { itwDisabledIdentificationMethodsSelector } from "../../common/store/selectors/remoteConfig";

export const ItwIdentificationModeSelectionScreen = () => {
const machineRef = ItwEidIssuanceMachineContext.useActorRef();
Expand Down
Original file line number Diff line number Diff line change
@@ -1,19 +1,26 @@
import { Errors } from "@pagopa/io-react-native-wallet";
import { sequenceS } from "fp-ts/lib/Apply";
import { constNull, pipe } from "fp-ts/lib/function";
import * as O from "fp-ts/lib/Option";
import { constNull, pipe } from "fp-ts/lib/function";
import React from "react";
import {
OperationResultScreenContent,
OperationResultScreenContentProps
} from "../../../../components/screens/OperationResultScreenContent";
import { useDebugInfo } from "../../../../hooks/useDebugInfo";
import I18n from "../../../../i18n";
import { useIOSelector } from "../../../../store/hooks";
import {
fallbackForLocalizedMessageKeys,
getFullLocale
} from "../../../../utils/locale";
import { useAvoidHardwareBackButton } from "../../../../utils/useAvoidHardwareBackButton";
import { trackWalletCreationFailed } from "../../analytics";
import { useItwDisableGestureNavigation } from "../../common/hooks/useItwDisableGestureNavigation";
import { itwDeferredIssuanceScreenContentSelector } from "../../common/store/selectors/remoteConfig";
import { getClaimsFullLocale } from "../../common/utils/itwClaimsUtils";
import { StatusAttestationError } from "../../common/utils/itwCredentialStatusAttestationUtils";
import { serializeFailureReason } from "../../common/utils/itwStoreUtils";
import { IssuerConfiguration } from "../../common/utils/itwTypesUtils";
import {
CredentialIssuanceFailure,
Expand All @@ -26,13 +33,6 @@ import {
} from "../../machine/credential/selectors";
import { ItwCredentialIssuanceMachineContext } from "../../machine/provider";
import { useCredentialEventsTracking } from "../hooks/useCredentialEventsTracking";
import { useIOSelector } from "../../../../store/hooks";
import { itwDeferredIssuanceScreenContentSelector } from "../../../../store/reducers/backendStatus/remoteConfig";
import {
fallbackForLocalizedMessageKeys,
getFullLocale
} from "../../../../utils/locale";
import { serializeFailureReason } from "../../common/utils/itwStoreUtils";

export const ItwIssuanceCredentialFailureScreen = () => {
const failureOption =
Expand Down
4 changes: 2 additions & 2 deletions ts/features/itwallet/navigation/useItwLinkingOptions.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import { PathConfigMap } from "@react-navigation/native";
import { AppParamsList } from "../../../navigation/params/AppParamsList";
import { useIOSelector } from "../../../store/hooks";
import { isItwEnabledSelector } from "../common/store/selectors/remoteConfig";
import { itwLifecycleIsValidSelector } from "../lifecycle/store/selectors";
import { isItwEnabledSelector } from "../../../store/reducers/backendStatus/remoteConfig";
import { AppParamsList } from "../../../navigation/params/AppParamsList";
import { ITW_ROUTES } from "./routes";

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,18 +6,14 @@ import {
VStack
} from "@pagopa/io-app-design-system";
import { useFocusEffect } from "@react-navigation/native";
import { constFalse, pipe } from "fp-ts/lib/function";
import * as O from "fp-ts/lib/Option";
import { constFalse, pipe } from "fp-ts/lib/function";
import React, { useCallback } from "react";
import { StyleSheet, View } from "react-native";
import { IOScrollViewWithLargeHeader } from "../../../../components/ui/IOScrollViewWithLargeHeader";
import I18n from "../../../../i18n";
import { useIONavigation } from "../../../../navigation/params/AppParamsList";
import { useIODispatch, useIOSelector } from "../../../../store/hooks";
import {
isItwEnabledSelector,
itwDisabledCredentialsSelector
} from "../../../../store/reducers/backendStatus/remoteConfig";
import { emptyContextualHelp } from "../../../../utils/emptyContextualHelp";
import { cgnActivationStart } from "../../../bonus/cgn/store/actions/activation";
import {
Expand All @@ -32,6 +28,10 @@ import {
} from "../../analytics";
import { ItwDiscoveryBannerOnboarding } from "../../common/components/discoveryBanner/ItwDiscoveryBannerOnboarding";
import { itwRequestedCredentialsSelector } from "../../common/store/selectors/preferences";
import {
isItwEnabledSelector,
itwDisabledCredentialsSelector
} from "../../common/store/selectors/remoteConfig";
import { CredentialType } from "../../common/utils/itwMocksUtils";
import { itwCredentialsTypesSelector } from "../../credentials/store/selectors";
import { itwLifecycleIsValidSelector } from "../../lifecycle/store/selectors";
Expand Down
Loading

0 comments on commit 40f6224

Please sign in to comment.