diff --git a/apps/dashboard/src/app/(dashboard)/contracts/deploy/page.tsx b/apps/dashboard/src/app/(dashboard)/contracts/deploy/page.tsx new file mode 100644 index 00000000000..3bd6f3f1401 --- /dev/null +++ b/apps/dashboard/src/app/(dashboard)/contracts/deploy/page.tsx @@ -0,0 +1,42 @@ +import { GenericLoadingPage } from "@/components/blocks/skeletons/GenericLoadingPage"; +import { DeployableContractTable } from "components/contract-components/contract-table"; +import Link from "next/link"; +import { notFound } from "next/navigation"; +import { Suspense } from "react"; + +export default async function DeployMultipleContractsPage(props: { + searchParams?: Promise<{ + ipfs?: string[] | string; + }>; +}) { + const searchParams = await props.searchParams; + const ipfsHashes = searchParams?.ipfs; + + if (!ipfsHashes || !Array.isArray(ipfsHashes) || ipfsHashes.length === 0) { + notFound(); + } + + return ( +
+

+ Deploy Contracts +

+

+ Welcome to the thirdweb contract deployment flow.{" "} + + Learn more about deploying your contracts. + +

+ +
+ + }> + + +
+ ); +} diff --git a/apps/dashboard/src/app/(dashboard)/contracts/publish/page.tsx b/apps/dashboard/src/app/(dashboard)/contracts/publish/page.tsx new file mode 100644 index 00000000000..e5eebee4511 --- /dev/null +++ b/apps/dashboard/src/app/(dashboard)/contracts/publish/page.tsx @@ -0,0 +1,42 @@ +import { GenericLoadingPage } from "@/components/blocks/skeletons/GenericLoadingPage"; +import { DeployableContractTable } from "components/contract-components/contract-table"; +import Link from "next/link"; +import { notFound } from "next/navigation"; +import { Suspense } from "react"; + +export default async function PublishMultipleContractsPage(props: { + searchParams?: Promise<{ + ipfs?: string[] | string; + }>; +}) { + const searchParams = await props.searchParams; + const ipfsHashes = searchParams?.ipfs; + + if (!ipfsHashes || !Array.isArray(ipfsHashes) || ipfsHashes.length === 0) { + notFound(); + } + + return ( +
+

+ Publish Contracts +

+

+ Welcome to the thirdweb contract publish flow.{" "} + + Learn more about publishing your contracts. + +

+ +
+ + }> + + +
+ ); +} diff --git a/apps/dashboard/src/app/account/components/account-header.client.tsx b/apps/dashboard/src/app/account/components/account-header.client.tsx deleted file mode 100644 index 09fc87a75d3..00000000000 --- a/apps/dashboard/src/app/account/components/account-header.client.tsx +++ /dev/null @@ -1,57 +0,0 @@ -"use client"; - -import type { Project } from "@/api/projects"; -import type { Team } from "@/api/team"; -import { useAccount } from "@3rdweb-sdk/react/hooks/useApi"; -import { useQuery } from "@tanstack/react-query"; -import { AccountHeader } from "./AccountHeader"; - -// Remove this file when AppShell is deleted - -export function AccountHeaderClient() { - const accountQuery = useAccount(); - const teamsQuery = useQuery({ - queryKey: ["teams", accountQuery.data?.id], - queryFn: () => getTeamsClient(), - }); - - const teamsAndProjectsQuery = useQuery({ - queryKey: [teamsQuery.data?.[0]?.slug, "projects"], - queryFn: async () => { - const teams = teamsQuery.data; - if (!teams) { - throw new Error("No teams"); - } - - const teamsAndProjects = await Promise.all( - teams.map(async (team) => ({ - team, - projects: await getProjectsForTeamClient(team.slug), - })), - ); - - return teamsAndProjects; - }, - enabled: !!teamsQuery.data, - }); - - return ; -} - -async function getTeamsClient() { - const res = await fetch("/api/server-proxy/api/v1/teams"); - if (res.ok) { - return (await res.json()).result as Team[]; - } - throw new Error("Failed to fetch teams"); -} - -async function getProjectsForTeamClient(teamSlug: string) { - const res = await fetch( - `/api/server-proxy/api/v1/teams/${teamSlug}/projects`, - ); - if (res.ok) { - return (await res.json()).result as Project[]; - } - throw new Error("Failed to fetch projects"); -} diff --git a/apps/dashboard/src/app/providers.tsx b/apps/dashboard/src/app/providers.tsx index 96178fd64a5..9d952c2562f 100644 --- a/apps/dashboard/src/app/providers.tsx +++ b/apps/dashboard/src/app/providers.tsx @@ -2,11 +2,15 @@ import { QueryClient, QueryClientProvider } from "@tanstack/react-query"; import { ThemeProvider } from "next-themes"; -import { ThirdwebProvider } from "thirdweb/react"; +import { useMemo } from "react"; +import { ThirdwebProvider, useActiveAccount } from "thirdweb/react"; +import { CustomConnectWallet } from "../@3rdweb-sdk/react/components/connect-wallet"; import { Onboarding } from "../components/onboarding"; import { OpCreditsGrantedModalWrapper } from "../components/onboarding/OpCreditsGrantedModalWrapper"; import { PosthogIdentifier } from "../components/wallets/PosthogIdentifier"; +import { isSanctionedAddress } from "../data/eth-sanctioned-addresses"; import { SyncChainStores } from "../stores/chainStores"; +import type { ComponentWithChildren } from "../types/component-with-children"; import { TWAutoConnect } from "./components/autoconnect"; const queryClient = new QueryClient(); @@ -26,9 +30,30 @@ export function AppRouterProviders(props: { children: React.ReactNode }) { enableSystem={false} defaultTheme="dark" > - {props.children} + + {props.children} + ); } + +const SanctionedAddressesChecker: ComponentWithChildren = ({ children }) => { + const address = useActiveAccount()?.address; + const isBlocked = useMemo(() => { + return address && isSanctionedAddress(address); + }, [address]); + + if (isBlocked) { + return ( +
+
+

