diff --git a/apps/dashboard/src/app/(app)/team/[team_slug]/(team)/~/analytics/page.tsx b/apps/dashboard/src/app/(app)/team/[team_slug]/(team)/~/analytics/page.tsx index da1521eb5df..b0c675b15bb 100644 --- a/apps/dashboard/src/app/(app)/team/[team_slug]/(team)/~/analytics/page.tsx +++ b/apps/dashboard/src/app/(app)/team/[team_slug]/(team)/~/analytics/page.tsx @@ -21,15 +21,14 @@ import type { } from "types/analytics"; import { AnalyticsHeader } from "../../../../components/Analytics/AnalyticsHeader"; import { CombinedBarChartCard } from "../../../../components/Analytics/CombinedBarChartCard"; -import { EmptyState } from "../../../../components/Analytics/EmptyState"; import { PieChartCard } from "../../../../components/Analytics/PieChartCard"; import { getTeamBySlug } from "@/api/team"; -import { GenericLoadingPage } from "@/components/blocks/skeletons/GenericLoadingPage"; import { EmptyStateCard, EmptyStateContent, } from "app/(app)/team/components/Analytics/EmptyStateCard"; +import { LoadingChartState } from "components/analytics/empty-chart-state"; import { Suspense } from "react"; import { TotalSponsoredChartCardUI } from "../../_components/TotalSponsoredCard"; import { TransactionsChartCardUI } from "../../_components/TransactionsCard"; @@ -76,159 +75,221 @@ export default async function TeamOverviewPage(props: { />
- }> - - +
+ } + > + + + +
+ } + > + + + + } + > + + +
+ + } + > + + + + } + > + + +
); } -async function OverviewPageContent(props: { +async function AsyncAppHighlightsCard(props: { teamId: string; range: Range; interval: "day" | "week"; searchParams: SearchParams; }) { - const { teamId, range, interval, searchParams } = props; - - const [ - walletConnections, - walletUserStatsTimeSeries, - inAppWalletUsage, - userOpUsageTimeSeries, - userOpUsage, - clientTransactionsTimeSeries, - clientTransactions, - universalBridgeUsage, - ] = await Promise.all([ - // Aggregated wallet connections - getWalletConnections({ - teamId: teamId, - from: range.from, - to: range.to, - period: "all", - }), - // Time series data for wallet users - getWalletUsers({ - teamId: teamId, - from: range.from, - to: range.to, - period: interval, - }), - // In-app wallet usage - getInAppWalletUsage({ - teamId: teamId, - from: range.from, - to: range.to, - period: "all", - }), - // User operations usage + const [walletUserStatsTimeSeries, universalBridgeUsage] = + await Promise.allSettled([ + getWalletUsers({ + teamId: props.teamId, + from: props.range.from, + to: props.range.to, + period: props.interval, + }), + getUniversalBridgeUsage({ + teamId: props.teamId, + from: props.range.from, + to: props.range.to, + period: props.interval, + }), + ]); + + if ( + walletUserStatsTimeSeries.status === "fulfilled" && + universalBridgeUsage.status === "fulfilled" && + walletUserStatsTimeSeries.value.some((w) => w.totalUsers !== 0) + ) { + return ( +
+ +
+ ); + } + + return ( + + ); +} + +async function AsyncWalletDistributionCard(props: { + teamId: string; + range: Range; +}) { + const walletConnections = await getWalletConnections({ + teamId: props.teamId, + from: props.range.from, + to: props.range.to, + period: "all", + }).catch(() => undefined); + + return walletConnections && walletConnections.length > 0 ? ( + + ) : ( + + ); +} + +async function AsyncAuthMethodDistributionCard(props: { + teamId: string; + range: Range; +}) { + const inAppWalletUsage = await getInAppWalletUsage({ + teamId: props.teamId, + from: props.range.from, + to: props.range.to, + period: "all", + }).catch(() => undefined); + + return inAppWalletUsage && inAppWalletUsage.length > 0 ? ( + + ) : ( + + ); +} + +async function AsyncTransactionsChartCard(props: { + teamId: string; + range: Range; + interval: "day" | "week"; + searchParams: SearchParams; +}) { + const [clientTransactionsTimeSeries, clientTransactions] = + await Promise.allSettled([ + getClientTransactions({ + teamId: props.teamId, + from: props.range.from, + to: props.range.to, + period: props.interval, + }), + getClientTransactions({ + teamId: props.teamId, + from: props.range.from, + to: props.range.to, + period: "all", + }), + ]); + + return clientTransactionsTimeSeries.status === "fulfilled" && + clientTransactions.status === "fulfilled" && + clientTransactions.value.length > 0 ? ( + + ) : ( + + ); +} + +async function AsyncTotalSponsoredCard(props: { + teamId: string; + range: Range; + interval: "day" | "week"; + searchParams: SearchParams; +}) { + const [userOpUsageTimeSeries, userOpUsage] = await Promise.allSettled([ getUserOpUsage({ - teamId, - from: range.from, - to: range.to, - period: interval, + teamId: props.teamId, + from: props.range.from, + to: props.range.to, + period: props.interval, }), getUserOpUsage({ - teamId, - from: range.from, - to: range.to, + teamId: props.teamId, + from: props.range.from, + to: props.range.to, period: "all", }), - // Client transactions - getClientTransactions({ - teamId: teamId, - from: range.from, - to: range.to, - period: interval, - }), - getClientTransactions({ - teamId: teamId, - from: range.from, - to: range.to, - period: "all", - }), - // Universal Bridge - getUniversalBridgeUsage({ - teamId: teamId, - from: range.from, - to: range.to, - period: interval, - }), ]); - const isEmpty = - !walletUserStatsTimeSeries.some((w) => w.totalUsers !== 0) && - walletConnections.length === 0 && - inAppWalletUsage.length === 0 && - userOpUsage.length === 0; - - if (isEmpty) { - return ; - } - - return ( -
- {walletUserStatsTimeSeries.some((w) => w.totalUsers !== 0) ? ( -
- -
- ) : ( - - )} -
- {walletConnections.length > 0 ? ( - - ) : ( - - )} - {inAppWalletUsage.length > 0 ? ( - - ) : ( - - )} -
- {clientTransactions.length > 0 && ( - - )} - {userOpUsage.length > 0 ? ( - - ) : ( - - )} -
+ return userOpUsageTimeSeries.status === "fulfilled" && + userOpUsage.status === "fulfilled" && + userOpUsage.value.length > 0 ? ( + + ) : ( + ); } @@ -251,11 +312,19 @@ function processTimeSeriesData( for (const stat of userStats) { const volume = volumeStats - .filter((v) => v.date === stat.date && v.status === "completed") + .filter( + (v) => + new Date(v.date).toISOString() === + new Date(stat.date).toISOString() && v.status === "completed", + ) .reduce((acc, curr) => acc + curr.amountUsdCents / 100, 0); const fees = volumeStats - .filter((v) => v.date === stat.date && v.status === "completed") + .filter( + (v) => + new Date(v.date).toISOString() === + new Date(stat.date).toISOString() && v.status === "completed", + ) .reduce((acc, curr) => acc + curr.developerFeeUsdCents / 100, 0); metrics.push({ diff --git a/apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/page.tsx b/apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/page.tsx index 74fa5c92959..563e77e018b 100644 --- a/apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/page.tsx +++ b/apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/page.tsx @@ -230,11 +230,19 @@ function processTimeSeriesData( for (const stat of userStats) { const volume = volumeStats - .filter((v) => v.date === stat.date && v.status === "completed") + .filter( + (v) => + new Date(v.date).toISOString() === + new Date(stat.date).toISOString() && v.status === "completed", + ) .reduce((acc, curr) => acc + curr.amountUsdCents / 100, 0); const fees = volumeStats - .filter((v) => v.date === stat.date && v.status === "completed") + .filter( + (v) => + new Date(v.date).toISOString() === + new Date(stat.date).toISOString() && v.status === "completed", + ) .reduce((acc, curr) => acc + curr.developerFeeUsdCents / 100, 0); metrics.push({ @@ -340,9 +348,8 @@ async function AsyncAppHighlightsCard(props: { if ( walletUserStatsTimeSeries.status === "fulfilled" && - universalBridgeUsage.status === "fulfilled" && - walletUserStatsTimeSeries.value.some((w) => w.totalUsers !== 0) - ) { + universalBridgeUsage.status === "fulfilled" + ) return (
); - } return ( {value.toLocaleString()} - {trend && ( + {trend && Math.abs(trend) !== Number.POSITIVE_INFINITY && ( // trend is rounded to 1 decimal place max