Skip to content

feat(web): auto-load list pages on scroll with a reliable "Load more" fallback#241

Merged
felixevers merged 1 commit into
mainfrom
claude/practical-cannon-R3Q61
Jun 3, 2026
Merged

feat(web): auto-load list pages on scroll with a reliable "Load more" fallback#241
felixevers merged 1 commit into
mainfrom
claude/practical-cannon-R3Q61

Conversation

@felixevers
Copy link
Copy Markdown
Member

What & why

The task and patient lists should pull the next page automatically as you scroll toward the bottom (when a next page exists), and otherwise offer a Load more button when not already loading — in both card and table views, including on mobile.

The infinite-scroll machinery already landed on this branch (useAccumulatedPagination + InfiniteScrollSentinel, with the end-of-results loop guard). This PR makes the auto-load actually behave as intended by fixing where the sentinel observes from.

The fix

InfiniteScrollSentinel ran its IntersectionObserver against the viewport (root: null). But the lists render inside the app shell's scroll container (Pagediv.overflow-y-auto). An intervening scroll container clips the observed target, so the generous 800px rootMargin lookahead was silently ignored — the next page only loaded once the user hit the very bottom, instead of as the bottom came into view.

Changes:

  • Resolve the nearest scrollable ancestor and use it as the observer root, so the lookahead margin works (loads before you reach the bottom). Falls back to the viewport when there is no nested scroll container. New helper utils/scrollableAncestor.ts.
  • Switch the sentinel to a callback ref so the observer re-attaches when the node remounts after hasMore toggles false → true. Previously the setup effect only depended on rootMargin and could be left observing a detached node (or never attach if the list started empty).
  • Unit test for the pure overflow predicate (utils/scrollableAncestor.test.ts).

Behaviour after this change

  • Auto-load on scroll triggers ~800px before the scroll container's bottom edge, in card and table views, on desktop and mobile.
  • Load more button still shows when there is a next page and a fetch isn't already in flight; a spinner shows while fetching.
  • No auto-load / no button when there is no next page (existing useAccumulatedPagination end-of-results gating is unchanged).
  • Short pages that don't fill the container keep loading until the viewport is filled or the data is exhausted.

Validation

  • npm run lint (tsc + eslint) — clean
  • npm run test — 21 passing (added scrollableAncestor test)
  • npm run check-translations — clean (loadMore key present in all locales)

Note: this branch is ahead of main by the recent web list/table commits (#230#240); the headline change here is the scroll-container observer fix described above.

https://claude.ai/code/session_01W5tHwmE9ZTnCa7HFzqid2A


Generated by Claude Code

The list auto-load sentinel observed against the viewport (root: null),
but task/patient lists render inside the app shell's overflow-y-auto
container. An intervening scroll container clips the observed target, so
the generous 800px rootMargin lookahead was silently ignored and the next
page only loaded once the user hit the very bottom instead of as the
bottom came into view.

Resolve the nearest scrollable ancestor and use it as the observer root so
the lookahead works in both card and table views (and on mobile). Also
switch the sentinel to a callback ref so the observer re-attaches when the
node remounts after hasMore toggles false->true, which previously left it
watching a detached node. Cover the pure overflow predicate with a test.

https://claude.ai/code/session_01W5tHwmE9ZTnCa7HFzqid2A
@felixevers felixevers merged commit 779e212 into main Jun 3, 2026
13 checks passed
@felixevers felixevers deleted the claude/practical-cannon-R3Q61 branch June 3, 2026 22:08
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants