diff --git a/apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/nfts/components/reveal-button.tsx b/apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/nfts/components/reveal-button.tsx index 9460ad40433..042b19bce8c 100644 --- a/apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/nfts/components/reveal-button.tsx +++ b/apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/nfts/components/reveal-button.tsx @@ -1,7 +1,6 @@ "use client"; -import { FormControl, Input, Select } from "@chakra-ui/react"; -import { FormErrorMessage, FormLabel } from "chakra/form"; +import { zodResolver } from "@hookform/resolvers/zod"; import { EyeIcon } from "lucide-react"; import { useState } from "react"; import { useForm } from "react-hook-form"; @@ -9,9 +8,26 @@ import { toast } from "sonner"; import type { ThirdwebContract } from "thirdweb"; import { getBatchesToReveal, reveal } from "thirdweb/extensions/erc721"; import { useReadContract, useSendAndConfirmTransaction } from "thirdweb/react"; +import * as z from "zod"; import { MinterOnly } from "@/components/contracts/roles/minter-only"; import { TransactionButton } from "@/components/tx-button"; import { Button } from "@/components/ui/button"; +import { + Form, + FormControl, + FormField, + FormItem, + FormLabel, + FormMessage, +} from "@/components/ui/form"; +import { Input } from "@/components/ui/input"; +import { + Select, + SelectContent, + SelectItem, + SelectTrigger, + SelectValue, +} from "@/components/ui/select"; import { Sheet, SheetContent, @@ -20,29 +36,35 @@ import { SheetTrigger, } from "@/components/ui/sheet"; import { ToolTipLabel } from "@/components/ui/tooltip"; +import { parseError } from "@/utils/errorParser"; -interface NFTRevealButtonProps { - contract: ThirdwebContract; - isLoggedIn: boolean; -} +const revealFormSchema = z.object({ + batchId: z.string().min(1, "Please select a batch"), + password: z.string().min(1, "Password is required"), +}); -const REVEAL_FORM_ID = "reveal-form"; +type RevealFormData = z.infer; -export const NFTRevealButton: React.FC = ({ +export function NFTRevealButton({ contract, isLoggedIn, -}) => { +}: { + contract: ThirdwebContract; + isLoggedIn: boolean; +}) { const batchesQuery = useReadContract(getBatchesToReveal, { contract, }); const sendTxMutation = useSendAndConfirmTransaction(); - const { - register, - handleSubmit, - formState: { errors, isDirty }, - } = useForm<{ batchId: string; password: string }>(); + const form = useForm({ + resolver: zodResolver(revealFormSchema), + defaultValues: { + batchId: "", + password: "", + }, + }); const [open, setOpen] = useState(false); @@ -67,6 +89,27 @@ export const NFTRevealButton: React.FC = ({ ); } + const onSubmit = async (data: RevealFormData) => { + const tx = reveal({ + batchId: BigInt(data.batchId), + contract, + password: data.password, + }); + + await sendTxMutation.mutateAsync(tx, { + onError: (error) => { + toast.error("Failed to reveal batch", { + description: parseError(error), + }); + console.error(error); + }, + onSuccess: () => { + toast.success("Batch revealed successfully"); + setOpen(false); + }, + }); + }; + return ( @@ -75,80 +118,80 @@ export const NFTRevealButton: React.FC = ({ Reveal NFTs - + Reveal batch -
{ - const tx = reveal({ - batchId: BigInt(data.batchId), - contract, - password: data.password, - }); - - const promise = sendTxMutation.mutateAsync(tx, { - onError: (error) => { - console.error(error); - }, - onSuccess: () => { - setOpen(false); - }, - }); - - toast.promise(promise, { - error: "Failed to reveal batch", - loading: "Revealing batch", - success: "Batch revealed successfully", - }); - })} - > - - Select a batch - - {errors?.password?.message} - - - Password - - {errors?.password?.message} - -
-
- +
- Reveal NFTs - -
+ ( + + Select a batch + + + + )} + /> + ( + + Password + + + + + + )} + /> + +
+ + Reveal NFTs + +
+ +
); -}; +} diff --git a/apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/nfts/components/shared-metadata-button.tsx b/apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/nfts/components/shared-metadata-button.tsx index c33b4ad1716..c06a3dca958 100644 --- a/apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/nfts/components/shared-metadata-button.tsx +++ b/apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/nfts/components/shared-metadata-button.tsx @@ -13,24 +13,23 @@ import { } from "@/components/ui/sheet"; import { SharedMetadataForm } from "./shared-metadata-form"; -interface NFTSharedMetadataButtonProps { +export function NFTSharedMetadataButton({ + contract, + isLoggedIn, +}: { contract: ThirdwebContract; isLoggedIn: boolean; -} - -export const NFTSharedMetadataButton: React.FC< - NFTSharedMetadataButtonProps -> = ({ contract, isLoggedIn, ...restButtonProps }) => { +}) { const [open, setOpen] = useState(false); return ( - - + Set NFT Metadata @@ -43,4 +42,4 @@ export const NFTSharedMetadataButton: React.FC< ); -}; +} diff --git a/apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/nfts/components/shared-metadata-form.tsx b/apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/nfts/components/shared-metadata-form.tsx index d3789d3f868..2489756145d 100644 --- a/apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/nfts/components/shared-metadata-form.tsx +++ b/apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/nfts/components/shared-metadata-form.tsx @@ -1,19 +1,5 @@ "use client"; -import { - Accordion, - AccordionButton, - AccordionIcon, - AccordionItem, - AccordionPanel, - Divider, - FormControl, - Input, - Textarea, -} from "@chakra-ui/react"; -import { Button } from "chakra/button"; -import { FormErrorMessage, FormHelperText, FormLabel } from "chakra/form"; -import { Heading } from "chakra/heading"; import type { Dispatch, SetStateAction } from "react"; import { useForm } from "react-hook-form"; import { toast } from "sonner"; @@ -22,30 +8,44 @@ import { setSharedMetadata } from "thirdweb/extensions/erc721"; import { useActiveAccount, useSendAndConfirmTransaction } from "thirdweb/react"; import { FileInput } from "@/components/blocks/FileInput"; import { TransactionButton } from "@/components/tx-button"; -import { useTxNotifications } from "@/hooks/useTxNotifications"; +import { + Accordion, + AccordionContent, + AccordionItem, + AccordionTrigger, +} from "@/components/ui/accordion"; +import { Button } from "@/components/ui/button"; +import { + Form, + FormControl, + FormDescription, + FormField, + FormItem, + FormLabel, + FormMessage, +} from "@/components/ui/form"; +import { Input } from "@/components/ui/input"; +import { Textarea } from "@/components/ui/textarea"; import type { NFTMetadataInputLimited } from "@/types/modified-types"; +import { parseError } from "@/utils/errorParser"; import { parseAttributes } from "@/utils/parseAttributes"; import { getUploadedNFTMediaMeta, handleNFTMediaUpload, } from "../../modules/components/nft/handleNFTMediaUpload"; -const SHARED_METADATA_FORM_ID = "shared-metadata-form"; - -export const SharedMetadataForm: React.FC<{ +export function SharedMetadataForm({ + contract, + setOpen, + isLoggedIn, +}: { contract: ThirdwebContract; setOpen: Dispatch>; isLoggedIn: boolean; -}> = ({ contract, setOpen, isLoggedIn }) => { +}) { const address = useActiveAccount()?.address; const sendAndConfirmTx = useSendAndConfirmTransaction(); const form = useForm(); - const { - setValue, - register, - handleSubmit, - formState: { errors, isDirty }, - } = form; const setFile = (file: File) => { handleNFTMediaUpload({ file, form }); @@ -54,17 +54,11 @@ export const SharedMetadataForm: React.FC<{ const { media, image, mediaFileError, showCoverImageUpload, animation_url } = getUploadedNFTMediaMeta(form); - const setSharedMetaNotifications = useTxNotifications( - "Shared metadata updated successfully", - "Failed to update shared metadata", - ); - return ( - <> +
{ + className="mt-4 space-y-6" + onSubmit={form.handleSubmit(async (data) => { if (!address) { toast.error("Please connect your wallet."); return; @@ -76,41 +70,42 @@ export const SharedMetadataForm: React.FC<{ image: data.image, }; - try { - const transaction = setSharedMetadata({ - contract, - nft: parseAttributes(dataWithCustom), - }); - await sendAndConfirmTx.mutateAsync(transaction, { - onError: (error) => { - console.error(error); - }, - onSuccess: () => { - setOpen(false); - }, - }); - - setSharedMetaNotifications.onSuccess(); - } catch (err) { - console.error(err); - setSharedMetaNotifications.onError(err); - } + const transaction = setSharedMetadata({ + contract, + nft: parseAttributes(dataWithCustom), + }); + await sendAndConfirmTx.mutateAsync(transaction, { + onError: (error) => { + toast.error("Failed to update shared metadata", { + description: parseError(error), + }); + }, + onSuccess: () => { + toast.success("Shared metadata updated successfully"); + setOpen(false); + }, + }); })} > -
- Metadata - -
- - Name - - {errors?.name?.message} - - + ( + + Name + + + + + + )} + /> + + Media
- + You can upload image, audio, video, html, text, pdf, and 3d model files here. - - - {mediaFileError?.message as unknown as string} - -
+ + {mediaFileError && ( + {mediaFileError.message} + )} + + {showCoverImageUpload && ( - + Cover Image setValue("image", file)} + setValue={(file) => + form.setValue("image", file, { + shouldValidate: true, + }) + } showUploadButton value={image} /> - + You can optionally upload an image as the cover of your NFT. - - - {errors?.image?.message as unknown as string} - - + + )} - - Description -