Skip to content

Commit 8e82ec8

Browse files
committed
[TOOL-3119] Dashboard: Move Connect settings from Project settings to Connect pages (#5980)
<!-- start pr-codex --> ## PR-Codex overview This PR focuses on restructuring and enhancing the routing and layout of the `settings` pages within the dashboard, as well as integrating new components for better user experience in the `account-abstraction` section. ### Detailed summary - Added a new `Settings` route in multiple layout files. - Refactored paths in `ProjectGeneralSettingsPageForTeams` to point to the new settings structure. - Updated imports to reflect the new file structure for components. - Introduced `AccountAbstractionAnalytics` and `AccountAbstractionSummary` components. - Modified layout components to improve styling and organization. - Replaced `AccountAbstractionPage` with `AccountAbstractionLayout` for better structure. - Implemented loading states for API calls in `AccountAbstractionSettingsPage`. > ✨ Ask PR-Codex anything about this PR by commenting with `/codex {your question}` <!-- end pr-codex -->
1 parent 0b62397 commit 8e82ec8

File tree

13 files changed

+150
-165
lines changed

13 files changed

+150
-165
lines changed

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

Lines changed: 39 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,29 +1,29 @@
11
"use client";
22
import { Alert, AlertDescription, AlertTitle } from "@/components/ui/alert";
3+
import { TabPathLinks } from "@/components/ui/tabs";
34
import { TrackedLinkTW } from "@/components/ui/tracked-link";
45
import {
56
type ApiKeyService,
67
accountStatus,
8+
useUserOpUsageAggregate,
79
} from "@3rdweb-sdk/react/hooks/useApi";
810
import { SmartWalletsBillingAlert } from "components/settings/ApiKeys/Alerts";
9-
import { SmartWallets } from "components/smart-wallets";
1011
import { CircleAlertIcon } from "lucide-react";
1112
import { useMemo } from "react";
1213
import { useActiveWalletChain } from "thirdweb/react";
14+
import { AccountAbstractionSummary } from "../../../../../../components/smart-wallets/AccountAbstractionAnalytics/AccountAbstractionSummary";
1315
import { AAFooterSection } from "./AAFooterSection";
1416
import { isOpChainId } from "./isOpChain";
1517

1618
const TRACKING_CATEGORY = "smart-wallet";
1719

18-
// TODO - the factories shown on this page is not project specific, need to revamp this page
19-
20-
export function AccountAbstractionPage(props: {
20+
export function AccountAbstractionLayout(props: {
2121
projectSlug: string;
2222
teamSlug: string;
2323
projectKey: string;
2424
apiKeyServices: ApiKeyService[];
2525
billingStatus: "validPayment" | (string & {}) | null;
26-
tab?: string;
26+
children: React.ReactNode;
2727
}) {
2828
const { apiKeyServices } = props;
2929

@@ -39,6 +39,12 @@ export function AccountAbstractionPage(props: {
3939

4040
const isOpChain = chain?.id ? isOpChainId(chain.id) : false;
4141

42+
const smartWalletsLayoutSlug = `/team/${props.teamSlug}/${props.projectSlug}/connect/account-abstraction`;
43+
44+
const aggregateUserOpUsageQuery = useUserOpUsageAggregate({
45+
clientId: props.projectKey,
46+
});
47+
4248
return (
4349
<div>
4450
<h1 className="mb-1 font-semibold text-2xl tracking-tight lg:text-3xl">
@@ -77,12 +83,34 @@ export function AccountAbstractionPage(props: {
7783
)
7884
)}
7985

80-
<SmartWallets
81-
smartWalletsLayoutSlug={`/team/${props.teamSlug}/${props.projectSlug}/connect/account-abstraction`}
82-
trackingCategory={TRACKING_CATEGORY}
83-
clientId={props.projectKey}
84-
tab={props.tab}
85-
/>
86+
<div>
87+
<AccountAbstractionSummary
88+
aggregateUserOpUsageQuery={aggregateUserOpUsageQuery.data}
89+
/>
90+
91+
<div className="h-12" />
92+
<TabPathLinks
93+
links={[
94+
{
95+
name: "Analytics",
96+
path: `${smartWalletsLayoutSlug}`,
97+
exactMatch: true,
98+
},
99+
{
100+
name: "Account Factories",
101+
path: `${smartWalletsLayoutSlug}/factories`,
102+
},
103+
{
104+
name: "Sponsorship Rules",
105+
path: `${smartWalletsLayoutSlug}/settings`,
106+
},
107+
]}
108+
/>
109+
110+
<div className="h-6" />
111+
112+
{props.children}
113+
</div>
86114
</div>
87115
<div className="h-14" />
88116
<AAFooterSection trackingCategory={TRACKING_CATEGORY} />
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
import { AccountFactories } from "../../../../../../../components/smart-wallets/AccountFactories";
2+
3+
export default async function Page() {
4+
return <AccountFactories trackingCategory="smart-wallet" />;
5+
}
Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
import { getProject } from "@/api/projects";
2+
import { getTeamBySlug } from "@/api/team";
3+
import type { Metadata } from "next";
4+
import { notFound, redirect } from "next/navigation";
5+
import { getAbsoluteUrl } from "../../../../../../lib/vercel-utils";
6+
import { getAPIKeyForProjectId } from "../../../../../api/lib/getAPIKeys";
7+
import { AccountAbstractionLayout } from "./AccountAbstractionPage";
8+
9+
export default async function Page(props: {
10+
params: Promise<{ team_slug: string; project_slug: string }>;
11+
children: React.ReactNode;
12+
}) {
13+
const { team_slug, project_slug } = await props.params;
14+
15+
const [team, project] = await Promise.all([
16+
getTeamBySlug(team_slug),
17+
getProject(team_slug, project_slug),
18+
]);
19+
20+
if (!team) {
21+
redirect("/team");
22+
}
23+
24+
if (!project) {
25+
redirect("/team");
26+
}
27+
28+
const apiKey = await getAPIKeyForProjectId(project.id);
29+
30+
if (!apiKey) {
31+
notFound();
32+
}
33+
34+
return (
35+
<AccountAbstractionLayout
36+
projectSlug={project.slug}
37+
teamSlug={team_slug}
38+
billingStatus={team.billingStatus}
39+
projectKey={project.publishableKey}
40+
apiKeyServices={apiKey.services || []}
41+
>
42+
{props.children}
43+
</AccountAbstractionLayout>
44+
);
45+
}
46+
47+
const seo = {
48+
title: "The Complete Account Abstraction Toolkit | thirdweb",
49+
desc: "Add account abstraction to your web3 app & unlock powerful features for seamless onboarding, customizable transactions, & maximum security. Get started.",
50+
};
51+
52+
export const metadata: Metadata = {
53+
title: seo.title,
54+
description: seo.desc,
55+
openGraph: {
56+
title: seo.title,
57+
description: seo.desc,
58+
images: [
59+
{
60+
url: `${getAbsoluteUrl()}/assets/og-image/dashboard-wallets-smart-wallet.png`,
61+
width: 1200,
62+
height: 630,
63+
alt: seo.title,
64+
},
65+
],
66+
},
67+
};
Lines changed: 5 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,11 @@
11
import { getProject } from "@/api/projects";
22
import { getTeamBySlug } from "@/api/team";
3-
import { ChakraProviderSetup } from "@/components/ChakraProviderSetup";
4-
import type { Metadata } from "next";
5-
import { notFound, redirect } from "next/navigation";
6-
import { getAbsoluteUrl } from "../../../../../../lib/vercel-utils";
7-
import { getAPIKeyForProjectId } from "../../../../../api/lib/getAPIKeys";
8-
import { AccountAbstractionPage } from "./AccountAbstractionPage";
3+
import { redirect } from "next/navigation";
4+
import { AccountAbstractionAnalytics } from "../../../../../../components/smart-wallets/AccountAbstractionAnalytics";
95

106
export default async function Page(props: {
117
params: Promise<{ team_slug: string; project_slug: string }>;
12-
searchParams: Promise<{ tab?: string }>;
8+
children: React.ReactNode;
139
}) {
1410
const { team_slug, project_slug } = await props.params;
1511

@@ -23,47 +19,8 @@ export default async function Page(props: {
2319
}
2420

2521
if (!project) {
26-
redirect("/team");
27-
}
28-
29-
const apiKey = await getAPIKeyForProjectId(project.id);
30-
31-
if (!apiKey) {
32-
notFound();
22+
redirect(`/team/${team_slug}`);
3323
}
3424

35-
return (
36-
<ChakraProviderSetup>
37-
<AccountAbstractionPage
38-
projectSlug={project.slug}
39-
teamSlug={team_slug}
40-
billingStatus={team.billingStatus}
41-
projectKey={project.publishableKey}
42-
apiKeyServices={apiKey.services || []}
43-
tab={(await props.searchParams).tab}
44-
/>
45-
</ChakraProviderSetup>
46-
);
25+
return <AccountAbstractionAnalytics clientId={project.publishableKey} />;
4726
}
48-
49-
const seo = {
50-
title: "The Complete Account Abstraction Toolkit | thirdweb",
51-
desc: "Add account abstraction to your web3 app & unlock powerful features for seamless onboarding, customizable transactions, & maximum security. Get started.",
52-
};
53-
54-
export const metadata: Metadata = {
55-
title: seo.title,
56-
description: seo.desc,
57-
openGraph: {
58-
title: seo.title,
59-
description: seo.desc,
60-
images: [
61-
{
62-
url: `${getAbsoluteUrl()}/assets/og-image/dashboard-wallets-smart-wallet.png`,
63-
width: 1200,
64-
height: 630,
65-
alt: seo.title,
66-
},
67-
],
68-
},
69-
};

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

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
import { getProject } from "@/api/projects";
22
import { ChakraProviderSetup } from "@/components/ChakraProviderSetup";
33
import { notFound } from "next/navigation";
4-
import { AccountAbstractionSettingsPage } from "../../../../../../components/smart-wallets/SponsorshipPolicies";
5-
import { getValidAccount } from "../../../../../account/settings/getAccount";
6-
import { getAPIKeyForProjectId } from "../../../../../api/lib/getAPIKeys";
4+
import { AccountAbstractionSettingsPage } from "../../../../../../../components/smart-wallets/SponsorshipPolicies";
5+
import { getValidAccount } from "../../../../../../account/settings/getAccount";
6+
import { getAPIKeyForProjectId } from "../../../../../../api/lib/getAPIKeys";
77

88
export default async function Page(props: {
99
params: Promise<{ team_slug: string; project_slug: string }>;

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

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,11 @@ export default async function Layout(props: {
4545
path: `/team/${team_slug}/${project_slug}/connect/in-app-wallets/users`,
4646
exactMatch: true,
4747
},
48+
{
49+
name: "Settings",
50+
path: `/team/${team_slug}/${project_slug}/connect/in-app-wallets/settings`,
51+
exactMatch: true,
52+
},
4853
]}
4954
/>
5055

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

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,14 @@
11
import { getProject } from "@/api/projects";
22
import { notFound, redirect } from "next/navigation";
3-
import { InAppWalletSettingsPage } from "../../../../../../components/embedded-wallets/Configure";
4-
import { getValidAccount } from "../../../../../account/settings/getAccount";
5-
import { getAPIKeyForProjectId } from "../../../../../api/lib/getAPIKeys";
3+
import { InAppWalletSettingsPage } from "../../../../../../../components/embedded-wallets/Configure";
4+
import { getValidAccount } from "../../../../../../account/settings/getAccount";
5+
import { getAPIKeyForProjectId } from "../../../../../../api/lib/getAPIKeys";
66

77
export default async function Page(props: {
88
params: Promise<{ team_slug: string; project_slug: string }>;
99
}) {
1010
const { team_slug, project_slug } = await props.params;
11+
1112
const [account, project] = await Promise.all([
1213
getValidAccount(),
1314
getProject(team_slug, project_slug),

apps/dashboard/src/app/team/[team_slug]/[project_slug]/connect/pay/layout.tsx

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ export default async function Layout(props: {
2020
const payLayoutPath = `/team/${params.team_slug}/${params.project_slug}/connect/pay`;
2121

2222
return (
23-
<div className="flex w-full flex-col gap-8">
23+
<div className="flex w-full flex-col gap-6">
2424
<div className="flex flex-col items-start justify-between gap-6 lg:flex-row">
2525
<div className="max-w-[700px]">
2626
<h1 className="mb-3 font-bold text-3xl tracking-tight md:text-4xl">
@@ -53,6 +53,10 @@ export default async function Layout(props: {
5353
name: "Webhooks",
5454
path: `${payLayoutPath}/webhooks`,
5555
},
56+
{
57+
name: "Settings",
58+
path: `${payLayoutPath}/settings`,
59+
},
5660
]}
5761
/>
5862

apps/dashboard/src/app/team/[team_slug]/[project_slug]/settings/pay/page.tsx renamed to apps/dashboard/src/app/team/[team_slug]/[project_slug]/connect/pay/settings/page.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import { getProject } from "@/api/projects";
22
import { notFound } from "next/navigation";
3-
import { PayConfig } from "../../../../../../components/pay/PayConfig";
4-
import { getAPIKeyForProjectId } from "../../../../../api/lib/getAPIKeys";
3+
import { PayConfig } from "../../../../../../../components/pay/PayConfig";
4+
import { getAPIKeyForProjectId } from "../../../../../../api/lib/getAPIKeys";
55

66
export default async function Page(props: {
77
params: Promise<{

apps/dashboard/src/app/team/[team_slug]/[project_slug]/settings/ProjectGeneralSettingsPageForTeams.tsx

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12,17 +12,17 @@ export function ProjectGeneralSettingsPageForTeams(props: {
1212
}) {
1313
const router = useDashboardRouter();
1414
const { team, project_slug, apiKey } = props;
15-
const projectSettingsLayout = `/team/${team.slug}/${project_slug}/settings`;
15+
const projectLayout = `/team/${team.slug}/${project_slug}`;
1616

1717
// TODO - add a Project Image form field on this page
1818

1919
return (
2020
<ProjectGeneralSettingsPage
2121
apiKey={apiKey}
2222
paths={{
23-
aaConfig: `${projectSettingsLayout}/account-abstraction`,
24-
inAppConfig: `${projectSettingsLayout}/in-app-wallets`,
25-
payConfig: `${projectSettingsLayout}/pay`,
23+
aaConfig: `${projectLayout}/connect/account-abstraction/settings`,
24+
inAppConfig: `${projectLayout}/connect/in-app-wallets/settings`,
25+
payConfig: `${projectLayout}/connect/pay/settings`,
2626
afterDeleteRedirectTo: `/team/${team.slug}`,
2727
}}
2828
onKeyUpdated={() => {

0 commit comments

Comments
 (0)