From d411d2d44a548ddc9741307b3bbc004ceb9e8fbe Mon Sep 17 00:00:00 2001 From: Petr Knetl Date: Wed, 15 Jan 2025 09:47:03 +0100 Subject: [PATCH] feat(suite-native): analytics consent screen redesign --- suite-native/intl/src/en.ts | 10 +- .../src/screens/AnalyticsConsentScreen.tsx | 4 +- .../src/components/AnalyticsInfoRow.tsx | 42 ++++++ .../navigation/OnboardingStackNavigator.tsx | 5 + .../src/screens/AnalyticsConsentScreen.tsx | 129 ++++++++++++++++++ .../src/screens/WelcomeScreen.tsx | 27 ++-- suite-native/navigation/src/navigators.ts | 1 + suite-native/navigation/src/routes.ts | 1 + 8 files changed, 202 insertions(+), 17 deletions(-) create mode 100644 suite-native/module-onboarding/src/components/AnalyticsInfoRow.tsx create mode 100644 suite-native/module-onboarding/src/screens/AnalyticsConsentScreen.tsx diff --git a/suite-native/intl/src/en.ts b/suite-native/intl/src/en.ts index ce9dc08fc83..b6ed51bd4f1 100644 --- a/suite-native/intl/src/en.ts +++ b/suite-native/intl/src/en.ts @@ -803,8 +803,9 @@ export const en = { }, }, analyticsConsentScreen: { - title: 'Better with you', - subtitle: 'Improve Trezor Suite Lite with your anonymous data.', + title: 'Better—with you.', + subtitle: + 'Help us shape a better experience for you by allowing anonymous data collection.', bulletPoints: { privacy: { title: 'Your data is private', @@ -818,6 +819,11 @@ export const en = { }, }, helpSwitchTitle: 'Help us anonymously', + learnMoreButton: 'More about privacy', + + // TODO: this should be removed when is the new onboarding enabled by default + titleLegacy: 'Better with you', + subtitleLegacy: 'Improve Trezor Suite Lite with your anonymous data.', learnMore: 'More about privacy', }, }, diff --git a/suite-native/module-onboarding-legacy/src/screens/AnalyticsConsentScreen.tsx b/suite-native/module-onboarding-legacy/src/screens/AnalyticsConsentScreen.tsx index a465f8cc3cc..1a5a49214ab 100644 --- a/suite-native/module-onboarding-legacy/src/screens/AnalyticsConsentScreen.tsx +++ b/suite-native/module-onboarding-legacy/src/screens/AnalyticsConsentScreen.tsx @@ -140,10 +140,10 @@ export const AnalyticsConsentScreen = () => { > - + - + diff --git a/suite-native/module-onboarding/src/components/AnalyticsInfoRow.tsx b/suite-native/module-onboarding/src/components/AnalyticsInfoRow.tsx new file mode 100644 index 00000000000..240487dc5db --- /dev/null +++ b/suite-native/module-onboarding/src/components/AnalyticsInfoRow.tsx @@ -0,0 +1,42 @@ +import { ReactNode } from 'react'; + +import { Icon, IconName } from '@suite-native/icons'; +import { prepareNativeStyle, useNativeStyles } from '@trezor/styles'; +import { Box, HStack, Text, VStack } from '@suite-native/atoms'; + +type AnalyticsInfoRowProps = { + iconName: IconName; + title: ReactNode; + description: ReactNode; +}; + +const WRAPPER_SIZE = 36; + +const iconWrapper = prepareNativeStyle(utils => ({ + justifyContent: 'center', + alignItems: 'center', + width: WRAPPER_SIZE, + height: WRAPPER_SIZE, + backgroundColor: utils.colors.backgroundSurfaceElevation2, + borderRadius: utils.borders.radii.r12, + borderWidth: 1, + borderColor: utils.colors.backgroundTertiaryDefaultOnElevation0, +})); + +export const AnalyticsInfoRow = ({ iconName, title, description }: AnalyticsInfoRowProps) => { + const { applyStyle } = useNativeStyles(); + + return ( + + + + + + {title} + + {description} + + + + ); +}; diff --git a/suite-native/module-onboarding/src/navigation/OnboardingStackNavigator.tsx b/suite-native/module-onboarding/src/navigation/OnboardingStackNavigator.tsx index 273f90fea1b..63f0a88222e 100644 --- a/suite-native/module-onboarding/src/navigation/OnboardingStackNavigator.tsx +++ b/suite-native/module-onboarding/src/navigation/OnboardingStackNavigator.tsx @@ -7,6 +7,7 @@ import { } from '@suite-native/navigation'; import { WelcomeScreen } from '../screens/WelcomeScreen'; +import { AnalyticsConsentScreen } from '../screens/AnalyticsConsentScreen'; export const OnboardingStack = createNativeStackNavigator(); @@ -16,5 +17,9 @@ export const OnboardingStackNavigator = () => ( screenOptions={stackNavigationOptionsConfig} > + ); diff --git a/suite-native/module-onboarding/src/screens/AnalyticsConsentScreen.tsx b/suite-native/module-onboarding/src/screens/AnalyticsConsentScreen.tsx new file mode 100644 index 00000000000..c3a6b53d712 --- /dev/null +++ b/suite-native/module-onboarding/src/screens/AnalyticsConsentScreen.tsx @@ -0,0 +1,129 @@ +import { useState } from 'react'; + +import { Screen } from '@suite-native/navigation'; +import { Box, Button, Card, Switch, Text, TitleHeader, VStack } from '@suite-native/atoms'; +import { Translation } from '@suite-native/intl'; +import { prepareNativeStyle, useNativeStyles } from '@trezor/styles'; +import { EventType, analytics } from '@suite-native/analytics'; +import { useOpenLink } from '@suite-native/link'; +import { useToast } from '@suite-native/toasts'; + +import { AnalyticsInfoRow } from '../components/AnalyticsInfoRow'; + +const LEARN_MORE_LINK = 'https://data.trezor.io/legal/privacy-policy.html'; + +const consentWrapperStyle = prepareNativeStyle(utils => ({ + padding: utils.spacings.sp16, + borderRadius: utils.borders.radii.r16, + backgroundColor: utils.colors.backgroundTertiaryDefaultOnElevation1, +})); + +const reportAnalyticsOnboardingCompleted = (isTrackingAllowed: boolean) => { + // For users who have not allowed tracking, enable analytics just for reporting + // the OnboardingCompleted event and then disable it again. + if (!isTrackingAllowed) analytics.enable(); + analytics.report({ + type: EventType.OnboardingCompleted, + payload: { analyticsPermission: isTrackingAllowed }, + }); + if (!isTrackingAllowed) analytics.disable(); +}; + +export const AnalyticsConsentScreen = () => { + const { showToast } = useToast(); + const [isEnabled, setIsEnabled] = useState(true); + + const { applyStyle } = useNativeStyles(); + + const handleOpenLink = useOpenLink(); + + const handleRedirect = () => { + reportAnalyticsOnboardingCompleted(isEnabled); + + showToast({ variant: 'warning', message: 'TODO: implement next screen' }); + // navigation.navigate(OnboardingStackRoutes.Biometrics); + }; + + const handleAnalyticsConsent = () => { + analytics.enable(); + handleRedirect(); + }; + + const handleClickOnLearMoreLink = () => { + handleOpenLink(LEARN_MORE_LINK); + }; + + return ( + + + + } + titleVariant="titleMedium" + subtitle={ + + } + titleSpacing="sp12" + /> + + + + + + } + description={ + + } + /> + + } + description={ + + } + /> + + + + + + { + setIsEnabled(enabled); + }} + /> + + + + + + + + + + + + ); +}; diff --git a/suite-native/module-onboarding/src/screens/WelcomeScreen.tsx b/suite-native/module-onboarding/src/screens/WelcomeScreen.tsx index a5c6cdf8532..494b2d88034 100644 --- a/suite-native/module-onboarding/src/screens/WelcomeScreen.tsx +++ b/suite-native/module-onboarding/src/screens/WelcomeScreen.tsx @@ -2,14 +2,18 @@ import { ImageBackground, StyleSheet } from 'react-native'; import { LinearGradient } from 'expo-linear-gradient'; -import { Screen } from '@suite-native/navigation'; +import { + OnboardingStackParamList, + OnboardingStackRoutes, + Screen, + StackProps, +} from '@suite-native/navigation'; import { Box, Button, Text, VStack } from '@suite-native/atoms'; import { Translation } from '@suite-native/intl'; import { Icon } from '@suite-native/icons'; import { prepareNativeStyle, useNativeStyles } from '@trezor/styles'; import { hexToRgba } from '@suite-common/suite-utils'; import { getWindowHeight } from '@trezor/env-utils'; -import { useToast } from '@suite-native/toasts'; import { colorVariants } from '@trezor/theme'; const GRADIENT_HEIGHT = getWindowHeight() / 3; @@ -29,14 +33,18 @@ const textColorStyle = prepareNativeStyle(() => ({ color: colorVariants.dark.textDefault, })); -export const WelcomeScreen = () => { - const { showToast } = useToast(); - +export const WelcomeScreen = ({ + navigation, +}: StackProps) => { const { applyStyle } = useNativeStyles(); // 'transparent' color is not working in context of LinearGradient on iOS. RGBA has to be used instead. const transparentColor = hexToRgba('#000000', 0.01); + const navigateToAnalyticsConsent = () => { + navigation.navigate(OnboardingStackRoutes.AnalyticsConsent); + }; + return ( <> { - diff --git a/suite-native/navigation/src/navigators.ts b/suite-native/navigation/src/navigators.ts index f034864722b..11ecfc2295f 100644 --- a/suite-native/navigation/src/navigators.ts +++ b/suite-native/navigation/src/navigators.ts @@ -114,6 +114,7 @@ export type LegacyOnboardingStackParamList = { export type OnboardingStackParamList = { [OnboardingStackRoutes.Welcome]: undefined; + [OnboardingStackRoutes.AnalyticsConsent]: undefined; }; export type AccountsImportStackParamList = { diff --git a/suite-native/navigation/src/routes.ts b/suite-native/navigation/src/routes.ts index 1688932e2e9..5ae8d45c967 100644 --- a/suite-native/navigation/src/routes.ts +++ b/suite-native/navigation/src/routes.ts @@ -35,6 +35,7 @@ export enum LegacyOnboardingStackRoutes { export enum OnboardingStackRoutes { Welcome = 'Welcome', + AnalyticsConsent = 'AnalyticsConsent', } export enum AccountsImportStackRoutes {