Add Project Setting pages Layout (#4620)
## Problem solved
Short description of the bug fixed or feature added
<!-- start pr-codex -->
---
## PR-Codex overview
The focus of this PR is to update the layout and styling of various pages in the dashboard app.
### Detailed summary
- Updated body and html styles for full height
- Added new pages for Pay Settings, In-App Wallet Settings, and Account Abstraction Settings
- Modified project selector UI link
- Updated text and layout for General Settings page
- Adjusted layout in TeamLayout and RootTeamLayout components
- Added a new Layout component for settings with sidebar links
- Added a new page for API key details with editing functionality
> ✨ Ask PR-Codex anything about this PR by commenting with `/codex {your question}`
<!-- end pr-codex -->
This commit is contained in:
@@ -139,3 +139,8 @@
|
|||||||
scrollbar-width: none; /* Firefox */
|
scrollbar-width: none; /* Firefox */
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
body,
|
||||||
|
html {
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
|||||||
@@ -69,7 +69,7 @@ export default function RootLayout({
|
|||||||
<PostHogProvider>
|
<PostHogProvider>
|
||||||
<body
|
<body
|
||||||
className={cn(
|
className={cn(
|
||||||
"h-screen bg-background font-sans antialiased",
|
"bg-background font-sans antialiased",
|
||||||
fontSans.variable,
|
fontSans.variable,
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
|
|||||||
@@ -34,7 +34,7 @@ export default async function TeamLayout(props: {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="h-full flex flex-col">
|
<div className="flex flex-col grow">
|
||||||
<div className="bg-muted/50">
|
<div className="bg-muted/50">
|
||||||
<TeamHeader
|
<TeamHeader
|
||||||
currentProject={project}
|
currentProject={project}
|
||||||
@@ -63,7 +63,7 @@ export default async function TeamLayout(props: {
|
|||||||
]}
|
]}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<main className="grow">{props.children}</main>
|
<div className="grow flex flex-col">{props.children}</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
+9
@@ -0,0 +1,9 @@
|
|||||||
|
export default function Page() {
|
||||||
|
return (
|
||||||
|
<div className="grow flex flex-col items-center justify-center">
|
||||||
|
<h1 className="text-4xl tracking-tighter text-muted-foreground">
|
||||||
|
Account Abstraction Settings
|
||||||
|
</h1>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
+9
@@ -0,0 +1,9 @@
|
|||||||
|
export default function Page() {
|
||||||
|
return (
|
||||||
|
<div className="grow flex flex-col items-center justify-center">
|
||||||
|
<h1 className="text-4xl tracking-tighter text-muted-foreground">
|
||||||
|
In-App wallet Settings
|
||||||
|
</h1>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -0,0 +1,38 @@
|
|||||||
|
import { SidebarLayout } from "@/components/blocks/SidebarLayout";
|
||||||
|
|
||||||
|
export default function Layout(props: {
|
||||||
|
children: React.ReactNode;
|
||||||
|
params: {
|
||||||
|
team_slug: string;
|
||||||
|
project_slug: string;
|
||||||
|
};
|
||||||
|
}) {
|
||||||
|
const { project_slug, team_slug } = props.params;
|
||||||
|
const layoutPath = `/team/${team_slug}/${project_slug}/settings`;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<SidebarLayout
|
||||||
|
sidebarLinks={[
|
||||||
|
{
|
||||||
|
label: "General",
|
||||||
|
href: `${layoutPath}`,
|
||||||
|
exactMatch: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "In-App Wallets",
|
||||||
|
href: `${layoutPath}/in-app-wallets`,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "Account Abstraction",
|
||||||
|
href: `${layoutPath}/account-abstraction`,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "Pay",
|
||||||
|
href: `${layoutPath}/pay`,
|
||||||
|
},
|
||||||
|
]}
|
||||||
|
>
|
||||||
|
{props.children}
|
||||||
|
</SidebarLayout>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -1,7 +1,9 @@
|
|||||||
export default function Page() {
|
export default function Page() {
|
||||||
return (
|
return (
|
||||||
<div className="h-full py-6 container flex items-center justify-center">
|
<div className="grow flex flex-col items-center justify-center">
|
||||||
<h1 className="text-4xl tracking-tighter text-muted-foreground">Usage</h1>
|
<h1 className="text-4xl tracking-tighter text-muted-foreground">
|
||||||
|
General Settings
|
||||||
|
</h1>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,9 @@
|
|||||||
|
export default function Page() {
|
||||||
|
return (
|
||||||
|
<div className="grow flex flex-col items-center justify-center">
|
||||||
|
<h1 className="text-4xl tracking-tighter text-muted-foreground">
|
||||||
|
Pay Settings
|
||||||
|
</h1>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -1,13 +1,13 @@
|
|||||||
import { AppFooter } from "@/components/blocks/app-footer";
|
import { AppFooter } from "@/components/blocks/app-footer";
|
||||||
import { TWAutoConnect } from "../../components/autoconnect";
|
import { TWAutoConnect } from "../../components/autoconnect";
|
||||||
|
|
||||||
export default async function RootTeamLayout(props: {
|
export default function RootTeamLayout(props: {
|
||||||
children: React.ReactNode;
|
children: React.ReactNode;
|
||||||
params: { team_slug: string };
|
params: { team_slug: string };
|
||||||
}) {
|
}) {
|
||||||
return (
|
return (
|
||||||
<div className="min-h-full flex flex-col bg-background">
|
<div className="min-h-full flex flex-col bg-background">
|
||||||
<div className="grow">{props.children}</div>
|
<div className="grow flex flex-col">{props.children}</div>
|
||||||
<TWAutoConnect />
|
<TWAutoConnect />
|
||||||
<AppFooter />
|
<AppFooter />
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -56,7 +56,9 @@ export function ProjectSelectorUI(props: {
|
|||||||
asChild
|
asChild
|
||||||
>
|
>
|
||||||
{/* TODO - when we have overview page, remove /connect */}
|
{/* TODO - when we have overview page, remove /connect */}
|
||||||
<Link href={`/team/${team.slug}/${project.slug}/connect`}>
|
<Link
|
||||||
|
href={`/team/${team.slug}/${project.slug}/connect/analytics`}
|
||||||
|
>
|
||||||
<div className="flex items-center gap-2">
|
<div className="flex items-center gap-2">
|
||||||
{/* TODO - placeholder for now */}
|
{/* TODO - placeholder for now */}
|
||||||
<div className="size-4 bg-muted border rounded-full" />
|
<div className="size-4 bg-muted border rounded-full" />
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import { useApiKeys } from "@3rdweb-sdk/react/hooks/useApi";
|
import { Spinner } from "@/components/ui/Spinner/Spinner";
|
||||||
|
import { type ApiKey, useApiKeys } from "@3rdweb-sdk/react/hooks/useApi";
|
||||||
import { useLoggedInUser } from "@3rdweb-sdk/react/hooks/useLoggedInUser";
|
import { useLoggedInUser } from "@3rdweb-sdk/react/hooks/useLoggedInUser";
|
||||||
import { AppLayout } from "components/app-layouts/app";
|
import { AppLayout } from "components/app-layouts/app";
|
||||||
import { ApiKeyDetails } from "components/settings/ApiKeys/Details";
|
import { ApiKeyDetails } from "components/settings/ApiKeys/Details";
|
||||||
@@ -10,7 +11,6 @@ import { useEffect, useMemo, useState } from "react";
|
|||||||
import type { ThirdwebNextPage } from "utils/types";
|
import type { ThirdwebNextPage } from "utils/types";
|
||||||
|
|
||||||
const SettingsApiKeyPage: ThirdwebNextPage = () => {
|
const SettingsApiKeyPage: ThirdwebNextPage = () => {
|
||||||
const [editing, setEditing] = useState(false);
|
|
||||||
const keysQuery = useApiKeys();
|
const keysQuery = useApiKeys();
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const { user } = useLoggedInUser();
|
const { user } = useLoggedInUser();
|
||||||
@@ -27,20 +27,29 @@ const SettingsApiKeyPage: ThirdwebNextPage = () => {
|
|||||||
}
|
}
|
||||||
}, [apiKey, keysQuery.isSuccess, router]);
|
}, [apiKey, keysQuery.isSuccess, router]);
|
||||||
|
|
||||||
if (!user) {
|
if (!user || !apiKey) {
|
||||||
return null;
|
return (
|
||||||
|
<div className="flex items-center justify-center">
|
||||||
|
<Spinner className="size-10" />
|
||||||
|
</div>
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!apiKey) {
|
return <APIKeyDetailsPage apiKey={apiKey} />;
|
||||||
return null;
|
};
|
||||||
}
|
|
||||||
|
function APIKeyDetailsPage(props: {
|
||||||
|
apiKey: ApiKey;
|
||||||
|
}) {
|
||||||
|
const { apiKey } = props;
|
||||||
|
const [editing, setEditing] = useState(false);
|
||||||
|
|
||||||
return editing ? (
|
return editing ? (
|
||||||
<EditApiKey apiKey={apiKey} onCancel={() => setEditing(false)} />
|
<EditApiKey apiKey={apiKey} onCancel={() => setEditing(false)} />
|
||||||
) : (
|
) : (
|
||||||
<ApiKeyDetails apiKey={apiKey} onEdit={() => setEditing(true)} />
|
<ApiKeyDetails apiKey={apiKey} onEdit={() => setEditing(true)} />
|
||||||
);
|
);
|
||||||
};
|
}
|
||||||
|
|
||||||
SettingsApiKeyPage.getLayout = (page, props) => (
|
SettingsApiKeyPage.getLayout = (page, props) => (
|
||||||
<AppLayout
|
<AppLayout
|
||||||
|
|||||||
Reference in New Issue
Block a user