summaryrefslogtreecommitdiff
path: root/apps/web/lib/queries/use-saved-entries.ts
diff options
context:
space:
mode:
Diffstat (limited to 'apps/web/lib/queries/use-saved-entries.ts')
-rw-r--r--apps/web/lib/queries/use-saved-entries.ts88
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
+ },
+ })
+}