diff --git a/apps/dashboard/src/app/(dashboard)/(chain)/[chain_id]/[contractAddress]/(marketplace)/components/list-button.tsx b/apps/dashboard/src/app/(dashboard)/(chain)/[chain_id]/[contractAddress]/(marketplace)/components/list-button.tsx index dd4067d60e2..6bc97b71620 100644 --- a/apps/dashboard/src/app/(dashboard)/(chain)/[chain_id]/[contractAddress]/(marketplace)/components/list-button.tsx +++ b/apps/dashboard/src/app/(dashboard)/(chain)/[chain_id]/[contractAddress]/(marketplace)/components/list-button.tsx @@ -1,17 +1,20 @@ "use client"; +import { Button } from "@/components/ui/button"; +import { + Sheet, + SheetContent, + SheetHeader, + SheetTitle, + SheetTrigger, +} from "@/components/ui/sheet"; import { ListerOnly } from "@3rdweb-sdk/react/components/roles/lister-only"; -import { useDisclosure } from "@chakra-ui/react"; -import { TransactionButton } from "components/buttons/TransactionButton"; import { PlusIcon } from "lucide-react"; import { useState } from "react"; import type { ThirdwebContract } from "thirdweb"; import { useActiveAccount } from "thirdweb/react"; -import { Button, Drawer } from "tw-components"; import { CreateListingsForm } from "./list-form"; -const LIST_FORM_ID = "marketplace-list-form"; - interface CreateListingButtonProps { contract: ThirdwebContract; createText?: string; @@ -25,59 +28,28 @@ export const CreateListingButton: React.FC = ({ ...restButtonProps }) => { const address = useActiveAccount()?.address; - const { isOpen, onOpen, onClose } = useDisclosure(); - const [isFormLoading, setIsFormLoading] = useState(false); + const [open, setOpen] = useState(false); return ( - - - - {createText} - - - ), - }} - > - - - + + + + + + + {createText} + + + + ); }; diff --git a/apps/dashboard/src/app/(dashboard)/(chain)/[chain_id]/[contractAddress]/(marketplace)/components/list-form.tsx b/apps/dashboard/src/app/(dashboard)/(chain)/[chain_id]/[contractAddress]/(marketplace)/components/list-form.tsx index 577a9340c4b..88cab8d9926 100644 --- a/apps/dashboard/src/app/(dashboard)/(chain)/[chain_id]/[contractAddress]/(marketplace)/components/list-form.tsx +++ b/apps/dashboard/src/app/(dashboard)/(chain)/[chain_id]/[contractAddress]/(marketplace)/components/list-form.tsx @@ -1,4 +1,5 @@ import { Alert, AlertTitle } from "@/components/ui/alert"; +import { Button } from "@/components/ui/button"; import { Card } from "@/components/ui/card"; import { useDashboardOwnedNFTs } from "@3rdweb-sdk/react/hooks/useDashboardOwnedNFTs"; import { useWalletNFTs } from "@3rdweb-sdk/react/hooks/useWalletNFTs"; @@ -10,19 +11,18 @@ import { Select, Spinner, Tooltip, - useModalContext, } from "@chakra-ui/react"; +import { TransactionButton } from "components/buttons/TransactionButton"; import { CurrencySelector } from "components/shared/CurrencySelector"; import { SolidityInput } from "contract-ui/components/solidity-inputs"; import { useTrack } from "hooks/analytics/useTrack"; import { useAllChainsData } from "hooks/chains/allChains"; -import { useTxNotifications } from "hooks/useTxNotifications"; import { isAlchemySupported } from "lib/wallet/nfts/alchemy"; import { isMoralisSupported } from "lib/wallet/nfts/moralis"; import { isSimpleHashSupported } from "lib/wallet/nfts/simpleHash"; import type { WalletNFT } from "lib/wallet/nfts/types"; import { CircleAlertIcon, InfoIcon } from "lucide-react"; -import { useMemo } from "react"; +import { type Dispatch, type SetStateAction, useMemo, useState } from "react"; import { useForm } from "react-hook-form"; import { toast } from "sonner"; import { @@ -58,6 +58,8 @@ import { import { NFTMediaWithEmptyState } from "tw-components/nft-media"; import { shortenIfAddress } from "utils/usedapp-external"; +const LIST_FORM_ID = "marketplace-list-form"; + type ListForm = | (Omit & { currencyContractAddress: string; @@ -79,9 +81,9 @@ type ListForm = type CreateListingsFormProps = { contract: ThirdwebContract; - formId: string; + actionText: string; + setOpen: Dispatch>; type?: "direct-listings" | "english-auctions"; - setIsFormLoading: (loading: boolean) => void; }; const auctionTimes = [ @@ -96,14 +98,15 @@ const auctionTimes = [ export const CreateListingsForm: React.FC = ({ contract, - formId, type, - setIsFormLoading, + actionText, + setOpen, }) => { const trackEvent = useTrack(); const chainId = contract.chain.id; const { idToChain } = useAllChainsData(); const network = idToChain.get(chainId); + const [isFormLoading, setIsFormLoading] = useState(false); const isSupportedChain = chainId && @@ -203,17 +206,10 @@ export const CreateListingsForm: React.FC = ({ const noNfts = !nfts?.length; - const modalContext = useModalContext(); - - const { onSuccess, onError } = useTxNotifications( - "NFT listed successfully", - "Failed to list NFT", - ); - return (
{ if (!formData.selected || !selectedContract) { return; @@ -247,12 +243,13 @@ export const CreateListingsForm: React.FC = ({ approved: true, }); - try { - await sendAndConfirmTx.mutateAsync(approveTx); - } catch { - setIsFormLoading(false); - return toast.error("Failed to approve NFT for marketplace"); - } + const promise = sendAndConfirmTx.mutateAsync(approveTx); + toast.promise(promise, { + loading: "Approving NFT for listing", + success: "NFT approved succesfully", + error: "Failed to approve NFT", + }); + await promise; } if (formData.listingType === "direct") { @@ -270,12 +267,14 @@ export const CreateListingsForm: React.FC = ({ pricePerToken: String(formData.pricePerToken), endTimestamp, }); - await sendAndConfirmTx.mutateAsync(transaction, { - onSuccess: () => { - onSuccess(); - modalContext.onClose(); - }, - onError, + + const promise = sendAndConfirmTx.mutateAsync(transaction, { + onSuccess: () => setOpen(false), + }); + toast.promise(promise, { + loading: "Listing NFT", + success: "NFT listed successfully", + error: "Failed to list NFT", }); } else if (formData.listingType === "auction") { let minimumBidAmountWei: bigint; @@ -323,16 +322,15 @@ export const CreateListingsForm: React.FC = ({ buyoutBidAmountWei * BigInt(formData.quantity), }); - await sendAndConfirmTx.mutateAsync(transaction, { + const promise = sendAndConfirmTx.mutateAsync(transaction, { onSuccess: () => { - onSuccess(); trackEvent({ category: "marketplace", action: "add-listing", label: "success", network, }); - modalContext.onClose(); + setOpen(false); }, onError: (error) => { trackEvent({ @@ -342,11 +340,16 @@ export const CreateListingsForm: React.FC = ({ network, error, }); - onError(error); }, }); + toast.promise(promise, { + loading: "Creating auction", + success: "Auction created successfully", + error: "Failed to create auction", + }); } - } catch { + } catch (err) { + console.error(err); toast.error("Failed to list NFT"); } @@ -540,6 +543,27 @@ export const CreateListingsForm: React.FC = ({ No NFT selected )} + + {/* Need to pin these at the bottom because this is a very long form */} +
+ + + {actionText} + +
); };