Skip to content

Commit a41e423

Browse files
committed
[Dashboard] Add published contracts page in teams, account and project layouts (#5659)
DASH-471 <!-- start pr-codex --> --- ## PR-Codex overview This PR focuses on refactoring components related to contracts in the dashboard, enhancing the layout with `SidebarLayout`, and improving the user interface for contract management with better structure and loading states. ### Detailed summary - Updated `layout.tsx` to use `SidebarLayout` for contracts. - Simplified return statements in `DeployedContractsPage` components. - Changed class names for better styling consistency. - Added authentication checks in published contract pages. - Created `PublishedContractsPage` to display published contracts with loading states. > ✨ Ask PR-Codex anything about this PR by commenting with `/codex {your question}` <!-- end pr-codex -->
1 parent 2d66242 commit a41e423

File tree

13 files changed

+216
-36
lines changed

13 files changed

+216
-36
lines changed

apps/dashboard/src/app/account/contracts/DeployedContractsPageHeader.tsx

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -17,14 +17,14 @@ export function DeployedContractsPageHeader() {
1717
setImportModalOpen(false);
1818
}}
1919
/>
20-
<div className="flex flex-col gap-4 md:pb-4 lg:flex-row lg:justify-between">
20+
<div className="flex flex-col gap-4 lg:flex-row lg:justify-between">
2121
<div>
22-
<h1 className="mb-1.5 font-semibold text-3xl tracking-tight lg:text-4xl">
23-
Your contracts
22+
<h1 className="mb-1 font-semibold text-2xl tracking-tight lg:text-3xl">
23+
Deployed contracts
2424
</h1>
2525
<p className="text-muted-foreground text-sm">
26-
The list of contract instances that you have deployed or imported
27-
with thirdweb across all networks
26+
The list of contracts that you have deployed or imported with
27+
thirdweb across all networks
2828
</p>
2929
</div>
3030
<div className="flex gap-2 [&>*]:grow">

apps/dashboard/src/app/account/contracts/_components/DeployedContractsPage.tsx

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,12 +8,11 @@ import { getSortedDeployedContracts } from "./getSortedDeployedContracts";
88

