Skip to content

Commit 6e87a86

Browse files
[Dashboard] Feature: Adds analytics to in-app-wallets page (#5186) (#5227)
Co-authored-by: gregfromstl <gregfromstl@gmail.com>
1 parent 043ee92 commit 6e87a86

File tree

26 files changed

+827
-256
lines changed

26 files changed

+827
-256
lines changed

apps/dashboard/src/@3rdweb-sdk/react/hooks/useApi.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -235,6 +235,12 @@ export interface WalletStats {
235235
walletType: string;
236236
}
237237

238+
export interface InAppWalletStats {
239+
date: string;
240+
authenticationMethod: string;
241+
uniqueWalletsConnected: number;
242+
}
243+
238244
export interface UserOpStats {
239245
date: string;
240246
successful: number;
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
"use client";
2+
import { TabLinks } from "@/components/ui/tabs";
3+
import { usePathname } from "next/navigation";
4+
5+
export function Tabs({ clientId }: { clientId: string }) {
6+
const path = usePathname();
7+
8+
return (
9+
<TabLinks
10+
links={[
11+
{
12+
name: "Analytics",
13+
href: `/dashboard/connect/in-app-wallets/${clientId}/analytics`,
14+
isActive: path?.endsWith("/analytics") || false,
15+
isDisabled: false,
16+
},
17+
{
18+
name: "Users",
19+
href: `/dashboard/connect/in-app-wallets/${clientId}/users`,
20+
isActive: path?.endsWith("/users") || false,
21+
isDisabled: false,
22+
},
23+
{
24+
name: "Configuration",
25+
href: `/dashboard/connect/in-app-wallets/${clientId}/config`,
26+
isActive: path?.endsWith("/config") || false,
27+
isDisabled: false,
28+
},
29+
]}
30+
/>
31+
);
32+
}
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
export const TRACKING_CATEGORY = "embedded-wallet";
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
import type { Range } from "components/analytics/date-range-selector";
2+
import { InAppWalletAnalytics } from "components/embedded-wallets/Analytics";
3+
4+
export default function Page({
5+
params,
6+
searchParams,
7+
}: {
8+
params: { team_slug: string; project_slug: string };
9+
searchParams: {
10+
from?: string;
11+
to?: string;
12+
type?: string;
13+
interval?: string;
14+
};
15+
}) {
16+
const range =
17+
searchParams.from && searchParams.to
18+
? {
19+
type: searchParams.type ?? "last-120",
20+
from: new Date(searchParams.from),
21+
to: new Date(searchParams.to),
22+
}
23+
: undefined;
24+
25+
const interval: "day" | "week" = ["day", "week"].includes(
26+
searchParams.interval ?? "",
27+
)
28+
? (searchParams.interval as "day" | "week")
29+
: "week";
30+
return (
31+
<InAppWalletAnalytics
32+
clientId={params.project_slug}
33+
interval={interval}
34+
range={range as Range}
35+
/>
36+
);
37+
}
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
import { InAppWalletSettingsPage } from "components/embedded-wallets/Configure";
2+
import { redirect } from "next/navigation";
3+
import { getInAppWalletSupportedAPIKeys } from "../../getInAppWalletSupportedAPIKeys";
4+
import { TRACKING_CATEGORY } from "../_constants";
5+
6+
export default async function Page({
7+
params: { clientId },
8+
}: { params: { clientId: string } }) {
9+
const apiKeys = await getInAppWalletSupportedAPIKeys();
10+
const apiKey = apiKeys.find((key) => key.key === clientId);
11+
12+
if (!apiKey) {
13+
redirect("/dashboard/connect/in-app-wallets");
14+
}
15+
return (
16+
<InAppWalletSettingsPage
17+
apiKey={apiKey}
18+
trackingCategory={TRACKING_CATEGORY}
19+
/>
20+
);
21+
}
Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
import { InAppWalletsSummary } from "components/embedded-wallets/Analytics/Summary";
2+
import { getInAppWalletUsage } from "data/analytics/wallets/in-app";
3+
import { redirect } from "next/navigation";
4+
import { getAuthToken } from "../../../../../api/lib/getAuthToken";
5+
import { PageHeader } from "../PageHeader";
6+
import { getInAppWalletSupportedAPIKeys } from "../getInAppWalletSupportedAPIKeys";
7+
import { InAppWalletsAPIKeysMenu } from "../inAppWalletsAPIKeysMenu";
8+
import { Tabs } from "./_components/tabs";
9+
10+
export default async function Page(props: {
11+
params: {
12+
clientId: string;
13+
};
14+
searchParams: {
15+
tab?: string;
16+
};
17+
children: React.ReactNode;
18+
}) {
19+
const authToken = getAuthToken();
20+
const { clientId } = props.params;
21+
22+
if (!authToken) {
23+
redirect(
24+
`/login?next=${encodeURIComponent(`/dashboard/connect/in-app-wallets/${clientId}`)}`,
25+
);
26+
}
27+
28+
const apiKeys = await getInAppWalletSupportedAPIKeys();
29+
const apiKey = apiKeys.find((key) => key.key === clientId);
30+
31+
if (!apiKey) {
32+
redirect("/dashboard/connect/in-app-wallets");
33+
}
34+
35+
const allTimeStats = await getInAppWalletUsage({
36+
clientId,
37+
from: new Date(2022, 0, 1),
38+
to: new Date(),
39+
period: "all",
40+
});
41+
42+
const monthlyStats = await getInAppWalletUsage({
43+
clientId,
44+
from: new Date(new Date().getFullYear(), new Date().getMonth(), 1),
45+
to: new Date(),
46+
period: "month",
47+
});
48+
49+
return (
50+
<div>
51+
{/* header */}
52+
<div className="flex flex-col gap-4 lg:flex-row lg:justify-between">
53+
<PageHeader />
54+
<div>
55+
<InAppWalletsAPIKeysMenu
56+
apiKeys={apiKeys.map((x) => ({
57+
name: x.name,
58+
key: x.key,
59+
}))}
60+
selectedAPIKey={apiKey}
61+
/>
62+
</div>
63+
</div>
64+
65+
<div className="h-8" />
66+
67+
<InAppWalletsSummary
68+
allTimeStats={allTimeStats}
69+
monthlyStats={monthlyStats}
70+
/>
71+
72+
<div className="h-8" />
73+
<Tabs clientId={clientId} />
74+
<div className="h-8" />
75+
{props.children}
76+
</div>
77+
);
78+
}
Lines changed: 1 addition & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,4 @@
11
import { redirect } from "next/navigation";
2-
import { EmbeddedWallets } from "../../../../../../components/embedded-wallets";
3-
import { getAuthToken } from "../../../../../api/lib/getAuthToken";
4-
import { PageHeader } from "../PageHeader";
5-
import { getInAppWalletSupportedAPIKeys } from "../getInAppWalletSupportedAPIKeys";
6-
import { InAppWalletsAPIKeysMenu } from "../inAppWalletsAPIKeysMenu";
72

83
export default async function Page(props: {
94
params: {
@@ -13,44 +8,7 @@ export default async function Page(props: {
138
tab?: string;
149
};
1510
}) {
16-
const authToken = getAuthToken();
1711
const { clientId } = props.params;
1812

19-
if (!authToken) {
20-
redirect(
21-
`/login?next=${encodeURIComponent(`/dashboard/connect/in-app-wallets/${clientId}`)}`,
22-
);
23-
}
24-
25-
const apiKeys = await getInAppWalletSupportedAPIKeys();
26-
const apiKey = apiKeys.find((key) => key.key === clientId);
27-
28-
if (!apiKey) {
29-
redirect("/dashboard/connect/in-app-wallets");
30-
}
31-
32-
return (
33-
<div>
34-
{/* header */}
35-
<div className="flex flex-col gap-4 lg:flex-row lg:justify-between">
36-
<PageHeader />
37-
<div>
38-
<InAppWalletsAPIKeysMenu
39-
apiKeys={apiKeys.map((x) => ({
40-
name: x.name,
41-
key: x.key,
42-
}))}
43-
selectedAPIKey={apiKey}
44-
/>
45-
</div>
46-
</div>
47-
48-
<div className="h-8" />
49-
<EmbeddedWallets
50-
apiKey={apiKey}
51-
trackingCategory="embedded-wallet"
52-
defaultTab={props.searchParams.tab === "1" ? 1 : 0}
53-
/>
54-
</div>
55-
);
13+
redirect(`/dashboard/connect/in-app-wallets/${clientId}/analytics`);
5614
}
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
import { InAppWalletUsersPageContent } from "components/embedded-wallets/Users";
2+
import { redirect } from "next/navigation";
3+
import { getInAppWalletSupportedAPIKeys } from "../../getInAppWalletSupportedAPIKeys";
4+
import { TRACKING_CATEGORY } from "../_constants";
5+
6+
export default async function Page(props: {
7+
params: {
8+
clientId: string;
9+
};
10+
}) {
11+
const { clientId } = props.params;
12+
const apiKeys = await getInAppWalletSupportedAPIKeys();
13+
const apiKey = apiKeys.find((key) => key.key === clientId);
14+
15+
if (!apiKey) {
16+
redirect("/dashboard/connect/in-app-wallets");
17+
}
18+
return (
19+
<InAppWalletUsersPageContent
20+
clientId={apiKey.key}
21+
trackingCategory={TRACKING_CATEGORY}
22+
/>
23+
);
24+
}

apps/dashboard/src/app/(dashboard)/dashboard/connect/in-app-wallets/layout.tsx

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
import { AnalyticsCallout } from "../../../../team/[team_slug]/[project_slug]/connect/in-app-wallets/_components/AnalyticsCallout";
21
import { InAppWaletFooterSection } from "../../../../team/[team_slug]/[project_slug]/connect/in-app-wallets/_components/footer";
32

43
export default function Layout(props: {
@@ -9,7 +8,6 @@ export default function Layout(props: {
98
{props.children}
109
<div className="h-16" />
1110
{/* Footer */}
12-
<AnalyticsCallout trackingCategory="embedded-wallet" />
1311
<div className="h-5" />
1412
<InAppWaletFooterSection trackingCategory="embedded-wallet" />
1513
</div>

apps/dashboard/src/app/team/[team_slug]/[project_slug]/connect/in-app-wallets/_components/AnalyticsCallout.tsx

Lines changed: 0 additions & 79 deletions
This file was deleted.

0 commit comments

Comments
 (0)