From 12475027d19259695215eea037740ef2fed9bf28 Mon Sep 17 00:00:00 2001 From: MananTank Date: Mon, 26 May 2025 20:59:12 +0000 Subject: [PATCH] Add Contract layout in team/project (#7152) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ## PR-Codex overview This PR introduces enhancements to the handling of contract pages, adding new types for parameters and project metadata, while refactoring existing components to incorporate team and project-specific data. ### Detailed summary - Added `PublicContractPageParams` and `ProjectContractPageParams` types. - Introduced `ProjectMeta` type for project metadata. - Refactored components to accept `teamSlug`, `projectSlug`, and `projectMeta`. - Updated routing and links to include project-specific paths. - Enhanced handling of contract page data retrieval and UI rendering. > The following files were skipped due to too many changes: `apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/account/AccountPage.client.tsx`, `apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/nfts/[tokenId]/TokenIdPage.client.tsx`, `apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/account-permissions/page.tsx`, `apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/nfts/ContractNFTPage.client.tsx`, `apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/_layout/contract-page-layout.client.tsx`, `apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/explorer/shared-explorer-page.tsx`, `apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/explorer/page.tsx`, `apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/permissions/ContractPermissionsPage.tsx`, `apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/tokens/shared-page.tsx`, `apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/overview/components/ContractChecklist.tsx`, `apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/permissions/shared-permissions-page.tsx`, `apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/split/page.tsx`, `apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/modules/page.tsx`, `apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/accounts/page.tsx`, `apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/proposals/page.tsx`, `apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/nfts/page.tsx`, `apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/account-permissions/shared-account-permissions-page.tsx`, `apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/account/page.tsx`, `apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/permissions/page.tsx`, `apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/split/shared-split-page.tsx`, `apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/accounts/shared-accounts-page.tsx`, `apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/tokens/page.tsx`, `apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/(marketplace)/direct-listings/page.tsx`, `apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/_layout/contract-page-layout.tsx`, `apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/modules/shared-modules-page.tsx`, `apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/proposals/shared-proposals-page.tsx`, `apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/(marketplace)/english-auctions/page.tsx`, `apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/account/shared-account-page.tsx`, `apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/(marketplace)/english-auctions/shared-english-auctions-page.tsx`, `apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/(marketplace)/direct-listings/shared-direct-listings-page.tsx`, `apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/nfts/shared-nfts-page.tsx`, `apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/cross-chain/data-table.tsx`, `apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/_layout/primary-dashboard-button.tsx`, `apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/claim-conditions/shared-claim-conditions-page.tsx`, `apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/claim-conditions/page.tsx`, `apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/settings/page.tsx`, `apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/settings/shared-settings-page.tsx`, `apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/page.tsx`, `apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/nfts/[tokenId]/page.tsx`, `apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/shared-overview-page.tsx`, `apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/analytics/page.tsx`, `apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/nfts/[tokenId]/token-id.tsx`, `apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/analytics/shared-analytics-page.tsx`, `apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/nfts/[tokenId]/shared-nfts-token-page.tsx`, `apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/overview/ContractOverviewPage.tsx`, `apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/events/events-feed.tsx`, `apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/contract/[chainIdOrSlug]/[contractAddress]/layout.tsx`, `apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/overview/components/MarketplaceDetails.tsx`, `apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/cross-chain/shared-cross-chain-page.tsx`, `apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/cross-chain/page.tsx`, `apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/shared-layout.tsx`, `apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/layout.tsx` > ✨ Ask PR-Codex anything about this PR by commenting with `/codex {your question}` ## Summary by CodeRabbit - **New Features** - Enhanced routing to include project and team slugs, enabling project-aware navigation for contract, NFT, marketplace, analytics, permissions, and proposal pages. - Passed project metadata (team and project info) throughout various pages and components for contextual consistency. - Introduced shared layout and page components for contract overview, NFTs, analytics, permissions, and settings, streamlining the user experience. - **Refactor** - Removed internal data fetching, validation, and conditional rendering from pages, delegating logic to shared components. - Updated navigation links and breadcrumbs to dynamically incorporate project and team slugs when available. - Centralized metadata and layout generation into utility functions to reduce duplication. - **Bug Fixes** - Improved handling of missing or invalid project/team data by triggering notFound responses appropriately. - **Chores** - Extended component props and interfaces to accept projectMeta objects. - Simplified page components to directly render shared components with minimal logic. - Updated URL construction to utilize utility functions for project-aware paths. --- .../ContractDirectListingsPage.client.tsx | 9 +- .../(marketplace)/direct-listings/page.tsx | 43 +-- .../shared-direct-listings-page.tsx | 53 ++++ .../ContractEnglishAuctionsPage.client.tsx | 9 +- .../(marketplace)/english-auctions/page.tsx | 46 +-- .../shared-english-auctions-page.tsx | 52 ++++ .../_components/NFTCards.tsx | 11 +- .../redirect-contract-overview.client.tsx | 13 +- .../_layout/contract-page-layout.client.tsx | 6 +- .../_layout/contract-page-layout.tsx | 10 +- .../_layout/primary-dashboard-button.tsx | 20 +- .../_utils/contract-page-path.ts | 15 + .../_utils/getContractFromParams.ts | 9 +- .../_utils/getContractPageSidebarLinks.ts | 9 +- .../AccountSigners.client.tsx | 9 +- .../account-permissions/page.tsx | 39 +-- .../shared-account-permissions-page.tsx | 47 +++ .../account/AccountPage.client.tsx | 10 +- .../[contractAddress]/account/AccountPage.tsx | 9 +- .../account/components/nfts-owned.tsx | 4 + .../[contractAddress]/account/page.tsx | 50 +-- .../account/shared-account-page.tsx | 57 ++++ .../accounts/AccountsPage.client.tsx | 15 +- .../accounts/AccountsPage.tsx | 5 +- .../accounts/components/accounts-table.tsx | 16 +- .../[contractAddress]/accounts/page.tsx | 48 +-- .../accounts/shared-accounts-page.tsx | 54 ++++ .../[contractAddress]/analytics/page.tsx | 70 +---- .../analytics/shared-analytics-page.tsx | 79 +++++ .../ClaimConditions.client.tsx | 9 +- .../claim-conditions/page.tsx | 57 +--- .../shared-claim-conditions-page.tsx | 59 ++++ .../[contractAddress]/code/page.tsx | 40 +-- .../code/shared-code-page.tsx | 44 +++ .../cross-chain/data-table.tsx | 26 +- .../[contractAddress]/cross-chain/page.tsx | 288 +----------------- .../cross-chain/shared-cross-chain-page.tsx | 282 +++++++++++++++++ .../[contractAddress]/events/events-feed.tsx | 38 ++- .../[contractAddress]/events/page.tsx | 24 +- .../events/shared-events-page.tsx | 27 ++ .../[contractAddress]/explorer/page.tsx | 42 +-- .../explorer/shared-explorer-page.tsx | 47 +++ .../[chain_id]/[contractAddress]/layout.tsx | 201 +----------- .../ContractEditModulesPage.client.tsx | 9 +- .../[contractAddress]/modules/page.tsx | 46 +-- .../modules/shared-modules-page.tsx | 53 ++++ .../nfts/ContractNFTPage.client.tsx | 10 +- .../nfts/ContractNFTPage.tsx | 4 + .../nfts/[tokenId]/TokenIdPage.client.tsx | 10 +- .../[contractAddress]/nfts/[tokenId]/page.tsx | 64 +--- .../nfts/[tokenId]/shared-nfts-token-page.tsx | 80 +++++ .../nfts/[tokenId]/token-id.tsx | 23 +- .../nfts/components/table.tsx | 21 +- .../[contractAddress]/nfts/page.tsx | 43 +-- .../nfts/shared-nfts-page.tsx | 56 ++++ .../[contractAddress]/opengraph-image.tsx | 6 +- .../overview/ContractOverviewPage.tsx | 10 + .../overview/components/Analytics.tsx | 14 +- .../overview/components/BuildYourApp.tsx | 12 +- .../overview/components/ContractChecklist.tsx | 18 +- .../overview/components/LatestEvents.tsx | 12 +- .../components/MarketplaceDetails.tsx | 39 ++- .../overview/components/NFTDetails.tsx | 12 +- .../overview/components/PermissionsTable.tsx | 12 +- .../contract-overview-page.client.tsx | 5 +- .../[chain_id]/[contractAddress]/page.tsx | 55 +--- .../ContractPermissionsPage.client.tsx | 3 + .../permissions/ContractPermissionsPage.tsx | 23 +- .../[contractAddress]/permissions/page.tsx | 44 +-- .../permissions/shared-permissions-page.tsx | 48 +++ .../ContractProposalsPage.client.tsx | 9 +- .../[contractAddress]/proposals/page.tsx | 43 +-- .../proposals/shared-proposals-page.tsx | 52 ++++ .../[contractAddress]/settings/page.tsx | 53 +--- .../settings/shared-settings-page.tsx | 62 ++++ .../[contractAddress]/shared-layout.tsx | 218 +++++++++++++ .../shared-overview-page.tsx | 61 ++++ .../[contractAddress]/sources/page.tsx | 24 +- .../sources/shared-sources-page.tsx | 22 ++ .../split/ContractSplitPage.client.tsx | 9 +- .../[contractAddress]/split/page.tsx | 44 +-- .../split/shared-split-page.tsx | 52 ++++ .../[contractAddress]/tokens/page.tsx | 47 +-- .../[contractAddress]/tokens/shared-page.tsx | 50 +++ .../[chain_id]/[contractAddress]/types.ts | 4 + .../_components/DeployedContractsPage.tsx | 6 + .../src/app/(app)/api/lib/getAuthToken.ts | 12 +- .../[project_slug]/(sidebar)/assets/page.tsx | 6 + .../account-abstraction/factories/page.tsx | 10 + .../(sidebar)/contracts/page.tsx | 2 + .../(marketplace)/direct-listings/page.tsx | 28 ++ .../(marketplace)/english-auctions/page.tsx | 28 ++ .../account-permissions/page.tsx | 27 ++ .../[contractAddress]/account/page.tsx | 28 ++ .../[contractAddress]/accounts/page.tsx | 28 ++ .../[contractAddress]/analytics/page.tsx | 27 ++ .../claim-conditions/page.tsx | 28 ++ .../[contractAddress]/code/page.tsx | 27 ++ .../[contractAddress]/cross-chain/page.tsx | 27 ++ .../[contractAddress]/events/page.tsx | 27 ++ .../[contractAddress]/explorer/page.tsx | 28 ++ .../[contractAddress]/layout.tsx | 88 ++++++ .../[contractAddress]/modules/page.tsx | 28 ++ .../[contractAddress]/nfts/[tokenId]/page.tsx | 33 ++ .../[contractAddress]/nfts/page.tsx | 28 ++ .../[contractAddress]/page.tsx | 27 ++ .../[contractAddress]/permissions/page.tsx | 28 ++ .../[contractAddress]/proposals/page.tsx | 28 ++ .../[contractAddress]/settings/page.tsx | 28 ++ .../[contractAddress]/sources/page.tsx | 27 ++ .../[contractAddress]/split/page.tsx | 28 ++ .../[contractAddress]/tokens/page.tsx | 28 ++ .../[contractAddress]/types.ts | 12 + .../[contractAddress]/utils.ts | 18 ++ .../contract-components/tables/cells.tsx | 4 +- .../tables/contract-table.stories.tsx | 13 + .../tables/contract-table.tsx | 8 + .../AccountFactories/factory-contracts.tsx | 6 + 118 files changed, 2952 insertions(+), 1302 deletions(-) create mode 100644 apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/(marketplace)/direct-listings/shared-direct-listings-page.tsx create mode 100644 apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/(marketplace)/english-auctions/shared-english-auctions-page.tsx create mode 100644 apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/_utils/contract-page-path.ts create mode 100644 apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/account-permissions/shared-account-permissions-page.tsx create mode 100644 apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/account/shared-account-page.tsx create mode 100644 apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/accounts/shared-accounts-page.tsx create mode 100644 apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/analytics/shared-analytics-page.tsx create mode 100644 apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/claim-conditions/shared-claim-conditions-page.tsx create mode 100644 apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/code/shared-code-page.tsx create mode 100644 apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/cross-chain/shared-cross-chain-page.tsx create mode 100644 apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/events/shared-events-page.tsx create mode 100644 apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/explorer/shared-explorer-page.tsx create mode 100644 apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/modules/shared-modules-page.tsx create mode 100644 apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/nfts/[tokenId]/shared-nfts-token-page.tsx create mode 100644 apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/nfts/shared-nfts-page.tsx create mode 100644 apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/permissions/shared-permissions-page.tsx create mode 100644 apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/proposals/shared-proposals-page.tsx create mode 100644 apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/settings/shared-settings-page.tsx create mode 100644 apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/shared-layout.tsx create mode 100644 apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/shared-overview-page.tsx create mode 100644 apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/sources/shared-sources-page.tsx create mode 100644 apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/split/shared-split-page.tsx create mode 100644 apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/tokens/shared-page.tsx create mode 100644 apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/types.ts create mode 100644 apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/contract/[chainIdOrSlug]/[contractAddress]/(marketplace)/direct-listings/page.tsx create mode 100644 apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/contract/[chainIdOrSlug]/[contractAddress]/(marketplace)/english-auctions/page.tsx create mode 100644 apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/contract/[chainIdOrSlug]/[contractAddress]/account-permissions/page.tsx create mode 100644 apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/contract/[chainIdOrSlug]/[contractAddress]/account/page.tsx create mode 100644 apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/contract/[chainIdOrSlug]/[contractAddress]/accounts/page.tsx create mode 100644 apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/contract/[chainIdOrSlug]/[contractAddress]/analytics/page.tsx create mode 100644 apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/contract/[chainIdOrSlug]/[contractAddress]/claim-conditions/page.tsx create mode 100644 apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/contract/[chainIdOrSlug]/[contractAddress]/code/page.tsx create mode 100644 apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/contract/[chainIdOrSlug]/[contractAddress]/cross-chain/page.tsx create mode 100644 apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/contract/[chainIdOrSlug]/[contractAddress]/events/page.tsx create mode 100644 apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/contract/[chainIdOrSlug]/[contractAddress]/explorer/page.tsx create mode 100644 apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/contract/[chainIdOrSlug]/[contractAddress]/layout.tsx create mode 100644 apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/contract/[chainIdOrSlug]/[contractAddress]/modules/page.tsx create mode 100644 apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/contract/[chainIdOrSlug]/[contractAddress]/nfts/[tokenId]/page.tsx create mode 100644 apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/contract/[chainIdOrSlug]/[contractAddress]/nfts/page.tsx create mode 100644 apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/contract/[chainIdOrSlug]/[contractAddress]/page.tsx create mode 100644 apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/contract/[chainIdOrSlug]/[contractAddress]/permissions/page.tsx create mode 100644 apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/contract/[chainIdOrSlug]/[contractAddress]/proposals/page.tsx create mode 100644 apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/contract/[chainIdOrSlug]/[contractAddress]/settings/page.tsx create mode 100644 apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/contract/[chainIdOrSlug]/[contractAddress]/sources/page.tsx create mode 100644 apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/contract/[chainIdOrSlug]/[contractAddress]/split/page.tsx create mode 100644 apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/contract/[chainIdOrSlug]/[contractAddress]/tokens/page.tsx create mode 100644 apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/contract/[chainIdOrSlug]/[contractAddress]/types.ts create mode 100644 apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/contract/[chainIdOrSlug]/[contractAddress]/utils.ts diff --git a/apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/(marketplace)/direct-listings/ContractDirectListingsPage.client.tsx b/apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/(marketplace)/direct-listings/ContractDirectListingsPage.client.tsx index 779be64a80f..a02e6bf35c2 100644 --- a/apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/(marketplace)/direct-listings/ContractDirectListingsPage.client.tsx +++ b/apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/(marketplace)/direct-listings/ContractDirectListingsPage.client.tsx @@ -1,6 +1,7 @@ "use client"; import type { ThirdwebContract } from "thirdweb"; +import type { ProjectMeta } from "../../../../../../team/[team_slug]/[project_slug]/contract/[chainIdOrSlug]/[contractAddress]/types"; import { ErrorPage, LoadingPage } from "../../_components/page-skeletons"; import { RedirectToContractOverview } from "../../_components/redirect-contract-overview.client"; import { useContractPageMetadata } from "../../_hooks/useContractPageMetadata"; @@ -9,6 +10,7 @@ import { ContractDirectListingsPage } from "./ContractDirectListingsPage"; export function ContractDirectListingsPageClient(props: { contract: ThirdwebContract; isLoggedIn: boolean; + projectMeta: ProjectMeta | undefined; }) { const metadataQuery = useContractPageMetadata(props.contract); @@ -21,7 +23,12 @@ export function ContractDirectListingsPageClient(props: { } if (!metadataQuery.data.isDirectListingSupported) { - return ; + return ( + + ); } return ( diff --git a/apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/(marketplace)/direct-listings/page.tsx b/apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/(marketplace)/direct-listings/page.tsx index 0ca53a259b5..cb45767bc19 100644 --- a/apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/(marketplace)/direct-listings/page.tsx +++ b/apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/(marketplace)/direct-listings/page.tsx @@ -1,45 +1,18 @@ -import { notFound, redirect } from "next/navigation"; import { getRawAccount } from "../../../../../../account/settings/getAccount"; -import { getContractPageParamsInfo } from "../../_utils/getContractFromParams"; -import { getContractPageMetadata } from "../../_utils/getContractPageMetadata"; -import { ContractDirectListingsPage } from "./ContractDirectListingsPage"; -import { ContractDirectListingsPageClient } from "./ContractDirectListingsPage.client"; +import type { PublicContractPageParams } from "../../types"; +import { SharedDirectListingsPage } from "./shared-direct-listings-page"; export default async function Page(props: { - params: Promise<{ - contractAddress: string; - chain_id: string; - }>; + params: Promise; }) { - const params = await props.params; - const account = await getRawAccount(); - const info = await getContractPageParamsInfo(params); - - if (!info) { - notFound(); - } - - if (info.isLocalhostChain) { - return ( - - ); - } - - const { isDirectListingSupported, isInsightSupported } = - await getContractPageMetadata(info.serverContract); - - if (!isDirectListingSupported) { - redirect(`/${params.chain_id}/${params.contractAddress}`); - } + const [params, account] = await Promise.all([props.params, getRawAccount()]); return ( - ); } diff --git a/apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/(marketplace)/direct-listings/shared-direct-listings-page.tsx b/apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/(marketplace)/direct-listings/shared-direct-listings-page.tsx new file mode 100644 index 00000000000..c0babf8d735 --- /dev/null +++ b/apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/(marketplace)/direct-listings/shared-direct-listings-page.tsx @@ -0,0 +1,53 @@ +import { notFound } from "next/navigation"; +import type { ProjectMeta } from "../../../../../../team/[team_slug]/[project_slug]/contract/[chainIdOrSlug]/[contractAddress]/types"; +import { redirectToContractLandingPage } from "../../../../../../team/[team_slug]/[project_slug]/contract/[chainIdOrSlug]/[contractAddress]/utils"; +import { getContractPageParamsInfo } from "../../_utils/getContractFromParams"; +import { getContractPageMetadata } from "../../_utils/getContractPageMetadata"; +import { ContractDirectListingsPage } from "./ContractDirectListingsPage"; +import { ContractDirectListingsPageClient } from "./ContractDirectListingsPage.client"; + +export async function SharedDirectListingsPage(props: { + contractAddress: string; + chainIdOrSlug: string; + projectMeta: ProjectMeta | undefined; + isLoggedIn: boolean; +}) { + const info = await getContractPageParamsInfo({ + contractAddress: props.contractAddress, + chainIdOrSlug: props.chainIdOrSlug, + teamId: props.projectMeta?.teamId, + }); + + if (!info) { + notFound(); + } + + if (info.isLocalhostChain) { + return ( + + ); + } + + const { isDirectListingSupported, isInsightSupported } = + await getContractPageMetadata(info.serverContract); + + if (!isDirectListingSupported) { + redirectToContractLandingPage({ + chainIdOrSlug: props.chainIdOrSlug, + contractAddress: props.contractAddress, + projectMeta: props.projectMeta, + }); + } + + return ( + + ); +} diff --git a/apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/(marketplace)/english-auctions/ContractEnglishAuctionsPage.client.tsx b/apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/(marketplace)/english-auctions/ContractEnglishAuctionsPage.client.tsx index 26d755c3cf4..cb52a20dce7 100644 --- a/apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/(marketplace)/english-auctions/ContractEnglishAuctionsPage.client.tsx +++ b/apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/(marketplace)/english-auctions/ContractEnglishAuctionsPage.client.tsx @@ -1,6 +1,7 @@ "use client"; import type { ThirdwebContract } from "thirdweb"; +import type { ProjectMeta } from "../../../../../../team/[team_slug]/[project_slug]/contract/[chainIdOrSlug]/[contractAddress]/types"; import { ErrorPage, LoadingPage } from "../../_components/page-skeletons"; import { RedirectToContractOverview } from "../../_components/redirect-contract-overview.client"; import { useContractPageMetadata } from "../../_hooks/useContractPageMetadata"; @@ -9,6 +10,7 @@ import { ContractEnglishAuctionsPage } from "./ContractEnglishAuctionsPage"; export function ContractEnglishAuctionsPageClient(props: { contract: ThirdwebContract; isLoggedIn: boolean; + projectMeta: ProjectMeta | undefined; }) { const metadataQuery = useContractPageMetadata(props.contract); @@ -21,7 +23,12 @@ export function ContractEnglishAuctionsPageClient(props: { } if (!metadataQuery.data.isEnglishAuctionSupported) { - return ; + return ( + + ); } return ( diff --git a/apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/(marketplace)/english-auctions/page.tsx b/apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/(marketplace)/english-auctions/page.tsx index c60483d1359..7dab8f11b57 100644 --- a/apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/(marketplace)/english-auctions/page.tsx +++ b/apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/(marketplace)/english-auctions/page.tsx @@ -1,46 +1,18 @@ -import { notFound, redirect } from "next/navigation"; import { getRawAccount } from "../../../../../../account/settings/getAccount"; -import { getContractPageParamsInfo } from "../../_utils/getContractFromParams"; -import { getContractPageMetadata } from "../../_utils/getContractPageMetadata"; -import { ContractEnglishAuctionsPage } from "./ContractEnglishAuctionsPage"; -import { ContractEnglishAuctionsPageClient } from "./ContractEnglishAuctionsPage.client"; +import type { PublicContractPageParams } from "../../types"; +import { SharedEnglishAuctionsPage } from "./shared-english-auctions-page"; export default async function Page(props: { - params: Promise<{ - contractAddress: string; - chain_id: string; - }>; + params: Promise; }) { - const params = await props.params; - const info = await getContractPageParamsInfo(params); - - if (!info) { - notFound(); - } - - const twAccount = await getRawAccount(); - - if (info.isLocalhostChain) { - return ( - - ); - } - - const { isEnglishAuctionSupported, isInsightSupported } = - await getContractPageMetadata(info.serverContract); - - if (!isEnglishAuctionSupported) { - redirect(`/${params.chain_id}/${params.contractAddress}`); - } + const [params, account] = await Promise.all([props.params, getRawAccount()]); return ( - ); } diff --git a/apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/(marketplace)/english-auctions/shared-english-auctions-page.tsx b/apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/(marketplace)/english-auctions/shared-english-auctions-page.tsx new file mode 100644 index 00000000000..adf4355a739 --- /dev/null +++ b/apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/(marketplace)/english-auctions/shared-english-auctions-page.tsx @@ -0,0 +1,52 @@ +import { notFound } from "next/navigation"; +import type { ProjectMeta } from "../../../../../../team/[team_slug]/[project_slug]/contract/[chainIdOrSlug]/[contractAddress]/types"; +import { redirectToContractLandingPage } from "../../../../../../team/[team_slug]/[project_slug]/contract/[chainIdOrSlug]/[contractAddress]/utils"; +import { getContractPageParamsInfo } from "../../_utils/getContractFromParams"; +import { getContractPageMetadata } from "../../_utils/getContractPageMetadata"; +import { ContractEnglishAuctionsPage } from "./ContractEnglishAuctionsPage"; +import { ContractEnglishAuctionsPageClient } from "./ContractEnglishAuctionsPage.client"; + +export async function SharedEnglishAuctionsPage(props: { + contractAddress: string; + chainIdOrSlug: string; + projectMeta: ProjectMeta | undefined; + isLoggedIn: boolean; +}) { + const info = await getContractPageParamsInfo({ + contractAddress: props.contractAddress, + chainIdOrSlug: props.chainIdOrSlug, + teamId: props.projectMeta?.teamId, + }); + + if (!info) { + notFound(); + } + + if (info.isLocalhostChain) { + return ( + + ); + } + + const metadata = await getContractPageMetadata(info.serverContract); + + if (!metadata.isEnglishAuctionSupported) { + redirectToContractLandingPage({ + contractAddress: props.contractAddress, + chainIdOrSlug: props.chainIdOrSlug, + projectMeta: props.projectMeta, + }); + } + + return ( + + ); +} diff --git a/apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/_components/NFTCards.tsx b/apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/_components/NFTCards.tsx index 71b3a838451..a51904e3a2e 100644 --- a/apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/_components/NFTCards.tsx +++ b/apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/_components/NFTCards.tsx @@ -3,6 +3,8 @@ import { TrackedLinkTW } from "@/components/ui/tracked-link"; import { useMemo } from "react"; import { type NFT, ZERO_ADDRESS } from "thirdweb"; import { NFTMediaWithEmptyState } from "tw-components/nft-media"; +import type { ProjectMeta } from "../../../../../team/[team_slug]/[project_slug]/contract/[chainIdOrSlug]/[contractAddress]/types"; +import { buildContractPagePath } from "../_utils/contract-page-path"; type NFTWithContract = NFT & { contractAddress: string; chainId: number }; @@ -29,6 +31,7 @@ interface NFTCardsProps { trackingCategory: string; isPending: boolean; allNfts?: boolean; + projectMeta: ProjectMeta | undefined; } export const NFTCards: React.FC = ({ @@ -36,6 +39,7 @@ export const NFTCards: React.FC = ({ trackingCategory, isPending, allNfts, + projectMeta, }) => { const dummyData = useMemo(() => { return Array.from({ @@ -87,7 +91,12 @@ export const NFTCards: React.FC = ({ {v.name} diff --git a/apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/_components/redirect-contract-overview.client.tsx b/apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/_components/redirect-contract-overview.client.tsx index a4758c55726..221582e459a 100644 --- a/apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/_components/redirect-contract-overview.client.tsx +++ b/apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/_components/redirect-contract-overview.client.tsx @@ -3,10 +3,13 @@ import { useDashboardRouter } from "@/lib/DashboardRouter"; import { useEffect, useRef } from "react"; import type { ThirdwebContract } from "thirdweb"; +import type { ProjectMeta } from "../../../../../team/[team_slug]/[project_slug]/contract/[chainIdOrSlug]/[contractAddress]/types"; +import { buildContractPagePath } from "../_utils/contract-page-path"; import { LoadingPage } from "./page-skeletons"; export function RedirectToContractOverview(props: { contract: ThirdwebContract; + projectMeta: ProjectMeta | undefined; }) { const router = useDashboardRouter(); const redirected = useRef(false); @@ -17,8 +20,14 @@ export function RedirectToContractOverview(props: { return; } redirected.current = true; - router.replace(`/${props.contract.chain.id}/${props.contract.address}`); - }, [router, props.contract]); + const landingPage = buildContractPagePath({ + projectMeta: props.projectMeta, + chainIdOrSlug: props.contract.chain.id.toString(), + contractAddress: props.contract.address, + }); + + router.replace(landingPage); + }, [router, props]); return ; } diff --git a/apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/_layout/contract-page-layout.client.tsx b/apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/_layout/contract-page-layout.client.tsx index cf57cd56d84..012cdf64db1 100644 --- a/apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/_layout/contract-page-layout.client.tsx +++ b/apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/_layout/contract-page-layout.client.tsx @@ -2,8 +2,9 @@ import { useQuery } from "@tanstack/react-query"; import type { MinimalTeamsAndProjects } from "components/contract-components/contract-deploy-form/add-to-project-card"; -import type { ThirdwebClient, ThirdwebContract } from "thirdweb"; +import type { ThirdwebContract } from "thirdweb"; import type { ChainMetadata } from "thirdweb/chains"; +import type { ProjectMeta } from "../../../../../team/[team_slug]/[project_slug]/contract/[chainIdOrSlug]/[contractAddress]/types"; import { ErrorPage, LoadingPage } from "../_components/page-skeletons"; import { useContractPageMetadata } from "../_hooks/useContractPageMetadata"; import { getContractPageSidebarLinks } from "../_utils/getContractPageSidebarLinks"; @@ -15,7 +16,7 @@ export function ContractPageLayoutClient(props: { contract: ThirdwebContract; children: React.ReactNode; teamsAndProjects: MinimalTeamsAndProjects | undefined; - client: ThirdwebClient; + projectMeta: ProjectMeta | undefined; }) { const metadataQuery = useContractPageMetadata(props.contract); const headerMetadataQuery = useQuery({ @@ -39,6 +40,7 @@ export function ContractPageLayoutClient(props: { chainSlug: props.chainMetadata.slug, contractAddress: props.contract.address, metadata: metadataQuery.data, + projectMeta: props.projectMeta, }); return ( diff --git a/apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/_layout/contract-page-layout.tsx b/apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/_layout/contract-page-layout.tsx index 1227d27bf1b..8604f1b41a2 100644 --- a/apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/_layout/contract-page-layout.tsx +++ b/apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/_layout/contract-page-layout.tsx @@ -4,8 +4,9 @@ import { SidebarLayout } from "@/components/blocks/SidebarLayout"; import type { DashboardContractMetadata } from "@3rdweb-sdk/react/hooks/useDashboardContractMetadata"; import type { MinimalTeamsAndProjects } from "components/contract-components/contract-deploy-form/add-to-project-card"; import { DeprecatedAlert } from "components/shared/DeprecatedAlert"; -import type { ThirdwebClient, ThirdwebContract } from "thirdweb"; +import type { ThirdwebContract } from "thirdweb"; import type { ChainMetadata } from "thirdweb/chains"; +import type { ProjectMeta } from "../../../../../team/[team_slug]/[project_slug]/contract/[chainIdOrSlug]/[contractAddress]/types"; import { ContractMetadata } from "./contract-metadata"; import { PrimaryDashboardButton } from "./primary-dashboard-button"; @@ -15,8 +16,8 @@ export function ContractPageLayout(props: { children: React.ReactNode; sidebarLinks: SidebarLink[]; dashboardContractMetadata: DashboardContractMetadata | undefined; - client: ThirdwebClient; teamsAndProjects: MinimalTeamsAndProjects | undefined; + projectMeta: ProjectMeta | undefined; externalLinks: | { name: string; @@ -31,7 +32,7 @@ export function ContractPageLayout(props: { dashboardContractMetadata, externalLinks, teamsAndProjects, - client, + projectMeta, } = props; return ( @@ -46,6 +47,7 @@ export function ContractPageLayout(props: { externalLinks={externalLinks} /> diff --git a/apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/_layout/primary-dashboard-button.tsx b/apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/_layout/primary-dashboard-button.tsx index 00abe63ea42..65ce88755df 100644 --- a/apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/_layout/primary-dashboard-button.tsx +++ b/apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/_layout/primary-dashboard-button.tsx @@ -26,6 +26,8 @@ import { useState } from "react"; import { toast } from "sonner"; import type { Chain, ThirdwebClient } from "thirdweb"; import { useAddContractToProject } from "../../../../../team/[team_slug]/[project_slug]/(sidebar)/hooks/project-contracts"; +import type { ProjectMeta } from "../../../../../team/[team_slug]/[project_slug]/contract/[chainIdOrSlug]/[contractAddress]/types"; +import { buildContractPagePath } from "../_utils/contract-page-path"; const TRACKING_CATEGORY = "add_to_dashboard_upsell"; @@ -36,6 +38,7 @@ type AddToDashboardCardProps = { hideCodePageLink?: boolean; teamsAndProjects: MinimalTeamsAndProjects | undefined; client: ThirdwebClient; + projectMeta: ProjectMeta | undefined; }; export const PrimaryDashboardButton: React.FC = ({ @@ -45,9 +48,17 @@ export const PrimaryDashboardButton: React.FC = ({ hideCodePageLink, teamsAndProjects, client, + projectMeta, }) => { const pathname = usePathname(); + const codePagePath = buildContractPagePath({ + projectMeta, + chainIdOrSlug: contractInfo.chainSlug, + contractAddress: contractAddress, + subpath: "/code", + }); + // if user is not logged in if (!teamsAndProjects) { if (hideCodePageLink) { @@ -57,9 +68,7 @@ export const PrimaryDashboardButton: React.FC = ({ if (!pathname?.endsWith("/code")) { return (