Skip to content

Commit 663c832

Browse files
committed
feat(winnings): add pagination
Signed-off-by: Rakib Ansary <rakibansary@topcoder.com>
1 parent 3c180fd commit 663c832

File tree

5 files changed

+131
-10
lines changed

5 files changed

+131
-10
lines changed

src/apps/wallet/src/home/tabs/winnings/WinningsTab.tsx

Lines changed: 39 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import { getPayments, processPayments } from '../../../lib/services/wallet'
1111
import { Winning, WinningDetail } from '../../../lib/models/WinningDetail'
1212
import { FilterBar } from '../../../lib'
1313
import { ConfirmFlowData } from '../../../lib/models/ConfirmFlowData'
14+
import { PaginationInfo } from '../../../lib/models/PaginationInfo'
1415
import PaymentsTable from '../../../lib/components/payments-table/PaymentTable'
1516

1617
import styles from './Winnings.module.scss'
@@ -74,6 +75,12 @@ const ListView: FC<ListViewProps> = (props: ListViewProps) => {
7475
const [winnings, setWinnings] = React.useState<ReadonlyArray<Winning>>([])
7576
const [isLoading, setIsLoading] = React.useState<boolean>(false)
7677
const [filters, setFilters] = React.useState<Record<string, string[]>>({})
78+
const [pagination, setPagination] = React.useState<PaginationInfo>({
79+
currentPage: 1,
80+
pageSize: 10,
81+
totalItems: 0,
82+
totalPages: 0,
83+
})
7784

7885
const convertToWinnings = useCallback(
7986
(payments: WinningDetail[]) => payments.map(payment => ({
@@ -96,15 +103,16 @@ const ListView: FC<ListViewProps> = (props: ListViewProps) => {
96103
const fetchWinnings = useCallback(async () => {
97104
setIsLoading(true)
98105
try {
99-
const payments = await getPayments(props.profile.userId.toString(), filters)
100-
const winningsData = convertToWinnings(payments)
106+
const payments = await getPayments(props.profile.userId.toString(), pagination.pageSize, (pagination.currentPage - 1) * pagination.pageSize, filters)
107+
const winningsData = convertToWinnings(payments.winnings)
101108
setWinnings(winningsData)
109+
setPagination(payments.pagination)
102110
} catch (apiError) {
103111
console.error('Failed to fetch winnings:', apiError)
104112
} finally {
105113
setIsLoading(false)
106114
}
107-
}, [props.profile.userId, convertToWinnings, filters])
115+
}, [props.profile.userId, convertToWinnings, filters, pagination.currentPage, pagination.pageSize])
108116

109117
const renderConfirmModalContent = React.useMemo(() => {
110118
if (confirmFlow?.content === undefined) {
@@ -243,7 +251,35 @@ const ListView: FC<ListViewProps> = (props: ListViewProps) => {
243251
{isLoading && <LoadingCircles className={styles.centered} />}
244252
{!isLoading && winnings.length > 0 && (
245253
<PaymentsTable
254+
currentPage={pagination.currentPage}
255+
numPages={pagination.totalPages}
246256
payments={winnings}
257+
onNextPageClick={async function onNextPageClicked() {
258+
if (pagination.currentPage === pagination.totalPages) {
259+
return
260+
}
261+
262+
setPagination({
263+
...pagination,
264+
currentPage: pagination.currentPage + 1,
265+
})
266+
}}
267+
onPreviousPageClick={async function onPrevPageClicked() {
268+
if (pagination.currentPage === 1) {
269+
return
270+
}
271+
272+
setPagination({
273+
...pagination,
274+
currentPage: pagination.currentPage - 1,
275+
})
276+
}}
277+
onPageClick={async function onPageClicked(pageNumber: number) {
278+
setPagination({
279+
...pagination,
280+
currentPage: pageNumber,
281+
})
282+
}}
247283
onPayMeClick={async function onPayMeClicked(
248284
paymentIds: PaymentId,
249285
totalAmount: string,

src/apps/wallet/src/lib/components/payments-table/PaymentTable.module.scss

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,22 @@ table {
5959
background-color: #e7f4ff;
6060
}
6161

62+
.pageButtons {
63+
display: flex;
64+
justify-content: flex-end;
65+
align-items: center;
66+
margin-top: 16px;
67+
gap: $sp-4;
68+
69+
.pageNumbers {
70+
display: flex;
71+
justify-content: center;
72+
align-items: center;
73+
gap: $sp-1;
74+
}
75+
76+
}
77+
6278
.paymentFooter {
6379
display: flex;
6480
justify-content: space-between;

src/apps/wallet/src/lib/components/payments-table/PaymentTable.tsx

Lines changed: 58 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
/* eslint-disable @typescript-eslint/explicit-function-return-type */
33
import React, { useState } from 'react'
44

5-
import { Button } from '~/libs/ui'
5+
import { Button, IconOutline, PageDivider } from '~/libs/ui'
66

77
import { Winning } from '../../models/WinningDetail'
88

@@ -11,6 +11,11 @@ import styles from './PaymentTable.module.scss'
1111
interface PaymentTableProps {
1212
payments: ReadonlyArray<Winning>
1313
onPayMeClick: (paymentIds: { [paymentId: string]: boolean }, totalAmount: string) => void
14+
currentPage: number
15+
numPages: number
16+
onNextPageClick: () => void
17+
onPreviousPageClick: () => void
18+
onPageClick: (pageNumber: number) => void
1419
}
1520
const PaymentsTable: React.FC<PaymentTableProps> = (props: PaymentTableProps) => {
1621
const [selectedPayments, setSelectedPayments] = useState<{ [paymentId: string]: boolean }>({})
@@ -52,8 +57,6 @@ const PaymentsTable: React.FC<PaymentTableProps> = (props: PaymentTableProps) =>
5257

5358
const total = calculateTotal()
5459

55-
console.log('All payments', props.payments)
56-
5760
return (
5861
<>
5962
<div className={styles.tableContainer}>
@@ -105,6 +108,58 @@ const PaymentsTable: React.FC<PaymentTableProps> = (props: PaymentTableProps) =>
105108
</tbody>
106109
</table>
107110
</div>
111+
112+
{props.numPages > 1 && (
113+
<>
114+
<PageDivider />
115+
<div className={styles.pageButtons}>
116+
<Button
117+
onClick={props.onPreviousPageClick}
118+
secondary
119+
size='md'
120+
icon={IconOutline.ChevronLeftIcon}
121+
iconToLeft
122+
label='PREVIOUS'
123+
disabled={props.currentPage === 1}
124+
/>
125+
{props.currentPage > 3 && <span>...</span>}
126+
<div className={styles.pageNumbers}>
127+
{Array.from(Array(props.numPages)
128+
.keys())
129+
.filter(pageNumber => {
130+
const currentPage = props.currentPage - 1
131+
const maxPagesToShow = 5
132+
const halfMaxPagesToShow = Math.floor(maxPagesToShow / 2)
133+
const startPage = Math.max(currentPage - halfMaxPagesToShow, 0)
134+
const endPage = Math.min(startPage + maxPagesToShow - 1, props.numPages - 1)
135+
136+
return pageNumber >= startPage && pageNumber <= endPage
137+
})
138+
.map(pageNumber => (
139+
<Button
140+
key={`page-${pageNumber}`}
141+
secondary
142+
variant='round'
143+
label={`${pageNumber + 1}`}
144+
onClick={() => props.onPageClick(pageNumber + 1)}
145+
disabled={pageNumber === props.currentPage - 1}
146+
/>
147+
))}
148+
</div>
149+
{props.currentPage < props.numPages - 2 && <span>...</span>}
150+
<Button
151+
onClick={props.onNextPageClick}
152+
secondary
153+
size='md'
154+
icon={IconOutline.ChevronRightIcon}
155+
iconToRight
156+
label='NEXT'
157+
disabled={props.currentPage === props.numPages}
158+
/>
159+
</div>
160+
</>
161+
)}
162+
108163
<div className={styles.paymentFooter}>
109164
<div className={styles.total}>
110165
Total: $
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
export interface PaginationInfo {
2+
totalItems: number;
3+
totalPages: number;
4+
pageSize: number;
5+
currentPage: number;
6+
}

src/apps/wallet/src/lib/services/wallet.ts

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import { WinningDetail } from '../models/WinningDetail'
99
import { TaxForm } from '../models/TaxForm'
1010
import { OtpVerificationResponse } from '../models/OtpVerificationResponse'
1111
import { TransactionResponse } from '../models/TransactionId'
12+
import { PaginationInfo } from '../models/PaginationInfo'
1213
import ApiResponse from '../models/ApiResponse'
1314

1415
const baseUrl = `${EnvironmentConfig.API.V5}/payments`
@@ -42,7 +43,11 @@ export async function getUserTaxFormDetails(): Promise<TaxForm[]> {
4243
return response.data
4344
}
4445

45-
export async function getPayments(userId: string, filters: Record<string, string[]>): Promise<WinningDetail[]> {
46+
// eslint-disable-next-line max-len
47+
export async function getPayments(userId: string, limit: number, offset: number, filters: Record<string, string[]>): Promise<{
48+
winnings: WinningDetail[],
49+
pagination: PaginationInfo
50+
}> {
4651
const filteredFilters: Record<string, string> = {}
4752

4853
for (const key in filters) {
@@ -52,14 +57,17 @@ export async function getPayments(userId: string, filters: Record<string, string
5257
}
5358

5459
const body = JSON.stringify({
60+
limit,
61+
offset,
5562
winnerId: userId,
5663
...filteredFilters,
5764
})
5865

59-
console.log('Ignoring filters for now', filteredFilters)
60-
6166
const url = `${baseUrl}/user/winnings`
62-
const response = await xhrPostAsync<string, ApiResponse<WinningDetail[]>>(url, body)
67+
const response = await xhrPostAsync<string, ApiResponse<{
68+
winnings: WinningDetail[],
69+
pagination: PaginationInfo
70+
}>>(url, body)
6371

6472
if (response.status === 'error') {
6573
throw new Error('Error fetching payments')

0 commit comments

Comments
 (0)