Skip to content

Commit

Permalink
chore: [IOAPPCROSS-209] Fix onboarding screens + Fix E2E test (#5410)
Browse files Browse the repository at this point in the history
## Short description
This PR restores the title and description in two onboarding screens
(`ShareDataScreen` and `ServicesPreferenceScreen`) using the new
component `RNavScreenWithLargeHeader` (also used in the profile-like
screens). The PR also fixes a failed E2E test (onboarding flow). Both
issues were introduced by the following PR:

- #5333

## List of changes proposed in this pull request
- Update `OnboardingShareDataScreen` and `ServicesPreferenceScreen` to
use the new `RNavScreenWithLargeHeader`
- Update the relative navigator to show the header through
`react-navigation`
- Update `RNavScreenWithLargeHeader` to accept a custom `goBack` handler
- Add the `titleTestID` optional prop to the `RNavScreenWithLargeHeader`
component

## How to test
- Launch the app with the flag `firstOnboarding` set to `true`
- Run the following E2E test: `/ts/__e2e__/login.e2e.ts`
  • Loading branch information
dmnplb authored Jan 18, 2024
1 parent b68ed9d commit 30fe477
Show file tree
Hide file tree
Showing 6 changed files with 100 additions and 63 deletions.
15 changes: 12 additions & 3 deletions ts/components/ui/RNavScreenWithLargeHeader.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,15 +14,21 @@ import Animated, {
useSharedValue
} from "react-native-reanimated";
import { useSafeAreaInsets } from "react-native-safe-area-context";
import { HeaderActionProps, useHeaderProps } from "../../hooks/useHeaderProps";
import {
BackProps,
HeaderActionProps,
useHeaderProps
} from "../../hooks/useHeaderProps";
import { SupportRequestParams } from "../../hooks/useStartSupportRequest";
import I18n from "../../i18n";

type Props = {
children: React.ReactNode;
fixedBottomSlot?: React.ReactNode;
title: string;
titleTestID?: string;
description?: string;
goBack?: BackProps["goBack"];
headerActionsProp?: HeaderActionProps;
} & SupportRequestParams;

Expand All @@ -33,6 +39,7 @@ type Props = {
* @param children
* @param fixedBottomSlot An optional React node that is fixed to the bottom of the screen. Useful for buttons or other actions. It will be positioned outside the main `ScrollView`.
* @param title
* @param titleTestID
* @param contextualHelp
* @param contextualHelpMarkdown
* @param faqCategories
Expand All @@ -42,6 +49,8 @@ export const RNavScreenWithLargeHeader = ({
children,
fixedBottomSlot,
title,
titleTestID,
goBack,
description,
contextualHelp,
contextualHelpMarkdown,
Expand All @@ -65,7 +74,7 @@ export const RNavScreenWithLargeHeader = ({

const headerProps: ComponentProps<typeof HeaderSecondLevel> = useHeaderProps({
backAccessibilityLabel: I18n.t("global.buttons.back"),
goBack: navigation.goBack,
goBack: goBack ?? navigation.goBack,
title,
scrollValues: {
contentOffsetY: translationY,
Expand Down Expand Up @@ -100,7 +109,7 @@ export const RNavScreenWithLargeHeader = ({
style={IOStyles.horizontalContentPadding}
onLayout={getTitleHeight}
>
<H2>{title}</H2>
<H2 testID={titleTestID}>{title}</H2>
</View>

{description && (
Expand Down
2 changes: 1 addition & 1 deletion ts/hooks/useHeaderProps.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ export type HeaderActionProps =
| HeaderTwoActionsProps
| HeaderThreeActionsProps;

type BackProps =
export type BackProps =
| {
goBack: () => void;
backAccessibilityLabel: string;
Expand Down
21 changes: 16 additions & 5 deletions ts/navigation/OnboardingNavigator.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { createStackNavigator } from "@react-navigation/stack";
import * as React from "react";
import FingerprintScreen from "../screens/onboarding/biometric&securityChecks/FingerprintScreen";
import { isEmailUniquenessValidationEnabledSelector } from "../features/fastLogin/store/selectors";
import OnboardingCompletedScreen from "../screens/onboarding/OnboardingCompletedScreen";
import OnboardingEmailInsertScreen from "../screens/onboarding/OnboardingEmailInsertScreen";
import OnboardingEmailReadScreen from "../screens/onboarding/OnboardingEmailReadScreen";
Expand All @@ -11,12 +11,12 @@ import OnboardingServicesPreferenceScreen from "../screens/onboarding/Onboarding
import OnboardingShareDataScreen from "../screens/onboarding/OnboardingShareDataScreen";
import OnboardingTosScreen from "../screens/onboarding/OnboardingTosScreen";
import ServicePreferenceCompleteScreen from "../screens/onboarding/ServicePreferenceCompleteScreen";
import { isGestureEnabled } from "../utils/navigation";
import MissingDevicePinScreen from "../screens/onboarding/biometric&securityChecks/MissingDevicePinScreen";
import FingerprintScreen from "../screens/onboarding/biometric&securityChecks/FingerprintScreen";
import MissingDeviceBiometricScreen from "../screens/onboarding/biometric&securityChecks/MissingDeviceBiometricScreen";
import MissingDevicePinScreen from "../screens/onboarding/biometric&securityChecks/MissingDevicePinScreen";
import CduEmailInsertScreen from "../screens/profile/CduEmailInsertScreen";
import { useIOSelector } from "../store/hooks";
import { isEmailUniquenessValidationEnabledSelector } from "../features/fastLogin/store/selectors";
import { isGestureEnabled } from "../utils/navigation";
import { OnboardingParamsList } from "./params/OnboardingParamsList";
import ROUTES from "./routes";

Expand All @@ -31,7 +31,6 @@ const OnboardingNavigator = () => {
return (
<Stack.Navigator
initialRouteName={ROUTES.ONBOARDING_SHARE_DATA}
headerMode={"none"}
screenOptions={{ gestureEnabled: isGestureEnabled }}
>
<Stack.Screen
Expand All @@ -43,53 +42,65 @@ const OnboardingNavigator = () => {
component={OnboardingServicesPreferenceScreen}
/>
<Stack.Screen
options={{ headerShown: false }}
name={ROUTES.ONBOARDING_SERVICES_PREFERENCE_COMPLETE}
component={ServicePreferenceCompleteScreen}
/>
<Stack.Screen
options={{ headerShown: false }}
name={ROUTES.ONBOARDING_TOS}
component={OnboardingTosScreen}
/>
<Stack.Screen
options={{ headerShown: false }}
name={ROUTES.ONBOARDING_PIN}
component={OnboardingPinScreen}
/>
<Stack.Screen
options={{ headerShown: false }}
name={ROUTES.ONBOARDING_FINGERPRINT}
component={FingerprintScreen}
/>
<Stack.Screen
options={{ headerShown: false }}
name={ROUTES.ONBOARDING_MISSING_DEVICE_PIN}
component={MissingDevicePinScreen}
/>
<Stack.Screen
options={{ headerShown: false }}
name={ROUTES.ONBOARDING_MISSING_DEVICE_BIOMETRIC}
component={MissingDeviceBiometricScreen}
/>
<Stack.Screen
options={{ headerShown: false }}
name={ROUTES.ONBOARDING_INSERT_EMAIL_SCREEN}
component={OnboardingEmailInsertScreen}
/>
{isEmailUniquenessValidationEnabled ? (
<Stack.Screen
options={{ headerShown: false }}
name={ROUTES.ONBOARDING_READ_EMAIL_SCREEN}
component={CduEmailInsertScreen}
/>
) : (
<Stack.Screen
options={{ headerShown: false }}
name={ROUTES.ONBOARDING_READ_EMAIL_SCREEN}
component={OnboardingEmailReadScreen}
/>
)}
<Stack.Screen
options={{ headerShown: false }}
name={ROUTES.ONBOARDING_COMPLETED}
component={OnboardingCompletedScreen}
/>
<Stack.Screen
options={{ headerShown: false }}
name={ROUTES.ONBOARDING_NOTIFICATIONS_PREFERENCES}
component={OnboardingNotificationsPreferencesScreen}
/>
<Stack.Screen
options={{ headerShown: false }}
name={ROUTES.ONBOARDING_NOTIFICATIONS_INFO_SCREEN_CONSENT}
component={OnboardingNotificationsInfoScreenConsent}
/>
Expand Down
48 changes: 29 additions & 19 deletions ts/screens/onboarding/OnboardingServicesPreferenceScreen.tsx
Original file line number Diff line number Diff line change
@@ -1,16 +1,16 @@
import { VSpacer } from "@pagopa/io-app-design-system";
import * as pot from "@pagopa/ts-commons/lib/pot";
import * as React from "react";
import { SafeAreaView, ScrollView } from "react-native";
import { SafeAreaView, View } from "react-native";
import { connect, useStore } from "react-redux";
import { VSpacer } from "@pagopa/io-app-design-system";
import { ServicesPreferencesModeEnum } from "../../../definitions/backend/ServicesPreferencesMode";
import { InfoBox } from "../../components/box/InfoBox";
import { confirmButtonProps } from "../../components/buttons/ButtonConfigurations";
import { H5 } from "../../components/core/typography/H5";
import { IOStyles } from "../../components/core/variables/IOStyles";
import { withLoadingSpinner } from "../../components/helpers/withLoadingSpinner";
import BaseScreenComponent from "../../components/screens/BaseScreenComponent";
import FooterWithButtons from "../../components/ui/FooterWithButtons";
import { confirmButtonProps } from "../../components/buttons/ButtonConfigurations";
import { RNavScreenWithLargeHeader } from "../../components/ui/RNavScreenWithLargeHeader";
import I18n from "../../i18n";
import { IOStackNavigationRouteProps } from "../../navigation/params/AppParamsList";
import { OnboardingParamsList } from "../../navigation/params/OnboardingParamsList";
Expand All @@ -24,16 +24,16 @@ import {
profileServicePreferencesModeSelector
} from "../../store/reducers/profile";
import { GlobalState } from "../../store/reducers/types";
import { getFlowType } from "../../utils/analytics";
import { emptyContextualHelp } from "../../utils/emptyContextualHelp";
import { showToast } from "../../utils/showToast";
import { useManualConfigBottomSheet } from "../profile/components/services/ManualConfigBottomSheet";
import ServicesContactComponent from "../profile/components/services/ServicesContactComponent";
import { useOnFirstRender } from "../../utils/hooks/useOnFirstRender";
import { showToast } from "../../utils/showToast";
import {
trackServiceConfiguration,
trackServiceConfigurationScreen
} from "../profile/analytics";
import { getFlowType } from "../../utils/analytics";
import { useManualConfigBottomSheet } from "../profile/components/services/ManualConfigBottomSheet";
import ServicesContactComponent from "../profile/components/services/ServicesContactComponent";

export type OnboardingServicesPreferenceScreenNavigationParams = {
isFirstOnboarding: boolean;
Expand Down Expand Up @@ -114,9 +114,25 @@ const OnboardingServicesPreferenceScreen = (
// show a badge when the user is not new
const showBadge = !isFirstOnboarding;
return (
<BaseScreenComponent contextualHelp={emptyContextualHelp}>
<RNavScreenWithLargeHeader
title={I18n.t("services.optIn.preferences.title")}
description={I18n.t("services.optIn.preferences.body")}
headerActionsProp={{ showHelp: true }}
contextualHelp={emptyContextualHelp}
fixedBottomSlot={
<SafeAreaView>
<FooterWithButtons
type={"SingleButton"}
leftButton={{
...confirmButtonProps(handleOnContinue),
disabled: !isServicesPreferenceModeSet(modeSelected)
}}
/>
</SafeAreaView>
}
>
<SafeAreaView style={IOStyles.flex}>
<ScrollView style={[IOStyles.horizontalContentPadding, IOStyles.flex]}>
<View style={[IOStyles.horizontalContentPadding, { flexGrow: 1 }]}>
<ServicesContactComponent
mode={modeSelected}
onSelectMode={handleOnSelectMode}
Expand All @@ -128,17 +144,11 @@ const OnboardingServicesPreferenceScreen = (
</H5>
</InfoBox>
<VSpacer size={16} />
</ScrollView>
<FooterWithButtons
type={"SingleButton"}
leftButton={{
...confirmButtonProps(handleOnContinue),
disabled: !isServicesPreferenceModeSet(modeSelected)
}}
/>
</View>

{manualConfigBottomSheet}
</SafeAreaView>
</BaseScreenComponent>
</RNavScreenWithLargeHeader>
);
};

Expand Down
70 changes: 38 additions & 32 deletions ts/screens/onboarding/OnboardingShareDataScreen.tsx
Original file line number Diff line number Diff line change
@@ -1,17 +1,17 @@
import { IOColors, VSpacer } from "@pagopa/io-app-design-system";
import { VSpacer } from "@pagopa/io-app-design-system";
import * as React from "react";
import { Alert, SafeAreaView, ScrollView, StatusBar } from "react-native";
import { Alert, SafeAreaView, View } from "react-native";
import { connect, useDispatch } from "react-redux";
import { Dispatch } from "redux";
import { InfoBox } from "../../components/box/InfoBox";
import { Label } from "../../components/core/typography/Label";
import { IOStyles } from "../../components/core/variables/IOStyles";
import BaseScreenComponent from "../../components/screens/BaseScreenComponent";
import FooterWithButtons from "../../components/ui/FooterWithButtons";
import {
cancelButtonProps,
confirmButtonProps
} from "../../components/buttons/ButtonConfigurations";
import { Label } from "../../components/core/typography/Label";
import { IOStyles } from "../../components/core/variables/IOStyles";
import FooterWithButtons from "../../components/ui/FooterWithButtons";
import { RNavScreenWithLargeHeader } from "../../components/ui/RNavScreenWithLargeHeader";
import I18n from "../../i18n";
import { setMixpanelEnabled } from "../../store/actions/mixpanel";
import { abortOnboarding } from "../../store/actions/onboarding";
Expand Down Expand Up @@ -69,43 +69,49 @@ const OnboardingShareDataScreen = (props: Props): React.ReactElement => {
};

return (
<BaseScreenComponent
<RNavScreenWithLargeHeader
goBack={handleGoBack}
headerTitle={I18n.t("onboarding.shareData.title")}
title={I18n.t("profile.main.privacy.shareData.screen.title")}
titleTestID={"share-data-component-title"}
description={I18n.t("profile.main.privacy.shareData.screen.description")}
fixedBottomSlot={
<SafeAreaView>
<FooterWithButtons
type={"TwoButtonsInlineHalf"}
leftButton={cancelButtonProps(
present,
I18n.t("profile.main.privacy.shareData.screen.cta.dontShare")
)}
rightButton={confirmButtonProps(
() => {
trackMixpanelSetEnabled(
true,
getFlowType(true, isFirstOnBoarding)
);
props.setMixpanelEnabled(true);
},
I18n.t("profile.main.privacy.shareData.screen.cta.shareData"),
undefined,
"share-data-confirm-button"
)}
/>
</SafeAreaView>
}
>
<SafeAreaView style={IOStyles.flex}>
<StatusBar backgroundColor={IOColors.white} barStyle={"dark-content"} />
<ScrollView style={IOStyles.horizontalContentPadding}>
<View style={[IOStyles.horizontalContentPadding, { flexGrow: 1 }]}>
<ShareDataComponent />
<VSpacer size={16} />
<VSpacer size={24} />
<InfoBox iconName="profile" iconColor="bluegrey">
<Label color={"bluegrey"} weight={"Regular"}>
{I18n.t("profile.main.privacy.shareData.screen.profileSettings")}
</Label>
</InfoBox>
</ScrollView>
<FooterWithButtons
type={"TwoButtonsInlineHalf"}
leftButton={cancelButtonProps(
present,
I18n.t("profile.main.privacy.shareData.screen.cta.dontShare")
)}
rightButton={confirmButtonProps(
() => {
trackMixpanelSetEnabled(
true,
getFlowType(true, isFirstOnBoarding)
);
props.setMixpanelEnabled(true);
},
I18n.t("profile.main.privacy.shareData.screen.cta.shareData"),
undefined,
"share-data-confirm-button"
)}
/>
</View>

{bottomSheet}
</SafeAreaView>
</BaseScreenComponent>
</RNavScreenWithLargeHeader>
);
};

Expand Down
7 changes: 4 additions & 3 deletions ts/screens/profile/ShareDataScreen.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,13 @@ import * as React from "react";
import { SafeAreaView, View } from "react-native";
import { connect } from "react-redux";
import { Dispatch } from "redux";
import { IOStyles } from "../../components/core/variables/IOStyles";
import FooterWithButtons from "../../components/ui/FooterWithButtons";
import { RNavScreenWithLargeHeader } from "../../components/ui/RNavScreenWithLargeHeader";
import {
cancelButtonProps,
confirmButtonProps
} from "../../components/buttons/ButtonConfigurations";
import { IOStyles } from "../../components/core/variables/IOStyles";
import FooterWithButtons from "../../components/ui/FooterWithButtons";
import { RNavScreenWithLargeHeader } from "../../components/ui/RNavScreenWithLargeHeader";
import I18n from "../../i18n";
import { setMixpanelEnabled } from "../../store/actions/mixpanel";
import { isMixpanelEnabled } from "../../store/reducers/persistedPreferences";
Expand Down Expand Up @@ -66,6 +66,7 @@ const ShareDataScreen = (props: Props): React.ReactElement => {
return (
<RNavScreenWithLargeHeader
title={I18n.t("profile.main.privacy.shareData.screen.title")}
titleTestID={"share-data-component-title"}
description={I18n.t("profile.main.privacy.shareData.screen.description")}
fixedBottomSlot={
<SafeAreaView>
Expand Down

0 comments on commit 30fe477

Please sign in to comment.