11import type { UserOpStats , WalletStats } from "@3rdweb-sdk/react/hooks/useApi" ;
22import {
3- ActivityIcon ,
4- CableIcon ,
5- CoinsIcon ,
6- WalletCardsIcon ,
3+ ActivityIcon ,
4+ CableIcon ,
5+ CoinsIcon ,
6+ WalletCardsIcon ,
77} from "lucide-react" ;
88import type React from "react" ;
99import { useMemo } from "react" ;
@@ -14,112 +14,100 @@ import { WalletConnectorsChartCard } from "./_components/WalletConnectorsChartCa
1414import { WalletDistributionChartCard } from "./_components/WalletDistributionChartCard" ;
1515
1616export function ConnectAnalyticsDashboardUI ( props : {
17- walletUsage : WalletStats [ ] ;
18- aggregateWalletUsage : WalletStats [ ] ;
19- userOpUsage : UserOpStats [ ] ;
20- aggregateUserOpUsage : UserOpStats [ ] ;
21- isPending : boolean ;
17+ walletUsage : WalletStats [ ] ;
18+ aggregateWalletUsage : WalletStats [ ] ;
19+ userOpUsage : UserOpStats [ ] ;
20+ aggregateUserOpUsage : UserOpStats [ ] ;
21+ isPending : boolean ;
2222} ) {
23- // This hook aggregates wallets across wallet types, only one date is returned for the aggregate query
24- const { totalWallets, uniqueWallets } = useMemo ( ( ) => {
25- return props . aggregateWalletUsage . reduce (
26- ( acc , curr ) => {
27- acc . totalWallets += curr . totalConnections ;
28- acc . uniqueWallets += curr . uniqueWalletsConnected ;
29- return acc ;
30- } ,
31- { uniqueWallets : 0 , totalWallets : 0 } ,
32- ) ;
33- } , [ props . aggregateWalletUsage ] ) ;
23+ const { totalSponsoredTransactions, totalSponsoredUsd } = useMemo ( ( ) => {
24+ return props . aggregateUserOpUsage . reduce (
25+ ( acc , curr ) => {
26+ acc . totalSponsoredTransactions += curr . successful ;
27+ acc . totalSponsoredUsd += curr . sponsoredUsd ;
28+ return acc ;
29+ } ,
30+ { totalSponsoredTransactions : 0 , totalSponsoredUsd : 0 } ,
31+ ) ;
32+ } , [ props . aggregateUserOpUsage ] ) ;
3433
35- const { totalSponsoredTransactions, totalSponsoredUsd } = useMemo ( ( ) => {
36- return props . aggregateUserOpUsage . reduce (
37- ( acc , curr ) => {
38- acc . totalSponsoredTransactions += curr . successful ;
39- acc . totalSponsoredUsd += curr . sponsoredUsd ;
40- return acc ;
41- } ,
42- { totalSponsoredTransactions : 0 , totalSponsoredUsd : 0 } ,
43- ) ;
44- } , [ props . aggregateUserOpUsage ] ) ;
34+ return (
35+ < div className = "flex flex-col gap-4 lg:gap-6" >
36+ { /* Connections */ }
37+ < div className = "grid grid-cols-2 gap-4 lg:gap-6" >
38+ < Stat label = "Connections" value = { totalWallets } icon = { CableIcon } />
39+ < Stat
40+ label = "Unique Wallets"
41+ value = { uniqueWallets }
42+ icon = { WalletCardsIcon }
43+ />
44+ </ div >
4545
46- return (
47- < div className = "flex flex-col gap-4 lg:gap-6" >
48- { /* Connections */ }
49- < div className = "grid grid-cols-2 gap-4 lg:gap-6" >
50- < Stat label = "Connections" value = { totalWallets } icon = { CableIcon } />
51- < Stat
52- label = "Unique Wallets"
53- value = { uniqueWallets }
54- icon = { WalletCardsIcon }
55- />
56- </ div >
46+ < DailyConnectionsChartCard
47+ walletStats = { props . walletUsage }
48+ isPending = { props . isPending }
49+ />
5750
58- < DailyConnectionsChartCard
59- walletStats = { props . walletUsage }
60- isPending = { props . isPending }
61- />
51+ < WalletConnectorsChartCard
52+ walletStats = { props . walletUsage }
53+ isPending = { props . isPending }
54+ />
6255
63- < WalletConnectorsChartCard
64- walletStats = { props . walletUsage }
65- isPending = { props . isPending }
66- />
56+ < WalletDistributionChartCard
57+ walletStats = { props . walletUsage }
58+ isPending = { props . isPending }
59+ />
6760
68- < WalletDistributionChartCard
69- walletStats = { props . walletUsage }
70- isPending = { props . isPending }
71- />
61+ { /* Connections */ }
62+ < div className = "grid grid-cols-2 gap-4 lg:gap-6" >
63+ < Stat
64+ label = "Sponsored Transactions"
65+ value = { totalSponsoredTransactions }
66+ icon = { ActivityIcon }
67+ />
68+ < Stat
69+ label = "Total Sponsored"
70+ value = { totalSponsoredUsd }
71+ formatter = { ( value ) =>
72+ new Intl . NumberFormat ( "en-US" , {
73+ style : "currency" ,
74+ currency : "USD" ,
75+ } ) . format ( value )
76+ }
77+ icon = { CoinsIcon }
78+ />
79+ </ div >
7280
73- { /* Connections */ }
74- < div className = "grid grid-cols-2 gap-4 lg:gap-6" >
75- < Stat
76- label = "Sponsored Transactions"
77- value = { totalSponsoredTransactions }
78- icon = { ActivityIcon }
79- />
80- < Stat
81- label = "Total Sponsored"
82- value = { totalSponsoredUsd }
83- formatter = { ( value ) =>
84- new Intl . NumberFormat ( "en-US" , {
85- style : "currency" ,
86- currency : "USD" ,
87- } ) . format ( value )
88- }
89- icon = { CoinsIcon }
90- />
91- </ div >
81+ < TotalSponsoredChartCard
82+ userOpStats = { props . userOpUsage }
83+ isPending = { props . isPending }
84+ />
9285
93- < TotalSponsoredChartCard
94- userOpStats = { props . userOpUsage }
95- isPending = { props . isPending }
96- />
97-
98- < SponsoredTransactionsChartCard
99- userOpStats = { props . userOpUsage }
100- isPending = { props . isPending }
101- />
102- </ div >
103- ) ;
86+ < SponsoredTransactionsChartCard
87+ userOpStats = { props . userOpUsage }
88+ isPending = { props . isPending }
89+ />
90+ </ div >
91+ ) ;
10492}
10593
10694const Stat : React . FC < {
107- label : string ;
108- value ?: number ;
109- icon : React . FC < { className ?: string } > ;
110- formatter ?: ( value : number ) => string ;
95+ label : string ;
96+ value ?: number ;
97+ icon : React . FC < { className ?: string } > ;
98+ formatter ?: ( value : number ) => string ;
11199} > = ( { label, value, formatter, icon : Icon } ) => {
112- return (
113- < dl className = "flex items-center justify-between gap-4 rounded-lg border border-border bg-muted/50 p-4 lg:p-6" >
114- < div >
115- < dd className = "font-semibold text-3xl tracking-tight lg:text-5xl" >
116- { value && formatter ? formatter ( value ) : value ?. toLocaleString ( ) }
117- </ dd >
118- < dt className = "font-medium text-muted-foreground text-sm tracking-tight lg:text-lg" >
119- { label }
120- </ dt >
121- </ div >
122- < Icon className = "hidden size-12 text-muted-foreground opacity-50 lg:block" />
123- </ dl >
124- ) ;
100+ return (
101+ < dl className = "flex items-center justify-between gap-4 rounded-lg border border-border bg-muted/50 p-4 lg:p-6" >
102+ < div >
103+ < dd className = "font-semibold text-3xl tracking-tight lg:text-5xl" >
104+ { value && formatter ? formatter ( value ) : value ?. toLocaleString ( ) }
105+ </ dd >
106+ < dt className = "font-medium text-muted-foreground text-sm tracking-tight lg:text-lg" >
107+ { label }
108+ </ dt >
109+ </ div >
110+ < Icon className = "hidden size-12 text-muted-foreground opacity-50 lg:block" />
111+ </ dl >
112+ ) ;
125113} ;
0 commit comments