summaryrefslogtreecommitdiff
path: root/apps/web/app/reader/_components
diff options
context:
space:
mode:
authorFuwn <[email protected]>2026-02-10 20:33:11 -0800
committerFuwn <[email protected]>2026-02-10 20:33:11 -0800
commit40592fe37310837ad4d6e6f9be76de17e9a33027 (patch)
tree58bfafe8de39a7555e9160ad1224e275b4a8ec71 /apps/web/app/reader/_components
parentfix: let display density apply to main content panel (diff)
downloadasa.news-40592fe37310837ad4d6e6f9be76de17e9a33027.tar.xz
asa.news-40592fe37310837ad4d6e6f9be76de17e9a33027.zip
fix: query entry state directly instead of relying on unfiltered timeline
The detail panel called useTimeline() with no args, creating a separate cache from the entry list's filtered query. Entries not in the first 50 of the global timeline had isSaved/isRead stuck at false.
Diffstat (limited to 'apps/web/app/reader/_components')
-rw-r--r--apps/web/app/reader/_components/entry-detail-panel.tsx35
1 files changed, 26 insertions, 9 deletions
diff --git a/apps/web/app/reader/_components/entry-detail-panel.tsx b/apps/web/app/reader/_components/entry-detail-panel.tsx
index 7901100..6760f52 100644
--- a/apps/web/app/reader/_components/entry-detail-panel.tsx
+++ b/apps/web/app/reader/_components/entry-detail-panel.tsx
@@ -10,7 +10,6 @@ import {
} from "@/lib/queries/use-entry-state-mutations"
import { queryKeys } from "@/lib/queries/query-keys"
import { useUserInterfaceStore } from "@/lib/stores/user-interface-store"
-import { useTimeline } from "@/lib/queries/use-timeline"
import { useEntryShare } from "@/lib/queries/use-entry-share"
import { useEntryHighlights } from "@/lib/queries/use-entry-highlights"
import {
@@ -90,10 +89,28 @@ export function EntryDetailPanel({
const [shareNoteText, setShareNoteText] = useState("")
const shareNoteTextareaReference = useRef<HTMLTextAreaElement>(null)
- const { data: timelineData } = useTimeline()
- const currentEntry = timelineData?.pages
- .flatMap((page) => page)
- .find((entry) => entry.entryIdentifier === entryIdentifier)
+ const { data: entryState } = useQuery({
+ queryKey: queryKeys.entryState.single(entryIdentifier),
+ queryFn: async () => {
+ const {
+ data: { user },
+ } = await supabaseClient.auth.getUser()
+
+ if (!user) return { isRead: false, isSaved: false }
+
+ const { data } = await supabaseClient
+ .from("user_entry_states")
+ .select("read, saved")
+ .eq("user_id", user.id)
+ .eq("entry_id", entryIdentifier)
+ .maybeSingle()
+
+ return {
+ isRead: data?.read ?? false,
+ isSaved: data?.saved ?? false,
+ }
+ },
+ })
const { data: entryDetail, isLoading } = useQuery({
queryKey: queryKeys.entryDetail.single(entryIdentifier),
@@ -140,7 +157,7 @@ export function EntryDetailPanel({
})
useEffect(() => {
- if (!currentEntry || currentEntry.isRead) return
+ if (!entryState || entryState.isRead) return
const autoReadTimeout = setTimeout(() => {
toggleReadState.mutate({
@@ -151,7 +168,7 @@ export function EntryDetailPanel({
return () => clearTimeout(autoReadTimeout)
// eslint-disable-next-line react-hooks/exhaustive-deps
- }, [entryIdentifier, currentEntry?.isRead])
+ }, [entryIdentifier, entryState?.isRead])
const contentHtml =
entryDetail?.content_html || entryDetail?.summary || ""
@@ -439,8 +456,8 @@ export function EntryDetailPanel({
}
const readingTimeMinutes = estimateReadingTimeMinutes(contentHtml)
- const isRead = currentEntry?.isRead ?? false
- const isSaved = currentEntry?.isSaved ?? false
+ const isRead = entryState?.isRead ?? false
+ const isSaved = entryState?.isSaved ?? false
const actionBarAtBottom = isMobile && toolbarPosition === "bottom"