@@ -37,6 +37,7 @@ import {
3737 getChainMetadata ,
3838} from "thirdweb/chains" ;
3939import { type WalletId , getWalletInfo } from "thirdweb/wallets" ;
40+ import { LoadingChartState } from "../../../../../../components/analytics/empty-chart-state" ;
4041import { getAuthToken } from "../../../../api/lib/getAuthToken" ;
4142import { loginRedirect } from "../../../../login/loginRedirect" ;
4243import { CombinedBarChartCard } from "../../../components/Analytics/CombinedBarChartCard" ;
@@ -148,107 +149,29 @@ async function ProjectAnalytics(props: {
148149} ) {
149150 const { project, params, range, interval, searchParams, client } = props ;
150151
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-
209152 return (
210153 < 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 }
230162 />
231- ) }
163+ </ Suspense >
164+
232165 < 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 >
251173 </ div >
174+
252175 < TransactionsCharts
253176 searchParams = { searchParams }
254177 from = { range . from }
@@ -257,22 +180,16 @@ async function ProjectAnalytics(props: {
257180 teamId = { project . teamId }
258181 client = { client }
259182 />
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 }
274190 />
275- ) }
191+ </ Suspense >
192+
276193 < RpcMethodBarChartCard
277194 from = { range . from }
278195 to = { range . to }
@@ -332,6 +249,154 @@ function processTimeSeriesData(
332249 return metrics ;
333250}
334251
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+
335400function AppHighlightsCard ( {
336401 chartKey,
337402 userStats,
0 commit comments