about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--src/state/models/me.ts15
-rw-r--r--src/state/models/notifications-view.ts37
-rw-r--r--src/view/com/notifications/Feed.tsx6
-rw-r--r--src/view/screens/Notifications.tsx32
4 files changed, 49 insertions, 41 deletions
diff --git a/src/state/models/me.ts b/src/state/models/me.ts
index 78c6d2e76..e3405b80d 100644
--- a/src/state/models/me.ts
+++ b/src/state/models/me.ts
@@ -1,6 +1,7 @@
 import {makeAutoObservable, runInAction} from 'mobx'
 import {RootStoreModel} from './root-store'
 import {MembershipsViewModel} from './memberships-view'
+import {NotificationsViewModel} from './notifications-view'
 
 export class MeModel {
   did?: string
@@ -9,9 +10,11 @@ export class MeModel {
   description?: string
   notificationCount: number = 0
   memberships?: MembershipsViewModel
+  notifications: NotificationsViewModel
 
   constructor(public rootStore: RootStoreModel) {
     makeAutoObservable(this, {rootStore: false}, {autoBind: true})
+    this.notifications = new NotificationsViewModel(this.rootStore, {})
   }
 
   clear() {
@@ -43,7 +46,12 @@ export class MeModel {
       this.memberships = new MembershipsViewModel(this.rootStore, {
         actor: this.did,
       })
-      await this.memberships?.setup()
+      await this.memberships?.setup().catch(e => {
+        console.error('Failed to setup memberships model', e)
+      })
+      await this.notifications.setup().catch(e => {
+        console.error('Failed to setup notifications model', e)
+      })
     } else {
       this.clear()
     }
@@ -56,7 +64,12 @@ export class MeModel {
   async fetchStateUpdate() {
     const res = await this.rootStore.api.app.bsky.notification.getCount()
     runInAction(() => {
+      const newNotifications = this.notificationCount !== res.data.count
       this.notificationCount = res.data.count
+      if (newNotifications) {
+        // trigger pre-emptive fetch on new notifications
+        this.notifications.refresh()
+      }
     })
   }
 
diff --git a/src/state/models/notifications-view.ts b/src/state/models/notifications-view.ts
index f3163822e..e81f31a25 100644
--- a/src/state/models/notifications-view.ts
+++ b/src/state/models/notifications-view.ts
@@ -203,7 +203,6 @@ export class NotificationsViewModel {
     await this._pendingWork()
     this._loadPromise = this._initialLoad(isRefreshing)
     await this._loadPromise
-    this._updateReadState()
     this._loadPromise = undefined
   }
 
@@ -240,6 +239,20 @@ export class NotificationsViewModel {
     this._updatePromise = undefined
   }
 
+  /**
+   * Update read/unread state
+   */
+  async updateReadState() {
+    try {
+      await this.rootStore.api.app.bsky.notification.updateSeen({
+        seenAt: new Date().toISOString(),
+      })
+      this.rootStore.me.clearNotificationCount()
+    } catch (e) {
+      console.log('Failed to update notifications read state', e)
+    }
+  }
+
   // state transitions
   // =
 
@@ -329,11 +342,10 @@ export class NotificationsViewModel {
   }
 
   private async _replaceAll(res: ListNotifications.Response) {
-    this.notifications.length = 0
-    return this._appendAll(res)
+    return this._appendAll(res, true)
   }
 
-  private async _appendAll(res: ListNotifications.Response) {
+  private async _appendAll(res: ListNotifications.Response, replace = false) {
     this.loadMoreCursor = res.data.cursor
     this.hasMore = !!this.loadMoreCursor
     let counter = this.notifications.length
@@ -357,7 +369,11 @@ export class NotificationsViewModel {
       )
     })
     runInAction(() => {
-      this.notifications = this.notifications.concat(itemModels)
+      if (replace) {
+        this.notifications = itemModels
+      } else {
+        this.notifications = this.notifications.concat(itemModels)
+      }
     })
   }
 
@@ -374,17 +390,6 @@ export class NotificationsViewModel {
       }
     }
   }
-
-  private async _updateReadState() {
-    try {
-      await this.rootStore.api.app.bsky.notification.updateSeen({
-        seenAt: new Date().toISOString(),
-      })
-      this.rootStore.me.clearNotificationCount()
-    } catch (e) {
-      console.log('Failed to update notifications read state', e)
-    }
-  }
 }
 
 function groupNotifications(
diff --git a/src/view/com/notifications/Feed.tsx b/src/view/com/notifications/Feed.tsx
index 90d16604d..78dcd2fa8 100644
--- a/src/view/com/notifications/Feed.tsx
+++ b/src/view/com/notifications/Feed.tsx
@@ -32,7 +32,7 @@ export const Feed = observer(function Feed({
   }
   return (
     <View style={{flex: 1}}>
-      {view.isLoading && !view.isRefreshing && !view.hasContent && (
+      {view.isLoading && !view.isRefreshing && (
         <NotificationFeedLoadingPlaceholder />
       )}
       {view.hasError && (
@@ -43,7 +43,7 @@ export const Feed = observer(function Feed({
           onPressTryAgain={onPressTryAgain}
         />
       )}
-      {view.hasContent && (
+      {view.hasLoaded && (
         <FlatList
           data={view.notifications}
           keyExtractor={item => item._reactKey}
@@ -53,7 +53,7 @@ export const Feed = observer(function Feed({
           onEndReached={onEndReached}
         />
       )}
-      {view.isEmpty && (
+      {view.hasLoaded && view.isEmpty && (
         <EmptyState icon="bell" message="No notifications yet!" />
       )}
     </View>
diff --git a/src/view/screens/Notifications.tsx b/src/view/screens/Notifications.tsx
index 1e7abdb90..b168ffaff 100644
--- a/src/view/screens/Notifications.tsx
+++ b/src/view/screens/Notifications.tsx
@@ -7,43 +7,33 @@ import {NotificationsViewModel} from '../../state/models/notifications-view'
 import {ScreenParams} from '../routes'
 
 export const Notifications = ({navIdx, visible}: ScreenParams) => {
-  const [hasSetup, setHasSetup] = useState<boolean>(false)
-  const [notesView, setNotesView] = useState<
-    NotificationsViewModel | undefined
-  >()
   const store = useStores()
 
   useEffect(() => {
-    let aborted = false
     if (!visible) {
       return
     }
+    console.log('Updating notifications feed')
     store.me.refreshMemberships() // needed for the invite notifications
-    if (hasSetup) {
-      console.log('Updating notifications feed')
-      notesView?.update()
-    } else {
-      store.nav.setTitle(navIdx, 'Notifications')
-      const newNotesView = new NotificationsViewModel(store, {})
-      setNotesView(newNotesView)
-      newNotesView.setup().then(() => {
-        if (aborted) return
-        setHasSetup(true)
+    store.me.notifications
+      .update()
+      .catch(e => {
+        console.error('Error while updating notifications feed', e)
       })
-    }
-    return () => {
-      aborted = true
-    }
+      .then(() => {
+        store.me.notifications.updateReadState()
+      })
+    store.nav.setTitle(navIdx, 'Notifications')
   }, [visible, store])
 
   const onPressTryAgain = () => {
-    notesView?.refresh()
+    store.me.notifications.refresh()
   }
 
   return (
     <View style={{flex: 1}}>
       <ViewHeader title="Notifications" />
-      {notesView && <Feed view={notesView} onPressTryAgain={onPressTryAgain} />}
+      <Feed view={store.me.notifications} onPressTryAgain={onPressTryAgain} />
     </View>
   )
 }