@@ -18,7 +18,15 @@ import {
1818 type PurchasedCredits ,
1919} from "@/services/hooks/useCredits" ;
2020import { formatDate } from "@/utils/date" ;
21- import { ChevronLeft , ChevronRight , RefreshCcw } from "lucide-react" ;
21+ import {
22+ ChevronLeft ,
23+ ChevronRight ,
24+ RefreshCcw ,
25+ AlertCircle ,
26+ Clock ,
27+ CheckCircle ,
28+ XCircle ,
29+ } from "lucide-react" ;
2230import Link from "next/link" ;
2331import Image from "next/image" ;
2432import { ReactElement , useState } from "react" ;
@@ -28,7 +36,8 @@ import { useFeatureFlag } from "@/services/hooks/admin";
2836import { FeatureWaitlist } from "@/components/templates/waitlist/FeatureWaitlist" ;
2937
3038const Credits : NextPageWithLayout < void > = ( ) => {
31- const [ currentPage , setCurrentPage ] = useState ( 0 ) ;
39+ const [ currentPageToken , setCurrentPageToken ] = useState < string | null > ( null ) ;
40+ const [ pageTokenHistory , setPageTokenHistory ] = useState < string [ ] > ( [ ] ) ;
3241 const [ pageSize , setPageSize ] = useState ( 5 ) ;
3342 const [ isPaymentModalOpen , setIsPaymentModalOpen ] = useState ( false ) ;
3443
@@ -49,15 +58,14 @@ const Credits: NextPageWithLayout<void> = () => {
4958 refetch : refetchTransactions ,
5059 error : transactionsError ,
5160 } = useCreditTransactions ( {
52- page : currentPage ,
53- pageSize : pageSize ,
61+ limit : pageSize ,
62+ page : currentPageToken ,
5463 } ) ;
5564
5665 const transactions = transactionsData ?. purchases || [ ] ;
57- const totalTransactions = transactionsData ?. total || 0 ;
58- const totalPages = Math . ceil ( totalTransactions / pageSize ) ;
59- const hasMore = currentPage < totalPages - 1 ;
60- const hasPrevious = currentPage > 0 ;
66+ const hasMore = transactionsData ?. hasMore || false ;
67+ const hasPrevious = pageTokenHistory . length > 0 ;
68+ const currentPageNumber = pageTokenHistory . length + 1 ;
6169
6270 const hasAccess = hasCreditsFeatureFlag ?. data ;
6371
@@ -330,7 +338,8 @@ const Credits: NextPageWithLayout<void> = () => {
330338 onValueChange = { ( value ) => {
331339 setPageSize ( Number ( value ) ) ;
332340 // Reset pagination when changing page size
333- setCurrentPage ( 0 ) ;
341+ setCurrentPageToken ( null ) ;
342+ setPageTokenHistory ( [ ] ) ;
334343 } }
335344 >
336345 < SelectTrigger className = "h-8 w-[60px]" >
@@ -367,41 +376,98 @@ const Credits: NextPageWithLayout<void> = () => {
367376 const created = new Date ( transaction . createdAt ) ;
368377 const createdStr = created . toISOString ( ) ;
369378
370- // All transactions are credit purchases for now
371- const description = "Credit purchase" ;
372- const isCredit = true ; // All are credits being added
379+ // Get status from transaction
380+ const status = transaction . status ;
381+
382+ // Determine status display properties
383+ const getStatusDisplay = ( ) => {
384+ switch ( status ) {
385+ case "succeeded" :
386+ return {
387+ label : "Completed" ,
388+ icon : CheckCircle ,
389+ className :
390+ "text-green-600 dark:text-green-500" ,
391+ showAmount : true ,
392+ } ;
393+ case "processing" :
394+ return {
395+ label : "Processing" ,
396+ icon : Clock ,
397+ className :
398+ "text-blue-600 dark:text-blue-500" ,
399+ showAmount : true ,
400+ } ;
401+ case "canceled" :
402+ return {
403+ label : "Canceled" ,
404+ icon : XCircle ,
405+ className : "text-muted-foreground" ,
406+ showAmount : false ,
407+ } ;
408+ case "requires_action" :
409+ case "requires_capture" :
410+ case "requires_confirmation" :
411+ case "requires_payment_method" :
412+ return {
413+ label : "Action Required" ,
414+ icon : AlertCircle ,
415+ className :
416+ "text-amber-600 dark:text-amber-500" ,
417+ showAmount : true ,
418+ } ;
419+ default :
420+ return {
421+ label : "Credit purchase" ,
422+ icon : CheckCircle ,
423+ className :
424+ "text-green-600 dark:text-green-500" ,
425+ showAmount : true ,
426+ } ;
427+ }
428+ } ;
429+
430+ const statusDisplay = getStatusDisplay ( ) ;
431+ const StatusIcon = statusDisplay . icon ;
373432
374433 return (
375434 < div
376435 key = { transaction . id || index }
377436 className = "flex items-center justify-between border-b border-border py-4 last:border-b-0"
378437 >
379- < div className = "flex flex-col gap-1" >
438+ < div className = "flex items-start gap-3" >
439+ < StatusIcon
440+ className = { `mt-0.5 h-4 w-4 ${ statusDisplay . className } ` }
441+ />
442+ < div className = "flex flex-col gap-1" >
443+ < div
444+ className = "text-sm"
445+ title = { created . toLocaleString ( "en-US" , {
446+ month : "short" ,
447+ day : "numeric" ,
448+ year : "numeric" ,
449+ hour : "2-digit" ,
450+ minute : "2-digit" ,
451+ } ) }
452+ >
453+ { formatDate ( createdStr ) }
454+ </ div >
455+ < XSmall className = "text-muted-foreground" >
456+ { statusDisplay . label }
457+ </ XSmall >
458+ </ div >
459+ </ div >
460+ { statusDisplay . showAmount && (
380461 < div
381- className = "text-sm"
382- title = { created . toLocaleString ( "en-US" , {
383- month : "short" ,
384- day : "numeric" ,
385- year : "numeric" ,
386- hour : "2-digit" ,
387- minute : "2-digit" ,
388- } ) }
462+ className = { `text-sm font-medium ${ statusDisplay . className } ` }
389463 >
390- { formatDate ( createdStr ) }
464+ { status === "succeeded" ? "+" : "" }
465+ { ( amount / 100 ) . toLocaleString ( "en-US" , {
466+ style : "currency" ,
467+ currency : "usd" ,
468+ } ) }
391469 </ div >
392- < XSmall className = "text-muted-foreground" >
393- { description }
394- </ XSmall >
395- </ div >
396- < div
397- className = { `text-sm font-medium ${ isCredit ? "text-green-600 dark:text-green-500" : "text-muted-foreground" } ` }
398- >
399- { isCredit ? "+" : "-" }
400- { ( amount / 100 ) . toLocaleString ( "en-US" , {
401- style : "currency" ,
402- currency : "usd" ,
403- } ) }
404- </ div >
470+ ) }
405471 </ div >
406472 ) ;
407473 } ,
@@ -423,23 +489,34 @@ const Credits: NextPageWithLayout<void> = () => {
423489 onClick = { ( ) => {
424490 // Go to previous page
425491 if ( hasPrevious ) {
426- setCurrentPage ( currentPage - 1 ) ;
492+ const newHistory = [ ...pageTokenHistory ] ;
493+ newHistory . pop ( ) ;
494+ const previousToken =
495+ newHistory . length > 0
496+ ? newHistory [ newHistory . length - 1 ]
497+ : null ;
498+ setPageTokenHistory ( newHistory ) ;
499+ setCurrentPageToken ( previousToken ) ;
427500 }
428501 } }
429502 disabled = { ! hasPrevious }
430503 >
431504 < ChevronLeft className = "h-3 w-3" />
432505 </ Button >
433506 < Badge variant = "secondary" className = "text-xs" >
434- Page { currentPage + 1 } of { totalPages || 1 }
507+ Page { currentPageNumber }
435508 </ Badge >
436509 < Button
437510 variant = "ghost"
438511 size = "sm"
439512 onClick = { ( ) => {
440513 // Go to next page
441- if ( hasMore ) {
442- setCurrentPage ( currentPage + 1 ) ;
514+ if ( hasMore && transactionsData ?. nextPage ) {
515+ setPageTokenHistory ( [
516+ ...pageTokenHistory ,
517+ currentPageToken || "" ,
518+ ] ) ;
519+ setCurrentPageToken ( transactionsData . nextPage ) ;
443520 }
444521 } }
445522 disabled = { ! hasMore }
0 commit comments