Skip to content

Commit 58ab8c2

Browse files
committed
[TOOL-3766] Dashboard: Account Abstraction page updates (#6609)
<!-- start pr-codex --> ## PR-Codex overview This PR focuses on improving the UI and functionality of various components in the dashboard by modifying styles, enhancing layout elements, and integrating new features related to account abstraction and user operation statistics. ### Detailed summary - Removed `lg:gap-6` from grid classes in multiple components. - Increased header sizes from `text-lg` to `text-xl` in `SponsoredTransactionsTableUI.tsx`. - Adjusted margins and padding for improved spacing in various components. - Added new `GasCreditAlert` component for displaying gas credit information. - Integrated `AccountAbstractionSummary` into `AccountAbstractionAnalytics`. - Updated `userOpStats` handling in `Page` component to use promises for better performance. - Replaced certain text with more concise phrasing in descriptions. - Removed unused imports and optimized component structure for clarity. > ✨ Ask PR-Codex anything about this PR by commenting with `/codex {your question}` <!-- end pr-codex -->
1 parent 447a519 commit 58ab8c2

File tree

16 files changed

+133
-123
lines changed

16 files changed

+133
-123
lines changed

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -88,10 +88,10 @@ export async function TotalSponsoredChartCardUI({
8888
const filteredData = timeSeriesData.filter((d) => d.mainnet > 0);
8989
return (
9090
<div className={cn("rounded-lg border p-4 lg:p-6", className)}>
91-
<h3 className="mb-1 font-semibold text-xl tracking-tight">
91+
<h3 className="mb-0.5 font-semibold text-xl tracking-tight">
9292
{title || "Total Sponsored"}
9393
</h3>
94-
<p className="text-muted-foreground"> {description}</p>
94+
<p className="text-muted-foreground text-sm"> {description}</p>
9595
<BarChart
9696
isCurrency
9797
chartConfig={chartConfig}

apps/dashboard/src/app/team/[team_slug]/(team)/~/settings/billing/components/PlanInfoCard.tsx

Lines changed: 2 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@ import { BillingPortalButton } from "@/components/billing";
55
import { Badge } from "@/components/ui/badge";
66
import { Button } from "@/components/ui/button";
77
import { Separator } from "@/components/ui/separator";
8-
import { TrackedLinkTW } from "@/components/ui/tracked-link";
98
import { differenceInDays, isAfter } from "date-fns";
109
import { format } from "date-fns/format";
1110
import { CircleAlertIcon } from "lucide-react";
@@ -37,7 +36,7 @@ export function PlanInfoCard(props: {
3736
<div className="rounded-lg border border-border bg-card">
3837
<div className="flex flex-col gap-4 p-4 lg:flex-row lg:items-center lg:justify-between lg:p-6">
3938
<div>
40-
<div className="flex flex-col items-start gap-1">
39+
<div className="flex flex-col items-start gap-0.5">
4140
<h3 className="font-semibold text-2xl capitalize tracking-tight">
4241
{validPlan} Plan
4342
</h3>
@@ -56,6 +55,7 @@ export function PlanInfoCard(props: {
5655

5756
<div className="flex flex-row items-center gap-2">
5857
{/* go to invoices page */}
58+
5959
<Button asChild variant="outline">
6060
<Link href={`/team/${team.slug}/~/settings/invoices`}>
6161
View Invoices
@@ -73,20 +73,6 @@ export function PlanInfoCard(props: {
7373
>
7474
Manage Billing
7575
</BillingPortalButton>
76-
77-
{isActualFreePlan && (
78-
<Button asChild variant="outline">
79-
<TrackedLinkTW
80-
category="account"
81-
href="/pricing"
82-
label="pricing-plans"
83-
target="_blank"
84-
className="inline-flex items-center gap-2 text-muted-foreground hover:text-foreground"
85-
>
86-
View Pricing
87-
</TrackedLinkTW>
88-
</Button>
89-
)}
9076
</div>
9177
</div>
9278

apps/dashboard/src/app/team/[team_slug]/(team)/~/usage/overview/components/SponsoredTransactionsTableUI.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,7 @@ export function SponsoredTransactionsTableUI(
7373
<div className="overflow-hidden rounded-lg border bg-card">
7474
{/* header */}
7575
<div className="flex flex-col justify-between gap-3 border-b px-4 py-4 lg:flex-row lg:items-center lg:px-6">
76-
<h2 className="font-semibold text-lg">Sponsored Transactions</h2>
76+
<h2 className="font-semibold text-xl">Sponsored Transactions</h2>
7777
<div className="flex flex-col gap-3 lg:flex-row lg:items-center">
7878
{/* Filters */}
7979
<div className="flex gap-2">

apps/dashboard/src/app/team/[team_slug]/(team)/~/usage/overview/components/UsageCard.tsx

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -23,13 +23,13 @@ export const UsageCard: React.FC<UsageCardProps> = ({
2323
totalUsage,
2424
}) => {
2525
return (
26-
<div className="relative flex min-h-[190px] flex-col rounded-lg border border-border bg-card p-4 lg:p-6">
27-
<h3 className="mb-1 font-semibold text-xl tracking-tight">{name}</h3>
28-
<p className="text-muted-foreground"> {description}</p>
26+
<div className="relative flex flex-col rounded-lg border border-border bg-card p-4 lg:p-6">
27+
<h3 className="mb-0.5 font-semibold text-xl tracking-tight">{name}</h3>
28+
<p className="text-muted-foreground text-sm"> {description}</p>
2929

3030
<div className="h-6" />
3131

32-
<div className="mt-auto flex flex-col gap-1.5">
32+
<div className="flex flex-col gap-1 text-sm">
3333
{title && <p className="text-foreground">{title}</p>}
3434

3535
{total !== undefined && (

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

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -34,12 +34,12 @@ function FooterCard(props: {
3434
trackingCategory: string;
3535
}) {
3636
return (
37-
<div className="rounded-lg border border-border bg-card p-4 lg:p-6">
38-
<h3 className="mb-5 font-semibold text-lg tracking-tight lg:text-xl">
37+
<div className="rounded-lg border border-border bg-card p-4">
38+
<h3 className="mb-4 border-border border-b pt-1 pb-4 font-semibold text-lg leading-none tracking-tight">
3939
{props.title}
4040
</h3>
4141

42-
<div className="flex flex-col gap-2">
42+
<div className="flex flex-col gap-2.5">
4343
{props.links.map((link) => (
4444
<TrackedLinkTW
4545
key={link.href}
Lines changed: 73 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -1,75 +1,54 @@
11
"use client";
22

3-
import { Alert, AlertDescription, AlertTitle } from "@/components/ui/alert";
3+
import { Button } from "@/components/ui/button";
44
import { TabPathLinks } from "@/components/ui/tabs";
5-
import { TrackedUnderlineLink } from "@/components/ui/tracked-link";
5+
import {
6+
TrackedLinkTW,
7+
TrackedUnderlineLink,
8+
} from "@/components/ui/tracked-link";
69
import { SmartWalletsBillingAlert } from "components/settings/ApiKeys/Alerts";
7-
import { CircleAlertIcon } from "lucide-react";
8-
import { useActiveWalletChain } from "thirdweb/react";
9-
import type { UserOpStats } from "types/analytics";
10-
import { AccountAbstractionSummary } from "../../../../../../components/smart-wallets/AccountAbstractionAnalytics/AccountAbstractionSummary";
10+
import { useLocalStorage } from "hooks/useLocalStorage";
11+
import { ArrowRightIcon } from "lucide-react";
12+
import { XIcon } from "lucide-react";
1113
import { AAFooterSection } from "./AAFooterSection";
12-
import { isOpChainId } from "./isOpChain";
1314

1415
const TRACKING_CATEGORY = "smart-wallet";
1516

1617
export function AccountAbstractionLayout(props: {
1718
projectSlug: string;
19+
projectId: string;
1820
teamSlug: string;
1921
projectKey: string;
2022
children: React.ReactNode;
2123
hasSmartWalletsWithoutBilling: boolean;
22-
userOpStats: UserOpStats;
2324
}) {
24-
const chain = useActiveWalletChain();
25-
26-
const isOpChain = chain?.id ? isOpChainId(chain.id) : false;
27-
2825
const smartWalletsLayoutSlug = `/team/${props.teamSlug}/${props.projectSlug}/connect/account-abstraction`;
2926

3027
return (
3128
<div>
32-
<h1 className="mb-1 font-semibold text-2xl tracking-tight lg:mb-2 lg:text-3xl">
29+
<h1 className="mb-1 font-semibold text-2xl tracking-tight lg:text-3xl">
3330
Account Abstraction
3431
</h1>
3532
<p className="text-muted-foreground text-sm">
36-
Easily integrate Account abstraction (ERC-4337) compliant smart accounts
37-
into your apps.{" "}
33+
Integrate ERC-4337 compliant smart accounts for gasless sponsorships and
34+
more. <br className="lg:hidden" />
3835
<TrackedUnderlineLink
3936
target="_blank"
4037
label="docs-wallets"
4138
category={TRACKING_CATEGORY}
4239
href="https://portal.thirdweb.com/wallets/smart-wallet"
4340
>
44-
View Documentation
41+
Learn more about Account Abstraction
4542
</TrackedUnderlineLink>
4643
</p>
44+
4745
<div className="h-6" />
46+
4847
<div className="flex flex-col gap-6">
49-
{props.hasSmartWalletsWithoutBilling ? (
50-
<SmartWalletsBillingAlert />
51-
) : (
52-
isOpChain && (
53-
<Alert variant="info">
54-
<CircleAlertIcon className="size-4" />
55-
<AlertTitle>
56-
Using the gas credits for OP chain paymaster
57-
</AlertTitle>
58-
<AlertDescription>
59-
Credits will automatically be applied to cover gas fees for any
60-
onchain activity across thirdweb services. <br />
61-
Eligible chains: OP Mainnet, Base, Zora, Frax, Mode.
62-
</AlertDescription>
63-
</Alert>
64-
)
65-
)}
48+
{props.hasSmartWalletsWithoutBilling && <SmartWalletsBillingAlert />}
49+
<GasCreditAlert teamSlug={props.teamSlug} projectId={props.projectId} />
6650

6751
<div>
68-
<AccountAbstractionSummary
69-
aggregateUserOpUsageQuery={props.userOpStats}
70-
/>
71-
72-
<div className="h-12" />
7352
<TabPathLinks
7453
links={[
7554
{
@@ -93,8 +72,64 @@ export function AccountAbstractionLayout(props: {
9372
{props.children}
9473
</div>
9574
</div>
75+
9676
<div className="h-14" />
77+
9778
<AAFooterSection trackingCategory={TRACKING_CATEGORY} />
9879
</div>
9980
);
10081
}
82+
83+
function GasCreditAlert(props: {
84+
teamSlug: string;
85+
projectId: string;
86+
}) {
87+
const [isVisible, setIsVisible] = useLocalStorage(
88+
`gas-credit-${props.projectId}`,
89+
true,
90+
false,
91+
);
92+
93+
if (!isVisible) return null;
94+
95+
return (
96+
<div className="relative rounded-lg border border-border bg-card p-4">
97+
<Button
98+
onClick={() => setIsVisible(false)}
99+
className="absolute top-4 right-4 h-auto w-auto p-1 text-muted-foreground"
100+
aria-label="Close alert"
101+
variant="ghost"
102+
>
103+
<XIcon className="size-5" />
104+
</Button>
105+
<div>
106+
<h2 className="mb-0.5 font-semibold">OP Gas Credit Program</h2>
107+
<p className="text-muted-foreground text-sm">
108+
Redeem credits towards gas Sponsorship. <br className="lg:hidden" />
109+
<TrackedUnderlineLink
110+
target="_blank"
111+
label="superchain-landing"
112+
category={TRACKING_CATEGORY}
113+
href="https://thirdweb.com/grant/superchain"
114+
>
115+
Learn More
116+
</TrackedUnderlineLink>
117+
</p>
118+
119+
<div className="mt-4 flex items-center gap-4">
120+
<Button asChild variant="outline" size="sm" className="bg-background">
121+
<TrackedLinkTW
122+
href={`/team/${props.teamSlug}/~/settings/credits`}
123+
target="_blank"
124+
className="gap-2"
125+
category={TRACKING_CATEGORY}
126+
label="claim-credits"
127+
>
128+
Claim your credits <ArrowRightIcon className="size-4" />
129+
</TrackedLinkTW>
130+
</Button>
131+
</div>
132+
</div>
133+
</div>
134+
);
135+
}

apps/dashboard/src/app/team/[team_slug]/[project_slug]/connect/account-abstraction/isOpChain.ts

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

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

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
import { getAggregateUserOpUsage } from "@/api/analytics";
21
import { getProject } from "@/api/projects";
32
import { getTeamBySlug } from "@/api/team";
43
import type { Metadata } from "next";
@@ -34,18 +33,13 @@ export default async function Page(props: {
3433
team.billingStatus !== "validPayment" &&
3534
team.billingStatus !== "pastDue";
3635

37-
const userOpStats = await getAggregateUserOpUsage({
38-
teamId: team.id,
39-
projectId: project.id,
40-
});
41-
4236
return (
4337
<AccountAbstractionLayout
44-
userOpStats={userOpStats}
4538
projectSlug={project.slug}
4639
teamSlug={team_slug}
4740
projectKey={project.publishableKey}
4841
hasSmartWalletsWithoutBilling={hasSmartWalletsWithoutBilling}
42+
projectId={project.id}
4943
>
5044
{props.children}
5145
</AccountAbstractionLayout>

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

Lines changed: 22 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
1-
import { getUserOpUsage } from "@/api/analytics";
1+
import { getAggregateUserOpUsage, getUserOpUsage } from "@/api/analytics";
22
import { getProject } from "@/api/projects";
3+
import { getTeamBySlug } from "@/api/team";
34
import { getThirdwebClient } from "@/constants/thirdweb.server";
45
import {
56
type Range,
@@ -31,7 +32,14 @@ export default async function Page(props: {
3132
notFound();
3233
}
3334

34-
const project = await getProject(params.team_slug, params.project_slug);
35+
const [team, project] = await Promise.all([
36+
getTeamBySlug(params.team_slug),
37+
getProject(params.team_slug, params.project_slug),
38+
]);
39+
40+
if (!team) {
41+
redirect("/team");
42+
}
3543

3644
if (!project) {
3745
redirect(`/team/${params.team_slug}`);
@@ -52,21 +60,32 @@ export default async function Page(props: {
5260
type: rangeType,
5361
};
5462

55-
const userOpStats = await getUserOpUsage({
63+
const userOpStatsPromise = getUserOpUsage({
5664
teamId: project.teamId,
5765
projectId: project.id,
5866
from: range.from,
5967
to: range.to,
6068
period: interval,
6169
});
6270

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+
6381
return (
6482
<AccountAbstractionAnalytics
6583
userOpStats={userOpStats}
6684
client={getThirdwebClient(authToken)}
6785
teamId={project.teamId}
6886
projectId={project.id}
6987
teamSlug={params.team_slug}
88+
aggregateUserOpStats={aggregateUserOpStats}
7089
/>
7190
);
7291
}

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

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -5,18 +5,16 @@ export const Stat: React.FC<{
55
formatter?: (value: number) => string;
66
}> = ({ label, value, formatter, icon: Icon }) => {
77
return (
8-
<dl className="flex items-center justify-between gap-4 rounded-lg border border-border bg-card p-4 lg:p-6">
8+
<dl className="flex items-center justify-between gap-4 rounded-lg border border-border bg-card p-4 pr-6">
99
<div>
10-
<dd className="font-semibold text-3xl tracking-tight lg:text-5xl">
10+
<dd className="mb-0.5 font-semibold text-2xl tracking-tight">
1111
{value !== undefined && formatter
1212
? formatter(value)
1313
: value?.toLocaleString()}
1414
</dd>
15-
<dt className="font-medium text-muted-foreground text-sm tracking-tight lg:text-lg">
16-
{label}
17-
</dt>
15+
<dt className="text-muted-foreground text-sm">{label}</dt>
1816
</div>
19-
<Icon className="hidden size-12 text-muted-foreground opacity-50 lg:block" />
17+
<Icon className="hidden size-8 text-muted-foreground opacity-50 lg:block" />
2018
</dl>
2119
);
2220
};

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -115,10 +115,10 @@ export function InAppWalletUsersChartCardUI(props: {
115115

116116
return (
117117
<div className="relative w-full rounded-lg border border-border bg-card p-4 md:p-6">
118-
<h3 className="mb-1 font-semibold text-xl tracking-tight">
118+
<h3 className="mb-0.5 font-semibold text-xl tracking-tight">
119119
{props.title}
120120
</h3>
121-
<p className="mb-3 text-muted-foreground">{props.description}</p>
121+
<p className="mb-3 text-muted-foreground text-sm">{props.description}</p>
122122

123123
<ExportToCSVButton
124124
className="top-6 right-6 mb-4 w-full bg-background md:absolute md:mb-0 md:flex md:w-auto"

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ export function InAppWalletsSummary(props: {
2727
);
2828

2929
return (
30-
<div className="grid grid-cols-2 gap-4 lg:gap-6">
30+
<div className="grid grid-cols-2 gap-4">
3131
<Stat
3232
label="Total Users"
3333
value={allTimeStats?.uniqueWalletsConnected || 0}

0 commit comments

Comments
 (0)