From 6753e3d210a0bd7fd2b32df32528468c0bd8b569 Mon Sep 17 00:00:00 2001 From: Kathy Luo Date: Mon, 27 Jan 2025 12:57:35 +0100 Subject: [PATCH 01/10] feat: add demo mode entry in onboarding screen --- src/app/actions.ts | 14 +++++++++++ src/app/reducers.ts | 7 ++++++ src/app/selectors.ts | 16 ++++++++++++ src/navigator/NavigatorWrapper.tsx | 39 +++++++++++++++++++++--------- src/onboarding/welcome/Welcome.tsx | 36 ++++++++++++++++++++++++--- src/redux/migrations.ts | 7 ++++++ src/redux/store.test.ts | 3 ++- src/redux/store.ts | 2 +- src/statsig/constants.ts | 7 ++++++ src/statsig/types.ts | 1 + src/web3/selectors.ts | 16 +++++++++++- test/RootStateSchema.json | 4 +++ test/schemas.ts | 14 ++++++++++- 13 files changed, 147 insertions(+), 19 deletions(-) diff --git a/src/app/actions.ts b/src/app/actions.ts index a3fb4fb41c2..74e2499b41a 100644 --- a/src/app/actions.ts +++ b/src/app/actions.ts @@ -34,6 +34,7 @@ export enum Actions { IN_APP_REVIEW_REQUESTED = 'APP/IN_APP_REVIEW_REQUESTED', NOTIFICATION_SPOTLIGHT_SEEN = 'APP/NOTIFICATION_SPOTLIGHT_SEEN', TOGGLE_HIDE_BALANCES = 'APP/TOGGLE_HIDE_BALANCES', + DEMO_MODE_TOGGLED = 'APP/DEMO_MODE_TOGGLED', } export interface SetAppState { @@ -157,6 +158,11 @@ interface ToggleHideBalances { type: Actions.TOGGLE_HIDE_BALANCES } +interface DemoModeToggled { + type: Actions.DEMO_MODE_TOGGLED + enabled: boolean +} + export type ActionTypes = | SetAppState | SetLoggedIn @@ -182,6 +188,7 @@ export type ActionTypes = | NotificationSpotlightSeen | ToggleHideBalances | DeepLinkDeferred + | DemoModeToggled export const setAppState = (state: string): SetAppState => ({ type: Actions.SET_APP_STATE, @@ -340,3 +347,10 @@ export const toggleHideBalances = (): ToggleHideBalances => { type: Actions.TOGGLE_HIDE_BALANCES, } } + +export const demoModeToggled = (enabled: boolean): DemoModeToggled => { + return { + type: Actions.DEMO_MODE_TOGGLED, + enabled, + } +} diff --git a/src/app/reducers.ts b/src/app/reducers.ts index c250f9b26b7..905e0b952d5 100644 --- a/src/app/reducers.ts +++ b/src/app/reducers.ts @@ -48,6 +48,7 @@ interface State { showNotificationSpotlight: boolean hideBalances: boolean pendingDeepLinks: PendingDeepLink[] + demoModeEnabled: boolean } interface PendingDeepLink { @@ -89,6 +90,7 @@ const initialState = { showNotificationSpotlight: false, hideBalances: false, pendingDeepLinks: [], + demoModeEnabled: false, } function getPersistedDeepLinks(deepLinks: PendingDeepLink[]) { @@ -257,6 +259,11 @@ export const appReducer = ( (pendingDeepLink) => pendingDeepLink.url !== action.deepLink ), } + case Actions.DEMO_MODE_TOGGLED: + return { + ...state, + demoModeEnabled: action.enabled, + } default: return state } diff --git a/src/app/selectors.ts b/src/app/selectors.ts index 4d245fc13ea..531ef12b14f 100644 --- a/src/app/selectors.ts +++ b/src/app/selectors.ts @@ -1,4 +1,8 @@ +import { createSelector } from 'reselect' import { RootState } from 'src/redux/reducers' +import { getDynamicConfigParams } from 'src/statsig' +import { DynamicConfigs } from 'src/statsig/constants' +import { StatsigDynamicConfigs } from 'src/statsig/types' export const getRequirePinOnAppOpen = (state: RootState) => { return state.app.requirePinOnAppOpen @@ -77,3 +81,15 @@ export const showNotificationSpotlightSelector = (state: RootState) => export const hideWalletBalancesSelector = (state: RootState) => state.app.hideBalances export const pendingDeepLinkSelector = (state: RootState) => state.app.pendingDeepLinks[0] ?? null + +export const demoModeEnabledSelector = createSelector( + [ + () => + getDynamicConfigParams(DynamicConfigs[StatsigDynamicConfigs.DEMO_MODE_CONFIG]) + .enabledInOnboarding, + (state: RootState) => state.app.demoModeEnabled, + ], + (dynamicConfigEnabled, demoModeToggledOn) => { + return dynamicConfigEnabled && demoModeToggledOn + } +) diff --git a/src/navigator/NavigatorWrapper.tsx b/src/navigator/NavigatorWrapper.tsx index 8607a720407..19e69a883bb 100644 --- a/src/navigator/NavigatorWrapper.tsx +++ b/src/navigator/NavigatorWrapper.tsx @@ -6,12 +6,13 @@ import { SeverityLevel } from '@sentry/types' import * as React from 'react' import { StyleSheet, View } from 'react-native' import DeviceInfo from 'react-native-device-info' +import LinearGradient from 'react-native-linear-gradient' import ShakeForSupport from 'src/account/ShakeForSupport' import AlertBanner from 'src/alert/AlertBanner' import AppAnalytics from 'src/analytics/AppAnalytics' import UpgradeScreen from 'src/app/UpgradeScreen' import { activeScreenChanged } from 'src/app/actions' -import { getAppLocked } from 'src/app/selectors' +import { demoModeEnabledSelector, getAppLocked } from 'src/app/selectors' import { useDeepLinks } from 'src/app/useDeepLinks' import { DEV_RESTORE_NAV_STATE_ON_RELOAD } from 'src/config' import JumpstartClaimStatusToasts from 'src/jumpstart/JumpstartClaimStatusToasts' @@ -30,6 +31,7 @@ import { getDynamicConfigParams } from 'src/statsig' import { DynamicConfigs } from 'src/statsig/constants' import { StatsigDynamicConfigs } from 'src/statsig/types' import appTheme from 'src/styles/appTheme' +import Colors from 'src/styles/colors' import Logger from 'src/utils/Logger' import { userInSanctionedCountrySelector } from 'src/utils/countryFeatures' import { isVersionBelowMinimum } from 'src/utils/versionCheck' @@ -62,6 +64,7 @@ export const NavigatorWrapper = () => { ) const routeNameRef = React.useRef() const inSanctionedCountry = useSelector(userInSanctionedCountrySelector) + const demoModeEnabled = useSelector(demoModeEnabledSelector) const dispatch = useDispatch() @@ -174,16 +177,26 @@ export const NavigatorWrapper = () => { initialState={initialState} theme={appTheme} > - - - - {(appLocked || updateRequired) && ( - {updateRequired ? : } - )} - - - - + + + + + {(appLocked || updateRequired) && ( + + {updateRequired ? : } + + )} + + + + + ) } @@ -194,6 +207,10 @@ const styles = StyleSheet.create({ flexDirection: 'column', alignItems: 'stretch', justifyContent: 'flex-start', + borderColor: 'transparent', + }, + linearGradientBackground: { + flex: 1, }, locked: { position: 'absolute', diff --git a/src/onboarding/welcome/Welcome.tsx b/src/onboarding/welcome/Welcome.tsx index a8023b24348..6212604eedd 100644 --- a/src/onboarding/welcome/Welcome.tsx +++ b/src/onboarding/welcome/Welcome.tsx @@ -1,23 +1,30 @@ -import React from 'react' +import React, { useEffect } from 'react' import { useTranslation } from 'react-i18next' import { ImageBackground, StyleSheet, View } from 'react-native' +import { TouchableWithoutFeedback } from 'react-native-gesture-handler' import { SafeAreaView, useSafeAreaInsets } from 'react-native-safe-area-context' import { chooseCreateAccount, chooseRestoreAccount } from 'src/account/actions' import { recoveringFromStoreWipeSelector } from 'src/account/selectors' import AppAnalytics from 'src/analytics/AppAnalytics' import { OnboardingEvents } from 'src/analytics/Events' +import { demoModeToggled } from 'src/app/actions' +import { demoModeEnabledSelector } from 'src/app/selectors' import Button, { BtnSizes, BtnTypes } from 'src/components/Button' import { welcomeBackground } from 'src/images/Images' import WelcomeLogo from 'src/images/WelcomeLogo' import { nuxNavigationOptions } from 'src/navigator/Headers' -import { navigate } from 'src/navigator/NavigationService' +import { navigate, navigateHome } from 'src/navigator/NavigationService' import { Screens } from 'src/navigator/Screens' import LanguageButton from 'src/onboarding/LanguageButton' import { firstOnboardingScreen } from 'src/onboarding/steps' import { useDispatch, useSelector } from 'src/redux/hooks' -import { patchUpdateStatsigUser } from 'src/statsig' +import { getDynamicConfigParams, patchUpdateStatsigUser } from 'src/statsig' +import { DynamicConfigs } from 'src/statsig/constants' +import { StatsigDynamicConfigs } from 'src/statsig/types' import { Spacing } from 'src/styles/styles' +const DEMO_MODE_LONG_PRESS_DELAY_MS = 5_000 + export default function Welcome() { const { t } = useTranslation() const dispatch = useDispatch() @@ -25,6 +32,21 @@ export default function Welcome() { const startOnboardingTime = useSelector((state) => state.account.startOnboardingTime) const insets = useSafeAreaInsets() const recoveringFromStoreWipe = useSelector(recoveringFromStoreWipeSelector) + const demoModeEnabled = useSelector(demoModeEnabledSelector) + + const { enabledInOnboarding } = getDynamicConfigParams( + DynamicConfigs[StatsigDynamicConfigs.DEMO_MODE_CONFIG] + ) + + useEffect(() => { + if (demoModeEnabled) { + navigateHome() + } + }, [demoModeEnabled]) + + const onActivateDemoMode = () => { + dispatch(demoModeToggled(true)) + } const startOnboarding = () => { navigate( @@ -65,7 +87,13 @@ export default function Welcome() { - + + +