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