feat: implement load more functionality for transaction history#61
feat: implement load more functionality for transaction history#61mrcentimetre wants to merge 1 commit intomainfrom
Conversation
|
@mrcentimetre must be a member of the CeyLabs Projects team on Vercel to deploy. Learn more about collaboration on Vercel and other options here. |
WalkthroughChanges introduce cursor-based pagination support to transaction listing. The API route now converts pagination parameters to integers, implements nextCursor logic, and adds structured error handling for various response scenarios. The frontend component migrates from single-page query to infinite query pattern with progressive loading. Changes
Sequence Diagram(s)sequenceDiagram
participant User
participant HistoryPage
participant useInfiniteQuery
participant API as /api/transaction/list
User->>HistoryPage: View initial page
HistoryPage->>useInfiniteQuery: Fetch with pageParam=1
useInfiniteQuery->>API: GET ?page=1&limit=20
API->>API: Convert params to integers
API->>API: Calculate nextCursor
API-->>useInfiniteQuery: {transactions: [...], nextCursor: 2}
useInfiniteQuery-->>HistoryPage: Render transactions + Load More btn
rect rgba(100, 150, 200, 0.2)
Note over User,API: User clicks Load More
User->>HistoryPage: Click Load More
HistoryPage->>useInfiniteQuery: fetchNextPage(pageParam=2)
useInfiniteQuery->>API: GET ?page=2&limit=20
API-->>useInfiniteQuery: {transactions: [...], nextCursor: 3}
useInfiniteQuery-->>HistoryPage: Append new transactions
end
HistoryPage-->>User: Show combined transactions + updated footer
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~20–30 minutes
Poem
📜 Recent review detailsConfiguration used: CodeRabbit UI Review profile: CHILL Plan: Free 📒 Files selected for processing (2)
Tip 📝 Customizable high-level summaries are now available in beta!You can now customize how CodeRabbit generates the high-level summary in your pull requests — including its content, structure, tone, and formatting.
Example instruction:
Note: This feature is currently in beta for Pro-tier users, and pricing will be announced later. Note 🎁 Summarized by CodeRabbit FreeYour organization is on the Free plan. CodeRabbit will generate a high-level summary and a walkthrough for each pull request. For a comprehensive line-by-line review, please upgrade your subscription to CodeRabbit Pro by visiting https://app.coderabbit.ai/login. Comment |
PR Compliance Guide 🔍Below is a summary of compliance checks for this PR:
Compliance status legend🟢 - Fully Compliant🟡 - Partial Compliant 🔴 - Not Compliant ⚪ - Requires Further Human Verification 🏷️ - Compliance label |
|||||||||||||||||||||||||
PR Code Suggestions ✨Explore these optional code suggestions:
|
|||||||||||||||
There was a problem hiding this comment.
Pull Request Overview
This PR implements infinite scroll/load more functionality for the transaction history page, migrating from simple pagination to a cursor-based approach using React Query's useInfiniteQuery.
Key Changes:
- Migrated from
useQuerytouseInfiniteQueryfor infinite loading support - Updated API route to return cursor-based pagination metadata (
nextCursor) - Added "Load More" button with loading state and transaction count summary
Reviewed Changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated 5 comments.
| File | Description |
|---|---|
| src/app/dashboard/history/page.tsx | Replaced useQuery with useInfiniteQuery, added data flattening logic, and implemented UI for load more functionality with loading states |
| src/app/api/transaction/list/route.ts | Added cursor-based pagination by parsing page parameters as integers and calculating nextCursor based on result count |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| staleTime: 1000 * 60 * 5, | ||
| }); | ||
|
|
||
| const apiTransactions = data?.pages.flatMap((page) => page.transactions) ?? []; |
There was a problem hiding this comment.
The data transformation assumes each page has a transactions property, but there's no safeguard if a page returns undefined or null for transactions. Consider adding a null check:
const apiTransactions = data?.pages.flatMap((page) => page.transactions || []) ?? [];This prevents potential runtime errors if the API response structure is malformed.
| const apiTransactions = data?.pages.flatMap((page) => page.transactions) ?? []; | |
| const apiTransactions = data?.pages.flatMap((page) => page.transactions || []) ?? []; |
| return NextResponse.json({ | ||
| transactions, | ||
| message: "Transactions fetched successfully", | ||
| nextCursor: transactions.length === limit ? page + 1 : null, |
There was a problem hiding this comment.
The logic for determining nextCursor assumes that if transactions.length === limit, there are more pages available. However, this creates a false positive when the last page happens to have exactly limit items. The external API should ideally provide explicit pagination metadata (like hasMore or totalPages).
If the external API doesn't provide this information, consider tracking whether the next page returns empty results to properly set hasNextPage to false. The current implementation may show a "Load More" button that returns no results.
|
|
||
| const transactions = await response.json(); | ||
| const data = await response.json(); | ||
| const transactions = data.transactions || []; |
There was a problem hiding this comment.
The code extracts transactions from data.transactions, but if the external API returns transactions as a direct array (not wrapped in an object), this will result in an empty array. The previous implementation handled multiple response structures, but this change removes that flexibility.
Consider adding a check to handle both response formats:
const data = await response.json();
const transactions = Array.isArray(data) ? data : (data.transactions || []);This ensures backward compatibility if the external API response format varies.
| const transactions = data.transactions || []; | |
| const transactions = Array.isArray(data) ? data : (data.transactions || []); |
| const page = parseInt(url.searchParams.get("page") || "1"); | ||
| const limit = parseInt(url.searchParams.get("limit") || "10"); |
There was a problem hiding this comment.
The pagination parameters are parsed with parseInt but lack validation for invalid values. If parseInt fails (e.g., for non-numeric input), it returns NaN, which would be passed to the external API.
Consider adding validation:
const page = Math.max(1, parseInt(url.searchParams.get("page") || "1") || 1);
const limit = Math.max(1, Math.min(100, parseInt(url.searchParams.get("limit") || "10") || 10));This ensures valid pagination parameters and prevents potential API errors or abuse (e.g., requesting extremely large limits).
| const page = parseInt(url.searchParams.get("page") || "1"); | |
| const limit = parseInt(url.searchParams.get("limit") || "10"); | |
| const page = Math.max(1, parseInt(url.searchParams.get("page") || "1") || 1); | |
| const limit = Math.max(1, Math.min(100, parseInt(url.searchParams.get("limit") || "10") || 10)); |
User description
As per title..
PR Type
Enhancement
Description
Implement infinite scroll with load more button for transaction history
Add cursor-based pagination support to transaction API endpoint
Replace useQuery with useInfiniteQuery for paginated data fetching
Display transaction count and loading state in UI
Diagram Walkthrough
File Walkthrough
route.ts
Add cursor-based pagination to transaction APIsrc/app/api/transaction/list/route.ts
handling
nextCursorfield to API response for pagination trackingarray
current limit
page.tsx
Implement infinite scroll with load more buttonsrc/app/dashboard/history/page.tsx
useQuerywithuseInfiniteQueryfor infinite scroll capabilityfetchNextPage,hasNextPage, andisFetchingNextPagestate variablesarray
loaded
Summary by CodeRabbit
New Features
Bug Fixes
✏️ Tip: You can customize this high-level summary in your review settings.