@@ -37,6 +37,7 @@ import {
37
37
getChainMetadata ,
38
38
} from "thirdweb/chains" ;
39
39
import { type WalletId , getWalletInfo } from "thirdweb/wallets" ;
40
+ import { LoadingChartState } from "../../../../../../components/analytics/empty-chart-state" ;
40
41
import { getAuthToken } from "../../../../api/lib/getAuthToken" ;
41
42
import { loginRedirect } from "../../../../login/loginRedirect" ;
42
43
import { CombinedBarChartCard } from "../../../components/Analytics/CombinedBarChartCard" ;
@@ -148,107 +149,29 @@ async function ProjectAnalytics(props: {
148
149
} ) {
149
150
const { project, params, range, interval, searchParams, client } = props ;
150
151
151
- // Fetch all analytics data in parallel
152
- const [
153
- walletConnections ,
154
- walletUserStatsTimeSeries ,
155
- inAppWalletUsage ,
156
- userOpUsageTimeSeries ,
157
- userOpUsage ,
158
- universalBridgeUsage ,
159
- ] = await Promise . allSettled ( [
160
- // Aggregated wallet connections
161
- getWalletConnections ( {
162
- teamId : project . teamId ,
163
- projectId : project . id ,
164
- from : range . from ,
165
- to : range . to ,
166
- period : "all" ,
167
- } ) ,
168
- // Time series data for wallet users
169
- getWalletUsers ( {
170
- teamId : project . teamId ,
171
- projectId : project . id ,
172
- from : range . from ,
173
- to : range . to ,
174
- period : interval ,
175
- } ) ,
176
- // In-app wallet usage
177
- getInAppWalletUsage ( {
178
- teamId : project . teamId ,
179
- projectId : project . id ,
180
- from : range . from ,
181
- to : range . to ,
182
- period : "all" ,
183
- } ) ,
184
- // User operations usage
185
- getUserOpUsage ( {
186
- teamId : project . teamId ,
187
- projectId : project . id ,
188
- from : range . from ,
189
- to : range . to ,
190
- period : interval ,
191
- } ) ,
192
- getUserOpUsage ( {
193
- teamId : project . teamId ,
194
- projectId : project . id ,
195
- from : range . from ,
196
- to : range . to ,
197
- period : "all" ,
198
- } ) ,
199
- // Universal Bridge
200
- getUniversalBridgeUsage ( {
201
- teamId : project . teamId ,
202
- projectId : project . id ,
203
- from : range . from ,
204
- to : range . to ,
205
- period : interval ,
206
- } ) ,
207
- ] ) ;
208
-
209
152
return (
210
153
< div className = "flex grow flex-col gap-6" >
211
- { walletUserStatsTimeSeries . status === "fulfilled" &&
212
- universalBridgeUsage . status === "fulfilled" &&
213
- walletUserStatsTimeSeries . value . some ( ( w ) => w . totalUsers !== 0 ) ? (
214
- < div className = "" >
215
- < AppHighlightsCard
216
- chartKey = {
217
- ( searchParams . appHighlights as keyof AggregatedMetrics ) ??
218
- "totalVolume"
219
- }
220
- params = { params }
221
- userStats = { walletUserStatsTimeSeries . value }
222
- volumeStats = { universalBridgeUsage . value }
223
- searchParams = { searchParams }
224
- />
225
- </ div >
226
- ) : (
227
- < EmptyStateCard
228
- metric = "Connect"
229
- link = "https://portal.thirdweb.com/connect/quickstart"
154
+ < Suspense fallback = { < LoadingChartState className = "h-[458px] border" /> } >
155
+ < AsyncAppHighlightsCard
156
+ project = { project }
157
+ range = { range }
158
+ interval = { interval }
159
+ searchParams = { searchParams }
160
+ client = { client }
161
+ params = { params }
230
162
/>
231
- ) }
163
+ </ Suspense >
164
+
232
165
< div className = "grid gap-6 md:grid-cols-2" >
233
- { walletConnections . status === "fulfilled" &&
234
- walletConnections . value . length > 0 ? (
235
- < WalletDistributionCard data = { walletConnections . value } />
236
- ) : (
237
- < EmptyStateCard
238
- metric = "Connect"
239
- link = "https://portal.thirdweb.com/connect/quickstart"
240
- />
241
- ) }
242
- { inAppWalletUsage . status === "fulfilled" &&
243
- inAppWalletUsage . value . length > 0 ? (
244
- < AuthMethodDistributionCard data = { inAppWalletUsage . value } />
245
- ) : (
246
- < EmptyStateCard
247
- metric = "In-App Wallets"
248
- link = "https://portal.thirdweb.com/typescript/v5/inAppWallet"
249
- />
250
- ) }
166
+ < Suspense fallback = { < LoadingChartState className = "h-[431px] border" /> } >
167
+ < AsyncWalletDistributionCard project = { project } range = { range } />
168
+ </ Suspense >
169
+
170
+ < Suspense fallback = { < LoadingChartState className = "h-[431px] border" /> } >
171
+ < AsyncAuthMethodDistributionCard project = { project } range = { range } />
172
+ </ Suspense >
251
173
</ div >
174
+
252
175
< TransactionsCharts
253
176
searchParams = { searchParams }
254
177
from = { range . from }
@@ -257,22 +180,16 @@ async function ProjectAnalytics(props: {
257
180
teamId = { project . teamId }
258
181
client = { client }
259
182
/>
260
- { userOpUsageTimeSeries . status === "fulfilled" &&
261
- userOpUsage . status === "fulfilled" &&
262
- userOpUsage . value . length > 0 ? (
263
- < div className = "" >
264
- < TotalSponsoredCard
265
- searchParams = { searchParams }
266
- data = { userOpUsageTimeSeries . value }
267
- aggregatedData = { userOpUsage . value }
268
- />
269
- </ div >
270
- ) : (
271
- < EmptyStateCard
272
- metric = "Sponsored Transactions"
273
- link = "https://portal.thirdweb.com/typescript/v5/account-abstraction/get-started"
183
+
184
+ < Suspense fallback = { < LoadingChartState className = "h-[458px] border" /> } >
185
+ < AsyncTotalSponsoredCard
186
+ project = { project }
187
+ range = { range }
188
+ interval = { interval }
189
+ searchParams = { searchParams }
274
190
/>
275
- ) }
191
+ </ Suspense >
192
+
276
193
< RpcMethodBarChartCard
277
194
from = { range . from }
278
195
to = { range . to }
@@ -332,6 +249,154 @@ function processTimeSeriesData(
332
249
return metrics ;
333
250
}
334
251
252
+ async function AsyncTotalSponsoredCard ( props : {
253
+ project : Project ;
254
+ range : Range ;
255
+ interval : "day" | "week" ;
256
+ searchParams : PageSearchParams ;
257
+ } ) {
258
+ const [ userOpUsageTimeSeries , userOpUsage ] = await Promise . allSettled ( [
259
+ getUserOpUsage ( {
260
+ teamId : props . project . teamId ,
261
+ projectId : props . project . id ,
262
+ from : props . range . from ,
263
+ to : props . range . to ,
264
+ period : props . interval ,
265
+ } ) ,
266
+ getUserOpUsage ( {
267
+ teamId : props . project . teamId ,
268
+ projectId : props . project . id ,
269
+ from : props . range . from ,
270
+ to : props . range . to ,
271
+ period : "all" ,
272
+ } ) ,
273
+ ] ) ;
274
+
275
+ return userOpUsageTimeSeries . status === "fulfilled" &&
276
+ userOpUsage . status === "fulfilled" &&
277
+ userOpUsage . value . length > 0 ? (
278
+ < div className = "" >
279
+ < TotalSponsoredCard
280
+ searchParams = { props . searchParams }
281
+ data = { userOpUsageTimeSeries . value }
282
+ aggregatedData = { userOpUsage . value }
283
+ />
284
+ </ div >
285
+ ) : (
286
+ < EmptyStateCard
287
+ metric = "Sponsored Transactions"
288
+ link = "https://portal.thirdweb.com/typescript/v5/account-abstraction/get-started"
289
+ />
290
+ ) ;
291
+ }
292
+
293
+ async function AsyncAuthMethodDistributionCard ( props : {
294
+ project : Project ;
295
+ range : Range ;
296
+ } ) {
297
+ const inAppWalletUsage = await getInAppWalletUsage ( {
298
+ teamId : props . project . teamId ,
299
+ projectId : props . project . id ,
300
+ from : props . range . from ,
301
+ to : props . range . to ,
302
+ period : "all" ,
303
+ } ) . catch ( ( ) => undefined ) ;
304
+
305
+ return inAppWalletUsage && inAppWalletUsage . length > 0 ? (
306
+ < AuthMethodDistributionCard data = { inAppWalletUsage } />
307
+ ) : (
308
+ < EmptyStateCard
309
+ metric = "In-App Wallets"
310
+ link = "https://portal.thirdweb.com/typescript/v5/inAppWallet"
311
+ />
312
+ ) ;
313
+ }
314
+
315
+ async function AsyncAppHighlightsCard ( props : {
316
+ project : Project ;
317
+ range : Range ;
318
+ interval : "day" | "week" ;
319
+ searchParams : PageSearchParams ;
320
+ client : ThirdwebClient ;
321
+ params : PageParams ;
322
+ } ) {
323
+ const [ walletUserStatsTimeSeries , universalBridgeUsage ] =
324
+ await Promise . allSettled ( [
325
+ getWalletUsers ( {
326
+ teamId : props . project . teamId ,
327
+ projectId : props . project . id ,
328
+ from : props . range . from ,
329
+ to : props . range . to ,
330
+ period : props . interval ,
331
+ } ) ,
332
+ getUniversalBridgeUsage ( {
333
+ teamId : props . project . teamId ,
334
+ projectId : props . project . id ,
335
+ from : props . range . from ,
336
+ to : props . range . to ,
337
+ period : props . interval ,
338
+ } ) ,
339
+ ] ) ;
340
+
341
+ if (
342
+ walletUserStatsTimeSeries . status === "fulfilled" &&
343
+ universalBridgeUsage . status === "fulfilled" &&
344
+ walletUserStatsTimeSeries . value . some ( ( w ) => w . totalUsers !== 0 )
345
+ ) {
346
+ return (
347
+ < div >
348
+ < AppHighlightsCard
349
+ chartKey = {
350
+ ( props . searchParams . appHighlights as keyof AggregatedMetrics ) ??
351
+ "totalVolume"
352
+ }
353
+ params = { props . params }
354
+ userStats = {
355
+ walletUserStatsTimeSeries . status === "fulfilled"
356
+ ? walletUserStatsTimeSeries . value
357
+ : [ ]
358
+ }
359
+ volumeStats = {
360
+ universalBridgeUsage . status === "fulfilled"
361
+ ? universalBridgeUsage . value
362
+ : [ ]
363
+ }
364
+ searchParams = { props . searchParams }
365
+ />
366
+ </ div >
367
+ ) ;
368
+ }
369
+
370
+ return (
371
+ < EmptyStateCard
372
+ metric = "Connect"
373
+ link = "https://portal.thirdweb.com/connect/quickstart"
374
+ />
375
+ ) ;
376
+ }
377
+
378
+ async function AsyncWalletDistributionCard ( props : {
379
+ project : Project ;
380
+ range : Range ;
381
+ } ) {
382
+ const walletConnections = await getWalletConnections ( {
383
+ teamId : props . project . teamId ,
384
+ projectId : props . project . id ,
385
+ from : props . range . from ,
386
+ to : props . range . to ,
387
+ period : "all" ,
388
+ } ) . catch ( ( ) => undefined ) ;
389
+
390
+ return walletConnections && walletConnections . length > 0 ? (
391
+ < WalletDistributionCard data = { walletConnections } />
392
+ ) : (
393
+ < EmptyStateCard
394
+ metric = "Connect"
395
+ link = "https://portal.thirdweb.com/connect/quickstart"
396
+ />
397
+ ) ;
398
+ }
399
+
335
400
function AppHighlightsCard ( {
336
401
chartKey,
337
402
userStats,
0 commit comments