Merge branch 'ansh/app-812-add-custom-feed-discovery-to-onboarding' into main

This commit is contained in:
Paul Frazee 2023-08-30 16:18:21 -07:00
commit f9cab178b9
29 changed files with 1033 additions and 217 deletions

View file

@ -0,0 +1,94 @@
import {makeAutoObservable} from 'mobx'
import {RootStoreModel} from '../root-store'
import {hasProp} from 'lib/type-guards'
import {track} from 'lib/analytics/analytics'
export const OnboardingScreenSteps = {
Welcome: 'Welcome',
RecommendedFeeds: 'RecommendedFeeds',
Home: 'Home',
} as const
type OnboardingStep =
(typeof OnboardingScreenSteps)[keyof typeof OnboardingScreenSteps]
const OnboardingStepsArray = Object.values(OnboardingScreenSteps)
export class OnboardingModel {
// state
step: OnboardingStep = 'Home' // default state to skip onboarding, only enabled for new users by calling start()
constructor(public rootStore: RootStoreModel) {
makeAutoObservable(this, {
rootStore: false,
hydrate: false,
serialize: false,
})
}
serialize(): unknown {
return {
step: this.step,
}
}
hydrate(v: unknown) {
if (typeof v === 'object' && v !== null) {
if (
hasProp(v, 'step') &&
typeof v.step === 'string' &&
OnboardingStepsArray.includes(v.step as OnboardingStep)
) {
this.step = v.step as OnboardingStep
}
} else {
// if there is no valid state, we'll just reset
this.reset()
}
}
/**
* Returns the name of the next screen in the onboarding process based on the current step or screen name provided.
* @param {OnboardingStep} [currentScreenName]
* @returns name of next screen in the onboarding process
*/
next(currentScreenName?: OnboardingStep) {
currentScreenName = currentScreenName || this.step
if (currentScreenName === 'Welcome') {
this.step = 'RecommendedFeeds'
return this.step
} else if (this.step === 'RecommendedFeeds') {
this.finish()
return this.step
} else {
// if we get here, we're in an invalid state, let's just go Home
return 'Home'
}
}
start() {
this.step = 'Welcome'
track('Onboarding:Begin')
}
finish() {
this.step = 'Home'
track('Onboarding:Complete')
}
reset() {
this.step = 'Welcome'
track('Onboarding:Reset')
}
skip() {
this.step = 'Home'
track('Onboarding:Skipped')
}
get isComplete() {
return this.step === 'Home'
}
get isActive() {
return !this.isComplete
}
}

View file

@ -67,6 +67,19 @@ export class CustomFeedModel {
}
}
async pin() {
try {
await this.rootStore.preferences.addPinnedFeed(this.uri)
} catch (error) {
this.rootStore.log.error('Failed to pin feed', error)
} finally {
track('CustomFeed:Pin', {
name: this.data.displayName,
uri: this.uri,
})
}
}
async unsave() {
try {
await this.rootStore.preferences.removeSavedFeed(this.uri)

View file

@ -27,6 +27,7 @@ import {reset as resetNavigation} from '../../Navigation'
// remove after backend testing finishes
// -prf
import {applyDebugHeader} from 'lib/api/debug-appview-proxy-header'
import {OnboardingModel} from './discovery/onboarding'
export const appInfo = z.object({
build: z.string(),
@ -44,6 +45,7 @@ export class RootStoreModel {
shell = new ShellUiModel(this)
preferences = new PreferencesModel(this)
me = new MeModel(this)
onboarding = new OnboardingModel(this)
invitedUsers = new InvitedUsers(this)
handleResolutions = new HandleResolutionsCache()
profiles = new ProfilesCache(this)
@ -70,6 +72,7 @@ export class RootStoreModel {
appInfo: this.appInfo,
session: this.session.serialize(),
me: this.me.serialize(),
onboarding: this.onboarding.serialize(),
shell: this.shell.serialize(),
preferences: this.preferences.serialize(),
invitedUsers: this.invitedUsers.serialize(),
@ -88,6 +91,9 @@ export class RootStoreModel {
if (hasProp(v, 'me')) {
this.me.hydrate(v.me)
}
if (hasProp(v, 'onboarding')) {
this.onboarding.hydrate(v.onboarding)
}
if (hasProp(v, 'session')) {
this.session.hydrate(v.session)
}

View file

@ -109,10 +109,10 @@ export class CreateAccountModel {
this.setError('')
this.setIsProcessing(true)
// open the onboarding modal after the session is created
// open the onboarding screens after the session is created
const sessionReadySub = this.rootStore.onSessionReady(() => {
sessionReadySub.remove()
this.rootStore.shell.openModal({name: 'onboarding'})
this.rootStore.onboarding.start()
})
try {

View file

@ -136,10 +136,6 @@ export interface PostLanguagesSettingsModal {
name: 'post-languages-settings'
}
export interface OnboardingModal {
name: 'onboarding'
}
export type Modal =
// Account
| AddAppPasswordModal
@ -171,9 +167,6 @@ export type Modal =
| WaitlistModal
| InviteCodesModal
// Onboarding
| OnboardingModal
// Generic
| ConfirmModal