about summary refs log tree commit diff
path: root/src/state/models/ui
diff options
context:
space:
mode:
Diffstat (limited to 'src/state/models/ui')
-rw-r--r--src/state/models/ui/reminders.ts65
-rw-r--r--src/state/models/ui/shell.ts22
2 files changed, 87 insertions, 0 deletions
diff --git a/src/state/models/ui/reminders.ts b/src/state/models/ui/reminders.ts
new file mode 100644
index 000000000..f8becdec3
--- /dev/null
+++ b/src/state/models/ui/reminders.ts
@@ -0,0 +1,65 @@
+import {makeAutoObservable} from 'mobx'
+import {isObj, hasProp} from 'lib/type-guards'
+import {RootStoreModel} from '../root-store'
+import {toHashCode} from 'lib/strings/helpers'
+
+const DAY = 60e3 * 24 * 1 // 1 day (ms)
+
+export class Reminders {
+  // NOTE
+  // by defaulting to the current date, we ensure that the user won't be nagged
+  // on first run (aka right after creating an account)
+  // -prf
+  lastEmailConfirm: Date = new Date()
+
+  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
+    }
+    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
+    }
+    // only ask once a day at most, but because of the bucketing
+    // this will be more like weekly
+    return Number(today) - Number(this.lastEmailConfirm) > DAY
+  }
+
+  setEmailConfirmationRequested() {
+    this.lastEmailConfirm = new Date()
+  }
+}
diff --git a/src/state/models/ui/shell.ts b/src/state/models/ui/shell.ts
index 647513563..15d92f927 100644
--- a/src/state/models/ui/shell.ts
+++ b/src/state/models/ui/shell.ts
@@ -24,6 +24,7 @@ export interface ConfirmModal {
   onPressCancel?: () => void | Promise<void>
   confirmBtnText?: string
   confirmBtnStyle?: StyleProp<ViewStyle>
+  cancelBtnText?: string
 }
 
 export interface EditProfileModal {
@@ -140,6 +141,15 @@ export interface BirthDateSettingsModal {
   name: 'birth-date-settings'
 }
 
+export interface VerifyEmailModal {
+  name: 'verify-email'
+  showReminder?: boolean
+}
+
+export interface ChangeEmailModal {
+  name: 'change-email'
+}
+
 export type Modal =
   // Account
   | AddAppPasswordModal
@@ -148,6 +158,8 @@ export type Modal =
   | EditProfileModal
   | ProfilePreviewModal
   | BirthDateSettingsModal
+  | VerifyEmailModal
+  | ChangeEmailModal
 
   // Curation
   | ContentFilteringSettingsModal
@@ -250,6 +262,7 @@ export class ShellUiModel {
     })
 
     this.setupClock()
+    this.setupLoginModals()
   }
 
   serialize(): unknown {
@@ -375,4 +388,13 @@ export class ShellUiModel {
       })
     }, 60_000)
   }
+
+  setupLoginModals() {
+    this.rootStore.onSessionReady(() => {
+      if (this.rootStore.reminders.shouldRequestEmailConfirmation) {
+        this.openModal({name: 'verify-email', showReminder: true})
+        this.rootStore.reminders.setEmailConfirmationRequested()
+      }
+    })
+  }
 }