From 2acc88e78df1c1f4c21bf9a333f3432781a64135 Mon Sep 17 00:00:00 2001 From: Paul Frazee Date: Tue, 7 Nov 2023 16:39:13 -0800 Subject: [PATCH] Move reminders to new persisted state layer (#1834) --- src/state/models/root-store.ts | 6 --- src/state/models/ui/reminders.e2e.ts | 24 ----------- src/state/models/ui/reminders.ts | 64 ---------------------------- src/state/models/ui/shell.ts | 13 +++++- src/state/persisted/legacy.ts | 4 +- src/state/persisted/schema.ts | 4 +- src/state/shell/reminders.e2e.ts | 11 +++++ src/state/shell/reminders.ts | 40 +++++++++++++++++ 8 files changed, 66 insertions(+), 100 deletions(-) delete mode 100644 src/state/models/ui/reminders.e2e.ts delete mode 100644 src/state/models/ui/reminders.ts create mode 100644 src/state/shell/reminders.e2e.ts create mode 100644 src/state/shell/reminders.ts diff --git a/src/state/models/root-store.ts b/src/state/models/root-store.ts index 1943f6db..6ba78e71 100644 --- a/src/state/models/root-store.ts +++ b/src/state/models/root-store.ts @@ -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) - } } } diff --git a/src/state/models/ui/reminders.e2e.ts b/src/state/models/ui/reminders.e2e.ts deleted file mode 100644 index ec0eca40..00000000 --- a/src/state/models/ui/reminders.e2e.ts +++ /dev/null @@ -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() {} -} diff --git a/src/state/models/ui/reminders.ts b/src/state/models/ui/reminders.ts deleted file mode 100644 index c650de00..00000000 --- a/src/state/models/ui/reminders.ts +++ /dev/null @@ -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() - } -} diff --git a/src/state/models/ui/shell.ts b/src/state/models/ui/shell.ts index d3913162..343fff86 100644 --- a/src/state/models/ui/shell.ts +++ b/src/state/models/ui/shell.ts @@ -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() } }) } diff --git a/src/state/persisted/legacy.ts b/src/state/persisted/legacy.ts index 6d0a2bcc..67eef81a 100644 --- a/src/state/persisted/legacy.ts +++ b/src/state/persisted/legacy.ts @@ -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: diff --git a/src/state/persisted/schema.ts b/src/state/persisted/schema.ts index 1c5d317c..c00ee500 100644 --- a/src/state/persisted/schema.ts +++ b/src/state/persisted/schema.ts @@ -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', diff --git a/src/state/shell/reminders.e2e.ts b/src/state/shell/reminders.e2e.ts new file mode 100644 index 00000000..6238ffa2 --- /dev/null +++ b/src/state/shell/reminders.e2e.ts @@ -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() {} diff --git a/src/state/shell/reminders.ts b/src/state/shell/reminders.ts new file mode 100644 index 00000000..d68a272a --- /dev/null +++ b/src/state/shell/reminders.ts @@ -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(), + }) +}