Move onboarding state to new persistence + reducer context (#1835)
This commit is contained in:
parent
3a211017d3
commit
4afed4be28
14 changed files with 199 additions and 167 deletions
|
@ -4,34 +4,35 @@ import {observer} from 'mobx-react-lite'
|
|||
import {ErrorBoundary} from 'view/com/util/ErrorBoundary'
|
||||
import {s} from 'lib/styles'
|
||||
import {usePalette} from 'lib/hooks/usePalette'
|
||||
import {useStores} from 'state/index'
|
||||
import {Welcome} from './onboarding/Welcome'
|
||||
import {RecommendedFeeds} from './onboarding/RecommendedFeeds'
|
||||
import {RecommendedFollows} from './onboarding/RecommendedFollows'
|
||||
import {useSetMinimalShellMode} from '#/state/shell/minimal-mode'
|
||||
import {useOnboardingState, useOnboardingDispatch} from '#/state/shell'
|
||||
|
||||
export const Onboarding = observer(function OnboardingImpl() {
|
||||
const pal = usePalette('default')
|
||||
const store = useStores()
|
||||
const setMinimalShellMode = useSetMinimalShellMode()
|
||||
const onboardingState = useOnboardingState()
|
||||
const onboardingDispatch = useOnboardingDispatch()
|
||||
|
||||
React.useEffect(() => {
|
||||
setMinimalShellMode(true)
|
||||
}, [setMinimalShellMode])
|
||||
|
||||
const next = () => store.onboarding.next()
|
||||
const skip = () => store.onboarding.skip()
|
||||
const next = () => onboardingDispatch({type: 'next'})
|
||||
const skip = () => onboardingDispatch({type: 'skip'})
|
||||
|
||||
return (
|
||||
<SafeAreaView testID="onboardingView" style={[s.hContentRegion, pal.view]}>
|
||||
<ErrorBoundary>
|
||||
{store.onboarding.step === 'Welcome' && (
|
||||
{onboardingState.step === 'Welcome' && (
|
||||
<Welcome skip={skip} next={next} />
|
||||
)}
|
||||
{store.onboarding.step === 'RecommendedFeeds' && (
|
||||
{onboardingState.step === 'RecommendedFeeds' && (
|
||||
<RecommendedFeeds next={next} />
|
||||
)}
|
||||
{store.onboarding.step === 'RecommendedFollows' && (
|
||||
{onboardingState.step === 'RecommendedFollows' && (
|
||||
<RecommendedFollows next={next} />
|
||||
)}
|
||||
</ErrorBoundary>
|
||||
|
|
|
@ -15,6 +15,7 @@ import {s} from 'lib/styles'
|
|||
import {useStores} from 'state/index'
|
||||
import {CreateAccountModel} from 'state/models/ui/create-account'
|
||||
import {usePalette} from 'lib/hooks/usePalette'
|
||||
import {useOnboardingDispatch} from '#/state/shell'
|
||||
|
||||
import {Step1} from './Step1'
|
||||
import {Step2} from './Step2'
|
||||
|
@ -29,6 +30,7 @@ export const CreateAccount = observer(function CreateAccountImpl({
|
|||
const pal = usePalette('default')
|
||||
const store = useStores()
|
||||
const model = React.useMemo(() => new CreateAccountModel(store), [store])
|
||||
const onboardingDispatch = useOnboardingDispatch()
|
||||
|
||||
React.useEffect(() => {
|
||||
screen('CreateAccount')
|
||||
|
@ -59,14 +61,14 @@ export const CreateAccount = observer(function CreateAccountImpl({
|
|||
model.next()
|
||||
} else {
|
||||
try {
|
||||
await model.submit()
|
||||
await model.submit(onboardingDispatch)
|
||||
} catch {
|
||||
// dont need to handle here
|
||||
} finally {
|
||||
track('Try Create Account')
|
||||
}
|
||||
}
|
||||
}, [model, track])
|
||||
}, [model, track, onboardingDispatch])
|
||||
|
||||
return (
|
||||
<LoggedOutLayout
|
||||
|
|
|
@ -11,6 +11,7 @@ import {useWebMediaQueries} from 'lib/hooks/useWebMediaQueries'
|
|||
import {usePalette} from 'lib/hooks/usePalette'
|
||||
import {useStores} from 'state/index'
|
||||
import {RecommendedFollowsItem} from './RecommendedFollowsItem'
|
||||
import {SuggestedActorsModel} from '#/state/models/discovery/suggested-actors'
|
||||
|
||||
type Props = {
|
||||
next: () => void
|
||||
|
@ -21,16 +22,10 @@ export const RecommendedFollows = observer(function RecommendedFollowsImpl({
|
|||
const store = useStores()
|
||||
const pal = usePalette('default')
|
||||
const {isTabletOrMobile} = useWebMediaQueries()
|
||||
|
||||
React.useEffect(() => {
|
||||
// Load suggested actors if not already loaded
|
||||
// prefetch should happen in the onboarding model
|
||||
if (
|
||||
!store.onboarding.suggestedActors.hasLoaded ||
|
||||
store.onboarding.suggestedActors.isEmpty
|
||||
) {
|
||||
store.onboarding.suggestedActors.loadMore(true)
|
||||
}
|
||||
const suggestedActors = React.useMemo(() => {
|
||||
const model = new SuggestedActorsModel(store)
|
||||
model.refresh()
|
||||
return model
|
||||
}, [store])
|
||||
|
||||
const title = (
|
||||
|
@ -98,13 +93,19 @@ export const RecommendedFollows = observer(function RecommendedFollowsImpl({
|
|||
horizontal
|
||||
titleStyle={isTabletOrMobile ? undefined : {minWidth: 470}}
|
||||
contentStyle={{paddingHorizontal: 0}}>
|
||||
{store.onboarding.suggestedActors.isLoading ? (
|
||||
{suggestedActors.isLoading ? (
|
||||
<ActivityIndicator size="large" />
|
||||
) : (
|
||||
<FlatList
|
||||
data={store.onboarding.suggestedActors.suggestions}
|
||||
data={suggestedActors.suggestions}
|
||||
renderItem={({item, index}) => (
|
||||
<RecommendedFollowsItem item={item} index={index} />
|
||||
<RecommendedFollowsItem
|
||||
item={item}
|
||||
index={index}
|
||||
insertSuggestionsByActor={suggestedActors.insertSuggestionsByActor.bind(
|
||||
suggestedActors,
|
||||
)}
|
||||
/>
|
||||
)}
|
||||
keyExtractor={(item, index) => item.did + index.toString()}
|
||||
style={{flex: 1}}
|
||||
|
@ -126,13 +127,19 @@ export const RecommendedFollows = observer(function RecommendedFollowsImpl({
|
|||
users.
|
||||
</Text>
|
||||
</View>
|
||||
{store.onboarding.suggestedActors.isLoading ? (
|
||||
{suggestedActors.isLoading ? (
|
||||
<ActivityIndicator size="large" />
|
||||
) : (
|
||||
<FlatList
|
||||
data={store.onboarding.suggestedActors.suggestions}
|
||||
data={suggestedActors.suggestions}
|
||||
renderItem={({item, index}) => (
|
||||
<RecommendedFollowsItem item={item} index={index} />
|
||||
<RecommendedFollowsItem
|
||||
item={item}
|
||||
index={index}
|
||||
insertSuggestionsByActor={suggestedActors.insertSuggestionsByActor.bind(
|
||||
suggestedActors,
|
||||
)}
|
||||
/>
|
||||
)}
|
||||
keyExtractor={(item, index) => item.did + index.toString()}
|
||||
style={{flex: 1}}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import React, {useMemo} from 'react'
|
||||
import React from 'react'
|
||||
import {View, StyleSheet, ActivityIndicator} from 'react-native'
|
||||
import {AppBskyActorDefs, moderateProfile} from '@atproto/api'
|
||||
import {observer} from 'mobx-react-lite'
|
||||
|
@ -18,22 +18,19 @@ import {useAnalytics} from 'lib/analytics/analytics'
|
|||
type Props = {
|
||||
item: SuggestedActor
|
||||
index: number
|
||||
insertSuggestionsByActor: (did: string, index: number) => Promise<void>
|
||||
}
|
||||
export const RecommendedFollowsItem: React.FC<Props> = ({item, index}) => {
|
||||
export const RecommendedFollowsItem: React.FC<Props> = ({
|
||||
item,
|
||||
index,
|
||||
insertSuggestionsByActor,
|
||||
}) => {
|
||||
const pal = usePalette('default')
|
||||
const store = useStores()
|
||||
const {isMobile} = useWebMediaQueries()
|
||||
const delay = useMemo(() => {
|
||||
return (
|
||||
50 *
|
||||
(Math.abs(store.onboarding.suggestedActors.lastInsertedAtIndex - index) %
|
||||
5)
|
||||
)
|
||||
}, [index, store.onboarding.suggestedActors.lastInsertedAtIndex])
|
||||
|
||||
return (
|
||||
<Animated.View
|
||||
entering={FadeInRight.delay(delay).springify()}
|
||||
entering={FadeInRight}
|
||||
style={[
|
||||
styles.cardContainer,
|
||||
pal.view,
|
||||
|
@ -43,7 +40,12 @@ export const RecommendedFollowsItem: React.FC<Props> = ({item, index}) => {
|
|||
borderRightWidth: isMobile ? undefined : 1,
|
||||
},
|
||||
]}>
|
||||
<ProfileCard key={item.did} profile={item} index={index} />
|
||||
<ProfileCard
|
||||
key={item.did}
|
||||
profile={item}
|
||||
index={index}
|
||||
insertSuggestionsByActor={insertSuggestionsByActor}
|
||||
/>
|
||||
</Animated.View>
|
||||
)
|
||||
}
|
||||
|
@ -51,9 +53,11 @@ export const RecommendedFollowsItem: React.FC<Props> = ({item, index}) => {
|
|||
export const ProfileCard = observer(function ProfileCardImpl({
|
||||
profile,
|
||||
index,
|
||||
insertSuggestionsByActor,
|
||||
}: {
|
||||
profile: AppBskyActorDefs.ProfileViewBasic
|
||||
index: number
|
||||
insertSuggestionsByActor: (did: string, index: number) => Promise<void>
|
||||
}) {
|
||||
const {track} = useAnalytics()
|
||||
const store = useStores()
|
||||
|
@ -94,10 +98,7 @@ export const ProfileCard = observer(function ProfileCardImpl({
|
|||
onToggleFollow={async isFollow => {
|
||||
if (isFollow) {
|
||||
setAddingMoreSuggestions(true)
|
||||
await store.onboarding.suggestedActors.insertSuggestionsByActor(
|
||||
profile.did,
|
||||
index,
|
||||
)
|
||||
await insertSuggestionsByActor(profile.did, index)
|
||||
setAddingMoreSuggestions(false)
|
||||
track('Onboarding:SuggestedFollowFollowed')
|
||||
}
|
||||
|
|
|
@ -13,19 +13,21 @@ import {Onboarding} from './Onboarding'
|
|||
import {Text} from '../util/text/Text'
|
||||
import {usePalette} from 'lib/hooks/usePalette'
|
||||
import {STATUS_PAGE_URL} from 'lib/constants'
|
||||
import {useOnboardingState} from '#/state/shell'
|
||||
|
||||
export const withAuthRequired = <P extends object>(
|
||||
Component: React.ComponentType<P>,
|
||||
): React.FC<P> =>
|
||||
observer(function AuthRequired(props: P) {
|
||||
const store = useStores()
|
||||
const onboardingState = useOnboardingState()
|
||||
if (store.session.isResumingSession) {
|
||||
return <Loading />
|
||||
}
|
||||
if (!store.session.hasSession) {
|
||||
return <LoggedOut />
|
||||
}
|
||||
if (store.onboarding.isActive) {
|
||||
if (onboardingState.isActive) {
|
||||
return <Onboarding />
|
||||
}
|
||||
return <Component {...props} />
|
||||
|
|
|
@ -52,6 +52,7 @@ import {
|
|||
useSetColorMode,
|
||||
useRequireAltTextEnabled,
|
||||
useSetRequireAltTextEnabled,
|
||||
useOnboardingDispatch,
|
||||
} from '#/state/shell'
|
||||
|
||||
// TEMPORARY (APP-700)
|
||||
|
@ -70,6 +71,7 @@ export const SettingsScreen = withAuthRequired(
|
|||
const setMinimalShellMode = useSetMinimalShellMode()
|
||||
const requireAltTextEnabled = useRequireAltTextEnabled()
|
||||
const setRequireAltTextEnabled = useSetRequireAltTextEnabled()
|
||||
const onboardingDispatch = useOnboardingDispatch()
|
||||
const navigation = useNavigation<NavigationProp>()
|
||||
const {isMobile} = useWebMediaQueries()
|
||||
const {screen, track} = useAnalytics()
|
||||
|
@ -157,9 +159,9 @@ export const SettingsScreen = withAuthRequired(
|
|||
}, [store])
|
||||
|
||||
const onPressResetOnboarding = React.useCallback(async () => {
|
||||
store.onboarding.reset()
|
||||
onboardingDispatch({type: 'start'})
|
||||
Toast.show('Onboarding reset')
|
||||
}, [store])
|
||||
}, [onboardingDispatch])
|
||||
|
||||
const onPressBuildInfo = React.useCallback(() => {
|
||||
Clipboard.setString(
|
||||
|
|
|
@ -17,12 +17,17 @@ import {BottomBarWeb} from './bottom-bar/BottomBarWeb'
|
|||
import {useNavigation} from '@react-navigation/native'
|
||||
import {NavigationProp} from 'lib/routes/types'
|
||||
import {useAuxClick} from 'lib/hooks/useAuxClick'
|
||||
import {useIsDrawerOpen, useSetDrawerOpen} from '#/state/shell'
|
||||
import {
|
||||
useIsDrawerOpen,
|
||||
useSetDrawerOpen,
|
||||
useOnboardingState,
|
||||
} from '#/state/shell'
|
||||
|
||||
const ShellInner = observer(function ShellInnerImpl() {
|
||||
const store = useStores()
|
||||
const isDrawerOpen = useIsDrawerOpen()
|
||||
const setDrawerOpen = useSetDrawerOpen()
|
||||
const onboardingState = useOnboardingState()
|
||||
const {isDesktop, isMobile} = useWebMediaQueries()
|
||||
const navigator = useNavigation<NavigationProp>()
|
||||
useAuxClick()
|
||||
|
@ -34,9 +39,9 @@ const ShellInner = observer(function ShellInnerImpl() {
|
|||
})
|
||||
}, [navigator, store.shell, setDrawerOpen])
|
||||
|
||||
const showBottomBar = isMobile && !store.onboarding.isActive
|
||||
const showBottomBar = isMobile && !onboardingState.isActive
|
||||
const showSideNavs =
|
||||
!isMobile && store.session.hasSession && !store.onboarding.isActive
|
||||
!isMobile && store.session.hasSession && !onboardingState.isActive
|
||||
return (
|
||||
<View style={[s.hContentRegion, {overflow: 'hidden'}]}>
|
||||
<View style={s.hContentRegion}>
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue