Skip to content

Commit 7eaf86a

Browse files
committed
[TOOL-3762] Dashboard: Update In-app wallet analytics page (#6610)
<!-- start pr-codex --> ## PR-Codex overview This PR focuses on refactoring components related to in-app wallets and account abstraction analytics. It introduces new loading states, replaces certain components with `StatCard`, and enhances the handling of asynchronous data fetching. ### Detailed summary - Removed `loading.tsx` files for in-app wallets and account abstraction. - Updated `InAppWalletsHeader` to no longer accept props. - Replaced `Stat` with `StatCard` in `EcosystemWalletsSummary` and `AccountAbstractionSummary`. - Added `isPending` state to `StatCard` for loading indication. - Refactored `InAppWalletsSummary` and `AccountAbstractionSummary` to utilize async data fetching with `Suspense`. - Enhanced `InAppWalletAnalytics` to manage loading states and data fetching more effectively. > ✨ Ask PR-Codex anything about this PR by commenting with `/codex {your question}` <!-- end pr-codex -->
1 parent 5788cbd commit 7eaf86a

File tree

12 files changed

+224
-117
lines changed

12 files changed

+224
-117
lines changed

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

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { Stat } from "components/analytics/stat";
1+
import { StatCard } from "components/analytics/stat";
22
import { ActivityIcon, UserIcon } from "lucide-react";
33
import type { EcosystemWalletStats } from "types/analytics";
44

@@ -28,15 +28,17 @@ export function EcosystemWalletsSummary(props: {
2828

2929
return (
3030
<div className="grid grid-cols-2 gap-4 lg:gap-6">
31-
<Stat
31+
<StatCard
3232
label="Total Users"
3333
value={allTimeStats?.uniqueWalletsConnected || 0}
3434
icon={ActivityIcon}
35+
isPending={false}
3536
/>
36-
<Stat
37+
<StatCard
3738
label="Monthly Active Users"
3839
value={monthlyStats?.uniqueWalletsConnected || 0}
3940
icon={UserIcon}
41+
isPending={false}
4042
/>
4143
</div>
4244
);

apps/dashboard/src/app/team/[team_slug]/[project_slug]/connect/account-abstraction/loading.tsx

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

apps/dashboard/src/app/team/[team_slug]/[project_slug]/connect/account-abstraction/page.tsx

Lines changed: 18 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { getAggregateUserOpUsage, getUserOpUsage } from "@/api/analytics";
1+
import { getUserOpUsage } from "@/api/analytics";
22
import { getProject } from "@/api/projects";
33
import { getTeamBySlug } from "@/api/team";
44
import { getThirdwebClient } from "@/constants/thirdweb.server";
@@ -9,6 +9,7 @@ import {
99
import { AccountAbstractionAnalytics } from "components/smart-wallets/AccountAbstractionAnalytics";
1010
import { notFound, redirect } from "next/navigation";
1111
import type { SearchParams } from "nuqs/server";
12+
import { AccountAbstractionSummary } from "../../../../../../components/smart-wallets/AccountAbstractionAnalytics/AccountAbstractionSummary";
1213
import { getAuthToken } from "../../../../../api/lib/getAuthToken";
1314
import { searchParamLoader } from "./search-params";
1415

@@ -60,32 +61,29 @@ export default async function Page(props: {
6061
type: rangeType,
6162
};
6263

63-
const userOpStatsPromise = getUserOpUsage({
64+
const userOpStats = await getUserOpUsage({
6465
teamId: project.teamId,
6566
projectId: project.id,
6667
from: range.from,
6768
to: range.to,
6869
period: interval,
6970
});
7071

71-
const aggregateUserOpStatsPromise = getAggregateUserOpUsage({
72-
teamId: team.id,
73-
projectId: project.id,
74-
});
75-
76-
const [userOpStats, aggregateUserOpStats] = await Promise.all([
77-
userOpStatsPromise,
78-
aggregateUserOpStatsPromise,
79-
]);
80-
8172
return (
82-
<AccountAbstractionAnalytics
83-
userOpStats={userOpStats}
84-
client={getThirdwebClient(authToken)}
85-
teamId={project.teamId}
86-
projectId={project.id}
87-
teamSlug={params.team_slug}
88-
aggregateUserOpStats={aggregateUserOpStats}
89-
/>
73+
<div>
74+
<AccountAbstractionSummary
75+
teamId={project.teamId}
76+
projectId={project.id}
77+
/>
78+
79+
<div className="h-10" />
80+
<AccountAbstractionAnalytics
81+
userOpStats={userOpStats}
82+
client={getThirdwebClient(authToken)}
83+
teamId={project.teamId}
84+
projectId={project.id}
85+
teamSlug={params.team_slug}
86+
/>
87+
</div>
9088
);
9189
}
Lines changed: 1 addition & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -1,34 +1,7 @@
1-
import { getInAppWalletUsage } from "@/api/analytics";
21
import { TrackedUnderlineLink } from "@/components/ui/tracked-link";
3-
import { InAppWalletsSummary } from "components/embedded-wallets/Analytics/Summary";
4-
import { subDays } from "date-fns";
52
import { TRACKING_CATEGORY } from "../_constants";
63

7-
export async function InAppWalletsHeader({
8-
teamId,
9-
projectId,
10-
}: { teamId: string; projectId: string }) {
11-
const allTimeStatsPromise = getInAppWalletUsage({
12-
teamId,
13-
projectId,
14-
from: new Date(2022, 0, 1),
15-
to: new Date(),
16-
period: "all",
17-
});
18-
19-
const monthlyStatsPromise = getInAppWalletUsage({
20-
teamId,
21-
projectId,
22-
from: subDays(new Date(), 30),
23-
to: new Date(),
24-
period: "month",
25-
});
26-
27-
const [allTimeStats, monthlyStats] = await Promise.all([
28-
allTimeStatsPromise,
29-
monthlyStatsPromise,
30-
]).catch(() => [null, null]);
31-
4+
export async function InAppWalletsHeader() {
325
return (
336
<div>
347
<h1 className="mb-1 font-semibold text-2xl tracking-tight lg:mb-2 lg:text-3xl">
@@ -47,10 +20,6 @@ export async function InAppWalletsHeader({
4720
Learn more
4821
</TrackedUnderlineLink>
4922
</p>
50-
<InAppWalletsSummary
51-
allTimeStats={allTimeStats || []}
52-
monthlyStats={monthlyStats || []}
53-
/>
5423
</div>
5524
);
5625
}

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

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -23,9 +23,7 @@ export default async function Layout(props: {
2323

2424
return (
2525
<div>
26-
<InAppWalletsHeader teamId={project.teamId} projectId={project.id} />
27-
<div className="h-8" />
28-
26+
<InAppWalletsHeader />
2927
<TabPathLinks
3028
links={[
3129
{

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

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

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

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
1+
import { getProject } from "@/api/projects";
12
import type { Range } from "components/analytics/date-range-selector";
23
import { InAppWalletAnalytics } from "components/embedded-wallets/Analytics";
34
import { redirect } from "next/navigation";
4-
import { getProject } from "../../../../../../@/api/projects";
5+
import { InAppWalletsSummary } from "../../../../../../components/embedded-wallets/Analytics/Summary";
56

67
export default async function Page(props: {
78
params: Promise<{ team_slug: string; project_slug: string }>;
@@ -39,11 +40,15 @@ export default async function Page(props: {
3940
}
4041

4142
return (
42-
<InAppWalletAnalytics
43-
teamId={project.teamId}
44-
projectId={project.id}
45-
interval={interval}
46-
range={range as Range}
47-
/>
43+
<div>
44+
<InAppWalletsSummary teamId={project.teamId} projectId={project.id} />
45+
<div className="h-10" />
46+
<InAppWalletAnalytics
47+
teamId={project.teamId}
48+
projectId={project.id}
49+
interval={interval}
50+
range={range as Range}
51+
/>
52+
</div>
4853
);
4954
}

apps/dashboard/src/components/analytics/stat.tsx

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,23 @@
1-
export const Stat: React.FC<{
1+
import { Skeleton } from "../../@/components/ui/skeleton";
2+
3+
export const StatCard: React.FC<{
24
label: string;
35
value?: number;
46
icon: React.FC<{ className?: string }>;
57
formatter?: (value: number) => string;
6-
}> = ({ label, value, formatter, icon: Icon }) => {
8+
isPending: boolean;
9+
}> = ({ label, value, formatter, icon: Icon, isPending }) => {
710
return (
811
<dl className="flex items-center justify-between gap-4 rounded-lg border border-border bg-card p-4 pr-6">
912
<div>
1013
<dd className="mb-0.5 font-semibold text-2xl tracking-tight">
11-
{value !== undefined && formatter
12-
? formatter(value)
13-
: value?.toLocaleString()}
14+
{isPending ? (
15+
<Skeleton className="h-8 w-20" />
16+
) : value !== undefined && formatter ? (
17+
formatter(value)
18+
) : (
19+
value?.toLocaleString()
20+
)}
1421
</dd>
1522
<dt className="text-muted-foreground text-sm">{label}</dt>
1623
</div>

apps/dashboard/src/components/embedded-wallets/Analytics/Summary.tsx

Lines changed: 67 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,14 @@
1-
import { Stat } from "components/analytics/stat";
1+
import { getInAppWalletUsage } from "@/api/analytics";
2+
import { StatCard } from "components/analytics/stat";
3+
import { subDays } from "date-fns";
24
import { ActivityIcon, UserIcon } from "lucide-react";
5+
import { Suspense } from "react";
36
import type { InAppWalletStats } from "types/analytics";
47

5-
export function InAppWalletsSummary(props: {
8+
function InAppWalletsSummaryInner(props: {
69
allTimeStats: InAppWalletStats[] | undefined;
710
monthlyStats: InAppWalletStats[] | undefined;
11+
isPending: boolean;
812
}) {
913
const allTimeStats = props.allTimeStats?.reduce(
1014
(acc, curr) => {
@@ -28,16 +32,75 @@ export function InAppWalletsSummary(props: {
2832

2933
return (
3034
<div className="grid grid-cols-2 gap-4">
31-
<Stat
35+
<StatCard
3236
label="Total Users"
3337
value={allTimeStats?.uniqueWalletsConnected || 0}
3438
icon={ActivityIcon}
39+
isPending={props.isPending}
3540
/>
36-
<Stat
41+
<StatCard
3742
label="Monthly Active Users"
3843
value={monthlyStats?.uniqueWalletsConnected || 0}
3944
icon={UserIcon}
45+
isPending={props.isPending}
4046
/>
4147
</div>
4248
);
4349
}
50+
51+
async function AsyncInAppWalletsSummary(props: {
52+
teamId: string;
53+
projectId: string;
54+
}) {
55+
const { teamId, projectId } = props;
56+
const allTimeStatsPromise = getInAppWalletUsage({
57+
teamId,
58+
projectId,
59+
from: new Date(2022, 0, 1),
60+
to: new Date(),
61+
period: "all",
62+
});
63+
64+
const monthlyStatsPromise = getInAppWalletUsage({
65+
teamId,
66+
projectId,
67+
from: subDays(new Date(), 30),
68+
to: new Date(),
69+
period: "month",
70+
});
71+
72+
const [allTimeStats, monthlyStats] = await Promise.all([
73+
allTimeStatsPromise,
74+
monthlyStatsPromise,
75+
]).catch(() => [null, null]);
76+
77+
return (
78+
<InAppWalletsSummaryInner
79+
allTimeStats={allTimeStats || undefined}
80+
monthlyStats={monthlyStats || undefined}
81+
isPending={false}
82+
/>
83+
);
84+
}
85+
86+
export function InAppWalletsSummary(props: {
87+
teamId: string;
88+
projectId: string;
89+
}) {
90+
return (
91+
<Suspense
92+
fallback={
93+
<InAppWalletsSummaryInner
94+
allTimeStats={undefined}
95+
monthlyStats={undefined}
96+
isPending={true}
97+
/>
98+
}
99+
>
100+
<AsyncInAppWalletsSummary
101+
teamId={props.teamId}
102+
projectId={props.projectId}
103+
/>
104+
</Suspense>
105+
);
106+
}

0 commit comments

Comments
 (0)