diff --git a/apps/dashboard/src/app/(dashboard)/(chain)/[chain_id]/[contractAddress]/sources/ContractSourcesPage.tsx b/apps/dashboard/src/app/(dashboard)/(chain)/[chain_id]/[contractAddress]/sources/ContractSourcesPage.tsx index 4db8aad7ca5..13020d4b0b5 100644 --- a/apps/dashboard/src/app/(dashboard)/(chain)/[chain_id]/[contractAddress]/sources/ContractSourcesPage.tsx +++ b/apps/dashboard/src/app/(dashboard)/(chain)/[chain_id]/[contractAddress]/sources/ContractSourcesPage.tsx @@ -1,41 +1,36 @@ "use client"; -import { Badge } from "@/components/ui/badge"; +import { GenericLoadingPage } from "@/components/blocks/skeletons/GenericLoadingPage"; +import { Spinner } from "@/components/ui/Spinner/Spinner"; import { Button } from "@/components/ui/button"; -import { Card } from "@/components/ui/card"; +import { + Dialog, + DialogContent, + DialogHeader, + DialogTitle, + DialogTrigger, +} from "@/components/ui/dialog"; import { useDashboardRouter } from "@/lib/DashboardRouter"; import { useResolveContractAbi } from "@3rdweb-sdk/react/hooks/useResolveContractAbi"; -import { - Divider, - Flex, - Modal, - ModalBody, - ModalCloseButton, - ModalContent, - ModalHeader, - ModalOverlay, - Spinner, - useDisclosure, -} from "@chakra-ui/react"; import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query"; import { SourcesPanel } from "components/contract-components/shared/sources-panel"; import { useContractSources } from "contract-ui/hooks/useContractSources"; -import { CircleCheckIcon, CircleXIcon } from "lucide-react"; -import { useMemo, useState } from "react"; +import { + CircleCheckIcon, + CircleXIcon, + RefreshCcwIcon, + ShieldCheckIcon, +} from "lucide-react"; +import { useMemo } from "react"; import { toast } from "sonner"; import type { ThirdwebContract } from "thirdweb"; -import { Heading } from "tw-components"; -interface ContractSourcesPageProps { - contract: ThirdwebContract; -} - -interface VerificationResult { +type VerificationResult = { explorerUrl: string; success: boolean; alreadyVerified: boolean; error?: string; -} +}; export async function verifyContract(contract: ThirdwebContract) { try { @@ -63,111 +58,80 @@ export async function verifyContract(contract: ThirdwebContract) { } } -interface ConnectorModalProps { - isOpen: boolean; - onClose: () => void; +function VerifyContractModalContent({ + contract, +}: { contract: ThirdwebContract; -} - -const VerifyContractModal: React.FC< - ConnectorModalProps & { resetSignal: number } -> = ({ isOpen, onClose, contract, resetSignal }) => { +}) { const verifyQuery = useQuery({ - queryKey: [ - "verify-contract", - contract.chain.id, - contract.address, - resetSignal, - ], + queryKey: ["verify-contract", contract.chain.id, contract.address], queryFn: () => verifyContract(contract), - enabled: isOpen, }); return ( - - - - - - Contract Verification - beta - - - - - - - {verifyQuery.isPending && ( - - - Verifying... - - )} - {verifyQuery?.error ? ( - - - - {verifyQuery?.error.toString()} - - - ) : null} +
+ {verifyQuery.isPending && ( +
+
+ +

Verifying

+
+
+ )} - {verifyQuery.data?.results - ? verifyQuery.data?.results.map( - (result: VerificationResult, index: number) => ( - // biome-ignore lint/suspicious/noArrayIndexKey: FIXME - - {result.success && ( - <> - - {result.alreadyVerified && ( - - {result.explorerUrl}: Already verified - - )} - {!result.alreadyVerified && ( - - {result.explorerUrl}: Verification successful - - )} - - )} - {!result.success && ( - <> - - - {`${result.explorerUrl}: Verification failed`} - - - )} - - ), - ) - : null} - - - - - ); -}; - -export const ContractSourcesPage: React.FC = ({ - contract, -}) => { - const [resetSignal, setResetSignal] = useState(0); + {verifyQuery?.error ? ( +
+
+ +

+ {verifyQuery?.error.toString()} +

+
+
+ ) : null} - const { isOpen, onOpen, onClose } = useDisclosure(); + {verifyQuery.data?.results ? ( +
+ {verifyQuery.data.results.map( + (result: VerificationResult, index: number) => ( + // biome-ignore lint/suspicious/noArrayIndexKey: +
+ {result.success && ( + <> + + {result.alreadyVerified && ( +

+ {result.explorerUrl}: Already verified +

+ )} + {!result.alreadyVerified && ( +

+ {result.explorerUrl}: Verification successful +

+ )} + + )} - const handleClose = () => { - onClose(); - // Increment to reset the query in the child component - setResetSignal((prev: number) => prev + 1); - }; + {!result.success && ( + <> + +

+ {`${result.explorerUrl}: Verification failed`} +

+ + )} +
+ ), + )} +
+ ) : null} +
+ ); +} +export function ContractSourcesPage({ + contract, +}: { contract: ThirdwebContract }) { const contractSourcesQuery = useContractSources(contract); const abiQuery = useResolveContractAbi(contract); @@ -187,44 +151,49 @@ export const ContractSourcesPage: React.FC = ({ .reverse(); }, [contractSourcesQuery.data]); - if (!contractSourcesQuery || contractSourcesQuery?.isPending) { - return ( - - - Loading... - - ); + if (!contractSourcesQuery || contractSourcesQuery.isPending) { + return ; } return ( - <> - handleClose()} - contract={contract} - resetSignal={resetSignal} - /> - - - - - Sources - +
+
+
+

Sources

+

+ View ABI and source code for the contract +

+
+
- - - - - - - + + + + + + + + Verify Contract + + + + +
+
+ +
+
+ +
+
); -}; +} function RefreshContractMetadataButton(props: { chainId: number; @@ -270,14 +239,19 @@ function RefreshContractMetadataButton(props: { onClick={() => { toast.promise(contractCacheMutation.mutateAsync(), { duration: 5000, - loading: "Refreshing contract data...", - success: () => "Contract data refreshed!", + success: () => "Contract refreshed successfully", error: (e) => e?.message || "Failed to refresh contract data.", }); }} - className="w-[182px]" + size="sm" + className="gap-2 bg-card" > - {contractCacheMutation.isPending ? : "Refresh Contract Data"} + {contractCacheMutation.isPending ? ( + + ) : ( + + )} + Refresh Contract Data ); } diff --git a/apps/dashboard/src/components/contract-components/shared/sources-accordion.tsx b/apps/dashboard/src/components/contract-components/shared/sources-accordion.tsx index bd5bcab863c..123dc6eec4e 100644 --- a/apps/dashboard/src/components/contract-components/shared/sources-accordion.tsx +++ b/apps/dashboard/src/components/contract-components/shared/sources-accordion.tsx @@ -1,74 +1,64 @@ -import { CodeClient } from "@/components/ui/code/code.client"; import { Accordion, - AccordionButton, - AccordionIcon, + AccordionContent, AccordionItem, - AccordionPanel, -} from "@chakra-ui/react"; + AccordionTrigger, +} from "@/components/ui/accordion"; +import { CodeClient } from "@/components/ui/code/code.client"; import type { Abi } from "abitype"; import type { SourceFile } from "../types"; -interface SourcesAccordionProps { - sources: SourceFile[]; - abi?: Abi; -} - -export const SourcesAccordion: React.FC = ({ +export function SourcesAccordion({ sources, abi, -}) => { +}: { sources: SourceFile[]; abi?: Abi }) { + console.log({ sources }); return ( - - {/* ABI Accordion is put at the top for better UX */} + {abi && ( - - {({ isExpanded }) => ( - <> - -

ABI

- -
- - {isExpanded && ( - - )} - - - )} -
+ )} + {sources.map((signature, i) => ( - - {({ isExpanded }) => ( - <> - -

{signature.filename}

- -
- - {isExpanded && ( - - )} - - - )} -
+ ))}
); -}; +} + +function SourceAccordionItem(props: { + filename: string; + code: string; + accordionId: string; + lang: "solidity" | "json"; +}) { + return ( + + + {props.filename} + + + + + + ); +} diff --git a/apps/dashboard/src/components/contract-components/shared/sources-panel.tsx b/apps/dashboard/src/components/contract-components/shared/sources-panel.tsx index b2c1a3ffb54..64b903e0d82 100644 --- a/apps/dashboard/src/components/contract-components/shared/sources-panel.tsx +++ b/apps/dashboard/src/components/contract-components/shared/sources-panel.tsx @@ -1,5 +1,5 @@ +import { UnderlineLink } from "@/components/ui/UnderlineLink"; import type { Abi } from "abitype"; -import { Link, Text } from "tw-components"; import type { SourceFile } from "../types"; import { SourcesAccordion } from "./sources-accordion"; @@ -15,16 +15,15 @@ export const SourcesPanel: React.FC = ({ sources, abi }) => { {sources && sources?.length > 0 ? ( ) : ( - +

Contract source code not available. Try deploying with{" "} - thirdweb CLI v0.5+ - - + +

)}