Your wallet address is blocked

+ +
+
+ ); + } + return <>{children}; +}; diff --git a/apps/dashboard/src/components/app-layouts/app.tsx b/apps/dashboard/src/components/app-layouts/app.tsx deleted file mode 100644 index 239ff9286d0..00000000000 --- a/apps/dashboard/src/components/app-layouts/app.tsx +++ /dev/null @@ -1,91 +0,0 @@ -import { isProd } from "@/constants/env"; -import type { EVMContractInfo } from "@3rdweb-sdk/react"; -import { CustomConnectWallet } from "@3rdweb-sdk/react/components/connect-wallet"; -import { SimpleGrid } from "@chakra-ui/react"; -import { - type DehydratedState, - HydrationBoundary, - QueryClient, - QueryClientProvider, -} from "@tanstack/react-query"; -import { AppShell, type AppShellProps } from "components/layout/app-shell"; -import { Onboarding as OnboardingModal } from "components/onboarding"; -import { OpCreditsGrantedModalWrapper } from "components/onboarding/OpCreditsGrantedModalWrapper"; -import { PosthogIdentifier } from "components/wallets/PosthogIdentifier"; -import { ErrorProvider } from "contexts/error-handler"; -import { isSanctionedAddress } from "data/eth-sanctioned-addresses"; -import { useEffect, useMemo, useState } from "react"; -import { useActiveAccount } from "thirdweb/react"; -import { Heading } from "tw-components"; -import type { ComponentWithChildren } from "types/component-with-children"; -import { SyncChainStores } from "../../stores/chainStores"; -import { DashboardThirdwebProvider } from "./providers"; - -interface AppLayoutProps extends AppShellProps { - dehydratedState?: DehydratedState; - contractInfo?: EVMContractInfo; -} - -export const AppLayout: ComponentWithChildren = (props) => { - // has to be constructed in here because it may otherwise share state between SSR'd pages - const [queryClient] = useState(() => new QueryClient({})); - - // will be deleted as part of: https://github.com/thirdweb-dev/dashboard/pull/2648 - // eslint-disable-next-line no-restricted-syntax - useEffect(() => { - if (!isProd) { - localStorage.setItem("IS_THIRDWEB_DEV", "true"); - localStorage.setItem( - "THIRDWEB_DEV_URL", - "https://embedded-wallet.thirdweb-dev.com", - ); - } - }, []); - - return ( - - - - - - - - - - - - - - - - - - ); -}; - -const SanctionedAddressesChecker: ComponentWithChildren = ({ children }) => { - const address = useActiveAccount()?.address; - const isBlocked = useMemo(() => { - return address && isSanctionedAddress(address); - }, [address]); - if (isBlocked) { - return ( - -
- Address is blocked - -
-
- ); - } - return <>{children}; -}; diff --git a/apps/dashboard/src/components/app-layouts/providers.tsx b/apps/dashboard/src/components/app-layouts/providers.tsx deleted file mode 100644 index bfa4661e292..00000000000 --- a/apps/dashboard/src/components/app-layouts/providers.tsx +++ /dev/null @@ -1,18 +0,0 @@ -"use client"; -import { useNativeColorMode } from "hooks/useNativeColorMode"; -import { ThirdwebProvider } from "thirdweb/react"; -import type { ComponentWithChildren } from "types/component-with-children"; -import { TWAutoConnect } from "../../app/components/autoconnect"; - -export const DashboardThirdwebProvider: ComponentWithChildren = ({ - children, -}) => { - useNativeColorMode(); - - return ( - - - {children} - - ); -}; diff --git a/apps/dashboard/src/components/contract-components/contract-table/cells/description.tsx b/apps/dashboard/src/components/contract-components/contract-table/cells/description.tsx deleted file mode 100644 index ef16ab7ef90..00000000000 --- a/apps/dashboard/src/components/contract-components/contract-table/cells/description.tsx +++ /dev/null @@ -1,25 +0,0 @@ -import { Skeleton } from "@chakra-ui/react"; -import { useFetchDeployMetadata } from "components/contract-components/hooks"; -import type { DeployableContractContractCellProps } from "components/contract-components/types"; - -import { Text } from "tw-components"; - -export const ContractDescriptionCell: React.FC< - DeployableContractContractCellProps -> = ({ cell: { value } }) => { - const deployMetadataResultQuery = useFetchDeployMetadata(value); - - return ( - - - {deployMetadataResultQuery.data?.description || - (!deployMetadataResultQuery.isFetching ? "First Version" : "None")} - - - ); -}; diff --git a/apps/dashboard/src/components/contract-components/contract-table/cells/image.tsx b/apps/dashboard/src/components/contract-components/contract-table/cells/image.tsx deleted file mode 100644 index 989b7be6197..00000000000 --- a/apps/dashboard/src/components/contract-components/contract-table/cells/image.tsx +++ /dev/null @@ -1,8 +0,0 @@ -import { ContractIdImage } from "components/contract-components/shared/contract-id-image"; -import type { DeployableContractContractCellProps } from "components/contract-components/types"; - -export const ContractImageCell: React.FC< - DeployableContractContractCellProps -> = ({ cell: { value } }) => { - return ; -}; diff --git a/apps/dashboard/src/components/contract-components/contract-table/cells/name.tsx b/apps/dashboard/src/components/contract-components/contract-table/cells/name.tsx deleted file mode 100644 index 5fcf6081a60..00000000000 --- a/apps/dashboard/src/components/contract-components/contract-table/cells/name.tsx +++ /dev/null @@ -1,18 +0,0 @@ -import { Skeleton } from "@chakra-ui/react"; -import { useFetchDeployMetadata } from "components/contract-components/hooks"; -import type { DeployableContractContractCellProps } from "components/contract-components/types"; -import { Text } from "tw-components"; - -export const ContractNameCell: React.FC< - DeployableContractContractCellProps -> = ({ cell: { value } }) => { - const publishMetadata = useFetchDeployMetadata(value); - - return ( - - - {publishMetadata.data?.name} - - - ); -}; diff --git a/apps/dashboard/src/components/contract-components/contract-table/index.tsx b/apps/dashboard/src/components/contract-components/contract-table/index.tsx index fc533d53daa..3aaf3765ca2 100644 --- a/apps/dashboard/src/components/contract-components/contract-table/index.tsx +++ b/apps/dashboard/src/components/contract-components/contract-table/index.tsx @@ -1,157 +1,93 @@ -import { TableContainer } from "@/components/ui/table"; -import { Spinner, Table, Tbody, Td, Th, Thead, Tr } from "@chakra-ui/react"; -import { useMemo } from "react"; -import { type Column, type Row, useTable } from "react-table"; -import { Text } from "tw-components"; -import type { ComponentWithChildren } from "types/component-with-children"; -import type { ContractCellContext, ContractId } from "../types"; -import { ContractDescriptionCell } from "./cells/description"; -import { ContractImageCell } from "./cells/image"; -import { ContractNameCell } from "./cells/name"; +import { + Table, + TableBody, + TableCell, + TableContainer, + TableHead, + TableHeader, + TableRow, +} from "@/components/ui/table"; +import Link from "next/link"; +import { fetchDeployMetadata } from "../fetchDeployMetadata"; +import { ContractIdImage } from "../shared/contract-id-image"; -interface DeployableContractTableProps { - contractIds: ContractId[]; - isFetching?: boolean; - context?: ContractCellContext; -} - -export const DeployableContractTable: ComponentWithChildren< - DeployableContractTableProps -> = ({ contractIds, isFetching, context, children }) => { - const tableColumns: Column<{ contractId: ContractId }>[] = useMemo(() => { - let cols: Column<{ contractId: ContractId }>[] = [ - { - Header: "Icon", - accessor: (row) => row.contractId, - // biome-ignore lint/suspicious/noExplicitAny: FIXME - Cell: (cell: any) => , - }, - { - Header: "Name", - accessor: (row) => row.contractId, - // biome-ignore lint/suspicious/noExplicitAny: FIXME - Cell: (cell: any) => , - }, - ]; +type DeployableContractTableProps = { + contractIds: string[]; + context: "deploy" | "publish"; +}; - if (context !== "deploy") { - cols = [ - ...cols, - { - Header: "Description", - accessor: (row) => row.contractId, - // biome-ignore lint/suspicious/noExplicitAny: FIXME - Cell: (cell: any) => , - }, - ]; - } +export async function DeployableContractTable( + props: DeployableContractTableProps, +) { + const { contractIds, context } = props; + const deployedContractMetadata = await Promise.all( + contractIds.map(async (id) => { + const res = await fetchDeployMetadata(id); + return { + contractId: id, + ...res, + }; + }), + ).catch(() => null); - return cols; - // this is to avoid re-rendering of the table when the contractIds array changes (it will always be a string array, so we can just join it and compare the string output) - }, [context]); + if (!deployedContractMetadata) { + return ( +
+ Failed to load deploy metadata for all contracts +
+ ); + } - const tableInstance = useTable({ - columns: tableColumns, - data: contractIds.map((contractId) => ({ contractId })), - }); + const showDescriptionCell = context === "publish"; return ( - {isFetching && ( - - )} - - - {tableInstance.headerGroups.map((headerGroup) => ( - - {headerGroup.headers.map((column) => ( - - ))} - - ))} - - - {tableInstance.rows.map((row) => { - tableInstance.prepareRow(row); +
- - {column.render("Header")} - -
+ + + Icon + Name + {showDescriptionCell && Description} + + + + + {deployedContractMetadata.map((metadata, i) => { return ( + className="relative cursor-pointer hover:bg-muted/50" + // biome-ignore lint/suspicious/noArrayIndexKey: static list + key={i} + > + {/* Icon */} + + + + + {/* name */} + + + {metadata.name} + + + + {showDescriptionCell && ( + + { + + {metadata.description || "First Version"} + + } + + )} + ); })} - +
- {children}
); -}; - -interface TableRowProps { - row: Row<{ contractId: ContractId }>; - context?: ContractCellContext; -} - -const TableRow: React.FC = ({ row, context }) => { - return ( - { - // always open in new tab - window.open(actionUrlPath(context, row.original.contractId)); - }} - {...row.getRowProps()} - > - {row.cells.map((cell) => ( - - {cell.render("Cell")} - - ))} - - ); -}; - -function actionUrlPath(context: ContractCellContext | undefined, hash: string) { - switch (context) { - case "publish": - return `/contracts/publish/${encodeURIComponent(hash)}`; - case "deploy": - return `/contracts/deploy/${encodeURIComponent(hash)}`; - default: - // should never happen - return `/contracts/deploy/${encodeURIComponent(hash)}`; - } } diff --git a/apps/dashboard/src/components/contract-components/hooks.ts b/apps/dashboard/src/components/contract-components/hooks.ts index 8943cf933e6..e6ebbf1eedf 100644 --- a/apps/dashboard/src/components/contract-components/hooks.ts +++ b/apps/dashboard/src/components/contract-components/hooks.ts @@ -14,18 +14,8 @@ import { fetchPublishedContractVersions, fetchPublisherProfile, } from "./fetch-contracts-with-versions"; -import { fetchDeployMetadata } from "./fetchDeployMetadata"; import { fetchPublishedContracts } from "./fetchPublishedContracts"; import { fetchPublishedContractsFromDeploy } from "./fetchPublishedContractsFromDeploy"; -import type { ContractId } from "./types"; - -export function useFetchDeployMetadata(contractId: ContractId) { - return useQuery({ - queryKey: ["publish-metadata", contractId], - queryFn: () => fetchDeployMetadata(contractId), - enabled: !!contractId, - }); -} function publisherProfileQuery(publisherAddress?: string) { return queryOptions({ diff --git a/apps/dashboard/src/components/contract-components/shared/contract-id-image.tsx b/apps/dashboard/src/components/contract-components/shared/contract-id-image.tsx index cbe5f8120a7..1ce8303ee6f 100644 --- a/apps/dashboard/src/components/contract-components/shared/contract-id-image.tsx +++ b/apps/dashboard/src/components/contract-components/shared/contract-id-image.tsx @@ -1,57 +1,33 @@ -import { Image, Skeleton } from "@chakra-ui/react"; -import { ChakraNextImage, type ChakraNextImageProps } from "components/Image"; +/* eslint-disable @next/next/no-img-element */ import { replaceIpfsUrl } from "lib/sdk"; import type { StaticImageData } from "next/image"; -import { useFetchDeployMetadata } from "../hooks"; -import type { ContractId } from "../types"; +import Image from "next/image"; +import type { FetchDeployMetadataResult } from "thirdweb/contract"; +import generalContractIcon from "../../../../public/assets/tw-icons/general.png"; -interface ContractIdImageProps - extends Omit { - contractId: ContractId; - boxSize?: number; -} +type ContractIdImageProps = { + deployedMetadataResult: FetchDeployMetadataResult; +}; export const ContractIdImage: React.FC = ({ - contractId, - boxSize = 8, - ...imgProps + deployedMetadataResult, }) => { - const deployMetadataResultQuery = useFetchDeployMetadata(contractId); - - const logo = deployMetadataResultQuery.data?.logo; + const logo = deployedMetadataResult.logo; const img = - deployMetadataResultQuery.data?.image !== "custom" - ? deployMetadataResultQuery.data?.image || - require("../../../../public/assets/tw-icons/general.png") - : require("../../../../public/assets/tw-icons/general.png"); + deployedMetadataResult.image !== "custom" + ? deployedMetadataResult.image || generalContractIcon + : generalContractIcon; + + if (logo) { + return ( + + ); + } - const isStaticImage = img && typeof img !== "string"; + if (typeof img !== "string") { + return {""}; + } - return ( - - {logo ? ( - - ) : isStaticImage ? ( - - ) : ( - {deployMetadataResultQuery.data?.name - )} - - ); + return {""}; }; diff --git a/apps/dashboard/src/components/contract-components/types.ts b/apps/dashboard/src/components/contract-components/types.ts index 9426aa10201..896e77ef267 100644 --- a/apps/dashboard/src/components/contract-components/types.ts +++ b/apps/dashboard/src/components/contract-components/types.ts @@ -1,14 +1,6 @@ import type { ContractType } from "constants/contracts"; export type ContractId = ContractType | string; -export type ContractCellContext = "deploy" | "publish"; - -export interface DeployableContractContractCellProps { - cell: { - value: ContractId; - }; - context?: ContractCellContext; -} export type SourceFile = { filename: string | undefined; diff --git a/apps/dashboard/src/components/layout/app-shell/index.tsx b/apps/dashboard/src/components/layout/app-shell/index.tsx deleted file mode 100644 index bd551d0bdd5..00000000000 --- a/apps/dashboard/src/components/layout/app-shell/index.tsx +++ /dev/null @@ -1,47 +0,0 @@ -import { AppFooter } from "@/components/blocks/app-footer"; -import { cn } from "@/lib/utils"; -import { Container } from "@chakra-ui/react"; -import { BillingAlerts } from "components/settings/Account/Billing/alerts/Alert"; -import type { ComponentWithChildren } from "types/component-with-children"; -import { AccountHeaderClient } from "../../../app/account/components/account-header.client"; - -export interface AppShellProps { - layout?: "custom-contract"; - noSEOOverride?: boolean; - hasSidebar?: boolean; - pageContainerClassName?: string; - mainClassName?: string; -} - -// TODO - remove AppShell entirely by moving the 3 pages that still use to app router / (dashboard) layout - -export const AppShell: ComponentWithChildren = ({ - children, - layout, - pageContainerClassName, - mainClassName, -}) => { - return ( -
-
- -
-
- - - - - {layout === "custom-contract" ? ( - children - ) : ( - - {children} - - )} -
- -
- ); -}; diff --git a/apps/dashboard/src/hooks/useNativeColorMode.ts b/apps/dashboard/src/hooks/useNativeColorMode.ts deleted file mode 100644 index 1663fcfb1df..00000000000 --- a/apps/dashboard/src/hooks/useNativeColorMode.ts +++ /dev/null @@ -1,14 +0,0 @@ -"use client"; - -import { useIsomorphicLayoutEffect } from "@/lib/useIsomorphicLayoutEffect"; -import { useColorModeValue } from "@chakra-ui/react"; - -export function useNativeColorMode() { - const activeColorMode = useColorModeValue("light", "dark"); - useIsomorphicLayoutEffect(() => { - document - .getElementById("tw-body-root") - ?.style.setProperty("color-scheme", activeColorMode); - }, [activeColorMode]); - return undefined; -} diff --git a/apps/dashboard/src/page-id.ts b/apps/dashboard/src/page-id.ts index 9d54e2c1cdd..a11a10cecb8 100644 --- a/apps/dashboard/src/page-id.ts +++ b/apps/dashboard/src/page-id.ts @@ -78,14 +78,10 @@ export enum PageId { // --------------------------------------------------------------------------- // "publish" product pages // --------------------------------------------------------------------------- - // thirdweb.com/contracts/publish - PublishMultiple = "publish-multiple-contracts", // --------------------------------------------------------------------------- // "deploy" product pages // --------------------------------------------------------------------------- - // thirdweb.com/contracts/deploy - DeployMultiple = "deploy-multiple-contracts", // thirdweb.com/:network/:contractAddress (evm) // example: thirdweb.com/goerli/0x2eaDAa60dBB74Ead3E20b23E4C5A0Dd789932846 diff --git a/apps/dashboard/src/pages/contracts/deploy/index.tsx b/apps/dashboard/src/pages/contracts/deploy/index.tsx deleted file mode 100644 index b60096d3d09..00000000000 --- a/apps/dashboard/src/pages/contracts/deploy/index.tsx +++ /dev/null @@ -1,53 +0,0 @@ -import { Flex, Link } from "@chakra-ui/react"; -import { AppLayout } from "components/app-layouts/app"; -import { DeployableContractTable } from "components/contract-components/contract-table"; -// import dynamic from "next/dynamic"; -import { useRouter } from "next/router"; -import { PageId } from "page-id"; -import { useMemo } from "react"; -import { Heading, Text } from "tw-components"; -import type { ThirdwebNextPage } from "utils/types"; - -const ContractsDeployPage: ThirdwebNextPage = () => { - const router = useRouter(); - - const ipfsHashes = useMemo(() => { - const ipfs = router.query.ipfs; - return Array.isArray(ipfs) ? ipfs : [ipfs || ""]; - }, [router.query]); - - return ( - <> - - - Deploy Contract - - Welcome to the thirdweb contract deployment flow. -
- - Learn more about deploying your contracts. - -
-
- - -
- - ); -}; - -// const AppLayout = dynamic( -// async () => (await import("components/app-layouts/app")).AppLayout, -// ); - -ContractsDeployPage.getLayout = function getLayout(page, props) { - return {page}; -}; - -ContractsDeployPage.pageId = PageId.DeployMultiple; - -export default ContractsDeployPage; diff --git a/apps/dashboard/src/pages/contracts/publish/index.tsx b/apps/dashboard/src/pages/contracts/publish/index.tsx deleted file mode 100644 index 18d82c5c80a..00000000000 --- a/apps/dashboard/src/pages/contracts/publish/index.tsx +++ /dev/null @@ -1,51 +0,0 @@ -import { Flex, Link } from "@chakra-ui/react"; -import { AppLayout } from "components/app-layouts/app"; -import { DeployableContractTable } from "components/contract-components/contract-table"; -// import dynamic from "next/dynamic"; -import { useRouter } from "next/router"; -import { PageId } from "page-id"; -import { useMemo } from "react"; -import { Heading, Text } from "tw-components"; -import type { ThirdwebNextPage } from "utils/types"; - -const ContractsPublishPage: ThirdwebNextPage = () => { - const router = useRouter(); - - const ipfsHashes = useMemo(() => { - const ipfs = router.query.ipfs; - return Array.isArray(ipfs) ? ipfs : [ipfs || ""]; - }, [router.query]); - - return ( - - - Publish Contracts - - Welcome to the thirdweb contract publish flow. -
- - Learn more about publishing your contracts. - -
-
- - -
- ); -}; - -// const AppLayout = dynamic( -// async () => (await import("components/app-layouts/app")).AppLayout, -// ); - -ContractsPublishPage.getLayout = function getLayout(page, props) { - return {page}; -}; - -ContractsPublishPage.pageId = PageId.PublishMultiple; - -export default ContractsPublishPage;