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,111 +14,112 @@ 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- const { totalWallets, uniqueWallets } = useMemo ( ( ) => {
24- return props . aggregateWalletUsage . reduce (
25- ( acc , curr ) => {
26- acc . totalWallets += curr . totalConnections ;
27- acc . uniqueWallets += curr . uniqueWalletsConnected ;
28- return acc ;
29- } ,
30- { uniqueWallets : 0 , totalWallets : 0 } ,
31- ) ;
32- } , [ props . aggregateWalletUsage ] ) ;
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 ] ) ;
3334
34- const { totalSponsoredTransactions, totalSponsoredUsd } = useMemo ( ( ) => {
35- return props . aggregateUserOpUsage . reduce (
36- ( acc , curr ) => {
37- acc . totalSponsoredTransactions += curr . successful ;
38- acc . totalSponsoredUsd += curr . sponsoredUsd ;
39- return acc ;
40- } ,
41- { totalSponsoredTransactions : 0 , totalSponsoredUsd : 0 } ,
42- ) ;
43- } , [ props . aggregateUserOpUsage ] ) ;
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 ] ) ;
4445
45- return (
46- < div className = "flex flex-col gap-4 lg:gap-6" >
47- { /* Connections */ }
48- < div className = "grid grid-cols-2 gap-4 lg:gap-6" >
49- < Stat label = "Connections" value = { totalWallets } icon = { CableIcon } />
50- < Stat
51- label = "Unique Wallets"
52- value = { uniqueWallets }
53- icon = { WalletCardsIcon }
54- />
55- </ div >
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 >
5657
57- < DailyConnectionsChartCard
58- walletStats = { props . walletUsage }
59- isPending = { props . isPending }
60- />
58+ < DailyConnectionsChartCard
59+ walletStats = { props . walletUsage }
60+ isPending = { props . isPending }
61+ />
6162
62- < WalletConnectorsChartCard
63- walletStats = { props . walletUsage }
64- isPending = { props . isPending }
65- />
63+ < WalletConnectorsChartCard
64+ walletStats = { props . walletUsage }
65+ isPending = { props . isPending }
66+ />
6667
67- < WalletDistributionChartCard
68- walletStats = { props . walletUsage }
69- isPending = { props . isPending }
70- />
68+ < WalletDistributionChartCard
69+ walletStats = { props . walletUsage }
70+ isPending = { props . isPending }
71+ />
7172
72- { /* Connections */ }
73- < div className = "grid grid-cols-2 gap-4 lg:gap-6" >
74- < Stat
75- label = "Sponsored Transactions"
76- value = { totalSponsoredTransactions }
77- icon = { ActivityIcon }
78- />
79- < Stat
80- label = "Total Sponsored"
81- value = { totalSponsoredUsd }
82- formatter = { ( value ) =>
83- new Intl . NumberFormat ( "en-US" , {
84- style : "currency" ,
85- currency : "USD" ,
86- } ) . format ( value )
87- }
88- icon = { CoinsIcon }
89- />
90- </ div >
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 >
9192
92- < TotalSponsoredChartCard
93- userOpStats = { props . userOpUsage }
94- isPending = { props . isPending }
95- />
93+ < TotalSponsoredChartCard
94+ userOpStats = { props . userOpUsage }
95+ isPending = { props . isPending }
96+ />
9697
97- < SponsoredTransactionsChartCard
98- userOpStats = { props . userOpUsage }
99- isPending = { props . isPending }
100- />
101- </ div >
102- ) ;
98+ < SponsoredTransactionsChartCard
99+ userOpStats = { props . userOpUsage }
100+ isPending = { props . isPending }
101+ />
102+ </ div >
103+ ) ;
103104}
104105
105106const Stat : React . FC < {
106- label : string ;
107- value ?: number ;
108- icon : React . FC < { className ?: string } > ;
109- formatter ?: ( value : number ) => string ;
107+ label : string ;
108+ value ?: number ;
109+ icon : React . FC < { className ?: string } > ;
110+ formatter ?: ( value : number ) => string ;
110111} > = ( { label, value, formatter, icon : Icon } ) => {
111- return (
112- < dl className = "flex items-center justify-between gap-4 rounded-lg border border-border bg-muted/50 p-4 lg:p-6" >
113- < div >
114- < dd className = "font-semibold text-3xl tracking-tight lg:text-5xl" >
115- { value && formatter ? formatter ( value ) : value ?. toLocaleString ( ) }
116- </ dd >
117- < dt className = "font-medium text-muted-foreground text-sm tracking-tight lg:text-lg" >
118- { label }
119- </ dt >
120- </ div >
121- < Icon className = "hidden size-12 text-muted-foreground opacity-50 lg:block" />
122- </ dl >
123- ) ;
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+ ) ;
124125} ;
0 commit comments