Skip to content

fix: load activity and expense histories with infinite scrolling - #789

Merged
krokosik merged 3 commits into
mainfrom
fix/issue-757-infinite-scroll
Nov 1, 2026
Merged

krokosik merged 3 commits into
mainfrom
fix/issue-757-infinite-scroll

Conversation

@krokosik

@krokosik krokosik commented Nov 1, 2026 •

Copy link
Copy Markdown
Collaborator

Large expense histories currently load every row into a single response, causing multi-megabyte tRPC responses and slow activity, friend, and group pages. These pages now load 50 rows at a time and fetch the next page as the user scrolls.

Shared pagination helpers use date-and-ID cursors with stable ordering, including when expenses share a date or the cursor row is deleted. A reusable scroll control provides loading, manual load-more, and retry states. Future server-side search and filter criteria can extend query inputs while keeping pagination and cache handling intact.

CSV exports still include the full history, collected through bounded requests on demand. The group's first-expense statistic is fetched independently of the loaded pages.

Closes #757.

Validation

  • Prettier, lint, and TypeScript checks passed.
  • 447 unit/component tests and 17 PostgreSQL integration tests passed.
  • Three Chromium tests verified activity, friend, and group histories load 50 rows initially and fetch the remaining rows on scroll; the friend test also verified full CSV export before scrolling.
  • Production build passed.
  • Manual testing completed against the seeded development database.

Rows are appended without virtualization. Scrolling through an entire large history can still create a large DOM; concurrent edits that change sort dates may move rows across page boundaries until refresh.

Summary by CodeRabbit

  • New Features
    • Activity, friend, and group expense histories now load more items as you scroll, with options to load or retry manually.
    • CSV exports can include all expenses without first loading every page in the list.
    • Expense lists load up to 50 items at a time, with additional pages available as needed.
  • Bug Fixes
    • Group statistics now show the date of the earliest qualifying expense.

@coderabbitai

coderabbitai Bot commented Nov 1, 2026 •

Copy link
Copy Markdown
Contributor

Review in Change Stack →

No actionable comments were generated in the recent review.

Recent review info
Run configuration
  • Source mode: Auto
  • Repository: Unavailable
  • Branch: Unavailable
  • File: No configuration file from this repository applied
  • Commit: Unavailable
  • Layers: defaults
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: 23dde925-e41e-4de5-931a-a13cd9876fb8
Commits

Reviewing files that changed from the base of the PR and between 3583568 and 046e4a8.

Files selected for processing: 17
  • docs/expense-pagination.md
  • public/locales/en/common.json
  • src/components/Expense/ExpenseList.tsx
  • src/components/Friend/Export.tsx
  • src/components/InfiniteScroll.test.tsx
  • src/components/InfiniteScroll.tsx
  • src/pages/activity.tsx
  • src/pages/balances/[friendId].tsx
  • src/pages/groups/[groupId].tsx
  • src/server/api/routers/expense.ts
  • src/server/api/routers/group.ts
  • src/tests/integration/balances.integration.test.ts
  • src/tests/integration/expense.integration.test.ts
  • src/tests/integration/pagination.integration.test.ts
  • src/utils/pagination.test.ts
  • src/utils/pagination.ts
  • tests/e2e/infinite-scroll.spec.ts

Included review availability: This review used your included allowance. Your plan provides up to 4 included reviews per hour; 1 remain after this review.

Walkthrough

Expense histories now load in cursor-based pages across activity, friend, and group views. The changes add shared pagination utilities, server-side pagination, incremental loading, and an option to fetch all pages for friend CSV export.

Changes: Expense History Pagination

Layer / File(s) Summary
Pagination contract and server queries
src/utils/pagination.ts, src/server/api/routers/expense.ts, src/tests/integration/pagination.integration.test.ts, src/utils/pagination.test.ts, src/tests/integration/{balances,expense}.integration.test.ts, docs/expense-pagination.md
Shared utilities define page limits, date-and-ID cursors, page construction, flattening, and sequential collection. Expense history endpoints return bounded pages. Integration tests cover ordering, cursor traversal, deletion visibility, authorization, and page limits.
Infinite history views
src/components/InfiniteScroll.tsx, src/components/InfiniteScroll.test.tsx, src/pages/activity.tsx, src/pages/balances/[friendId].tsx, src/pages/groups/[groupId].tsx, src/components/Expense/ExpenseList.tsx, public/locales/en/common.json, tests/e2e/infinite-scroll.spec.ts, docs/expense-pagination.md
Activity, friend, and group pages flatten loaded pages and use InfiniteScroll to load more. The control supports automatic loading, retry, and loading and error states. Group details supply the earliest qualifying expense date separately.
Friend CSV export across pages
src/components/Friend/Export.tsx, src/pages/balances/[friendId].tsx, src/utils/pagination.ts, tests/e2e/infinite-scroll.spec.ts, docs/expense-pagination.md
Friend CSV export can fetch all expense pages through a callback. The export button tracks progress and reports failures. The end-to-end test checks export before scrolling through all visible pages.

