11import {
22 getClientTransactions ,
33 getInAppWalletUsage ,
4+ getUniversalBridgeUsage ,
45 getUserOpUsage ,
56 getWalletConnections ,
67 getWalletUsers ,
@@ -14,6 +15,7 @@ import { redirect } from "next/navigation";
1415import { type WalletId , getWalletInfo } from "thirdweb/wallets" ;
1516import type {
1617 InAppWalletStats ,
18+ UniversalBridgeStats ,
1719 WalletStats ,
1820 WalletUserStats ,
1921} from "types/analytics" ;
@@ -24,7 +26,10 @@ import { PieChartCard } from "../../../../components/Analytics/PieChartCard";
2426
2527import { getTeamBySlug } from "@/api/team" ;
2628import { GenericLoadingPage } from "@/components/blocks/skeletons/GenericLoadingPage" ;
27- import { EmptyStateCard } from "app/(app)/team/components/Analytics/EmptyStateCard" ;
29+ import {
30+ EmptyStateCard ,
31+ EmptyStateContent ,
32+ } from "app/(app)/team/components/Analytics/EmptyStateCard" ;
2833import { Suspense } from "react" ;
2934import { TotalSponsoredChartCardUI } from "../../_components/TotalSponsoredCard" ;
3035import { TransactionsChartCardUI } from "../../_components/TransactionsCard" ;
@@ -100,6 +105,7 @@ async function OverviewPageContent(props: {
100105 userOpUsage ,
101106 clientTransactionsTimeSeries ,
102107 clientTransactions ,
108+ universalBridgeUsage ,
103109 ] = await Promise . all ( [
104110 // Aggregated wallet connections
105111 getWalletConnections ( {
@@ -148,6 +154,13 @@ async function OverviewPageContent(props: {
148154 to : range . to ,
149155 period : "all" ,
150156 } ) ,
157+ // Universal Bridge
158+ getUniversalBridgeUsage ( {
159+ teamId : teamId ,
160+ from : range . from ,
161+ to : range . to ,
162+ period : interval ,
163+ } ) ,
151164 ] ) ;
152165
153166 const isEmpty =
@@ -164,8 +177,9 @@ async function OverviewPageContent(props: {
164177 < div className = "flex grow flex-col gap-6" >
165178 { walletUserStatsTimeSeries . some ( ( w ) => w . totalUsers !== 0 ) ? (
166179 < div className = "" >
167- < UsersChartCard
180+ < AppHighlightsCard
168181 userStats = { walletUserStatsTimeSeries }
182+ volumeStats = { universalBridgeUsage }
169183 searchParams = { searchParams }
170184 />
171185 </ div >
@@ -218,70 +232,96 @@ async function OverviewPageContent(props: {
218232 ) ;
219233}
220234
221- type UserMetrics = {
222- totalUsers : number ;
235+ type AggregatedMetrics = {
223236 activeUsers : number ;
224237 newUsers : number ;
225- returningUsers : number ;
238+ totalVolume : number ;
239+ feesCollected : number ;
226240} ;
227241
228- type TimeSeriesMetrics = UserMetrics & {
242+ type TimeSeriesMetrics = AggregatedMetrics & {
229243 date : string ;
230244} ;
231245
232246function processTimeSeriesData (
233247 userStats : WalletUserStats [ ] ,
248+ volumeStats : UniversalBridgeStats [ ] ,
234249) : TimeSeriesMetrics [ ] {
235250 const metrics : TimeSeriesMetrics [ ] = [ ] ;
236251
237- let cumulativeUsers = 0 ;
238252 for ( const stat of userStats ) {
239- cumulativeUsers += stat . newUsers ?? 0 ;
253+ const volume = volumeStats
254+ . filter ( ( v ) => v . date === stat . date && v . status === "completed" )
255+ . reduce ( ( acc , curr ) => acc + curr . amountUsdCents / 100 , 0 ) ;
256+
257+ const fees = volumeStats
258+ . filter ( ( v ) => v . date === stat . date && v . status === "completed" )
259+ . reduce ( ( acc , curr ) => acc + curr . developerFeeUsdCents / 100 , 0 ) ;
260+
240261 metrics . push ( {
241262 date : stat . date ,
242263 activeUsers : stat . totalUsers ?? 0 ,
243- returningUsers : stat . returningUsers ?? 0 ,
244264 newUsers : stat . newUsers ?? 0 ,
245- totalUsers : cumulativeUsers ,
265+ totalVolume : volume ,
266+ feesCollected : fees ,
246267 } ) ;
247268 }
248269
249270 return metrics ;
250271}
251272
252- function UsersChartCard ( {
273+ function AppHighlightsCard ( {
253274 userStats,
275+ volumeStats,
254276 searchParams,
255277} : {
256278 userStats : WalletUserStats [ ] ;
279+ volumeStats : UniversalBridgeStats [ ] ;
257280 searchParams ?: { [ key : string ] : string | string [ ] | undefined } ;
258281} ) {
259- const timeSeriesData = processTimeSeriesData ( userStats ) ;
282+ const timeSeriesData = processTimeSeriesData ( userStats , volumeStats ) ;
260283
261284 const chartConfig = {
262- activeUsers : { label : "Active Users" , color : "hsl(var(--chart-1))" } ,
263- totalUsers : { label : "Total Users" , color : "hsl(var(--chart-2))" } ,
264- newUsers : { label : "New Users" , color : "hsl(var(--chart-3))" } ,
265- returningUsers : {
266- label : "Returning Users" ,
285+ totalVolume : {
286+ label : "Total Volume" ,
287+ color : "hsl(var(--chart-2))" ,
288+ isCurrency : true ,
289+ emptyContent : (
290+ < EmptyStateContent
291+ metric = "Payments"
292+ description = "Onramp, swap, and bridge with thirdweb's Universal Bridge."
293+ link = "https://portal.thirdweb.com/connect/pay/overview"
294+ />
295+ ) ,
296+ } ,
297+ feesCollected : {
298+ label : "Fee Revenue" ,
267299 color : "hsl(var(--chart-4))" ,
300+ isCurrency : true ,
301+ emptyContent : (
302+ < EmptyStateContent
303+ metric = "Fees"
304+ description = "Your apps haven't collected any fees yet."
305+ link = { "https://portal.thirdweb.com/connect/pay/fees" }
306+ />
307+ ) ,
268308 } ,
309+ activeUsers : { label : "Active Users" , color : "hsl(var(--chart-1))" } ,
310+ newUsers : { label : "New Users" , color : "hsl(var(--chart-3))" } ,
269311 } as const ;
270312
271313 return (
272314 < CombinedBarChartCard
273315 className = "max-md:rounded-none max-md:border-r-0 max-md:border-l-0"
274- title = "Users "
316+ title = "App Highlights "
275317 chartConfig = { chartConfig }
276318 activeChart = {
277- ( searchParams ?. usersChart as keyof UserMetrics ) ?? "activeUsers"
319+ ( searchParams ?. appHighlights as keyof AggregatedMetrics ) ??
320+ "totalVolume"
278321 }
279322 data = { timeSeriesData }
280323 aggregateFn = { ( _data , key ) =>
281- // If there is only one data point, use that one, otherwise use the previous
282- timeSeriesData . filter ( ( d ) => ( d [ key ] as number ) > 0 ) . length >= 2
283- ? timeSeriesData [ timeSeriesData . length - 2 ] ?. [ key ]
284- : timeSeriesData [ timeSeriesData . length - 1 ] ?. [ key ]
324+ timeSeriesData . reduce ( ( acc , curr ) => acc + curr [ key ] , 0 )
285325 }
286326 // Get the trend from the last two COMPLETE periods
287327 trendFn = { ( data , key ) =>
@@ -291,7 +331,7 @@ function UsersChartCard({
291331 1
292332 : undefined
293333 }
294- queryKey = "usersChart "
334+ queryKey = "appHighlights "
295335 existingQueryParams = { searchParams }
296336 />
297337 ) ;
0 commit comments