@@ -17,6 +17,8 @@ import TopBar from 'components/TopBar'
1717import { fetchUserWithSupertokens , UserWithSupertokens } from 'services/userService'
1818import { UserProfile } from '@prisma/client'
1919import Button from 'components/Button'
20+ import style from './payments.module.css'
21+ import SettingsIcon from '../../assets/settings-slider-icon.png'
2022
2123export const getServerSideProps : GetServerSideProps = async ( context ) => {
2224 // this runs on the backend, so we must call init on supertokens-node SDK
@@ -57,6 +59,15 @@ export default function Payments ({ user, userId }: PaybuttonsProps): React.Reac
5759 const [ selectedCurrencyCSV , setSelectedCurrencyCSV ] = useState < string > ( '' )
5860 const [ paybuttonNetworks , setPaybuttonNetworks ] = useState < Set < number > > ( new Set ( ) )
5961 const [ loading , setLoading ] = useState ( false )
62+ const [ buttons , setButtons ] = useState < any [ ] > ( [ ] )
63+ const [ selectedButtonIds , setSelectedButtonIds ] = useState < any [ ] > ( [ ] )
64+ const [ showFilters , setShowFilters ] = useState < boolean > ( false )
65+ const [ tableLoading , setTableLoading ] = useState < boolean > ( true )
66+ const [ refreshCount , setRefreshCount ] = useState ( 0 )
67+
68+ useEffect ( ( ) => {
69+ setRefreshCount ( prev => prev + 1 )
70+ } , [ selectedButtonIds ] )
6071
6172 const fetchPaybuttons = async ( ) : Promise < any > => {
6273 const res = await fetch ( `/api/paybuttons?userId=${ user ?. userProfile . id } ` , {
@@ -69,6 +80,7 @@ export default function Payments ({ user, userId }: PaybuttonsProps): React.Reac
6980 const getDataAndSetUpCurrencyCSV = async ( ) : Promise < void > => {
7081 const paybuttons = await fetchPaybuttons ( )
7182 const networkIds : Set < number > = new Set ( )
83+ setButtons ( paybuttons )
7284
7385 paybuttons . forEach ( ( p : { addresses : any [ ] } ) => {
7486 return p . addresses . forEach ( ( c : { address : { networkId : number } } ) => networkIds . add ( c . address . networkId ) )
@@ -81,20 +93,43 @@ export default function Payments ({ user, userId }: PaybuttonsProps): React.Reac
8193 void getDataAndSetUpCurrencyCSV ( )
8294 } , [ ] )
8395
84- function fetchData ( ) : Function {
85- return async ( page : number , pageSize : number , orderBy : string , orderDesc : boolean ) => {
86- const paymentsResponse = await fetch ( `/api/payments?page=${ page } &pageSize=${ pageSize } &orderBy=${ orderBy } &orderDesc=${ String ( orderDesc ) } ` )
87- const paymentsCountResponse = await fetch ( '/api/payments/count' , {
88- headers : {
89- Timezone : timezone
90- }
91- } )
96+ const loadData = async (
97+ page : number ,
98+ pageSize : number ,
99+ orderBy : string ,
100+ orderDesc : boolean
101+ ) : Promise < { data : [ ] , totalCount : number } > => {
102+ setTableLoading ( true )
103+ try {
104+ // Build the URL including the filter if any buttons are selected
105+ let url = `/api/payments?page=${ page } &pageSize=${ pageSize } &orderBy=${ orderBy } &orderDesc=${ String ( orderDesc ) } `
106+ if ( selectedButtonIds . length > 0 ) {
107+ url += `&buttonIds=${ selectedButtonIds . join ( ',' ) } `
108+ }
109+
110+ const paymentsResponse = await fetch ( url )
111+ const paymentsCountResponse = await fetch (
112+ `/api/payments/count${ selectedButtonIds . length > 0 ? `?buttonIds=${ selectedButtonIds . join ( ',' ) } ` : '' } ` ,
113+ { headers : { Timezone : timezone } }
114+ )
115+
116+ if ( ! paymentsResponse . ok || ! paymentsCountResponse . ok ) {
117+ console . log ( 'paymentsResponse status' , paymentsResponse . status )
118+ console . log ( 'paymentsResponse status text' , paymentsResponse . statusText )
119+ console . log ( 'paymentsResponse body' , paymentsResponse . body )
120+ console . log ( 'paymentsResponse json' , await paymentsResponse . json ( ) )
121+ throw new Error ( 'Failed to fetch payments or count' )
122+ }
123+
92124 const totalCount = await paymentsCountResponse . json ( )
93125 const payments = await paymentsResponse . json ( )
94- return {
95- data : payments ,
96- totalCount
97- }
126+
127+ return { data : payments , totalCount }
128+ } catch ( error ) {
129+ console . error ( 'Error fetching payments:' , error )
130+ throw error
131+ } finally {
132+ setLoading ( false )
98133 }
99134 }
100135
@@ -171,6 +206,9 @@ export default function Payments ({ user, userId }: PaybuttonsProps): React.Reac
171206 setLoading ( true )
172207 const preferredCurrencyId = userProfile ?. preferredCurrencyId ?? ''
173208 let url = `/api/payments/download/?currency=${ preferredCurrencyId } `
209+ if ( selectedButtonIds . length > 0 ) {
210+ url += `&buttonIds=${ selectedButtonIds . join ( ',' ) } `
211+ }
174212 const isCurrencyEmptyOrUndefined = ( value : string ) : boolean => ( value === '' || value === undefined )
175213
176214 if ( ! isCurrencyEmptyOrUndefined ( currency ) ) {
@@ -187,7 +225,18 @@ export default function Payments ({ user, userId }: PaybuttonsProps): React.Reac
187225 throw new Error ( 'Failed to download CSV' )
188226 }
189227
190- const fileName = `${ isCurrencyEmptyOrUndefined ( currency ) ? 'all' : `${ currency . toLowerCase ( ) } ` } -transactions`
228+ const selectedButtonNames = buttons
229+ . filter ( btn => selectedButtonIds . includes ( btn . id ) )
230+ . map ( btn => btn . name . replace ( / \s + / g, '-' ) )
231+ . join ( '_' )
232+
233+ const buttonSuffix = selectedButtonIds . length > 0
234+ ? `-${ selectedButtonNames !== '' ? selectedButtonNames : 'filtered' } `
235+ : ''
236+ const currencyLabel = isCurrencyEmptyOrUndefined ( currency ) ? 'all' : currency . toLowerCase ( )
237+ const timestamp = moment ( ) . format ( 'YYYY-MM-DD_HH-mm-ss' )
238+
239+ const fileName = `${ currencyLabel } -transactions${ buttonSuffix } -${ timestamp } `
191240 const blob = await response . blob ( )
192241 const downloadUrl = window . URL . createObjectURL ( blob )
193242 const link = document . createElement ( 'a' )
@@ -213,8 +262,24 @@ export default function Payments ({ user, userId }: PaybuttonsProps): React.Reac
213262
214263 return (
215264 < >
216- < TopBar title = "Payments" user = { user ?. stUser ?. email } />
217- < div style = { { display : 'flex' , alignItems : 'center' , gap : '10px' , justifyContent : 'right' } } >
265+ < TopBar title = "Payments" user = { user ?. stUser ?. email } />
266+ < div className = { style . filters_export_ctn } >
267+ < div className = { style . filter_btns } >
268+ < div
269+ onClick = { ( ) => setShowFilters ( ! showFilters ) }
270+ className = { `${ style . show_filters_button } ${ selectedButtonIds . length > 0 ? style . active : '' } ` }
271+ >
272+ < Image src = { SettingsIcon } alt = "filters" width = { 15 } /> Filters
273+ </ div >
274+ { selectedButtonIds . length > 0 &&
275+ < div
276+ onClick = { ( ) => setSelectedButtonIds ( [ ] ) }
277+ className = { style . show_filters_button }
278+ >
279+ Clear
280+ </ div >
281+ }
282+ </ div >
218283 { paybuttonNetworks . size > 1
219284 ? (
220285 < select
@@ -246,11 +311,35 @@ export default function Payments ({ user, userId }: PaybuttonsProps): React.Reac
246311 Export as CSV
247312 </ Button > ) }
248313 </ div >
314+ { showFilters && (
315+ < div className = { style . showfilters_ctn } >
316+ < span > Filter by button</ span >
317+ < div className = { style . filters_ctn } >
318+ { buttons . map ( ( button ) => (
319+ < div
320+ key = { button . id }
321+ onClick = { ( ) => {
322+ setSelectedButtonIds ( prev =>
323+ prev . includes ( button . id )
324+ ? prev . filter ( id => id !== button . id )
325+ : [ ...prev , button . id ]
326+ )
327+ } }
328+ className = { `${ style . filter_button } ${ selectedButtonIds . includes ( button . id ) ? style . active : '' } ` }
329+ >
330+ { button . name }
331+ </ div >
332+ ) ) }
333+ </ div >
334+ </ div >
335+ ) }
249336 < TableContainerGetter
250337 columns = { columns }
251- dataGetter = { fetchData ( ) }
252- tableRefreshCount = { 1 }
253- emptyMessage = 'No Payments to show yet'
338+ dataGetter = { async ( page , pageSize , orderBy , orderDesc ) =>
339+ await loadData ( page , pageSize , orderBy , orderDesc )
340+ }
341+ tableRefreshCount = { refreshCount }
342+ emptyMessage = { tableLoading ? 'Loading...' : 'No Payments to show yet' }
254343 />
255344 </ >
256345 )
0 commit comments