[Reduced Onboarding] Add new step, new state to reducer (#3931)
* Add new step, new state to reducer * Don't set default feedszio/stable
parent
08979f37e7
commit
80ce6f980e
|
@ -7,7 +7,7 @@ import {useLingui} from '@lingui/react'
|
||||||
import {useAnalytics} from '#/lib/analytics/analytics'
|
import {useAnalytics} from '#/lib/analytics/analytics'
|
||||||
import {BSKY_APP_ACCOUNT_DID, IS_PROD_SERVICE} from '#/lib/constants'
|
import {BSKY_APP_ACCOUNT_DID, IS_PROD_SERVICE} from '#/lib/constants'
|
||||||
import {DISCOVER_SAVED_FEED, TIMELINE_SAVED_FEED} 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 {logger} from '#/logger'
|
||||||
import {useOverwriteSavedFeedsMutation} from '#/state/queries/preferences'
|
import {useOverwriteSavedFeedsMutation} from '#/state/queries/preferences'
|
||||||
import {useAgent} from '#/state/session'
|
import {useAgent} from '#/state/session'
|
||||||
|
@ -41,6 +41,7 @@ export function StepFinished() {
|
||||||
const [saving, setSaving] = React.useState(false)
|
const [saving, setSaving] = React.useState(false)
|
||||||
const {mutateAsync: overwriteSavedFeeds} = useOverwriteSavedFeedsMutation()
|
const {mutateAsync: overwriteSavedFeeds} = useOverwriteSavedFeedsMutation()
|
||||||
const {getAgent} = useAgent()
|
const {getAgent} = useAgent()
|
||||||
|
const gate = useGate()
|
||||||
|
|
||||||
const finishOnboarding = React.useCallback(async () => {
|
const finishOnboarding = React.useCallback(async () => {
|
||||||
setSaving(true)
|
setSaving(true)
|
||||||
|
@ -67,8 +68,13 @@ export function StepFinished() {
|
||||||
(async () => {
|
(async () => {
|
||||||
await getAgent().setInterestsPref({tags: selectedInterests})
|
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
|
const otherFeeds = selectedFeeds.length
|
||||||
? selectedFeeds.map(f => ({
|
? selectedFeeds.map(f => ({
|
||||||
type: 'feed',
|
type: 'feed',
|
||||||
|
@ -101,6 +107,7 @@ export function StepFinished() {
|
||||||
},
|
},
|
||||||
...otherFeeds,
|
...otherFeeds,
|
||||||
])
|
])
|
||||||
|
}
|
||||||
})(),
|
})(),
|
||||||
])
|
])
|
||||||
} catch (e: any) {
|
} catch (e: any) {
|
||||||
|
@ -123,6 +130,7 @@ export function StepFinished() {
|
||||||
overwriteSavedFeeds,
|
overwriteSavedFeeds,
|
||||||
track,
|
track,
|
||||||
getAgent,
|
getAgent,
|
||||||
|
gate,
|
||||||
])
|
])
|
||||||
|
|
||||||
React.useEffect(() => {
|
React.useEffect(() => {
|
||||||
|
|
|
@ -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 (
|
||||||
|
<View style={[a.align_start]}>
|
||||||
|
<IconCircle icon={StreamingLive} style={[a.mb_2xl]} />
|
||||||
|
|
||||||
|
<TitleText>
|
||||||
|
<Trans>Give your profile a face</Trans>
|
||||||
|
</TitleText>
|
||||||
|
<DescriptionText>
|
||||||
|
<Trans>
|
||||||
|
Help people know you're not a bot by uploading a picture or creating
|
||||||
|
an avatar.
|
||||||
|
</Trans>
|
||||||
|
</DescriptionText>
|
||||||
|
|
||||||
|
<OnboardingControls.Portal>
|
||||||
|
<Button
|
||||||
|
variant="gradient"
|
||||||
|
color="gradient_sky"
|
||||||
|
size="large"
|
||||||
|
label={_(msg`Continue to next step`)}
|
||||||
|
onPress={onContinue}>
|
||||||
|
<ButtonText>
|
||||||
|
<Trans>Continue</Trans>
|
||||||
|
</ButtonText>
|
||||||
|
<ButtonIcon icon={ChevronRight} position="right" />
|
||||||
|
</Button>
|
||||||
|
</OnboardingControls.Portal>
|
||||||
|
</View>
|
||||||
|
)
|
||||||
|
}
|
|
@ -16,6 +16,7 @@ import {StepFinished} from '#/screens/Onboarding/StepFinished'
|
||||||
import {StepFollowingFeed} from '#/screens/Onboarding/StepFollowingFeed'
|
import {StepFollowingFeed} from '#/screens/Onboarding/StepFollowingFeed'
|
||||||
import {StepInterests} from '#/screens/Onboarding/StepInterests'
|
import {StepInterests} from '#/screens/Onboarding/StepInterests'
|
||||||
import {StepModeration} from '#/screens/Onboarding/StepModeration'
|
import {StepModeration} from '#/screens/Onboarding/StepModeration'
|
||||||
|
import {StepProfile} from '#/screens/Onboarding/StepProfile'
|
||||||
import {StepSuggestedAccounts} from '#/screens/Onboarding/StepSuggestedAccounts'
|
import {StepSuggestedAccounts} from '#/screens/Onboarding/StepSuggestedAccounts'
|
||||||
import {StepTopicalFeeds} from '#/screens/Onboarding/StepTopicalFeeds'
|
import {StepTopicalFeeds} from '#/screens/Onboarding/StepTopicalFeeds'
|
||||||
import {Portal} from '#/components/Portal'
|
import {Portal} from '#/components/Portal'
|
||||||
|
@ -65,6 +66,7 @@ export function Onboarding() {
|
||||||
[state, dispatch, interestsDisplayNames],
|
[state, dispatch, interestsDisplayNames],
|
||||||
)}>
|
)}>
|
||||||
<Layout>
|
<Layout>
|
||||||
|
{state.activeStep === 'profile' && <StepProfile />}
|
||||||
{state.activeStep === 'interests' && <StepInterests />}
|
{state.activeStep === 'interests' && <StepInterests />}
|
||||||
{state.activeStep === 'suggestedAccounts' && (
|
{state.activeStep === 'suggestedAccounts' && (
|
||||||
<StepSuggestedAccounts />
|
<StepSuggestedAccounts />
|
||||||
|
|
|
@ -6,6 +6,7 @@ export type OnboardingState = {
|
||||||
hasPrev: boolean
|
hasPrev: boolean
|
||||||
totalSteps: number
|
totalSteps: number
|
||||||
activeStep:
|
activeStep:
|
||||||
|
| 'profile'
|
||||||
| 'interests'
|
| 'interests'
|
||||||
| 'suggestedAccounts'
|
| 'suggestedAccounts'
|
||||||
| 'followingFeed'
|
| 'followingFeed'
|
||||||
|
@ -28,6 +29,10 @@ export type OnboardingState = {
|
||||||
topicalFeedsStepResults: {
|
topicalFeedsStepResults: {
|
||||||
feedUris: string[]
|
feedUris: string[]
|
||||||
}
|
}
|
||||||
|
profileStepResults: {
|
||||||
|
imageUri?: string
|
||||||
|
imageMime?: string
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export type OnboardingAction =
|
export type OnboardingAction =
|
||||||
|
@ -57,6 +62,11 @@ export type OnboardingAction =
|
||||||
type: 'setTopicalFeedsStepResults'
|
type: 'setTopicalFeedsStepResults'
|
||||||
feedUris: string[]
|
feedUris: string[]
|
||||||
}
|
}
|
||||||
|
| {
|
||||||
|
type: 'setProfileStepResults'
|
||||||
|
imageUri: string
|
||||||
|
imageMime: string
|
||||||
|
}
|
||||||
|
|
||||||
export type ApiResponseMap = {
|
export type ApiResponseMap = {
|
||||||
interests: string[]
|
interests: string[]
|
||||||
|
@ -91,6 +101,10 @@ export const initialState: OnboardingState = {
|
||||||
topicalFeedsStepResults: {
|
topicalFeedsStepResults: {
|
||||||
feedUris: [],
|
feedUris: [],
|
||||||
},
|
},
|
||||||
|
profileStepResults: {
|
||||||
|
imageUri: '',
|
||||||
|
imageMime: '',
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
export const INTEREST_TO_DISPLAY_NAME_DEFAULTS: {
|
export const INTEREST_TO_DISPLAY_NAME_DEFAULTS: {
|
||||||
|
@ -240,8 +254,8 @@ export function reducer(
|
||||||
|
|
||||||
export const initialStateReduced: OnboardingState = {
|
export const initialStateReduced: OnboardingState = {
|
||||||
hasPrev: false,
|
hasPrev: false,
|
||||||
totalSteps: 7,
|
totalSteps: 3,
|
||||||
activeStep: 'interests',
|
activeStep: 'profile',
|
||||||
activeStepIndex: 1,
|
activeStepIndex: 1,
|
||||||
|
|
||||||
interestsStepResults: {
|
interestsStepResults: {
|
||||||
|
@ -261,6 +275,10 @@ export const initialStateReduced: OnboardingState = {
|
||||||
topicalFeedsStepResults: {
|
topicalFeedsStepResults: {
|
||||||
feedUris: [],
|
feedUris: [],
|
||||||
},
|
},
|
||||||
|
profileStepResults: {
|
||||||
|
imageUri: '',
|
||||||
|
imageMime: '',
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
export function reducerReduced(
|
export function reducerReduced(
|
||||||
|
@ -271,51 +289,27 @@ export function reducerReduced(
|
||||||
|
|
||||||
switch (a.type) {
|
switch (a.type) {
|
||||||
case 'next': {
|
case 'next': {
|
||||||
if (s.activeStep === 'interests') {
|
if (s.activeStep === 'profile') {
|
||||||
next.activeStep = 'suggestedAccounts'
|
next.activeStep = 'interests'
|
||||||
next.activeStepIndex = 2
|
next.activeStepIndex = 2
|
||||||
} else if (s.activeStep === 'suggestedAccounts') {
|
} else if (s.activeStep === 'interests') {
|
||||||
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') {
|
|
||||||
next.activeStep = 'finished'
|
next.activeStep = 'finished'
|
||||||
next.activeStepIndex = 7
|
next.activeStepIndex = 3
|
||||||
}
|
}
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
case 'prev': {
|
case 'prev': {
|
||||||
if (s.activeStep === 'suggestedAccounts') {
|
if (s.activeStep === 'interests') {
|
||||||
next.activeStep = 'interests'
|
next.activeStep = 'profile'
|
||||||
next.activeStepIndex = 1
|
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') {
|
} else if (s.activeStep === 'finished') {
|
||||||
next.activeStep = 'moderation'
|
next.activeStep = 'interests'
|
||||||
next.activeStepIndex = 6
|
next.activeStepIndex = 2
|
||||||
}
|
}
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
case 'finish': {
|
case 'finish': {
|
||||||
next = initialState
|
next = initialStateReduced
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
case 'setInterestsStepResults': {
|
case 'setInterestsStepResults': {
|
||||||
|
@ -326,22 +320,18 @@ export function reducerReduced(
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
case 'setSuggestedAccountsStepResults': {
|
case 'setSuggestedAccountsStepResults': {
|
||||||
next.suggestedAccountsStepResults = {
|
|
||||||
accountDids: next.suggestedAccountsStepResults.accountDids.concat(
|
|
||||||
a.accountDids,
|
|
||||||
),
|
|
||||||
}
|
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
case 'setAlgoFeedsStepResults': {
|
case 'setAlgoFeedsStepResults': {
|
||||||
next.algoFeedsStepResults = {
|
|
||||||
feedUris: a.feedUris,
|
|
||||||
}
|
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
case 'setTopicalFeedsStepResults': {
|
case 'setTopicalFeedsStepResults': {
|
||||||
next.topicalFeedsStepResults = {
|
break
|
||||||
feedUris: next.topicalFeedsStepResults.feedUris.concat(a.feedUris),
|
}
|
||||||
|
case 'setProfileStepResults': {
|
||||||
|
next.profileStepResults = {
|
||||||
|
imageUri: a.imageUri,
|
||||||
|
imageMime: a.imageMime,
|
||||||
}
|
}
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
@ -349,7 +339,7 @@ export function reducerReduced(
|
||||||
|
|
||||||
const state = {
|
const state = {
|
||||||
...next,
|
...next,
|
||||||
hasPrev: next.activeStep !== 'interests',
|
hasPrev: next.activeStep !== 'profile',
|
||||||
}
|
}
|
||||||
|
|
||||||
logger.debug(`onboarding`, {
|
logger.debug(`onboarding`, {
|
||||||
|
@ -362,6 +352,7 @@ export function reducerReduced(
|
||||||
suggestedAccountsStepResults: state.suggestedAccountsStepResults,
|
suggestedAccountsStepResults: state.suggestedAccountsStepResults,
|
||||||
algoFeedsStepResults: state.algoFeedsStepResults,
|
algoFeedsStepResults: state.algoFeedsStepResults,
|
||||||
topicalFeedsStepResults: state.topicalFeedsStepResults,
|
topicalFeedsStepResults: state.topicalFeedsStepResults,
|
||||||
|
profileStepResults: state.profileStepResults,
|
||||||
})
|
})
|
||||||
|
|
||||||
if (s.activeStep !== state.activeStep) {
|
if (s.activeStep !== state.activeStep) {
|
||||||
|
|
Loading…
Reference in New Issue