From 80ce6f980ed44df75dc40817ebfb33285998f9c9 Mon Sep 17 00:00:00 2001 From: Eric Bailey Date: Fri, 10 May 2024 23:19:16 -0500 Subject: [PATCH] [Reduced Onboarding] Add new step, new state to reducer (#3931) * Add new step, new state to reducer * Don't set default feeds --- src/screens/Onboarding/StepFinished.tsx | 68 +++++++++------- src/screens/Onboarding/StepProfile/index.tsx | 55 +++++++++++++ src/screens/Onboarding/index.tsx | 2 + src/screens/Onboarding/state.ts | 83 +++++++++----------- 4 files changed, 132 insertions(+), 76 deletions(-) create mode 100644 src/screens/Onboarding/StepProfile/index.tsx diff --git a/src/screens/Onboarding/StepFinished.tsx b/src/screens/Onboarding/StepFinished.tsx index 4cc611ef4f..7d0bfa4222 100644 --- a/src/screens/Onboarding/StepFinished.tsx +++ b/src/screens/Onboarding/StepFinished.tsx @@ -7,7 +7,7 @@ import {useLingui} from '@lingui/react' import {useAnalytics} from '#/lib/analytics/analytics' import {BSKY_APP_ACCOUNT_DID, IS_PROD_SERVICE} from '#/lib/constants' import {DISCOVER_SAVED_FEED, TIMELINE_SAVED_FEED} from '#/lib/constants' -import {logEvent} from '#/lib/statsig/statsig' +import {logEvent, useGate} from '#/lib/statsig/statsig' import {logger} from '#/logger' import {useOverwriteSavedFeedsMutation} from '#/state/queries/preferences' import {useAgent} from '#/state/session' @@ -41,6 +41,7 @@ export function StepFinished() { const [saving, setSaving] = React.useState(false) const {mutateAsync: overwriteSavedFeeds} = useOverwriteSavedFeedsMutation() const {getAgent} = useAgent() + const gate = useGate() const finishOnboarding = React.useCallback(async () => { setSaving(true) @@ -67,40 +68,46 @@ export function StepFinished() { (async () => { await getAgent().setInterestsPref({tags: selectedInterests}) - // TODO: In the reduced onboarding, we'll want to exit early here. + /* + * In the reduced onboading experiment, we'll rely on the default + * feeds set in `createAgentAndCreateAccount`. No feeds will be + * selected in onboarding and therefore we don't need to run this + * code (which would overwrite the other feeds already set). + */ + if (!gate('reduced_onboarding_and_home_algo')) { + const otherFeeds = selectedFeeds.length + ? selectedFeeds.map(f => ({ + type: 'feed', + value: f, + pinned: true, + id: TID.nextStr(), + })) + : [] - const otherFeeds = selectedFeeds.length - ? selectedFeeds.map(f => ({ - type: 'feed', - value: f, + /* + * If no selected feeds and we're in prod, add the discover feed + * (mimics old behavior) + */ + if ( + IS_PROD_SERVICE(getAgent().service.toString()) && + !otherFeeds.length + ) { + otherFeeds.push({ + ...DISCOVER_SAVED_FEED, pinned: true, id: TID.nextStr(), - })) - : [] + }) + } - /* - * If no selected feeds and we're in prod, add the discover feed - * (mimics old behavior) - */ - if ( - IS_PROD_SERVICE(getAgent().service.toString()) && - !otherFeeds.length - ) { - otherFeeds.push({ - ...DISCOVER_SAVED_FEED, - pinned: true, - id: TID.nextStr(), - }) + await overwriteSavedFeeds([ + { + ...TIMELINE_SAVED_FEED, + pinned: true, + id: TID.nextStr(), + }, + ...otherFeeds, + ]) } - - await overwriteSavedFeeds([ - { - ...TIMELINE_SAVED_FEED, - pinned: true, - id: TID.nextStr(), - }, - ...otherFeeds, - ]) })(), ]) } catch (e: any) { @@ -123,6 +130,7 @@ export function StepFinished() { overwriteSavedFeeds, track, getAgent, + gate, ]) React.useEffect(() => { diff --git a/src/screens/Onboarding/StepProfile/index.tsx b/src/screens/Onboarding/StepProfile/index.tsx new file mode 100644 index 0000000000..8db3e77616 --- /dev/null +++ b/src/screens/Onboarding/StepProfile/index.tsx @@ -0,0 +1,55 @@ +import React from 'react' +import {View} from 'react-native' +import {msg, Trans} from '@lingui/macro' +import {useLingui} from '@lingui/react' + +import { + DescriptionText, + OnboardingControls, + TitleText, +} from '#/screens/Onboarding/Layout' +import {Context} from '#/screens/Onboarding/state' +import {atoms as a} from '#/alf' +import {Button, ButtonIcon, ButtonText} from '#/components/Button' +import {IconCircle} from '#/components/IconCircle' +import {ChevronRight_Stroke2_Corner0_Rounded as ChevronRight} from '#/components/icons/Chevron' +import {StreamingLive_Stroke2_Corner0_Rounded as StreamingLive} from '#/components/icons/StreamingLive' + +export function StepProfile() { + const {_} = useLingui() + const {dispatch} = React.useContext(Context) + + const onContinue = React.useCallback(() => { + dispatch({type: 'next'}) + }, [dispatch]) + + return ( + + + + + Give your profile a face + + + + Help people know you're not a bot by uploading a picture or creating + an avatar. + + + + + + + + ) +} diff --git a/src/screens/Onboarding/index.tsx b/src/screens/Onboarding/index.tsx index 4296491062..5af7a12dc7 100644 --- a/src/screens/Onboarding/index.tsx +++ b/src/screens/Onboarding/index.tsx @@ -16,6 +16,7 @@ import {StepFinished} from '#/screens/Onboarding/StepFinished' import {StepFollowingFeed} from '#/screens/Onboarding/StepFollowingFeed' import {StepInterests} from '#/screens/Onboarding/StepInterests' import {StepModeration} from '#/screens/Onboarding/StepModeration' +import {StepProfile} from '#/screens/Onboarding/StepProfile' import {StepSuggestedAccounts} from '#/screens/Onboarding/StepSuggestedAccounts' import {StepTopicalFeeds} from '#/screens/Onboarding/StepTopicalFeeds' import {Portal} from '#/components/Portal' @@ -65,6 +66,7 @@ export function Onboarding() { [state, dispatch, interestsDisplayNames], )}> + {state.activeStep === 'profile' && } {state.activeStep === 'interests' && } {state.activeStep === 'suggestedAccounts' && ( diff --git a/src/screens/Onboarding/state.ts b/src/screens/Onboarding/state.ts index d67dc88f3a..9452fbbc71 100644 --- a/src/screens/Onboarding/state.ts +++ b/src/screens/Onboarding/state.ts @@ -6,6 +6,7 @@ export type OnboardingState = { hasPrev: boolean totalSteps: number activeStep: + | 'profile' | 'interests' | 'suggestedAccounts' | 'followingFeed' @@ -28,6 +29,10 @@ export type OnboardingState = { topicalFeedsStepResults: { feedUris: string[] } + profileStepResults: { + imageUri?: string + imageMime?: string + } } export type OnboardingAction = @@ -57,6 +62,11 @@ export type OnboardingAction = type: 'setTopicalFeedsStepResults' feedUris: string[] } + | { + type: 'setProfileStepResults' + imageUri: string + imageMime: string + } export type ApiResponseMap = { interests: string[] @@ -91,6 +101,10 @@ export const initialState: OnboardingState = { topicalFeedsStepResults: { feedUris: [], }, + profileStepResults: { + imageUri: '', + imageMime: '', + }, } export const INTEREST_TO_DISPLAY_NAME_DEFAULTS: { @@ -240,8 +254,8 @@ export function reducer( export const initialStateReduced: OnboardingState = { hasPrev: false, - totalSteps: 7, - activeStep: 'interests', + totalSteps: 3, + activeStep: 'profile', activeStepIndex: 1, interestsStepResults: { @@ -261,6 +275,10 @@ export const initialStateReduced: OnboardingState = { topicalFeedsStepResults: { feedUris: [], }, + profileStepResults: { + imageUri: '', + imageMime: '', + }, } export function reducerReduced( @@ -271,51 +289,27 @@ export function reducerReduced( switch (a.type) { case 'next': { - if (s.activeStep === 'interests') { - next.activeStep = 'suggestedAccounts' + if (s.activeStep === 'profile') { + next.activeStep = 'interests' next.activeStepIndex = 2 - } else if (s.activeStep === 'suggestedAccounts') { - next.activeStep = 'followingFeed' - next.activeStepIndex = 3 - } else if (s.activeStep === 'followingFeed') { - next.activeStep = 'algoFeeds' - next.activeStepIndex = 4 - } else if (s.activeStep === 'algoFeeds') { - next.activeStep = 'topicalFeeds' - next.activeStepIndex = 5 - } else if (s.activeStep === 'topicalFeeds') { - next.activeStep = 'moderation' - next.activeStepIndex = 6 - } else if (s.activeStep === 'moderation') { + } else if (s.activeStep === 'interests') { next.activeStep = 'finished' - next.activeStepIndex = 7 + next.activeStepIndex = 3 } break } case 'prev': { - if (s.activeStep === 'suggestedAccounts') { - next.activeStep = 'interests' + if (s.activeStep === 'interests') { + next.activeStep = 'profile' next.activeStepIndex = 1 - } else if (s.activeStep === 'followingFeed') { - next.activeStep = 'suggestedAccounts' - next.activeStepIndex = 2 - } else if (s.activeStep === 'algoFeeds') { - next.activeStep = 'followingFeed' - next.activeStepIndex = 3 - } else if (s.activeStep === 'topicalFeeds') { - next.activeStep = 'algoFeeds' - next.activeStepIndex = 4 - } else if (s.activeStep === 'moderation') { - next.activeStep = 'topicalFeeds' - next.activeStepIndex = 5 } else if (s.activeStep === 'finished') { - next.activeStep = 'moderation' - next.activeStepIndex = 6 + next.activeStep = 'interests' + next.activeStepIndex = 2 } break } case 'finish': { - next = initialState + next = initialStateReduced break } case 'setInterestsStepResults': { @@ -326,22 +320,18 @@ export function reducerReduced( break } case 'setSuggestedAccountsStepResults': { - next.suggestedAccountsStepResults = { - accountDids: next.suggestedAccountsStepResults.accountDids.concat( - a.accountDids, - ), - } break } case 'setAlgoFeedsStepResults': { - next.algoFeedsStepResults = { - feedUris: a.feedUris, - } break } case 'setTopicalFeedsStepResults': { - next.topicalFeedsStepResults = { - feedUris: next.topicalFeedsStepResults.feedUris.concat(a.feedUris), + break + } + case 'setProfileStepResults': { + next.profileStepResults = { + imageUri: a.imageUri, + imageMime: a.imageMime, } break } @@ -349,7 +339,7 @@ export function reducerReduced( const state = { ...next, - hasPrev: next.activeStep !== 'interests', + hasPrev: next.activeStep !== 'profile', } logger.debug(`onboarding`, { @@ -362,6 +352,7 @@ export function reducerReduced( suggestedAccountsStepResults: state.suggestedAccountsStepResults, algoFeedsStepResults: state.algoFeedsStepResults, topicalFeedsStepResults: state.topicalFeedsStepResults, + profileStepResults: state.profileStepResults, }) if (s.activeStep !== state.activeStep) {