Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[LLM][PROTECT-3391/3392/3393/3401/3403] Auto redirection to Recover upsell at the end of Stax/Flex onboarding #8226

Merged
merged 3 commits into from
Oct 31, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions .changeset/green-rice-cheer.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
---
"live-mobile": patch
---

Stax/Flex onboarding:
- Hide "Backup with Recover" section
- Auto redirect to Recover upsell between the onboarding and the post onboarding

6 changes: 6 additions & 0 deletions .changeset/slow-buses-end.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
"@ledgerhq/types-live": patch
"@ledgerhq/live-common": patch
---

Add recoverUpsellRedirection feature flag
6 changes: 6 additions & 0 deletions apps/ledger-live-mobile/src/actions/settings.ts
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@ import {
SettingsAddStarredMarketcoinsPayload,
SettingsRemoveStarredMarketcoinsPayload,
SettingsSetFromLedgerSyncOnboardingPayload,
SettingsSetHasBeenRedirectedToPostOnboardingPayload,
} from "./types";
import { ImageType } from "~/components/CustomImage/types";

Expand Down Expand Up @@ -264,6 +265,11 @@ export const setHasBeenUpsoldProtect = createAction<SettingsSetHasBeenUpsoldProt
SettingsActionTypes.SET_HAS_BEEN_UPSOLD_PROTECT,
);

export const setHasBeenRedirectedToPostOnboarding =
createAction<SettingsSetHasBeenRedirectedToPostOnboardingPayload>(
SettingsActionTypes.SET_HAS_BEEN_REDIRECTED_TO_POST_ONBOARDING,
);

