fix: sync unread when mismatched, close #4028
This commit is contained in:
parent
71408ea923
commit
35d7f9e784
|
|
@ -99,18 +99,12 @@ const useRemoteEntries = (): UseEntriesReturn => {
|
|||
|
||||
const refetch = useCallback(async () => void query.refetch(), [query])
|
||||
const fetchNextPage = useCallback(async () => void query.fetchNextPage(), [query])
|
||||
const entriesIds = useMemo(() => {
|
||||
if (!query.data || query.isLoading || query.isError) {
|
||||
return []
|
||||
}
|
||||
return query.data?.pages?.map((page) => page.data?.map((entry) => entry.entries.id)).flat()
|
||||
}, [query.data, query.isLoading, query.isError])
|
||||
|
||||
if (!query.data || query.isLoading) {
|
||||
return fallbackReturn
|
||||
}
|
||||
return {
|
||||
entriesIds,
|
||||
entriesIds: query.entriesIds,
|
||||
hasNext: query.hasNextPage,
|
||||
hasUpdate,
|
||||
refetch,
|
||||
|
|
|
|||
|
|
@ -178,24 +178,13 @@ function useRemoteEntries(props?: UseEntriesProps): UseEntriesReturn {
|
|||
|
||||
const refetch = useCallback(async () => void query.refetch(), [query])
|
||||
const fetchNextPage = useCallback(async () => void query.fetchNextPage(), [query])
|
||||
const entriesIds = useMemo(() => {
|
||||
if (!query.data || query.isLoading || query.isError) {
|
||||
return []
|
||||
}
|
||||
return (
|
||||
query.data?.pages
|
||||
?.map((page) => page.data?.map((entry) => entry.entries.id))
|
||||
.flat()
|
||||
.filter((id) => typeof id === "string") || []
|
||||
)
|
||||
}, [query.data, query.isLoading, query.isError])
|
||||
|
||||
if (!query.data || query.isLoading) {
|
||||
return fallbackReturn
|
||||
}
|
||||
|
||||
return {
|
||||
entriesIds,
|
||||
entriesIds: query.entriesIds,
|
||||
hasNext: query.hasNextPage,
|
||||
hasUpdate: false,
|
||||
refetch,
|
||||
|
|
|
|||
|
|
@ -1,11 +1,12 @@
|
|||
import type { FeedViewType } from "@follow/constants"
|
||||
import { useInfiniteQuery, useQuery } from "@tanstack/react-query"
|
||||
import { useCallback } from "react"
|
||||
import { useCallback, useMemo } from "react"
|
||||
|
||||
import { useFeedUnreadIsDirty } from "../atoms/feed"
|
||||
import { FEED_COLLECTION_LIST } from "../constants/app"
|
||||
import { queryClient } from "../context"
|
||||
import { getSubscriptionByEntryId } from "../subscription/getter"
|
||||
import { useSyncUnreadWhenUnMatch } from "../unread/hooks"
|
||||
import { getEntry } from "./getter"
|
||||
import { entrySyncServices, useEntryStore } from "./store"
|
||||
import type { EntryModel, FetchEntriesProps, FetchEntriesPropsSettings } from "./types"
|
||||
|
|
@ -62,7 +63,7 @@ export const useEntriesQuery = (
|
|||
const isPop =
|
||||
"history" in globalThis && "isPop" in globalThis.history && !!globalThis.history.isPop
|
||||
|
||||
return useInfiniteQuery({
|
||||
const query = useInfiniteQuery({
|
||||
queryKey: [
|
||||
"entries",
|
||||
feedId,
|
||||
|
|
@ -96,6 +97,27 @@ export const useEntriesQuery = (
|
|||
isPop ? Infinity : fetchUnread && feedUnreadDirty ? 0 : defaultStaleTime,
|
||||
enabled: !!props,
|
||||
})
|
||||
|
||||
const entriesIds = useMemo(() => {
|
||||
if (!query.data || query.isLoading || query.isError) {
|
||||
return []
|
||||
}
|
||||
return (
|
||||
query.data?.pages
|
||||
?.map((page) => page.data?.map((entry) => entry.entries.id))
|
||||
.flat()
|
||||
.filter((id) => typeof id === "string") || []
|
||||
)
|
||||
}, [query.data, query.isLoading, query.isError])
|
||||
|
||||
useSyncUnreadWhenUnMatch(entriesIds)
|
||||
|
||||
return useMemo(() => {
|
||||
return {
|
||||
...query,
|
||||
entriesIds,
|
||||
}
|
||||
}, [entriesIds, query])
|
||||
}
|
||||
|
||||
export const usePrefetchEntryDetail = (entryId: string) => {
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@ import type { FeedViewType } from "@follow/constants"
|
|||
import { useMutation, useQuery } from "@tanstack/react-query"
|
||||
import { useCallback, useEffect } from "react"
|
||||
|
||||
import { getEntry } from "../entry/getter"
|
||||
import { useListFeedIds } from "../list/hooks"
|
||||
import { useSubscriptionIdsByView } from "../subscription/hooks"
|
||||
import { unreadCountAllSelector, unreadCountIdSelector, unreadCountIdsSelector } from "./selectors"
|
||||
|
|
@ -15,6 +16,32 @@ export const usePrefetchUnread = () => {
|
|||
})
|
||||
}
|
||||
|
||||
export const useSyncUnreadWhenUnMatch = (entryIds: string[]) => {
|
||||
useEffect(() => {
|
||||
const entries = entryIds.map((id) => getEntry(id))
|
||||
const unreadCountMap = entries.reduce(
|
||||
(acc, entry) => {
|
||||
if (entry && entry.feedId && !entry?.read) {
|
||||
acc[entry.feedId] = (acc[entry.feedId] || 0) + 1
|
||||
}
|
||||
return acc
|
||||
},
|
||||
{} as Record<string, number>,
|
||||
)
|
||||
|
||||
const unread = useUnreadStore.getState().data
|
||||
|
||||
const hasUnreadMismatch = Object.keys(unreadCountMap).some(
|
||||
(feedId) =>
|
||||
!unread[feedId] || (unreadCountMap[feedId] && unreadCountMap[feedId] > unread[feedId]),
|
||||
)
|
||||
|
||||
if (hasUnreadMismatch) {
|
||||
unreadSyncService.resetFromRemote()
|
||||
}
|
||||
}, [entryIds.toString()])
|
||||
}
|
||||
|
||||
export const useAutoMarkAsRead = (entryId: string) => {
|
||||
const { mutate } = useMutation({
|
||||
mutationFn: (entryId: string) => unreadSyncService.markEntryAsRead(entryId),
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@ import type { FeedViewType } from "@follow/constants"
|
|||
import type { UnreadSchema } from "@follow/database/schemas/types"
|
||||
import { EntryService } from "@follow/database/services/entry"
|
||||
import { UnreadService } from "@follow/database/services/unread"
|
||||
import { isEqual } from "es-toolkit"
|
||||
|
||||
import { setFeedUnreadDirty } from "../atoms/feed"
|
||||
import { apiClient } from "../context"
|
||||
|
|
@ -34,6 +35,10 @@ class UnreadSyncService {
|
|||
query: {},
|
||||
})
|
||||
|
||||
if (isEqual(res.data, get().data)) {
|
||||
return res.data
|
||||
}
|
||||
|
||||
await unreadActions.upsertMany(res.data, { reset: true })
|
||||
return res.data
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue