about summary refs log tree commit diff
path: root/src/state/queries/notifications/feed.ts
diff options
context:
space:
mode:
Diffstat (limited to 'src/state/queries/notifications/feed.ts')
-rw-r--r--src/state/queries/notifications/feed.ts51
1 files changed, 40 insertions, 11 deletions
diff --git a/src/state/queries/notifications/feed.ts b/src/state/queries/notifications/feed.ts
index a74670b5b..b6aa3d753 100644
--- a/src/state/queries/notifications/feed.ts
+++ b/src/state/queries/notifications/feed.ts
@@ -16,7 +16,7 @@
  * 3. Don't call this query's `refetch()` if you're trying to sync latest; call `checkUnread()` instead.
  */
 
-import {useEffect} from 'react'
+import {useEffect, useRef} from 'react'
 import {AppBskyFeedDefs} from '@atproto/api'
 import {
   useInfiniteQuery,
@@ -49,6 +49,8 @@ export function useNotificationFeedQuery(opts?: {enabled?: boolean}) {
   const threadMutes = useMutedThreads()
   const unreads = useUnreadNotificationsApi()
   const enabled = opts?.enabled !== false
+  // state tracked across page fetches
+  const pageState = useRef({pageNum: 0, hasMarkedRead: false})
 
   const query = useInfiniteQuery<
     FeedPage,
@@ -60,17 +62,44 @@ export function useNotificationFeedQuery(opts?: {enabled?: boolean}) {
     staleTime: STALE.INFINITY,
     queryKey: RQKEY(),
     async queryFn({pageParam}: {pageParam: RQPageParam}) {
-      let page = await fetchPage({
-        limit: PAGE_SIZE,
-        cursor: pageParam,
-        queryClient,
-        moderationOpts,
-        threadMutes,
-      })
+      let page
+      if (!pageParam) {
+        // for the first page, we check the cached page held by the unread-checker first
+        page = unreads.getCachedUnreadPage()
+        // reset the page state
+        pageState.current = {pageNum: 0, hasMarkedRead: false}
+      }
+      if (!page) {
+        page = await fetchPage({
+          limit: PAGE_SIZE,
+          cursor: pageParam,
+          queryClient,
+          moderationOpts,
+          threadMutes,
+        })
+      }
 
-      // if the first page has an unread, mark all read
-      if (!pageParam && page.items[0] && !page.items[0].notification.isRead) {
-        unreads.markAllRead()
+      // NOTE
+      // this section checks to see if we need to mark notifs read
+      // we want to wait until we've seen a read notification because
+      // of a timing challenge; marking read on the first page would
+      // cause subsequent pages of unread notifs to incorrectly come
+      // back as "read". we use page 6 as an abort condition, which means
+      // after ~180 notifs we give up on tracking unread state correctly
+      // -prf
+      if (!pageState.current.hasMarkedRead) {
+        let hasMarkedRead = false
+        if (
+          pageState.current.pageNum > 5 ||
+          page.items.some(item => item.notification.isRead)
+        ) {
+          unreads.markAllRead()
+          hasMarkedRead = true
+        }
+        pageState.current = {
+          pageNum: pageState.current.pageNum + 1,
+          hasMarkedRead,
+        }
       }
 
       return page