Skip to content

Commit cd30ba4

Browse files
[Dashboard] Add partner-based analytics for ecosystem wallet usage (#6717)
1 parent 0ea8987 commit cd30ba4

File tree

6 files changed

+71
-15
lines changed

6 files changed

+71
-15
lines changed

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

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -346,7 +346,7 @@ export async function getEcosystemWalletUsage(args: {
346346
searchParams.append("period", period);
347347
}
348348
const res = await fetchAnalytics(
349-
`v2/wallets/connects/${ecosystemSlug}?${searchParams.toString()}`,
349+
`v2/wallet/connects?${searchParams.toString()}`,
350350
{
351351
method: "GET",
352352
headers: {
@@ -356,7 +356,10 @@ export async function getEcosystemWalletUsage(args: {
356356
);
357357

358358
if (res?.status !== 200) {
359-
console.error("Failed to fetch ecosystem wallet stats");
359+
const reason = await res?.text();
360+
console.error(
361+
`Failed to fetch ecosystem wallet stats: ${res?.status} - ${res.statusText} - ${reason}`,
362+
);
360363
return null;
361364
}
362365

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

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import {
44
getLastNDaysRange,
55
} from "components/analytics/date-range-selector";
66
import { RangeSelector } from "components/analytics/range-selector";
7+
import type { Partner } from "../../../../types";
78
import { EcosystemWalletUsersChartCard } from "./EcosystemWalletUsersChartCard";
89
import { EcosystemWalletsSummary } from "./Summary";
910

@@ -12,11 +13,13 @@ export async function EcosystemAnalyticsPage({
1213
teamId,
1314
interval,
1415
range,
16+
partners,
1517
}: {
1618
ecosystemSlug: string;
1719
teamId: string;
1820
interval: "day" | "week";
1921
range?: Range;
22+
partners: Partner[];
2023
}) {
2124
if (!range) {
2225
range = getLastNDaysRange("last-120");
@@ -69,6 +72,14 @@ export async function EcosystemAnalyticsPage({
6972
<EcosystemWalletUsersChartCard
7073
ecosystemWalletStats={stats || []}
7174
isPending={false}
75+
groupBy="authenticationMethod"
76+
partners={partners}
77+
/>
78+
<EcosystemWalletUsersChartCard
79+
ecosystemWalletStats={stats || []}
80+
isPending={false}
81+
groupBy="ecosystemPartnerId"
82+
partners={partners}
7283
/>
7384
</div>
7485
</div>

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

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@ function ecosystemWalletStatsStub(
5353
date: formattedDate,
5454
authenticationMethod: authMethod || "MetaMask",
5555
uniqueWalletsConnected: Math.floor(Math.random() * 1000) + 1,
56+
ecosystemPartnerId: "123",
5657
});
5758
}
5859
}
@@ -65,6 +66,7 @@ export const EmptyData: Story = {
6566
args: {
6667
ecosystemWalletStats: [],
6768
isPending: false,
69+
groupBy: "authenticationMethod",
6870
},
6971
};
7072

@@ -73,6 +75,7 @@ export const Loading: Story = {
7375
args: {
7476
ecosystemWalletStats: [],
7577
isPending: true,
78+
groupBy: "authenticationMethod",
7679
},
7780
};
7881

@@ -81,6 +84,7 @@ export const ThirtyDaysData: Story = {
8184
args: {
8285
ecosystemWalletStats: ecosystemWalletStatsStub(30),
8386
isPending: false,
87+
groupBy: "authenticationMethod",
8488
},
8589
};
8690

@@ -89,6 +93,7 @@ export const SixtyDaysData: Story = {
8993
args: {
9094
ecosystemWalletStats: ecosystemWalletStatsStub(60),
9195
isPending: false,
96+
groupBy: "authenticationMethod",
9297
},
9398
};
9499

@@ -97,6 +102,7 @@ export const OneHundredTwentyDaysData: Story = {
97102
args: {
98103
ecosystemWalletStats: ecosystemWalletStatsStub(120),
99104
isPending: false,
105+
groupBy: "authenticationMethod",
100106
},
101107
};
102108

@@ -114,6 +120,7 @@ export const ManyAuthMethods: Story = {
114120
}));
115121
})(),
116122
isPending: false,
123+
groupBy: "authenticationMethod",
117124
},
118125
};
119126

@@ -125,5 +132,6 @@ export const ZeroValues: Story = {
125132
uniqueWalletsConnected: 0,
126133
})),
127134
isPending: false,
135+
groupBy: "authenticationMethod",
128136
},
129137
};

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

Lines changed: 36 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import { formatDate } from "date-fns";
1010
import { useMemo } from "react";
1111
import type { EcosystemWalletStats } from "types/analytics";
1212
import { formatTickerNumber } from "../../../../../../../../../../lib/format-utils";
13+
import type { Partner } from "../../../../types";
1314