export const setGeneralTermsVersionAccepted = createAction<SettingsSetGeneralTermsVersionAccepted>(
SettingsActionTypes.SET_GENERAL_TERMS_VERSION_ACCEPTED,
);
Expand Down
3 changes: 3 additions & 0 deletions apps/ledger-live-mobile/src/actions/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -273,6 +273,7 @@ export enum SettingsActionTypes {
SET_FEATURE_FLAGS_BANNER_VISIBLE = "SET_FEATURE_FLAGS_BANNER_VISIBLE",
SET_DEBUG_APP_LEVEL_DRAWER_OPENED = "SET_DEBUG_APP_LEVEL_DRAWER_OPENED",
SET_HAS_BEEN_UPSOLD_PROTECT = "SET_HAS_BEEN_UPSOLD_PROTECT",
SET_HAS_BEEN_REDIRECTED_TO_POST_ONBOARDING = "SET_HAS_BEEN_REDIRECTED_TO_POST_ONBOARDING",
SET_GENERAL_TERMS_VERSION_ACCEPTED = "SET_GENERAL_TERMS_VERSION_ACCEPTED",
SET_ONBOARDING_TYPE = "SET_ONBOARDING_TYPE",
SET_CLOSED_NETWORK_BANNER = "SET_CLOSED_NETWORK_BANNER",
Expand Down Expand Up @@ -379,6 +380,8 @@ export type SettingsSetDebugAppLevelDrawerOpenedPayload =
SettingsState["debugAppLevelDrawerOpened"];

export type SettingsSetHasBeenUpsoldProtectPayload = SettingsState["hasBeenUpsoldProtect"];
export type SettingsSetHasBeenRedirectedToPostOnboardingPayload =
SettingsState["hasBeenRedirectedToPostOnboarding"];

export type SettingsCompleteOnboardingPayload = void | SettingsState["hasCompletedOnboarding"];
export type SettingsSetGeneralTermsVersionAccepted = SettingsState["generalTermsVersionAccepted"];
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import { useEffect } from "react";
import { useSelector } from "react-redux";
import { lastConnectedDeviceSelector } from "~/reducers/settings";
import { useOpenPostOnboardingCallback } from "./useOpenPostOnboardingCallback";
import { useShouldRedirect } from "./useShouldRedirect";
import { useOpenProtectUpsellCallback } from "./useOpenProtectUpsellCallback";
import { useIsFocused } from "@react-navigation/core";

/**
* Redirects the user to the post onboarding or the protect (Ledger Recover) upsell if needed
* */
export function useAutoRedirectToPostOnboarding() {
const focused = useIsFocused();
const lastConnectedDevice = useSelector(lastConnectedDeviceSelector);

const { shouldRedirectToProtectUpsell, shouldRedirectToPostOnboarding } = useShouldRedirect();

const openProtectUpsell = useOpenProtectUpsellCallback();
const openPostOnboarding = useOpenPostOnboardingCallback();

const isFocused = useIsFocused();

useEffect(() => {
if (!isFocused) return;
if (shouldRedirectToProtectUpsell) {
openProtectUpsell();
} else if (shouldRedirectToPostOnboarding && lastConnectedDevice) {
openPostOnboarding(lastConnectedDevice.modelId);
}
}, [
lastConnectedDevice,
openPostOnboarding,
openProtectUpsell,
shouldRedirectToPostOnboarding,
shouldRedirectToProtectUpsell,
focused,
isFocused,
]);
Comment on lines +23 to +38
Copy link
Contributor

@Justkant Justkant Oct 31, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm wondering if there is a risk of us calling again an open because isFocused toggles when opening the first time and coming back to the screen using this hook

Edit: probably handled here I suppose https://github.com/LedgerHQ/ledger-live/pull/8226/files#diff-3f35818d8304ffbf87ae671eca670437cfc8eade2dfac067406cdb959ae5f496R37-R41

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Once the redirection to whatever is done, shouldRedirectToWhatever will be false, so it won't trigger again 👍

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import { useStartPostOnboardingCallback } from "@ledgerhq/live-common/postOnboarding/hooks/useStartPostOnboardingCallback";
import { DeviceModelId } from "@ledgerhq/types-devices";
import { useCallback } from "react";

/**
* Returns a callback to open the post onboarding screen
* */
export function useOpenPostOnboardingCallback() {
const startPostOnboarding = useStartPostOnboardingCallback();
return useCallback(
(deviceModelId: DeviceModelId) => {
startPostOnboarding({
deviceModelId: deviceModelId,
resetNavigationStack: false,
});
},
[startPostOnboarding],
);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
import { useFeature } from "@ledgerhq/live-common/featureFlags/index";
import {
Source,
useAlreadyOnboardedURI,
useHomeURI,
usePostOnboardingURI,
useTouchScreenOnboardingUpsellURI,
} from "@ledgerhq/live-common/hooks/recoverFeatureFlag";
import { DeviceModelId } from "@ledgerhq/types-devices";
import { useIsFocused } from "@react-navigation/core";
import { useCallback, useEffect, useState } from "react";
import { Linking } from "react-native";
import { useDispatch, useSelector } from "react-redux";
import { setHasBeenUpsoldProtect } from "~/actions/settings";
import { internetReachable } from "~/logic/internetReachable";
import { lastConnectedDeviceSelector, onboardingTypeSelector } from "~/reducers/settings";
import { OnboardingType } from "~/reducers/types";

/**
* Returns a callback to open the Protect (Ledger Recover) upsell
* */
export function useOpenProtectUpsellCallback() {
const lastConnectedDevice = useSelector(lastConnectedDeviceSelector);
const onboardingType = useSelector(onboardingTypeSelector);
const protectFeature = useFeature("protectServicesMobile");
const recoverAlreadyOnboardedURI = useAlreadyOnboardedURI(protectFeature);
const recoverPostOnboardingURI = usePostOnboardingURI(protectFeature);
const touchScreenURI = useTouchScreenOnboardingUpsellURI(
protectFeature,
Source.LLM_ONBOARDING_24,
);
const recoverHomeURI = useHomeURI(protectFeature);
const dispatch = useDispatch();
const [redirectionStarted, setRedirectionStarted] = useState(false);
const isFocused = useIsFocused();

useEffect(() => {
if (redirectionStarted && !isFocused) {
dispatch(setHasBeenUpsoldProtect(true));
}
}, [redirectionStarted, isFocused, dispatch]);

return useCallback(async () => {
const internetConnected = await internetReachable();
if (internetConnected && protectFeature?.enabled) {
const redirect = (url: string) => {
Linking.openURL(url);
setRedirectionStarted(true);
};
if (
lastConnectedDevice &&
touchScreenURI &&
[DeviceModelId.stax, DeviceModelId.europa].includes(lastConnectedDevice.modelId)
) {
redirect(touchScreenURI);
} else if (recoverPostOnboardingURI && onboardingType === OnboardingType.restore) {
redirect(recoverPostOnboardingURI);
} else if (recoverHomeURI && onboardingType === OnboardingType.setupNew) {
redirect(recoverHomeURI);
} else if (recoverAlreadyOnboardedURI) {
redirect(recoverAlreadyOnboardedURI);
}
}
}, [
lastConnectedDevice,
onboardingType,
protectFeature?.enabled,
recoverAlreadyOnboardedURI,
recoverHomeURI,
recoverPostOnboardingURI,
touchScreenURI,
]);
}
Loading
Loading