summaryrefslogtreecommitdiff
path: root/apps
diff options
context:
space:
mode:
authorFuwn <[email protected]>2026-02-12 03:45:49 -0800
committerFuwn <[email protected]>2026-02-12 03:45:49 -0800
commit369e7ef2d19f5656391a894e7b0e55e6d849776e (patch)
tree825fff793bf5fa952a1d814656f04f9af1b4f88b /apps
parentfix: use singular "entry" in mark-as-read toast when count is 1 (diff)
downloadasa.news-369e7ef2d19f5656391a894e7b0e55e6d849776e.tar.xz
asa.news-369e7ef2d19f5656391a894e7b0e55e6d849776e.zip
fix: prioritise unread entries server-side so they appear in all-entries view
Diffstat (limited to 'apps')
-rw-r--r--apps/web/app/reader/_components/entry-list.tsx27
-rw-r--r--apps/web/lib/queries/query-keys.ts4
-rw-r--r--apps/web/lib/queries/use-timeline.ts24
3 files changed, 31 insertions, 24 deletions
diff --git a/apps/web/app/reader/_components/entry-list.tsx b/apps/web/app/reader/_components/entry-list.tsx
index 7786e55..ee2dad2 100644
--- a/apps/web/app/reader/_components/entry-list.tsx
+++ b/apps/web/app/reader/_components/entry-list.tsx
@@ -20,12 +20,14 @@ function useEntryData(
feedFilter: "all" | "saved",
folderIdentifier?: string | null,
feedIdentifier?: string | null,
- customFeedIdentifier?: string | null
+ customFeedIdentifier?: string | null,
+ prioritiseUnread?: boolean
) {
const timelineQuery = useTimeline(
feedFilter === "all" && !customFeedIdentifier ? folderIdentifier : undefined,
feedFilter === "all" && !customFeedIdentifier ? feedIdentifier : undefined,
- false
+ false,
+ prioritiseUnread
)
const savedQuery = useSavedEntries()
const customFeedQuery = useCustomFeedTimeline(
@@ -49,8 +51,12 @@ export function EntryList({
feedIdentifier,
customFeedIdentifier,
}: EntryListProperties) {
+ const prioritiseUnreadEntries = useUserInterfaceStore(
+ (state) => state.prioritiseUnreadEntries
+ )
+
const { data, fetchNextPage, hasNextPage, isFetchingNextPage, isLoading } =
- useEntryData(feedFilter, folderIdentifier, feedIdentifier, customFeedIdentifier)
+ useEntryData(feedFilter, folderIdentifier, feedIdentifier, customFeedIdentifier, prioritiseUnreadEntries)
const entryListViewMode = useUserInterfaceStore(
(state) => state.entryListViewMode
@@ -72,20 +78,9 @@ export function EntryList({
(state) => state.setNavigableEntryIdentifiers
)
- const prioritiseUnreadEntries = useUserInterfaceStore(
- (state) => state.prioritiseUnreadEntries
- )
-
const allEntries = useMemo(() => {
- const flatEntries = data?.pages.flatMap((page) => page) ?? []
-
- if (!prioritiseUnreadEntries) return flatEntries
-
- const unreadEntries = flatEntries.filter((entry) => !entry.isRead)
- const readEntries = flatEntries.filter((entry) => entry.isRead)
-
- return [...unreadEntries, ...readEntries]
- }, [data, prioritiseUnreadEntries])
+ return data?.pages.flatMap((page) => page) ?? []
+ }, [data])
const scrollContainerReference = useRef<HTMLDivElement>(null)
const firstEntryIdentifier = allEntries[0]?.entryIdentifier
diff --git a/apps/web/lib/queries/query-keys.ts b/apps/web/lib/queries/query-keys.ts
index 8c1098e..d893165 100644
--- a/apps/web/lib/queries/query-keys.ts
+++ b/apps/web/lib/queries/query-keys.ts
@@ -1,8 +1,8 @@
export const queryKeys = {
timeline: {
all: ["timeline"] as const,
- list: (folderIdentifier?: string | null, feedIdentifier?: string | null, unreadOnly?: boolean) =>
- ["timeline", { folderIdentifier, feedIdentifier, unreadOnly }] as const,
+ list: (folderIdentifier?: string | null, feedIdentifier?: string | null, unreadOnly?: boolean, prioritiseUnread?: boolean) =>
+ ["timeline", { folderIdentifier, feedIdentifier, unreadOnly, prioritiseUnread }] as const,
},
savedEntries: {
all: ["saved-entries"] as const,
diff --git a/apps/web/lib/queries/use-timeline.ts b/apps/web/lib/queries/use-timeline.ts
index 5a38aba..cb1f099 100644
--- a/apps/web/lib/queries/use-timeline.ts
+++ b/apps/web/lib/queries/use-timeline.ts
@@ -43,36 +43,48 @@ function mapRowToTimelineEntry(row: TimelineRow): TimelineEntry {
}
}
+interface TimelineCursor {
+ publishedAt: string
+ isRead: boolean
+}
+
export function useTimeline(
folderIdentifier?: string | null,
feedIdentifier?: string | null,
- unreadOnly?: boolean
+ unreadOnly?: boolean,
+ prioritiseUnread?: boolean
) {
const supabaseClient = createSupabaseBrowserClient()
return useInfiniteQuery({
- queryKey: queryKeys.timeline.list(folderIdentifier, feedIdentifier, unreadOnly),
+ queryKey: queryKeys.timeline.list(folderIdentifier, feedIdentifier, unreadOnly, prioritiseUnread),
queryFn: async ({
pageParam,
}: {
- pageParam: string | undefined
+ pageParam: TimelineCursor | undefined
}) => {
const { data, error } = await supabaseClient.rpc("get_timeline", {
target_folder_id: folderIdentifier ?? undefined,
target_feed_id: feedIdentifier ?? undefined,
result_limit: TIMELINE_PAGE_SIZE,
- pagination_cursor: pageParam ?? undefined,
+ pagination_cursor: pageParam?.publishedAt ?? undefined,
unread_only: unreadOnly ?? false,
+ prioritise_unread: prioritiseUnread ?? false,
+ cursor_is_read: pageParam?.isRead ?? undefined,
})
if (error) throw error
return ((data as TimelineRow[]) ?? []).map(mapRowToTimelineEntry)
},
- initialPageParam: undefined as string | undefined,
+ initialPageParam: undefined as TimelineCursor | undefined,
getNextPageParam: (lastPage: TimelineEntry[]) => {
if (lastPage.length < TIMELINE_PAGE_SIZE) return undefined
- return lastPage[lastPage.length - 1].publishedAt
+ const lastEntry = lastPage[lastPage.length - 1]
+ return {
+ publishedAt: lastEntry.publishedAt,
+ isRead: lastEntry.isRead,
+ }
},
})
}