Move reminders to new persisted state layer (#1834)

zio/stable
Paul Frazee 2023-11-07 16:39:13 -08:00 committed by GitHub
parent 96d8faf4b0
commit 2acc88e78d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 66 additions and 100 deletions

View File

@ -20,7 +20,6 @@ import {PreferencesModel} from './ui/preferences'
import {resetToTab} from '../../Navigation'
import {ImageSizesCache} from './cache/image-sizes'
import {MutedThreads} from './muted-threads'
import {Reminders} from './ui/reminders'
import {reset as resetNavigation} from '../../Navigation'
import {logger} from '#/logger'
@ -53,7 +52,6 @@ export class RootStoreModel {
linkMetas = new LinkMetasCache(this)
imageSizes = new ImageSizesCache()
mutedThreads = new MutedThreads()
reminders = new Reminders(this)
constructor(agent: BskyAgent) {
this.agent = agent
@ -77,7 +75,6 @@ export class RootStoreModel {
preferences: this.preferences.serialize(),
invitedUsers: this.invitedUsers.serialize(),
mutedThreads: this.mutedThreads.serialize(),
reminders: this.reminders.serialize(),
}
}
@ -107,9 +104,6 @@ export class RootStoreModel {
if (hasProp(v, 'mutedThreads')) {
this.mutedThreads.hydrate(v.mutedThreads)
}
if (hasProp(v, 'reminders')) {
this.reminders.hydrate(v.reminders)
}
}
}

View File

@ -1,24 +0,0 @@
import {makeAutoObservable} from 'mobx'
import {RootStoreModel} from '../root-store'
export class Reminders {
constructor(public rootStore: RootStoreModel) {
makeAutoObservable(
this,
{serialize: false, hydrate: false},
{autoBind: true},
)
}
serialize() {
return {}
}
hydrate(_v: unknown) {}
get shouldRequestEmailConfirmation() {
return false
}
setEmailConfirmationRequested() {}
}

View File

@ -1,64 +0,0 @@
import {makeAutoObservable} from 'mobx'
import {isObj, hasProp} from 'lib/type-guards'
import {RootStoreModel} from '../root-store'
import {toHashCode} from 'lib/strings/helpers'
export class Reminders {
lastEmailConfirm: Date | null = null
constructor(public rootStore: RootStoreModel) {
makeAutoObservable(
this,
{serialize: false, hydrate: false},
{autoBind: true},
)
}
serialize() {
return {
lastEmailConfirm: this.lastEmailConfirm
? this.lastEmailConfirm.toISOString()
: undefined,
}
}
hydrate(v: unknown) {
if (
isObj(v) &&
hasProp(v, 'lastEmailConfirm') &&
typeof v.lastEmailConfirm === 'string'
) {
this.lastEmailConfirm = new Date(v.lastEmailConfirm)
}
}
get shouldRequestEmailConfirmation() {
const sess = this.rootStore.session.currentSession
if (!sess) {
return false
}
if (sess.emailConfirmed) {
return false
}
if (this.rootStore.onboarding.isActive) {
return false
}
// only prompt once
if (this.lastEmailConfirm) {
return false
}
const today = new Date()
// shard the users into 2 day of the week buckets
// (this is to avoid a sudden influx of email updates when
// this feature rolls out)
const code = toHashCode(sess.did) % 7
if (code !== today.getDay() && code !== (today.getDay() + 1) % 7) {
return false
}
return true
}
setEmailConfirmationRequested() {
this.lastEmailConfirm = new Date()
}
}

View File

@ -7,6 +7,10 @@ import {ImageModel} from '../media/image'
import {ListModel} from '../content/list'
import {GalleryModel} from '../media/gallery'
import {StyleProp, ViewStyle} from 'react-native'
import {
shouldRequestEmailConfirmation,
setEmailConfirmationRequested,
} from '#/state/shell/reminders'
export type ColorMode = 'system' | 'light' | 'dark'
@ -358,9 +362,14 @@ export class ShellUiModel {
setupLoginModals() {
this.rootStore.onSessionReady(() => {
if (this.rootStore.reminders.shouldRequestEmailConfirmation) {
if (
shouldRequestEmailConfirmation(
this.rootStore.session,
this.rootStore.onboarding,
)
) {
this.openModal({name: 'verify-email', showReminder: true})
this.rootStore.reminders.setEmailConfirmationRequested()
setEmailConfirmationRequested()
}
})
}

View File

@ -76,9 +76,9 @@ export function transform(legacy: LegacySchema): Schema {
defaults.session.currentAccount,
},
reminders: {
lastEmailConfirmReminder:
lastEmailConfirm:
legacy.reminders.lastEmailConfirm ||
defaults.reminders.lastEmailConfirmReminder,
defaults.reminders.lastEmailConfirm,
},
languagePrefs: {
primaryLanguage:

View File

@ -19,7 +19,7 @@ export const schema = z.object({
currentAccount: accountSchema.optional(),
}),
reminders: z.object({
lastEmailConfirmReminder: z.string().optional(),
lastEmailConfirm: z.string().optional(),
}),
languagePrefs: z.object({
primaryLanguage: z.string(), // should move to server
@ -46,7 +46,7 @@ export const defaults: Schema = {
currentAccount: undefined,
},
reminders: {
lastEmailConfirmReminder: undefined,
lastEmailConfirm: undefined,
},
languagePrefs: {
primaryLanguage: deviceLocales[0] || 'en',

View File

@ -0,0 +1,11 @@
import {OnboardingModel} from '../models/discovery/onboarding'
import {SessionModel} from '../models/session'
export function shouldRequestEmailConfirmation(
_session: SessionModel,
_onboarding: OnboardingModel,
) {
return false
}
export function setEmailConfirmationRequested() {}

View File

@ -0,0 +1,40 @@
import * as persisted from '#/state/persisted'
import {OnboardingModel} from '../models/discovery/onboarding'
import {SessionModel} from '../models/session'
import {toHashCode} from 'lib/strings/helpers'
export function shouldRequestEmailConfirmation(
session: SessionModel,
onboarding: OnboardingModel,
) {
const sess = session.currentSession
if (!sess) {
return false
}
if (sess.emailConfirmed) {
return false
}
if (onboarding.isActive) {
return false
}
// only prompt once
if (persisted.get('reminders').lastEmailConfirm) {
return false
}
const today = new Date()
// shard the users into 2 day of the week buckets
// (this is to avoid a sudden influx of email updates when
// this feature rolls out)
const code = toHashCode(sess.did) % 7
if (code !== today.getDay() && code !== (today.getDay() + 1) % 7) {
return false
}
return true
}
export function setEmailConfirmationRequested() {
persisted.write('reminders', {
...persisted.get('reminders'),
lastEmailConfirm: new Date().toISOString(),
})
}