1415
type ChartData = Record<string, number> & {
1516
time: string; // human readable date
@@ -19,8 +20,10 @@ const defaultLabel = "Unknown Auth";
1920
export function EcosystemWalletUsersChartCard(props: {
2021
ecosystemWalletStats: EcosystemWalletStats[];
2122
isPending: boolean;
23+
groupBy: "ecosystemPartnerId" | "authenticationMethod";
24+
partners?: Partner[];
2225
}) {
23-
const { ecosystemWalletStats } = props;
26+
const { ecosystemWalletStats, groupBy, partners } = props;
2427

2528
const topChainsToShow = 10;
2629

@@ -31,25 +34,40 @@ export function EcosystemWalletUsersChartCard(props: {
3134
// for each stat, add it in _chartDataMap
3235
for (const stat of ecosystemWalletStats) {
3336
const chartData = _chartDataMap.get(stat.date);
34-
const { authenticationMethod } = stat;
37+
const { authenticationMethod, ecosystemPartnerId } = stat;
3538

3639
// if no data for current day - create new entry
3740
if (!chartData) {
3841
_chartDataMap.set(stat.date, {
3942
time: stat.date,
40-
[authenticationMethod || defaultLabel]: stat.uniqueWalletsConnected,
43+
[groupBy === "ecosystemPartnerId"
44+
? ecosystemPartnerId
45+
: authenticationMethod || defaultLabel]:
46+
stat.uniqueWalletsConnected,
4147
} as ChartData);
4248
} else if (chartData) {
43-
chartData[authenticationMethod || defaultLabel] =
44-
(chartData[authenticationMethod || defaultLabel] || 0) +
45-
stat.uniqueWalletsConnected;
49+
chartData[
50+
groupBy === "ecosystemPartnerId"
51+
? ecosystemPartnerId
52+
: authenticationMethod || defaultLabel
53+
] =
54+
(chartData[
55+
groupBy === "ecosystemPartnerId"
56+
? ecosystemPartnerId
57+
: authenticationMethod || defaultLabel
58+
] || 0) + stat.uniqueWalletsConnected;
4659
}
4760

4861
authMethodToVolumeMap.set(
49-
authenticationMethod || defaultLabel,
62+
groupBy === "ecosystemPartnerId"
63+
? ecosystemPartnerId
64+
: authenticationMethod || defaultLabel,
5065
stat.uniqueWalletsConnected +
51-
(authMethodToVolumeMap.get(authenticationMethod || defaultLabel) ||
52-
0),
66+
(authMethodToVolumeMap.get(
67+
groupBy === "ecosystemPartnerId"
68+
? ecosystemPartnerId
69+
: authenticationMethod || defaultLabel,
70+
) || 0),
5371
);
5472
}
5573

@@ -72,7 +90,12 @@ export function EcosystemWalletUsersChartCard(props: {
7290

7391
authMethodsToShow.forEach((walletType, i) => {
7492
_chartConfig[walletType] = {
75-
label: authMethodsToShow[i],
93+
label:
94+
groupBy === "ecosystemPartnerId"
95+
? partners?.find((p) => p.id === walletType)?.name ||
96+
authMethodsToShow[i] ||
97+
"none"
98+
: authMethodsToShow[i],
7699
color: `hsl(var(--chart-${(i % 10) + 1}))`,
77100
};
78101
});
@@ -92,7 +115,7 @@ export function EcosystemWalletUsersChartCard(props: {
92115
),
93116
chartConfig: _chartConfig,
94117
};
95-
}, [ecosystemWalletStats]);
118+
}, [ecosystemWalletStats, groupBy, partners]);
96119

97120
const uniqueAuthMethods = Object.keys(chartConfig);
98121
const disableActions =
@@ -108,7 +131,8 @@ export function EcosystemWalletUsersChartCard(props: {
108131
customHeader={
109132
<div className="relative px-6 pt-6">
110133
<h3 className="mb-1 font-semibold text-xl tracking-tight md:text-2xl">
111-
Unique Users
134+
Unique Users by{" "}
135+
{groupBy === "ecosystemPartnerId" ? "Partner" : "Auth Method"}
112136
</h3>
113137
<p className="mb-3 text-muted-foreground text-sm">
114138
The total number of active users in your ecosystem for each period.

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

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import { redirect } from "next/navigation";
22
import { getTeamBySlug } from "../../../../../../../../../@/api/team";
33
import { getAuthToken } from "../../../../../../../../api/lib/getAuthToken";
44
import { fetchEcosystem } from "../../../utils/fetchEcosystem";
5+
import { fetchPartners } from "../configuration/hooks/fetchPartners";
56
import { EcosystemAnalyticsPage } from "./components/EcosystemAnalyticsPage";
67

78
export default async function Page(props: {
@@ -40,11 +41,18 @@ export default async function Page(props: {
4041
redirect("/team");
4142
}
4243

44+
const partners = await fetchPartners({
45+
ecosystem,
46+
authToken,
47+
teamId: team.id,
48+
});
49+
4350
return (
4451
<EcosystemAnalyticsPage
4552
ecosystemSlug={ecosystem.slug}
4653
teamId={team.id}
4754
interval={searchParams.interval || "week"}
55+
partners={partners}
4856
range={
4957
searchParams.from && searchParams.to
5058
? {

apps/dashboard/src/types/analytics.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,9 @@ export interface InAppWalletStats {
1818
uniqueWalletsConnected: number;
1919
}
2020

21-
export interface EcosystemWalletStats extends InAppWalletStats {}
21+
export interface EcosystemWalletStats extends InAppWalletStats {
22+
ecosystemPartnerId: string;
23+
}
2224

2325
export interface UserOpStats {
2426
date: string;

0 commit comments

Comments
 (0)