Skip to content

Commit 5612542

Browse files
authored
migrate analytics params from clientId/accountId to teamId/projectId (#6331)
1 parent 1fa36c1 commit 5612542

File tree

13 files changed

+201
-230
lines changed

13 files changed

+201
-230
lines changed

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

Lines changed: 152 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -1,34 +1,72 @@
1-
import { fetchAnalytics } from "data/analytics/fetch-analytics";
1+
import "server-only";
2+
23
import type {
34
AnalyticsQueryParams,
4-
AnalyticsQueryParamsV2,
5+
EcosystemWalletStats,
56
InAppWalletStats,
67
RpcMethodStats,
78
TransactionStats,
89
UserOpStats,
910
WalletStats,
1011
WalletUserStats,
1112
} from "types/analytics";
13+
import { getAuthToken } from "../../app/api/lib/getAuthToken";
1214
import { getChains } from "./chain";
1315

14-
function buildSearchParams(
15-
params: AnalyticsQueryParams | AnalyticsQueryParamsV2,
16-
): URLSearchParams {
17-
const searchParams = new URLSearchParams();
16+
async function fetchAnalytics(
17+
input: string | URL,
18+
init?: RequestInit,
19+
): Promise<Response> {
20+
const token = await getAuthToken();
1821

19-
// v1 params
20-
if ("clientId" in params && params.clientId) {
21-
searchParams.append("clientId", params.clientId);
22+
if (!token) {
23+
throw new Error("You are not authorized to perform this action");
2224
}
23-
if ("accountId" in params && params.accountId) {
24-
searchParams.append("accountId", params.accountId);
25+
26+
const [pathname, searchParams] = input.toString().split("?");
27+
if (!pathname) {
28+
throw new Error("Invalid input, no pathname provided");
2529
}
2630

27-
// v2 params
28-
if ("teamId" in params && params.teamId) {
29-
searchParams.append("teamId", params.teamId);
31+
// create a new URL object for the analytics server
32+
const ANALYTICS_SERVICE_URL = new URL(
33+
process.env.ANALYTICS_SERVICE_URL || "https://analytics.thirdweb.com",
34+
);
35+
ANALYTICS_SERVICE_URL.pathname = pathname;
36+
for (const param of searchParams?.split("&") || []) {
37+
const [key, value] = param.split("=");
38+
if (!key || !value) {
39+
throw new Error("Invalid input, no key or value provided");
40+
}
41+
ANALYTICS_SERVICE_URL.searchParams.append(
42+
decodeURIComponent(key),
43+
decodeURIComponent(value),
44+
);
3045
}
31-
if ("projectId" in params && params.projectId) {
46+
// client id DEBUG OVERRIDE
47+
// ANALYTICS_SERVICE_URL.searchParams.delete("clientId");
48+
// ANALYTICS_SERVICE_URL.searchParams.delete("accountId");
49+
// ANALYTICS_SERVICE_URL.searchParams.append(
50+
// "clientId",
51+
// "...",
52+
// );
53+
54+
return fetch(ANALYTICS_SERVICE_URL, {
55+
...init,
56+
headers: {
57+
"content-type": "application/json",
58+
...init?.headers,
59+
authorization: `Bearer ${token}`,
60+
},
61+
});
62+
}
63+
64+
function buildSearchParams(params: AnalyticsQueryParams): URLSearchParams {
65+
const searchParams = new URLSearchParams();
66+
67+
searchParams.append("teamId", params.teamId);
68+
69+
if (params.projectId) {
3270
searchParams.append("projectId", params.projectId);
3371
}
3472

@@ -46,7 +84,7 @@ function buildSearchParams(
4684
}
4785

4886
export async function getWalletConnections(
49-
params: AnalyticsQueryParamsV2,
87+
params: AnalyticsQueryParams,
5088
): Promise<WalletStats[]> {
5189
const searchParams = buildSearchParams(params);
5290
const res = await fetchAnalytics(
@@ -70,7 +108,7 @@ export async function getWalletConnections(
70108
}
71109

72110
export async function getInAppWalletUsage(
73-
params: AnalyticsQueryParamsV2,
111+
params: AnalyticsQueryParams,
74112
): Promise<InAppWalletStats[]> {
75113
const searchParams = buildSearchParams(params);
76114
const res = await fetchAnalytics(
@@ -94,7 +132,7 @@ export async function getInAppWalletUsage(
94132
}
95133

96134
export async function getUserOpUsage(
97-
params: AnalyticsQueryParamsV2,
135+
params: AnalyticsQueryParams,
98136
): Promise<UserOpStats[]> {
99137
const searchParams = buildSearchParams(params);
100138
const res = await fetchAnalytics(
@@ -118,7 +156,7 @@ export async function getUserOpUsage(
118156
}
119157

120158
export async function getAggregateUserOpUsage(
121-
params: Omit<AnalyticsQueryParamsV2, "period">,
159+
params: Omit<AnalyticsQueryParams, "period">,
122160
): Promise<UserOpStats> {
123161
const [userOpStats, chains] = await Promise.all([
124162
getUserOpUsage({ ...params, period: "all" }),
@@ -152,7 +190,7 @@ export async function getAggregateUserOpUsage(
152190
}
153191

154192
export async function getClientTransactions(
155-
params: AnalyticsQueryParamsV2,
193+
params: AnalyticsQueryParams,
156194
): Promise<TransactionStats[]> {
157195
const searchParams = buildSearchParams(params);
158196
const res = await fetchAnalytics(
@@ -180,7 +218,7 @@ export async function getRpcMethodUsage(
180218
): Promise<RpcMethodStats[]> {
181219
const searchParams = buildSearchParams(params);
182220
const res = await fetchAnalytics(
183-
`v1/rpc/evm-methods?${searchParams.toString()}`,
221+
`v2/rpc/evm-methods?${searchParams.toString()}`,
184222
{
185223
method: "GET",
186224
headers: { "Content-Type": "application/json" },
@@ -201,7 +239,7 @@ export async function getWalletUsers(
201239
): Promise<WalletUserStats[]> {
202240
const searchParams = buildSearchParams(params);
203241
const res = await fetchAnalytics(
204-
`v1/wallets/users?${searchParams.toString()}`,
242+
`v2/wallet-connects/users?${searchParams.toString()}`,
205243
{
206244
method: "GET",
207245
headers: { "Content-Type": "application/json" },
@@ -220,23 +258,108 @@ export async function getWalletUsers(
220258
return json.data as WalletUserStats[];
221259
}
222260

261+
type ActiveStatus = {
262+
bundler: boolean;
263+
storage: boolean;
264+
rpc: boolean;
265+
nebula: boolean;
266+
sdk: boolean;
267+
insight: boolean;
268+
pay: boolean;
269+
inAppWallet: boolean;
270+
ecosystemWallet: boolean;
271+
};
272+
223273
export async function isProjectActive(
224274
params: AnalyticsQueryParams,
225-
): Promise<boolean> {
275+
): Promise<ActiveStatus> {
226276
const searchParams = buildSearchParams(params);
227-
const res = await fetchAnalytics(`v1/active?${searchParams.toString()}`, {
228-
method: "GET",
229-
headers: { "Content-Type": "application/json" },
230-
});
277+
const res = await fetchAnalytics(
278+
`v2/active-usage?${searchParams.toString()}`,
279+
{
280+
method: "GET",
281+
headers: { "Content-Type": "application/json" },
282+
},
283+
);
231284

232285
if (res?.status !== 200) {
233286
const reason = await res?.text();
234287
console.error(
235288
`Failed to fetch project active status: ${res?.status} - ${res.statusText} - ${reason}`,
236289
);
237-
return false;
290+
return {
291+
bundler: false,
292+
storage: false,
293+
rpc: false,
294+
nebula: false,
295+
sdk: false,
296+
insight: false,
297+
pay: false,
298+
inAppWallet: false,
299+
ecosystemWallet: false,
300+
} as ActiveStatus;
238301
}
239302

240303
const json = await res.json();
241-
return json.data.isActive as boolean;
304+
return json.data as ActiveStatus;
305+
}
306+
307+
export async function getEcosystemWalletUsage(args: {
308+
teamId: string;
309+
ecosystemSlug: string;
310+
ecosystemPartnerId?: string;
311+
projectId?: string;
312+
from?: Date;
313+
to?: Date;
314+
period?: "day" | "week" | "month" | "year" | "all";
315+
}) {
316+
const {
317+
ecosystemSlug,
318+
ecosystemPartnerId,
319+
teamId,
320+
projectId,
321+
from,
322+
to,
323+
period,
324+
} = args;
325+
326+
const searchParams = new URLSearchParams();
327+
// required params
328+
searchParams.append("ecosystemSlug", ecosystemSlug);
329+
searchParams.append("teamId", teamId);
330+
331+
// optional params
332+
if (ecosystemPartnerId) {
333+
searchParams.append("ecosystemPartnerId", ecosystemPartnerId);
334+
}
335+
if (projectId) {
336+
searchParams.append("projectId", projectId);
337+
}
338+
if (from) {
339+
searchParams.append("from", from.toISOString());
340+
}
341+
if (to) {
342+
searchParams.append("to", to.toISOString());
343+
}
344+
if (period) {
345+
searchParams.append("period", period);
346+
}
347+
const res = await fetchAnalytics(
348+
`v2/wallets/connects/${ecosystemSlug}?${searchParams.toString()}`,
349+
{
350+
method: "GET",
351+
headers: {
352+
"Content-Type": "application/json",
353+
},
354+
},
355+
);
356+
357+
if (res?.status !== 200) {
358+
console.error("Failed to fetch ecosystem wallet stats");
359+
return null;
360+
}
361+
362+
const json = await res.json();
363+
364+
return json.data as EcosystemWalletStats[];
242365
}

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

Lines changed: 8 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -5,30 +5,25 @@ import {
55
getWalletConnections,
66
getWalletUsers,
77
} from "@/api/analytics";
8-
import { redirect } from "next/navigation";
9-
10-
import type {
11-
InAppWalletStats,
12-
WalletStats,
13-
WalletUserStats,
14-
} from "types/analytics";
15-
168
import {
179
type DurationId,
1810
type Range,
1911
getLastNDaysRange,
2012
} from "components/analytics/date-range-selector";
21-
13+
import { redirect } from "next/navigation";
2214
import { type WalletId, getWalletInfo } from "thirdweb/wallets";
15+
import type {
16+
InAppWalletStats,
17+
WalletStats,
18+
WalletUserStats,
19+
} from "types/analytics";
2320
import { AnalyticsHeader } from "../../../../components/Analytics/AnalyticsHeader";
2421
import { CombinedBarChartCard } from "../../../../components/Analytics/CombinedBarChartCard";
2522
import { EmptyState } from "../../../../components/Analytics/EmptyState";
2623
import { PieChartCard } from "../../../../components/Analytics/PieChartCard";
2724

2825
import { getTeamBySlug } from "@/api/team";
2926
import { GenericLoadingPage } from "@/components/blocks/skeletons/GenericLoadingPage";
30-
import type { Account } from "@3rdweb-sdk/react/hooks/useApi";
31-
import { getValidAccount } from "app/account/settings/getAccount";
3227
import { EmptyStateCard } from "app/team/components/Analytics/EmptyStateCard";
3328
import { Suspense } from "react";
3429
import { TotalSponsoredChartCardUI } from "../../_components/TotalSponsoredCard";
@@ -51,7 +46,6 @@ export default async function TeamOverviewPage(props: {
5146
props.searchParams,
5247
]);
5348

54-
const account = await getValidAccount(`/team/${params.team_slug}`);
5549
const team = await getTeamBySlug(params.team_slug);
5650

5751
if (!team) {
@@ -75,7 +69,6 @@ export default async function TeamOverviewPage(props: {
7569
<Suspense fallback={<GenericLoadingPage />}>
7670
<OverviewPageContent
7771
teamId={team.id}
78-
account={account}
7972
range={range}
8073
interval={interval}
8174
searchParams={searchParams}
@@ -88,12 +81,11 @@ export default async function TeamOverviewPage(props: {
8881

8982
async function OverviewPageContent(props: {
9083
teamId: string;
91-
account: Account;
9284
range: Range;
9385
interval: "day" | "week";
9486
searchParams: SearchParams;
9587
}) {
96-
const { teamId, account, range, interval, searchParams } = props;
88+
const { teamId, range, interval, searchParams } = props;
9789

9890
const [
9991
walletConnections,
@@ -113,7 +105,7 @@ async function OverviewPageContent(props: {
113105
}),
114106
// Time series data for wallet users
115107
getWalletUsers({
116-
accountId: account.id,
108+
teamId: teamId,
117109
from: range.from,
118110
to: range.to,
119111
period: interval,

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
1+
import { getEcosystemWalletUsage } from "@/api/analytics";
12
import {
23
type Range,
34
getLastNDaysRange,
45
} from "components/analytics/date-range-selector";
56
import { RangeSelector } from "components/analytics/range-selector";
6-
import { getEcosystemWalletUsage } from "data/analytics/wallets/ecosystem";
77
import { EcosystemWalletUsersChartCard } from "./EcosystemWalletUsersChartCard";
88
import { EcosystemWalletsSummary } from "./Summary";
99

apps/dashboard/src/app/team/[team_slug]/[project_slug]/components/Transactions/index.tsx

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
11
import { LoadingChartState } from "components/analytics/empty-chart-state";
22
import { Suspense } from "react";
3-
import type { AnalyticsQueryParamsV2 } from "types/analytics";
3+
import type { AnalyticsQueryParams } from "types/analytics";
44
import { getClientTransactions } from "../../../../../../@/api/analytics";
55
import { TransactionsChartsUI } from "./TransactionCharts";
66

77
export function TransactionsCharts(
8-
props: AnalyticsQueryParamsV2 & {
8+
props: AnalyticsQueryParams & {
99
searchParams: { [key: string]: string | string[] | undefined };
1010
},
1111
) {
@@ -24,7 +24,7 @@ export function TransactionsCharts(
2424
}
2525

2626
async function TransactionsChartCardAsync(
27-
props: AnalyticsQueryParamsV2 & {
27+
props: AnalyticsQueryParams & {
2828
searchParams: { [key: string]: string | string[] | undefined };
2929
},
3030
) {

0 commit comments

Comments
 (0)