diff options
Diffstat (limited to 'apps/web/lib/queries/use-saved-entries.ts')
| -rw-r--r-- | apps/web/lib/queries/use-saved-entries.ts | 88 |
1 files changed, 88 insertions, 0 deletions
diff --git a/apps/web/lib/queries/use-saved-entries.ts b/apps/web/lib/queries/use-saved-entries.ts new file mode 100644 index 0000000..bdfcec9 --- /dev/null +++ b/apps/web/lib/queries/use-saved-entries.ts @@ -0,0 +1,88 @@ +"use client" + +import { useInfiniteQuery } from "@tanstack/react-query" +import { createSupabaseBrowserClient } from "@/lib/supabase/client" +import { queryKeys } from "./query-keys" +import type { TimelineEntry } from "@/lib/types/timeline" + +const SAVED_PAGE_SIZE = 50 + +interface SavedEntryRow { + entry_id: string + read: boolean + saved: boolean + saved_at: string + entries: { + id: string + feed_id: string + title: string | null + url: string | null + author: string | null + summary: string | null + image_url: string | null + published_at: string | null + enclosure_url: string | null + enclosure_type: string | null + feeds: { + title: string | null + } + } +} + +function mapSavedRowToTimelineEntry(row: SavedEntryRow): TimelineEntry { + return { + entryIdentifier: row.entries.id, + feedIdentifier: row.entries.feed_id, + feedTitle: row.entries.feeds?.title ?? "", + customTitle: null, + entryTitle: row.entries.title ?? "", + entryUrl: row.entries.url ?? "", + author: row.entries.author, + summary: row.entries.summary, + imageUrl: row.entries.image_url, + publishedAt: row.entries.published_at ?? "", + isRead: row.read, + isSaved: row.saved, + enclosureUrl: row.entries.enclosure_url, + enclosureType: row.entries.enclosure_type, + } +} + +export function useSavedEntries() { + const supabaseClient = createSupabaseBrowserClient() + + return useInfiniteQuery({ + queryKey: queryKeys.savedEntries.all, + queryFn: async ({ + pageParam, + }: { + pageParam: string | undefined + }) => { + let query = supabaseClient + .from("user_entry_states") + .select( + "entry_id, read, saved, saved_at, entries!inner(id, feed_id, title, url, author, summary, image_url, published_at, enclosure_url, enclosure_type, feeds!inner(title))" + ) + .eq("saved", true) + .order("saved_at", { ascending: false }) + .limit(SAVED_PAGE_SIZE) + + if (pageParam) { + query = query.lt("saved_at", pageParam) + } + + const { data, error } = await query + + if (error) throw error + + return ((data as unknown as SavedEntryRow[]) ?? []).map( + mapSavedRowToTimelineEntry + ) + }, + initialPageParam: undefined as string | undefined, + getNextPageParam: (lastPage: TimelineEntry[]) => { + if (lastPage.length < SAVED_PAGE_SIZE) return undefined + return lastPage[lastPage.length - 1].publishedAt + }, + }) +} |