Skip to content

Commit 9408a51

Browse files
committed
[TOOL-3766] Dashboard: Account Abstraction page updates
1 parent 447a519 commit 9408a51

File tree

16 files changed

+129
-92
lines changed

16 files changed

+129
-92
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
};

0 commit comments

Comments
 (0)