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 (