Estimated code review effort: 3 (Moderate) | ~25 minutes

Change: Bug fix · Severity of issue fixed: Medium

Sequence Diagram(s)

sequenceDiagram
  actor User
  participant InfiniteScroll
  participant ActivityPage
  participant expense.getAllExpenses
  User->>InfiniteScroll: reach the observed sentinel
  InfiniteScroll->>ActivityPage: request another page
  ActivityPage->>expense.getAllExpenses: fetch with the next cursor
  expense.getAllExpenses->>ActivityPage: return items and optional nextCursor
  ActivityPage->>User: render flattened expense pages
Loading

Possibly related PRs

  • oss-apps/split-pro#784: Adds offset-paginated expense listing procedures. This PR changes the same expense history procedures to cursor pagination and changes their response shape.

Suggested reviewers: kiwilmao

Merge Risk: Minimal · previous review 046e4

No actionable risk introduced by this change remains identified; it is ready to merge after normal checks.

Pre-merge checks: Passed 5
Check name Status Explanation
Title check Passed The title "fix: load activity and expense histories with infinite scrolling" matches the main change. The PR adds cursor pagination and an InfiniteScroll control so activity, friend, and group expense…
Linked Issues check Passed Issue #757 requires responsive large expense histories through pagination or incremental loading. The PR adds cursor pagination with a default limit of 50 to getExpensesWithFriend, `getGroupExpenses…
Out of Scope Changes check Passed The changes support the pagination objective in #757. Shared pagination utilities, scroll-state translations and tests, CSV page collection, the separate earliest group expense query, and documentatio…
Docstring Coverage Passed No eligible functions found in the changed files. Skipping docstring coverage check. Docstring coverage is scoped to functions touched by this diff with cyclomatic complexity of at least 2. Documentat…
Description check Passed The description clearly explains the change, testing performed, related issue, demo coverage, and known limitations. It does not include the template's Demo or Checklist headings, but the missing sect…
Full details: Title check

Explanation

The title "fix: load activity and expense histories with infinite scrolling" matches the main change. The PR adds cursor pagination and an InfiniteScroll control so activity, friend, and group expense histories load 50 rows at a time and fetch more as the user scrolls. The title names the primary change and uses a conventional prefix. It does not mention the server-side cursor pagination or CSV export changes, which is acceptable because the title does not need to cover every detail.

Full details: Linked Issues check

Explanation

Issue #757 requires responsive large expense histories through pagination or incremental loading. The PR adds cursor pagination with a default limit of 50 to getExpensesWithFriend, getGroupExpenses, and getAllExpenses. Activity, friend, and group pages use infinite queries and load-more controls. Integration and end-to-end tests cover page limits, stable ordering, deleted cursors, authorization, termination, and incremental loading. CSV export still collects all pages through bounded requests.

Full details: Out of Scope Changes check

Explanation

The changes support the pagination objective in #757. Shared pagination utilities, scroll-state translations and tests, CSV page collection, the separate earliest group expense query, and documentation address pagination behavior or preserve existing history features. No unrelated change is established by the provided scope evidence.

Full details: Docstring Coverage

Explanation

No eligible functions found in the changed files. Skipping docstring coverage check. Docstring coverage is scoped to functions touched by this diff with cyclomatic complexity of at least 2. Documentation-only edits and deletions within surviving functions are included; unchanged diff context and fully deleted functions are excluded. Analyzed 0 functions across 15 files. (2 skipped: 2 unsupported.)

Full details: Description check

Explanation

The description clearly explains the change, testing performed, related issue, demo coverage, and known limitations. It does not include the template's Demo or Checklist headings, but the missing sections are non-critical because the description includes validation details and closes issue #757.

Finishing Touches
Generate docstrings
  • Commit to this branch
  • Create a new PR
Generate unit tests (beta)
  • Commit to this branch
  • Create a new PR
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

Share

@krokosik
krokosik merged commit bf2eb9b into main Nov 1, 2026
8 checks passed
@krokosik
krokosik deleted the fix/issue-757-infinite-scroll branch November 1, 2026 18:27
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.

Performance degradation with large expense histories (>4 MB tRPC responses)

1 participant