@@ -3,16 +3,19 @@ import { toast } from 'react-toastify'
33import { AxiosError } from 'axios'
44import React , { FC , useCallback , useEffect } from 'react'
55
6- import { Collapsible , LoadingCircles } from '~/libs/ui'
6+ import { Collapsible , ConfirmModal , LoadingCircles } from '~/libs/ui'
77import { UserProfile } from '~/libs/core'
88
99import { getPayments , processPayments } from '../../../lib/services/wallet'
1010import { Winning , WinningDetail } from '../../../lib/models/WinningDetail'
1111import { FilterBar } from '../../../lib'
12+ import { ConfirmFlowData } from '../../../lib/models/ConfirmFlowData'
1213import PaymentsTable from '../../../lib/components/payments-table/PaymentTable'
1314
1415import styles from './Winnings.module.scss'
1516
17+ type PaymentId = { [ paymentId : string ] : boolean }
18+
1619interface ListViewProps {
1720 profile : UserProfile
1821}
@@ -66,6 +69,7 @@ const formatCurrency = (amountStr: string, currency: string): string => {
6669}
6770
6871const ListView : FC < ListViewProps > = ( props : ListViewProps ) => {
72+ const [ confirmFlow , setConfirmFlow ] = React . useState < ConfirmFlowData | undefined > ( undefined )
6973 const [ winnings , setWinnings ] = React . useState < ReadonlyArray < Winning > > ( [ ] )
7074 const [ isLoading , setIsLoading ] = React . useState < boolean > ( false )
7175
@@ -100,128 +104,170 @@ const ListView: FC<ListViewProps> = (props: ListViewProps) => {
100104 }
101105 } , [ props . profile . userId , convertToWinnings ] )
102106
107+ const renderConfirmModalContent = React . useMemo ( ( ) => {
108+ if ( confirmFlow ?. content === undefined ) {
109+ return undefined
110+ }
111+
112+ if ( typeof confirmFlow ?. content === 'function' ) {
113+ return confirmFlow ?. content ( )
114+ }
115+
116+ return confirmFlow ?. content
117+ } , [ confirmFlow ] )
118+
103119 useEffect ( ( ) => {
104120 fetchWinnings ( )
105121 } , [ fetchWinnings ] )
106122
107- return (
108- < div className = { styles . container } >
109- < div className = { styles . header } >
110- < h3 > Winnings</ h3 >
111- </ div >
112- < div className = { styles . content } >
113- < Collapsible header = { < h3 > Payments</ h3 > } >
114- < FilterBar
115- filters = { [
116- {
117- key : 'date' ,
118- label : 'Date' ,
119- options : [
120- {
121- label : 'Last 7 days' ,
122- value : 'last7days' ,
123- } ,
124- {
125- label : 'Last 30 days' ,
126- value : 'last30days' ,
127- } ,
128- {
129- label : 'All' ,
130- value : 'all' ,
131- } ,
132- ] ,
133- type : 'dropdown' ,
134- } ,
135- {
136- key : 'type' ,
137- label : 'Type' ,
138- options : [
139- {
140- label : 'Contest Payment' ,
141- value : 'CONTEST_PAYMENT' ,
142- } ,
143- {
144- label : 'Review Board Payment' ,
145- value : 'REVIEW_BOARD_PAYMENT' ,
146- } ,
147- ] ,
148- type : 'dropdown' ,
149- } ,
150- {
151- key : 'status' ,
152- label : 'Status' ,
153- options : [
154- {
155- label : 'Available' ,
156- value : 'OWED' ,
157- } ,
158- {
159- label : 'On Hold' ,
160- value : 'ON_HOLD' ,
161- } ,
162- {
163- label : 'Paid' ,
164- value : 'PAID' ,
165- } ,
166- {
167- label : 'Cancelled' ,
168- value : 'CANCELLED' ,
169- } ,
170- ] ,
171- type : 'dropdown' ,
172- } ,
173- ] }
174- onFilterChange = { ( key : string , value : string [ ] ) => {
175- console . log ( key , value )
176- } }
177- onResetFilters = { ( ) => {
178- console . log ( 'reset' )
179- } }
180- />
181- { /* <PageDivider /> */ }
182- { isLoading && < LoadingCircles /> }
183- { ! isLoading && (
184- < PaymentsTable
185- payments = { winnings }
186- onPayMeClick = { async function onPayMeClicked ( paymentIds : { [ paymentId : string ] : boolean } ) {
187- const winningIds : string [ ] = [ ]
188- Object . keys ( paymentIds )
189- . forEach ( ( key : string ) => {
190- if ( paymentIds [ key ] ) {
191- winningIds . push ( key )
192- }
193- } )
123+ const processPayouts = async ( paymentIds : PaymentId ) : Promise < void > => {
124+ const winningIds : string [ ] = [ ]
125+ Object . keys ( paymentIds )
126+ . forEach ( ( key : string ) => {
127+ if ( paymentIds [ key ] ) {
128+ winningIds . push ( key )
129+ }
130+ } )
194131
195- toast . info ( 'Processing payments...' , {
196- position : toast . POSITION . BOTTOM_RIGHT ,
197- } )
198- try {
199- await processPayments ( winningIds )
200- toast . success ( 'Payments processed successfully!' , {
201- position : toast . POSITION . BOTTOM_RIGHT ,
202- } )
203- } catch ( error ) {
204- let message = 'Failed to process payments. Please try again later.'
132+ toast . info ( 'Processing payments...' , {
133+ position : toast . POSITION . BOTTOM_RIGHT ,
134+ } )
135+ try {
136+ await processPayments ( winningIds )
137+ toast . success ( 'Payments processed successfully!' , {
138+ position : toast . POSITION . BOTTOM_RIGHT ,
139+ } )
140+ } catch ( error ) {
141+ let message = 'Failed to process payments. Please try again later.'
205142
206- if ( error instanceof AxiosError ) {
207- message = error . response ?. data ?. error ?. message
143+ if ( error instanceof AxiosError ) {
144+ message = error . response ?. data ?. error ?. message
208145
209- message = message . charAt ( 0 )
210- . toUpperCase ( ) + message . slice ( 1 )
211- }
146+ message = message . charAt ( 0 )
147+ . toUpperCase ( ) + message . slice ( 1 )
148+ }
212149
213- toast . error ( message , {
214- position : toast . POSITION . BOTTOM_RIGHT ,
215- } )
216- }
150+ toast . error ( message , {
151+ position : toast . POSITION . BOTTOM_RIGHT ,
152+ } )
153+ }
217154
218- fetchWinnings ( )
155+ fetchWinnings ( )
156+ }
157+
158+ return (
159+ < >
160+ < div className = { styles . container } >
161+ < div className = { styles . header } >
162+ < h3 > Winnings</ h3 >
163+ </ div >
164+ < div className = { styles . content } >
165+ < Collapsible header = { < h3 > Payments</ h3 > } >
166+ < FilterBar
167+ filters = { [
168+ {
169+ key : 'date' ,
170+ label : 'Date' ,
171+ options : [
172+ {
173+ label : 'Last 7 days' ,
174+ value : 'last7days' ,
175+ } ,
176+ {
177+ label : 'Last 30 days' ,
178+ value : 'last30days' ,
179+ } ,
180+ {
181+ label : 'All' ,
182+ value : 'all' ,
183+ } ,
184+ ] ,
185+ type : 'dropdown' ,
186+ } ,
187+ {
188+ key : 'type' ,
189+ label : 'Type' ,
190+ options : [
191+ {
192+ label : 'Contest Payment' ,
193+ value : 'CONTEST_PAYMENT' ,
194+ } ,
195+ {
196+ label : 'Review Board Payment' ,
197+ value : 'REVIEW_BOARD_PAYMENT' ,
198+ } ,
199+ ] ,
200+ type : 'dropdown' ,
201+ } ,
202+ {
203+ key : 'status' ,
204+ label : 'Status' ,
205+ options : [
206+ {
207+ label : 'Available' ,
208+ value : 'OWED' ,
209+ } ,
210+ {
211+ label : 'On Hold' ,
212+ value : 'ON_HOLD' ,
213+ } ,
214+ {
215+ label : 'Paid' ,
216+ value : 'PAID' ,
217+ } ,
218+ {
219+ label : 'Cancelled' ,
220+ value : 'CANCELLED' ,
221+ } ,
222+ ] ,
223+ type : 'dropdown' ,
224+ } ,
225+ ] }
226+ onFilterChange = { ( key : string , value : string [ ] ) => {
227+ console . log ( key , value )
228+ } }
229+ onResetFilters = { ( ) => {
230+ console . log ( 'reset' )
219231 } }
220232 />
221- ) }
222- </ Collapsible >
233+ { /* <PageDivider /> */ }
234+ { isLoading && < LoadingCircles /> }
235+ { ! isLoading && (
236+ < PaymentsTable
237+ payments = { winnings }
238+ onPayMeClick = { async function onPayMeClicked (
239+ paymentIds : PaymentId ,
240+ totalAmount : string ,
241+ ) {
242+ setConfirmFlow ( {
243+ action : 'Yes' ,
244+ callback : ( ) => processPayouts ( paymentIds ) ,
245+ content : `You are about to process payments for a total of USD ${ totalAmount } ` ,
246+ title : 'Are you sure?' ,
247+ } )
248+ } }
249+ />
250+ ) }
251+ </ Collapsible >
252+ </ div >
223253 </ div >
224- </ div >
254+ { confirmFlow && (
255+ < ConfirmModal
256+ title = { confirmFlow . title }
257+ action = { confirmFlow . action }
258+ onClose = { function onClose ( ) {
259+ setConfirmFlow ( undefined )
260+ } }
261+ onConfirm = { function onConfirm ( ) {
262+ confirmFlow . callback ?.( )
263+ setConfirmFlow ( undefined )
264+ } }
265+ open = { confirmFlow !== undefined }
266+ >
267+ < div > { renderConfirmModalContent } </ div >
268+ </ ConfirmModal >
269+ ) }
270+ </ >
225271 )
226272}
227273
0 commit comments