99
export function DeployedContractsPage(props: {
1010
address: string;
11-
className?: string;
1211
}) {
1312
return (
14-
<div className={props.className}>
13+
<div className="flex grow flex-col">
1514
<DeployedContractsPageHeader />
16-
<div className="h-6" />
15+
<div className="h-8" />
1716
<Suspense fallback={<Loading />}>
1817
<DeployedContractsPageAsync {...props} />
1918
</Suspense>
Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,26 @@
1+
import { SidebarLayout } from "@/components/blocks/SidebarLayout";
2+
13
export default function Layout(props: {
24
children: React.ReactNode;
35
}) {
4-
return <div className="container flex grow flex-col">{props.children}</div>;
6+
const layoutPath = "/account/contracts";
7+
8+
return (
9+
<SidebarLayout
10+
sidebarLinks={[
11+
{
12+
href: layoutPath,
13+
label: "Deployed contracts",
14+
exactMatch: true,
15+
},
16+
{
17+
href: `${layoutPath}/published`,
18+
label: "Published contracts",
19+
exactMatch: true,
20+
},
21+
]}
22+
>
23+
{props.children}
24+
</SidebarLayout>
25+
);
526
}

apps/dashboard/src/app/account/contracts/page.tsx

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -9,10 +9,5 @@ export default async function Page() {
99
return redirect(`/login?next=${encodeURIComponent("/account/contracts")}`);
1010
}
1111

12-
return (
13-
<DeployedContractsPage
14-
address={accountAddress}
15-
className="flex grow flex-col pt-10 pb-10"
16-
/>
17-
);
12+
return <DeployedContractsPage address={accountAddress} />;
1813
}
Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
import { GenericLoadingPage } from "@/components/blocks/skeletons/GenericLoadingPage";
2+
import { Button } from "@/components/ui/button";
3+
import { PlusIcon } from "lucide-react";
4+
import Link from "next/link";
5+
import { Suspense } from "react";
6+
import { PublishedContracts } from "../../../(dashboard)/profile/[addressOrEns]/components/published-contracts";
7+
import { resolveAddressAndEns } from "../../../(dashboard)/profile/[addressOrEns]/resolveAddressAndEns";
8+
import { fetchPublishedContracts } from "../../../../components/contract-components/fetchPublishedContracts";
9+
10+
export async function PublishedContractsPage(props: {
11+
publisherAddress: string;
12+
}) {
13+
const resolvedInfo = await resolveAddressAndEns(props.publisherAddress);
14+
15+
return (
16+
<div className="flex grow flex-col">
17+
<div className="flex flex-col justify-between gap-4 md:flex-row md:items-start">
18+
<div>
19+
<h2 className="mb-1 font-semibold text-2xl tracking-tight lg:text-3xl">
20+
Published contracts
21+
</h2>
22+
23+
<p className="text-muted-foreground text-sm">
24+
The list of contracts published to thirdweb across all networks.{" "}
25+
<Link
26+
href="https://portal.thirdweb.com/contracts/publish/overview"
27+
className="text-link-foreground hover:text-foreground"
28+
target="_blank"
29+
>
30+
Learn more about publishing contracts
31+
</Link>
32+
</p>
33+
</div>
34+
35+
<Button asChild>
36+
<Link
37+
href="https://portal.thirdweb.com/contracts/publish/publish-contract"
38+
target="_blank"
39+
className="gap-2"
40+
>
41+
<PlusIcon className="size-4" />
42+
Publish Contract
43+
</Link>
44+
</Button>
45+
</div>
46+
47+
<div className="h-8" />
48+
49+
<Suspense fallback={<GenericLoadingPage />}>
50+
<AsyncPublishedContractsTable
51+
publisherAddress={props.publisherAddress}
52+
publisherEnsName={resolvedInfo?.ensName}
53+
/>
54+
</Suspense>
55+
</div>
56+
);
57+
}
58+
59+
async function AsyncPublishedContractsTable(props: {
60+
publisherAddress: string;
61+
publisherEnsName: string | undefined;
62+
}) {
63+
const publishedContracts = await fetchPublishedContracts(
64+
props.publisherAddress,
65+
);
66+
67+
if (publishedContracts.length === 0) {
68+
return (
69+
<div className="flex min-h-[300px] grow items-center justify-center rounded-lg border border-border">
70+
No published contracts found
71+
</div>
72+
);
73+
}
74+
75+
return (
76+
<PublishedContracts
77+
publishedContracts={publishedContracts}
78+
publisherEnsName={props.publisherEnsName}
79+
/>
80+
);
81+
}
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
import { getAuthTokenWalletAddress } from "../../../api/lib/getAuthToken";
2+
import { loginRedirect } from "../../../login/loginRedirect";
3+
import { PublishedContractsPage } from "./PublishedContractsPage";
4+
5+
export default async function Page() {
6+
const accountAddress = await getAuthTokenWalletAddress();
7+
8+
if (!accountAddress) {
9+
loginRedirect("/account/contracts");
10+
}
11+
12+
return <PublishedContractsPage publisherAddress={accountAddress} />;
13+
}

apps/dashboard/src/app/account/layout.tsx

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,6 @@ async function HeaderAndNav(props: {
5151
{
5252
path: "/account/contracts",
5353
name: "Contracts",
54-
exactMatch: true,
5554
},
5655
{
5756
path: "/account/settings",
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
import { SidebarLayout } from "@/components/blocks/SidebarLayout";
2+
3+
export default async function Layout(props: {
4+
children: React.ReactNode;
5+
params: Promise<{ team_slug: string }>;
6+
}) {
7+
const params = await props.params;
8+
const layoutPath = `/team/${params.team_slug}/~/contracts`;
9+
10+
return (
11+
<SidebarLayout
12+
sidebarLinks={[
13+
{
14+
href: layoutPath,
15+
label: "Deployed contracts",
16+
exactMatch: true,
17+
},
18+
{
19+
href: `${layoutPath}/published`,
20+
label: "Published contracts",
21+
exactMatch: true,
22+
},
23+
]}
24+
>
25+
{props.children}
26+
</SidebarLayout>
27+
);
28+
}

apps/dashboard/src/app/team/[team_slug]/(team)/~/contracts/page.tsx

Lines changed: 1 addition & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -14,12 +14,5 @@ export default async function Page(props: {
1414
);
1515
}
1616

17-
return (
18-
<div className="container flex grow flex-col">
19-
<DeployedContractsPage
20-
address={accountAddress}
21-
className="flex grow flex-col pt-10 pb-10"
22-
/>
23-
</div>
24-
);
17+
return <DeployedContractsPage address={accountAddress} />;
2518
}
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
import { PublishedContractsPage } from "../../../../../../account/contracts/published/PublishedContractsPage";
2+
import { getAuthTokenWalletAddress } from "../../../../../../api/lib/getAuthToken";
3+
import { loginRedirect } from "../../../../../../login/loginRedirect";
4+
5+
export default async function Page(props: {
6+
params: Promise<{ team_slug: string }>;
7+
}) {
8+
const accountAddress = await getAuthTokenWalletAddress();
9+
const params = await props.params;
10+
11+
if (!accountAddress) {
12+
loginRedirect(`/team/${params.team_slug}/~/contracts`);
13+
}
14+
15+
return <PublishedContractsPage publisherAddress={accountAddress} />;
16+
}

0 commit comments

Comments
 (0)