Skip to content

Commit a2bccbc

Browse files
committed
fix: payments export
Signed-off-by: Rakib Ansary <rakibansary@topcoder.com>
1 parent 6ef9ebb commit a2bccbc

File tree

3 files changed

+75
-3
lines changed

3 files changed

+75
-3
lines changed

src/apps/wallet-admin/src/home/tabs/payments/PaymentsTab.tsx

Lines changed: 31 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,9 @@ import React, { FC, useCallback, useEffect } from 'react'
66

77
import { Collapsible, ConfirmModal, LoadingCircles } from '~/libs/ui'
88
import { UserProfile } from '~/libs/core'
9+
import { downloadBlob } from '~/libs/shared'
910

10-
import { editPayment, getMemberHandle, getPaymentMethods, getPayments, getTaxForms } from '../../../lib/services/wallet'
11+
import { editPayment, exportSearchResults, getMemberHandle, getPaymentMethods, getPayments, getTaxForms } from '../../../lib/services/wallet'
1112
import { Winning, WinningDetail } from '../../../lib/models/WinningDetail'
1213
import { FilterBar, formatIOSDateString, PaymentView } from '../../../lib'
1314
import { ConfirmFlowData } from '../../../lib/models/ConfirmFlowData'
@@ -311,6 +312,16 @@ const ListView: FC<ListViewProps> = (props: ListViewProps) => {
311312
<div className={styles.content}>
312313
<Collapsible header={<h3>Payment Listing</h3>}>
313314
<FilterBar
315+
showExportButton
316+
onExport={async () => {
317+
toast.success('Downloading payments report. This may take a few moments.', { position: toast.POSITION.BOTTOM_RIGHT })
318+
downloadBlob(
319+
await exportSearchResults(filters),
320+
`payments-${new Date()
321+
.getTime()}.csv`,
322+
)
323+
toast.success('Download complete', { position: toast.POSITION.BOTTOM_RIGHT })
324+
}}
314325
filters={[
315326
{
316327
key: 'winnerIds',
@@ -344,6 +355,25 @@ const ListView: FC<ListViewProps> = (props: ListViewProps) => {
344355
],
345356
type: 'dropdown',
346357
},
358+
{
359+
key: 'date',
360+
label: 'Date',
361+
options: [
362+
{
363+
label: 'Last 7 days',
364+
value: 'last7days',
365+
},
366+
{
367+
label: 'Last 30 days',
368+
value: 'last30days',
369+
},
370+
{
371+
label: 'All',
372+
value: 'all',
373+
},
374+
],
375+
type: 'dropdown',
376+
},
347377
{
348378
key: 'pageSize',
349379
label: 'Payments per page',

src/apps/wallet-admin/src/lib/components/filter-bar/FilterBar.tsx

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
/* eslint-disable react/jsx-no-bind */
22
import React, { ChangeEvent } from 'react'
33

4-
import { Button, InputSelect, InputText } from '~/libs/ui'
4+
import { Button, IconOutline, InputSelect, InputText } from '~/libs/ui'
55
import { InputHandleAutocomplete, MembersAutocompeteResult } from '~/apps/gamification-admin/src/game-lib'
66

77
import styles from './FilterBar.module.scss'
@@ -20,8 +20,10 @@ type Filter = {
2020

2121
interface FilterBarProps {
2222
filters: Filter[];
23+
showExportButton?: boolean;
2324
onFilterChange: (key: string, value: string[]) => void;
2425
onResetFilters?: () => void;
26+
onExport?: () => void;
2527
}
2628

2729
const FilterBar: React.FC<FilterBarProps> = (props: FilterBarProps) => {
@@ -104,6 +106,14 @@ const FilterBar: React.FC<FilterBarProps> = (props: FilterBarProps) => {
104106
</div>
105107
))}
106108
</div>
109+
{props.showExportButton && (
110+
<Button
111+
className={styles.exportButton}
112+
icon={IconOutline.DownloadIcon}
113+
onClick={props.onExport}
114+
size='lg'
115+
/>
116+
)}
107117
<Button
108118
primary
109119
className={styles.resetButton}

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

Lines changed: 33 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { EnvironmentConfig } from '~/config'
22
import { xhrDeleteAsync, xhrGetAsync, xhrPatchAsync, xhrPostAsync } from '~/libs/core'
3-
import { getAsyncWithBlobHandling } from '~/libs/core/lib/xhr/xhr-functions/xhr.functions'
3+
import { getAsyncWithBlobHandling, postAsyncWithBlobHandling } from '~/libs/core/lib/xhr/xhr-functions/xhr.functions'
44

55
import { WalletDetails } from '../models/WalletDetails'
66
import { PaymentProvider } from '../models/PaymentProvider'
@@ -127,6 +127,38 @@ export async function getPaymentMethods(limit: number, offset: number, userIds:
127127

128128
}
129129

130+
export async function exportSearchResults(filters: Record<string, string[]>): Promise<Blob> {
131+
const url = `${baseUrl}/admin/winnings/export`
132+
133+
const filteredFilters: Record<string, string> = {}
134+
135+
for (const key in filters) {
136+
if (filters[key].length > 0 && key !== 'pageSize') {
137+
filteredFilters[key] = filters[key][0]
138+
}
139+
}
140+
141+
const payload: {
142+
winnerIds?: string[], [key: string]: string | number | string[] | undefined
143+
} = {
144+
...filteredFilters,
145+
}
146+
147+
if (filters.winnerIds && filters.winnerIds.length > 0) {
148+
payload.winnerIds = filters.winnerIds
149+
}
150+
151+
const body = JSON.stringify(payload)
152+
153+
try {
154+
return await postAsyncWithBlobHandling<string, Blob>(url, body, {
155+
responseType: 'blob',
156+
})
157+
} catch (err) {
158+
throw new Error('Failed to export search results')
159+
}
160+
}
161+
130162
export async function downloadTaxForm(userId: string, taxFormId: string): Promise<Blob> {
131163
const url = `${baseUrl}/admin/tax-forms/${userId}/${taxFormId}/download`
132164
try {

0 commit comments

Comments
 (0)