-
Notifications
You must be signed in to change notification settings - Fork 0
feat: implement load more functionality for transaction history #61
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||
|---|---|---|---|---|---|---|
|
|
@@ -22,13 +22,13 @@ export async function GET(request: Request) { | |||||
|
|
||||||
| // Get pagination parameters from URL | ||||||
| const url = new URL(request.url); | ||||||
| const page = url.searchParams.get("page") || "1"; | ||||||
| const limit = url.searchParams.get("limit") || "10"; | ||||||
| const page = parseInt(url.searchParams.get("page") || "1"); | ||||||
| const limit = parseInt(url.searchParams.get("limit") || "10"); | ||||||
|
|
||||||
| // Build API URL with pagination parameters | ||||||
| const apiUrl = new URL(`${process.env.API_BASE_URL}/transaction/list`); | ||||||
| apiUrl.searchParams.set("page", page); | ||||||
| apiUrl.searchParams.set("limit", limit); | ||||||
| apiUrl.searchParams.set("page", String(page)); | ||||||
| apiUrl.searchParams.set("limit", String(limit)); | ||||||
|
|
||||||
| // Make request to external API to get current user transactions | ||||||
| const response = await fetch(apiUrl.toString(), { | ||||||
|
|
@@ -46,6 +46,7 @@ export async function GET(request: Request) { | |||||
| return NextResponse.json( | ||||||
| { | ||||||
| transactions: [], | ||||||
| nextCursor: null, | ||||||
| message: "No transactions found", | ||||||
| }, | ||||||
| { status: 200 } | ||||||
|
|
@@ -62,11 +63,12 @@ export async function GET(request: Request) { | |||||
| ); | ||||||
| } | ||||||
|
|
||||||
| const transactions = await response.json(); | ||||||
| const data = await response.json(); | ||||||
| const transactions = data.transactions || []; | ||||||
|
||||||
| const transactions = data.transactions || []; | |
| const transactions = Array.isArray(data) ? data : (data.transactions || []); |
Copilot
AI
Nov 21, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
| Original file line number | Diff line number | Diff line change | ||||
|---|---|---|---|---|---|---|
|
|
@@ -6,7 +6,7 @@ import type { ApiTransaction } from "@/lib/types"; | |||||
| import { cn } from "@/lib/cn"; | ||||||
| import ListItemSkeleton from "@/components/skeletons/ListItemSkeleton"; | ||||||
| import { formatDate, formatSatoshis } from "@/lib/formatters"; | ||||||
| import { useQuery } from "@tanstack/react-query"; | ||||||
| import { useInfiniteQuery } from "@tanstack/react-query"; | ||||||
| import { queryKeys } from "@/lib/query-keys"; | ||||||
|
|
||||||
| export default function HistoryPage() { | ||||||
|
|
@@ -16,14 +16,17 @@ export default function HistoryPage() { | |||||
| const [selectedTransaction, setSelectedTransaction] = useState<ApiTransaction | null>(null); | ||||||
|
|
||||||
| const { | ||||||
| data: apiTransactions = [], | ||||||
| data, | ||||||
| error, | ||||||
| isLoading, | ||||||
| fetchNextPage, | ||||||
| hasNextPage, | ||||||
| isFetchingNextPage, | ||||||
| refetch, | ||||||
| } = useQuery<ApiTransaction[]>({ | ||||||
| } = useInfiniteQuery({ | ||||||
| queryKey: queryKeys.transactions, | ||||||
| queryFn: async () => { | ||||||
| const response = await fetch(`/api/transaction/list`, { | ||||||
| queryFn: async ({ pageParam = 1 }) => { | ||||||
| const response = await fetch(`/api/transaction/list?page=${pageParam}`, { | ||||||
| headers: { | ||||||
| "Content-Type": "application/json", | ||||||
| Authorization: `Bearer ${authToken}`, | ||||||
|
|
@@ -35,21 +38,16 @@ export default function HistoryPage() { | |||||
| result.message || `Failed to fetch transactions: ${response.statusText}` | ||||||
| ); | ||||||
| } | ||||||
| // Handle different response structures | ||||||
| if (Array.isArray(result)) { | ||||||
| return result; | ||||||
| } | ||||||
| if (result.transactions) { | ||||||
| return Array.isArray(result.transactions) | ||||||
| ? result.transactions | ||||||
| : result.transactions?.transactions || []; | ||||||
| } | ||||||
| return []; | ||||||
| return result; | ||||||
| }, | ||||||
| initialPageParam: 1, | ||||||
| getNextPageParam: (lastPage) => lastPage.nextCursor, | ||||||
| enabled: !!authToken, | ||||||
| staleTime: 1000 * 60 * 5, | ||||||
| }); | ||||||
|
|
||||||
| const apiTransactions = data?.pages.flatMap((page) => page.transactions) ?? []; | ||||||
|
||||||
| const apiTransactions = data?.pages.flatMap((page) => page.transactions) ?? []; | |
| const apiTransactions = data?.pages.flatMap((page) => page.transactions || []) ?? []; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The pagination parameters are parsed with
parseIntbut lack validation for invalid values. IfparseIntfails (e.g., for non-numeric input), it returnsNaN, which would be passed to the external API.Consider adding validation:
This ensures valid pagination parameters and prevents potential API errors or abuse (e.g., requesting extremely large limits).