From 0d7115c47317a28a53af1f6ae6b96947b9525c66 Mon Sep 17 00:00:00 2001 From: Lucas Werey <73439207+LucasWerey@users.noreply.github.com> Date: Mon, 2 Dec 2024 16:11:39 +0100 Subject: [PATCH] :sparkles: (llm): onboarding analytics (#8552) --- .changeset/beige-moose-worry.md | 5 +++ .../src/analytics/segment.ts | 4 +++ .../src/screens/GetDeviceScreen.tsx | 16 ++++++++-- .../Onboarding/steps/discoverLiveInfo.tsx | 6 ++-- .../Onboarding/steps/postWelcomeSelection.tsx | 31 ++++++++++++++----- .../src/screens/Onboarding/steps/welcome.tsx | 5 +-- 6 files changed, 53 insertions(+), 14 deletions(-) create mode 100644 .changeset/beige-moose-worry.md diff --git a/.changeset/beige-moose-worry.md b/.changeset/beige-moose-worry.md new file mode 100644 index 000000000000..38521fb4a0ca --- /dev/null +++ b/.changeset/beige-moose-worry.md @@ -0,0 +1,5 @@ +--- +"live-mobile": minor +--- + +Rework reborn analytics diff --git a/apps/ledger-live-mobile/src/analytics/segment.ts b/apps/ledger-live-mobile/src/analytics/segment.ts index ec34d59a7d72..a745b6acc57c 100644 --- a/apps/ledger-live-mobile/src/analytics/segment.ts +++ b/apps/ledger-live-mobile/src/analytics/segment.ts @@ -40,6 +40,7 @@ import { personalizedRecommendationsEnabledSelector, hasSeenAnalyticsOptInPromptSelector, mevProtectionSelector, + readOnlyModeEnabledSelector, } from "../reducers/settings"; import { knownDevicesSelector } from "../reducers/ble"; import { DeviceLike, State } from "../reducers/types"; @@ -171,7 +172,9 @@ const extraProperties = async (store: AppStore) => { modelId: lastDevice.modelId, } : {}; + const onboardingHasDevice = onboardingHasDeviceSelector(state); + const isReborn = readOnlyModeEnabledSelector(state); const notifications = notificationsSelector(state); const notificationsOptedIn = { notificationsAllowed: notifications.areNotificationsAllowed, @@ -227,6 +230,7 @@ const extraProperties = async (store: AppStore) => { devicesCount: devices.length, modelIdQtyList: aggregateData(devices), modelIdList: getUniqueModelIdList(devices), + isReborn, onboardingHasDevice, ...(satisfaction ? { diff --git a/apps/ledger-live-mobile/src/screens/GetDeviceScreen.tsx b/apps/ledger-live-mobile/src/screens/GetDeviceScreen.tsx index 8ffbc83e9f26..494bc3a553f6 100644 --- a/apps/ledger-live-mobile/src/screens/GetDeviceScreen.tsx +++ b/apps/ledger-live-mobile/src/screens/GetDeviceScreen.tsx @@ -14,7 +14,7 @@ import { useNavigation } from "@react-navigation/native"; import { useTranslation } from "react-i18next"; import { Linking, TouchableOpacity } from "react-native"; import { useFeature } from "@ledgerhq/live-common/featureFlags/index"; -import { useSelector } from "react-redux"; +import { useDispatch, useSelector } from "react-redux"; import Button from "~/components/wrappedUi/Button"; import { urls } from "~/utils/urls"; @@ -30,6 +30,7 @@ import { import { BuyDeviceNavigatorParamList } from "~/components/RootNavigator/types/BuyDeviceNavigator"; import { OnboardingNavigatorParamList } from "~/components/RootNavigator/types/OnboardingNavigator"; import videoSources from "../../assets/videos"; +import { setOnboardingHasDevice } from "~/actions/settings"; const sourceDark = videoSources.nanoXDark; const sourceLight = videoSources.nanoXLight; @@ -92,6 +93,9 @@ export default function GetDeviceScreen() { const buyDeviceFromLive = useFeature("buyDeviceFromLive"); const hasCompletedOnboarding = useSelector(hasCompletedOnboardingSelector); const readOnlyModeEnabled = useSelector(readOnlyModeEnabledSelector); + const dispatch = useDispatch(); + const currentNavigation = navigation.getParent()?.getParent()?.getState().routes[0].name; + const isInOnboarding = currentNavigation === NavigatorName.BaseOnboarding; const handleBack = useCallback(() => { navigation.goBack(); @@ -106,6 +110,7 @@ export default function GetDeviceScreen() { const setupDevice = useCallback(() => { setShowWelcome(false); setFirstTimeOnboarding(false); + if (isInOnboarding) dispatch(setOnboardingHasDevice(true)); navigation.navigate(NavigatorName.BaseOnboarding, { screen: NavigatorName.Onboarding, params: { @@ -118,7 +123,14 @@ export default function GetDeviceScreen() { page: "Upsell Nano", }); } - }, [readOnlyModeEnabled, navigation, setFirstTimeOnboarding, setShowWelcome]); + }, [ + setShowWelcome, + setFirstTimeOnboarding, + isInOnboarding, + dispatch, + navigation, + readOnlyModeEnabled, + ]); const buyLedger = useCallback(() => { if (buyDeviceFromLive?.enabled) { diff --git a/apps/ledger-live-mobile/src/screens/Onboarding/steps/discoverLiveInfo.tsx b/apps/ledger-live-mobile/src/screens/Onboarding/steps/discoverLiveInfo.tsx index 18e4dcb8dd71..b39b5dfa96c9 100644 --- a/apps/ledger-live-mobile/src/screens/Onboarding/steps/discoverLiveInfo.tsx +++ b/apps/ledger-live-mobile/src/screens/Onboarding/steps/discoverLiveInfo.tsx @@ -7,7 +7,7 @@ import styled, { useTheme } from "styled-components/native"; import { useDispatch } from "react-redux"; import Svg, { Defs, LinearGradient, Rect, Stop } from "react-native-svg"; import { Image, ImageProps } from "react-native"; -import { completeOnboarding, setReadOnlyMode } from "~/actions/settings"; +import { completeOnboarding, setOnboardingHasDevice, setReadOnlyMode } from "~/actions/settings"; import { NavigatorName, ScreenName } from "~/const"; import { screen, track } from "~/analytics"; @@ -79,6 +79,7 @@ const Item = ({ dispatch(completeOnboarding()); dispatch(setReadOnlyMode(true)); onClick("Explore without a device"); + dispatch(setOnboardingHasDevice(false)); navigation.reset({ index: 0, @@ -88,8 +89,9 @@ const Item = ({ const pressExplore = useCallback(() => { exploreLedger(); + dispatch(setOnboardingHasDevice(false)); onClick("Explore without a device"); - }, [exploreLedger, onClick]); + }, [exploreLedger, dispatch, onClick]); const pressBuy = useCallback(() => { buyLedger(); diff --git a/apps/ledger-live-mobile/src/screens/Onboarding/steps/postWelcomeSelection.tsx b/apps/ledger-live-mobile/src/screens/Onboarding/steps/postWelcomeSelection.tsx index f2c6c34b740c..67055b048e20 100644 --- a/apps/ledger-live-mobile/src/screens/Onboarding/steps/postWelcomeSelection.tsx +++ b/apps/ledger-live-mobile/src/screens/Onboarding/steps/postWelcomeSelection.tsx @@ -1,6 +1,6 @@ import { Button, Icons } from "@ledgerhq/native-ui"; -import { useNavigation } from "@react-navigation/native"; -import React, { useState } from "react"; +import { useFocusEffect, useNavigation } from "@react-navigation/native"; +import React, { useCallback, useState } from "react"; import { useTranslation } from "react-i18next"; import { useDispatch } from "react-redux"; import { useTheme } from "styled-components/native"; @@ -8,7 +8,7 @@ import { setOnboardingHasDevice, setReadOnlyMode } from "~/actions/settings"; import { track, updateIdentify } from "~/analytics"; import { OnboardingNavigatorParamList } from "~/components/RootNavigator/types/OnboardingNavigator"; import { StackNavigatorProps } from "~/components/RootNavigator/types/helpers"; -import { ScreenName } from "~/const"; +import { NavigatorName, ScreenName } from "~/const"; import { SelectionCards } from "./Cards/SelectionCard"; import { NoLedgerYetModal } from "./NoLedgerYetModal"; import OnboardingView from "./OnboardingView"; @@ -23,23 +23,38 @@ function PostWelcomeSelection() { const { colors } = useTheme(); const { t } = useTranslation(); const navigation = useNavigation(); + const currentNavigation = navigation.getParent()?.getParent()?.getState().routes[0].name; + const isInOnboarding = currentNavigation === NavigatorName.BaseOnboarding; const [modalOpen, setModalOpen] = useState(false); const openModal = () => { + identifyUser(false); setModalOpen(true); track("button_clicked", { button: "I don’t have a Ledger yet", }); }; - const closeModal = () => setModalOpen(false); - - const identifyUser = (hasDevice: boolean) => { - dispatch(setOnboardingHasDevice(hasDevice)); - updateIdentify(); + const closeModal = () => { + setModalOpen(false); }; + const identifyUser = useCallback( + (hasDevice: boolean | null) => { + if (isInOnboarding) dispatch(setOnboardingHasDevice(hasDevice)); + updateIdentify(); + }, + [dispatch, isInOnboarding], + ); + + useFocusEffect(() => { + if (!modalOpen) { + identifyUser(null); + dispatch(setReadOnlyMode(true)); + } + }); + const setupLedger = () => { dispatch(setReadOnlyMode(false)); identifyUser(true); diff --git a/apps/ledger-live-mobile/src/screens/Onboarding/steps/welcome.tsx b/apps/ledger-live-mobile/src/screens/Onboarding/steps/welcome.tsx index d3eefb933e83..9bbe884247a2 100644 --- a/apps/ledger-live-mobile/src/screens/Onboarding/steps/welcome.tsx +++ b/apps/ledger-live-mobile/src/screens/Onboarding/steps/welcome.tsx @@ -12,7 +12,7 @@ import { NavigatorName, ScreenName } from "~/const"; import StyledStatusBar from "~/components/StyledStatusBar"; import { urls } from "~/utils/urls"; import { useAcceptGeneralTerms } from "~/logic/terms"; -import { setAnalytics } from "~/actions/settings"; +import { setAnalytics, setOnboardingHasDevice } from "~/actions/settings"; import useIsAppInBackground from "~/components/useIsAppInBackground"; import ForceTheme from "~/components/theme/ForceTheme"; import Button from "~/components/wrappedUi/Button"; @@ -119,10 +119,11 @@ function OnboardingStepWelcome({ navigation }: NavigationProps) { ); useEffect(() => { + dispatch(setOnboardingHasDevice(null)); return () => { if (timeout.current) clearTimeout(timeout.current); }; - }, []); + }, [dispatch]); const videoSource = videoSources.welcomeScreenStax;