Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 19 additions & 5 deletions src/app/_app.read.$id.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -100,28 +100,42 @@
},
});

// Restore progress on open — wait a frame so layout is complete
const hasRestoredRef = useRef(false);
// Disable browser scroll restoration so it doesn't fight with our
// programmatic restoration (especially on full page reloads).
useEffect(() => {
const original = history.scrollRestoration;
history.scrollRestoration = "manual";
return () => {
history.scrollRestoration = original;
};
}, []);

// Restore progress on open — wait a frame so layout is complete.
// We track the last restored progress value so we can re-run when the
// stored progress changes (e.g. IDB hydrates with stale data first, then
// SSE updates to the real saved progress).
const restoredProgressRef = useRef<number | null>(null);
useEffect(() => {
if (hasRestoredRef.current) return;
if (feedItem == null) return;

const progress = feedItem.progress ?? 0;

if (progress <= 0) {
hasRestoredRef.current = true;
restoredProgressRef.current = progress;
return;
}

if (restoredProgressRef.current === progress) return;

const elements = getElements(articleRef.current);
if (elements.length === 0) return;

const targetIndex = Math.min(progress, elements.length - 1);
hasRestoredRef.current = true;
restoredProgressRef.current = progress;
requestAnimationFrame(() => {
selectElement(elements, targetIndex, true);
});
}, [feedItem?.progress, feedItem?.content, selectElement]);

Check warning on line 138 in src/app/_app.read.$id.tsx

View workflow job for this annotation

GitHub Actions / build

React Hook useEffect has a missing dependency: 'feedItem'. Either include it or remove the dependency array

return (
<div
Expand Down
8 changes: 5 additions & 3 deletions tests/e2e/self-hosted/article-progress.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -57,8 +57,10 @@ test.describe("article progress tracking", () => {
await page.mouse.wheel(0, 300);
await page.waitForTimeout(50);
}
// Allow scroll event handlers and debounce (500ms) + buffer
await page.waitForTimeout(1000);
// Allow scroll event handlers and debounce (500ms) to fire, plus extra
// buffer for the RPC call and IDB write (throttled at 2000ms) to finish
// before we reload the page.
await page.waitForTimeout(3000);

// Verify we scrolled
const scrolledTop = await scrollContainer.evaluate((el) => el.scrollTop);
Expand Down Expand Up @@ -89,7 +91,7 @@ test.describe("article progress tracking", () => {
// Wait for progress restoration — the element with data-article-selected
// appears once the restoration effect fires and selects the saved element.
const restoredSelected = page.locator("[data-article-selected]");
await expect(restoredSelected.first()).toBeVisible({ timeout: 10000 });
await expect(restoredSelected.first()).toBeVisible({ timeout: 20000 });

// Wait for SSE processing to settle so the scroll position is stable.
await page.waitForTimeout(2000);
Expand Down
Loading