Skip to content

Commit 3126d87

Browse files
[Dashboard] improve wallet stats (#7880)
1 parent b9e63ff commit 3126d87

File tree

11 files changed

+143
-188
lines changed

11 files changed

+143
-188
lines changed

apps/dashboard/src/@/api/analytics.ts

Lines changed: 7 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,6 @@ import type {
1313
UniversalBridgeWalletStats,
1414
UserOpStats,
1515
WalletStats,
16-
WalletUserStats,
1716
WebhookLatencyStats,
1817
WebhookRequestStats,
1918
WebhookSummaryStats,
@@ -147,7 +146,13 @@ const cached_getWalletConnections = unstable_cache(
147146
}
148147

149148
const json = await res.json();
150-
return json.data as WalletStats[];
149+
return (json.data as WalletStats[]).filter(
150+
(w) =>
151+
w.walletType !== "smart" &&
152+
w.walletType !== "smartWallet" &&
153+
w.walletType !== "inApp" &&
154+
w.walletType !== "inAppWallet",
155+
);
151156
},
152157
["getWalletConnections"],
153158
{
@@ -398,44 +403,6 @@ export function getRpcUsageByType(
398403
return cached_getRpcUsageByType(normalizedParams(params), authToken);
399404
}
400405

401-
const cached_getWalletUsers = unstable_cache(
402-
async (
403-
params: AnalyticsQueryParams,
404-
authToken: string,
405-
): Promise<WalletUserStats[]> => {
406-
const searchParams = buildSearchParams(params);
407-
const res = await fetchAnalytics({
408-
authToken,
409-
url: `v2/sdk/wallet-connects/users?${searchParams.toString()}`,
410-
init: {
411-
method: "GET",
412-
},
413-
});
414-
415-
if (res?.status !== 200) {
416-
const reason = await res?.text();
417-
console.error(
418-
`Failed to fetch wallet user stats: ${res?.status} - ${res.statusText} - ${reason}`,
419-
);
420-
return [];
421-
}
422-
423-
const json = await res.json();
424-
return json.data as WalletUserStats[];
425-
},
426-
["getWalletUsers"],
427-
{
428-
revalidate: 60 * 60, // 1 hour
429-
},
430-
);
431-
432-
export function getWalletUsers(
433-
params: AnalyticsQueryParams,
434-
authToken: string,
435-
) {
436-
return cached_getWalletUsers(normalizedParams(params), authToken);
437-
}
438-
439406
type ActiveStatus = {
440407
bundler: boolean;
441408
storage: boolean;

apps/dashboard/src/@/types/analytics.ts

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -7,17 +7,11 @@ export interface WalletStats {
77
walletType: string;
88
}
99

10-
export interface WalletUserStats {
11-
date: string;
12-
newUsers: number;
13-
returningUsers: number;
14-
totalUsers: number;
15-
}
16-
1710
export interface InAppWalletStats {
1811
date: string;
1912
authenticationMethod: string;
2013
uniqueWalletsConnected: number;
14+
newUsers: number;
2115
}
2216

2317
export interface EcosystemWalletStats extends InAppWalletStats {

apps/dashboard/src/app/(app)/team/[team_slug]/(team)/page.tsx

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { subDays } from "date-fns";
22
import { redirect } from "next/navigation";
3-
import { getWalletConnections } from "@/api/analytics";
3+
import { getInAppWalletUsage } from "@/api/analytics";
44
import { getAuthToken } from "@/api/auth-token";
55
import { getProjects, type Project } from "@/api/project/projects";
66
import { getTeamBySlug } from "@/api/team/get-team";
@@ -90,7 +90,8 @@ async function getProjectsWithAnalytics(
9090
const today = new Date();
9191
const thirtyDaysAgo = subDays(today, 30);
9292

93-
const data = await getWalletConnections(
93+
// TODO (stats): also add the external wallet usage?
94+
const data = await getInAppWalletUsage(
9495
{
9596
from: thirtyDaysAgo,
9697
period: "all",

apps/dashboard/src/app/(app)/team/[team_slug]/(team)/~/analytics/highlights-card.tsx

Lines changed: 36 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
import { useMemo } from "react";
44
import { useSetResponsiveSearchParams } from "responsive-rsc";
5-
import type { UniversalBridgeStats, WalletUserStats } from "@/types/analytics";
5+
import type { InAppWalletStats, UniversalBridgeStats } from "@/types/analytics";
66
import { CombinedBarChartCard } from "../../../../components/Analytics/CombinedBarChartCard";
77
import { EmptyStateContent } from "../../../../components/Analytics/EmptyStateCard";
88

@@ -19,7 +19,7 @@ export function TeamHighlightsCard({
1919
selectedChart,
2020
selectedChartQueryParam,
2121
}: {
22-
userStats: WalletUserStats[];
22+
userStats: InAppWalletStats[];
2323
volumeStats: UniversalBridgeStats[];
2424
selectedChart: string | undefined;
2525
selectedChartQueryParam: string;
@@ -32,18 +32,6 @@ export function TeamHighlightsCard({
3232

3333
const chartConfig = {
3434
activeUsers: { color: "hsl(var(--chart-1))", label: "Active Users" },
35-
feesCollected: {
36-
color: "hsl(var(--chart-4))",
37-
emptyContent: (
38-
<EmptyStateContent
39-
description="Your apps haven't collected any fees yet."
40-
link={"https://portal.thirdweb.com/payments"}
41-
metric="Fees"
42-
/>
43-
),
44-
isCurrency: true,
45-
label: "Fee Revenue",
46-
},
4735
newUsers: { color: "hsl(var(--chart-3))", label: "New Users" },
4836
totalVolume: {
4937
color: "hsl(var(--chart-2))",
@@ -57,6 +45,18 @@ export function TeamHighlightsCard({
5745
isCurrency: true,
5846
label: "Total Volume",
5947
},
48+
feesCollected: {
49+
color: "hsl(var(--chart-4))",
50+
emptyContent: (
51+
<EmptyStateContent
52+
description="Your apps haven't collected any fees yet."
53+
link={"https://portal.thirdweb.com/payments"}
54+
metric="Fees"
55+
/>
56+
),
57+
isCurrency: true,
58+
label: "Fee Revenue",
59+
},
6060
} as const;
6161

6262
return (
@@ -96,33 +96,46 @@ type TimeSeriesMetrics = AggregatedMetrics & {
9696
};
9797

9898
function processTimeSeriesData(
99-
userStats: WalletUserStats[],
99+
userStats: InAppWalletStats[],
100100
volumeStats: UniversalBridgeStats[],
101101
): TimeSeriesMetrics[] {
102102
const metrics: TimeSeriesMetrics[] = [];
103+
const dates = [...new Set(userStats.map((a) => a.date))];
104+
105+
for (const date of dates) {
106+
const activeUsers = userStats
107+
.filter(
108+
(u) => new Date(u.date).toISOString() === new Date(date).toISOString(),
109+
)
110+
.reduce((acc, curr) => acc + curr.uniqueWalletsConnected, 0);
111+
112+
const newUsers = userStats
113+
.filter(
114+
(u) => new Date(u.date).toISOString() === new Date(date).toISOString(),
115+
)
116+
.reduce((acc, curr) => acc + curr.newUsers, 0);
103117

104-
for (const stat of userStats) {
105118
const volume = volumeStats
106119
.filter(
107120
(v) =>
108-
new Date(v.date).toISOString() ===
109-
new Date(stat.date).toISOString() && v.status === "completed",
121+
new Date(v.date).toISOString() === new Date(date).toISOString() &&
122+
v.status === "completed",
110123
)
111124
.reduce((acc, curr) => acc + curr.amountUsdCents / 100, 0);
112125

113126
const fees = volumeStats
114127
.filter(
115128
(v) =>
116-
new Date(v.date).toISOString() ===
117-
new Date(stat.date).toISOString() && v.status === "completed",
129+
new Date(v.date).toISOString() === new Date(date).toISOString() &&
130+
v.status === "completed",
118131
)
119132
.reduce((acc, curr) => acc + curr.developerFeeUsdCents / 100, 0);
120133

121134
metrics.push({
122-
activeUsers: stat.totalUsers ?? 0,
123-
date: stat.date,
135+
activeUsers: activeUsers,
136+
date: date,
124137
feesCollected: fees,
125-
newUsers: stat.newUsers ?? 0,
138+
newUsers: newUsers,
126139
totalVolume: volume,
127140
});
128141
}

apps/dashboard/src/app/(app)/team/[team_slug]/(team)/~/analytics/page.tsx

Lines changed: 16 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,6 @@ import {
1313
getUniversalBridgeUsage,
1414
getUserOpUsage,
1515
getWalletConnections,
16-
getWalletUsers,
1716
} from "@/api/analytics";
1817
import { getAuthToken } from "@/api/auth-token";
1918
import { getTeamBySlug } from "@/api/team/get-team";
@@ -193,7 +192,7 @@ async function AsyncTeamHighlightsCard(props: {
193192
}) {
194193
const [walletUserStatsTimeSeries, universalBridgeUsage] =
195194
await Promise.allSettled([
196-
getWalletUsers(
195+
getInAppWalletUsage(
197196
{
198197
from: props.range.from,
199198
period: props.interval,
@@ -216,7 +215,7 @@ async function AsyncTeamHighlightsCard(props: {
216215
if (
217216
walletUserStatsTimeSeries.status === "fulfilled" &&
218217
universalBridgeUsage.status === "fulfilled" &&
219-
walletUserStatsTimeSeries.value.some((w) => w.totalUsers !== 0)
218+
walletUserStatsTimeSeries.value.some((w) => w.uniqueWalletsConnected !== 0)
220219
) {
221220
return (
222221
<TeamHighlightsCard
@@ -255,8 +254,8 @@ async function AsyncWalletDistributionCard(props: {
255254
<WalletDistributionCard data={walletConnections} />
256255
) : (
257256
<EmptyStateCard
258-
link="https://portal.thirdweb.com/wallets"
259-
metric="Wallets"
257+
link="https://portal.thirdweb.com/wallets/external-wallets"
258+
metric="External Wallets"
260259
/>
261260
);
262261
}
@@ -381,19 +380,17 @@ async function AsyncTotalSponsoredCard(props: {
381380

382381
async function WalletDistributionCard({ data }: { data: WalletStats[] }) {
383382
const formattedData = await Promise.all(
384-
data
385-
.filter((w) => w.walletType !== "smart" && w.walletType !== "smartWallet")
386-
.map(async (w) => {
387-
const wallet = await getWalletInfo(w.walletType as WalletId).catch(
388-
() => ({ name: w.walletType }),
389-
);
390-
return {
391-
totalConnections: w.totalConnections,
392-
uniqueWalletsConnected: w.uniqueWalletsConnected,
393-
walletName: wallet.name,
394-
walletType: w.walletType,
395-
};
396-
}),
383+
data.map(async (w) => {
384+
const wallet = await getWalletInfo(w.walletType as WalletId).catch(
385+
() => ({ name: w.walletType }),
386+
);
387+
return {
388+
totalConnections: w.totalConnections,
389+
uniqueWalletsConnected: w.uniqueWalletsConnected,
390+
walletName: wallet.name,
391+
walletType: w.walletType,
392+
};
393+
}),
397394
);
398395

399396
return (
@@ -404,7 +401,7 @@ async function WalletDistributionCard({ data }: { data: WalletStats[] }) {
404401
value: uniqueWalletsConnected,
405402
};
406403
})}
407-
title="Wallets Connected"
404+
title="External Wallets Connected"
408405
/>
409406
);
410407
}

apps/dashboard/src/app/(app)/team/[team_slug]/(team)/~/ecosystem/[slug]/(active)/analytics/components/EcosystemWalletUsersChartCard.stories.tsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@ function ecosystemWalletStatsStub(
5454
date: formattedDate,
5555
ecosystemPartnerId: "123",
5656
uniqueWalletsConnected: Math.floor(Math.random() * 1000) + 1,
57+
newUsers: Math.floor(Math.random() * 100) + 1,
5758
});
5859
}
5960
}

0 commit comments

Comments
 (0)