From ee951926fb8980df92b5194ca156544cd25e3076 Mon Sep 17 00:00:00 2001 From: MananTank Date: Tue, 18 Feb 2025 18:28:32 +0000 Subject: [PATCH] [TOOL-3453] Dashboard: Fix NFT Metadata issues when adding media URLs instead of uploading (#6288) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit = --- ## PR-Codex overview This PR focuses on updating the NFT metadata handling in the dashboard application, specifically renaming and refactoring properties related to custom images and animations, improving form handling, and enhancing user interface elements. ### Detailed summary - Updated documentation link in `next-env.d.ts`. - Changed `customImage` and `customAnimationUrl` to `image` and `animation_url` in multiple components. - Updated titles and headers for improved clarity in forms. - Enhanced form controls with better error handling and user feedback. - Adjusted layout and spacing in several components for better usability. > ✨ Ask PR-Codex anything about this PR by commenting with `/codex {your question}` --- apps/dashboard/next-env.d.ts | 2 +- .../modules/components/BatchMetadata.tsx | 2 - .../modules/components/Mintable.tsx | 9 +- .../nft/AdvancedNFTMetadataFormGroup.tsx | 18 ++- .../components/update-metadata-form.tsx | 107 ++++++++++-------- .../components/update-metadata-tab.tsx | 4 +- .../nfts/components/lazy-mint-form.tsx | 56 +++++---- .../nfts/components/mint-form.tsx | 56 +++++---- .../nfts/components/shared-metadata-form.tsx | 50 ++++---- .../src/components/shared/FileInput.tsx | 17 ++- 10 files changed, 193 insertions(+), 128 deletions(-) diff --git a/apps/dashboard/next-env.d.ts b/apps/dashboard/next-env.d.ts index 40c3d68096c..1b3be0840f3 100644 --- a/apps/dashboard/next-env.d.ts +++ b/apps/dashboard/next-env.d.ts @@ -2,4 +2,4 @@ /// // NOTE: This file should not be edited -// see https://nextjs.org/docs/app/building-your-application/configuring/typescript for more information. +// see https://nextjs.org/docs/app/api-reference/config/typescript for more information. diff --git a/apps/dashboard/src/app/(dashboard)/(chain)/[chain_id]/[contractAddress]/modules/components/BatchMetadata.tsx b/apps/dashboard/src/app/(dashboard)/(chain)/[chain_id]/[contractAddress]/modules/components/BatchMetadata.tsx index a71f40786e2..3248cbba442 100644 --- a/apps/dashboard/src/app/(dashboard)/(chain)/[chain_id]/[contractAddress]/modules/components/BatchMetadata.tsx +++ b/apps/dashboard/src/app/(dashboard)/(chain)/[chain_id]/[contractAddress]/modules/components/BatchMetadata.tsx @@ -41,8 +41,6 @@ const uploadMetadataFormSchema = z.object({ image: fileBufferOrStringSchema.optional(), animationUri: fileBufferOrStringSchema.optional(), external_url: fileBufferOrStringSchema.optional(), - customImage: z.string().optional(), - customAnimationUrl: z.string().optional(), background_color: z .string() .refine( diff --git a/apps/dashboard/src/app/(dashboard)/(chain)/[chain_id]/[contractAddress]/modules/components/Mintable.tsx b/apps/dashboard/src/app/(dashboard)/(chain)/[chain_id]/[contractAddress]/modules/components/Mintable.tsx index 62fd9fd0d03..2b930a1fb31 100644 --- a/apps/dashboard/src/app/(dashboard)/(chain)/[chain_id]/[contractAddress]/modules/components/Mintable.tsx +++ b/apps/dashboard/src/app/(dashboard)/(chain)/[chain_id]/[contractAddress]/modules/components/Mintable.tsx @@ -54,8 +54,6 @@ export type MintFormValues = NFTMetadataInputLimited & { useNextTokenId: boolean; recipient: string; amount: number; - customImage: string; - customAnimationUrl: string; attributes: { trait_type: string; value: string }[]; tokenId?: string; }; @@ -65,8 +63,7 @@ const isValidNft = (values: MintFormValues) => values.description || values.image || values.animation_url || - values.external_url || - values.customAnimationUrl; + values.external_url; const MINTER_ROLE = 1n; @@ -334,8 +331,6 @@ function PrimarySalesSection(props: { const mintFormSchema = z.object({ useNextTokenId: z.boolean(), - customImage: z.string().optional(), - customAnimationUrl: z.string().optional(), recipient: addressSchema, tokenId: z.coerce.number().min(0, { message: "Invalid tokenId" }).optional(), }); @@ -351,8 +346,6 @@ function MintNFTSection(props: { resolver: zodResolver(mintFormSchema), values: { useNextTokenId: false, - customImage: "", - customAnimationUrl: "", recipient: "", attributes: [{ trait_type: "", value: "" }], amount: 1, diff --git a/apps/dashboard/src/app/(dashboard)/(chain)/[chain_id]/[contractAddress]/modules/components/nft/AdvancedNFTMetadataFormGroup.tsx b/apps/dashboard/src/app/(dashboard)/(chain)/[chain_id]/[contractAddress]/modules/components/nft/AdvancedNFTMetadataFormGroup.tsx index 0550fa2e15d..bce2afaa91c 100644 --- a/apps/dashboard/src/app/(dashboard)/(chain)/[chain_id]/[contractAddress]/modules/components/nft/AdvancedNFTMetadataFormGroup.tsx +++ b/apps/dashboard/src/app/(dashboard)/(chain)/[chain_id]/[contractAddress]/modules/components/nft/AdvancedNFTMetadataFormGroup.tsx @@ -14,8 +14,8 @@ import type { UseFormReturn } from "react-hook-form"; import type { NFTInput } from "thirdweb/utils"; type AdvancedNFTMetadataFormGroupValues = { - customImage?: string; - customAnimationUrl?: string; + image?: NFTInput["image"]; + animation_url?: NFTInput["animation_url"]; background_color?: NFTInput["background_color"]; external_url?: NFTInput["external_url"]; }; @@ -56,12 +56,15 @@ export function AdvancedNFTMetadataFormGroup< ( Image URI - + If you already have your NFT image pre-uploaded, you can set the @@ -74,12 +77,15 @@ export function AdvancedNFTMetadataFormGroup< ( Animation URI - + If you already have your NFT Animation URL pre-uploaded, you can diff --git a/apps/dashboard/src/app/(dashboard)/(chain)/[chain_id]/[contractAddress]/nfts/[tokenId]/components/update-metadata-form.tsx b/apps/dashboard/src/app/(dashboard)/(chain)/[chain_id]/[contractAddress]/nfts/[tokenId]/components/update-metadata-form.tsx index 29fa3524010..41b4178b64e 100644 --- a/apps/dashboard/src/app/(dashboard)/(chain)/[chain_id]/[contractAddress]/nfts/[tokenId]/components/update-metadata-form.tsx +++ b/apps/dashboard/src/app/(dashboard)/(chain)/[chain_id]/[contractAddress]/nfts/[tokenId]/components/update-metadata-form.tsx @@ -7,7 +7,6 @@ import { AccordionIcon, AccordionItem, AccordionPanel, - Divider, FormControl, Input, Textarea, @@ -32,6 +31,7 @@ import { updateTokenURI as updateTokenURI1155, } from "thirdweb/extensions/erc1155"; import { useActiveAccount, useSendAndConfirmTransaction } from "thirdweb/react"; +import type { NFTMetadata } from "thirdweb/utils"; import { Button, FormErrorMessage, @@ -68,20 +68,20 @@ export const UpdateNftMetadata: React.FC = ({ const address = useActiveAccount()?.address; const transformedQueryData = useMemo(() => { - return { - name: nft?.metadata.name || "", - description: nft?.metadata.description || "", - external_url: nft?.metadata.external_url || "", - background_color: nft?.metadata.background_color || "", - attributes: nft?.metadata.attributes || [], - // We override these in the submit if they haven't been changed - image: nft?.metadata.image || undefined, - animation_url: nft?.metadata.animation_url || undefined, - // No need for these, but we need to pass them to the form - supply: 0, - customImage: "", - customAnimationUrl: "", + const nftMetadata: Partial = { + // basic + name: nft.metadata.name || "", + description: nft.metadata.description || "", + // media + image: nft.metadata.image, + animation_url: nft.metadata.animation_url, + // advanced + external_url: nft.metadata.external_url || "", + background_color: nft.metadata.background_color || "", + attributes: nft.metadata.attributes, }; + + return nftMetadata; }, [nft]); const { @@ -91,13 +91,7 @@ export const UpdateNftMetadata: React.FC = ({ watch, handleSubmit, formState: { errors, isDirty }, - } = useForm< - NFTMetadataInputLimited & { - supply: number; - customImage: string; - customAnimationUrl: string; - } - >({ + } = useForm({ defaultValues: transformedQueryData, values: transformedQueryData, }); @@ -140,6 +134,9 @@ export const UpdateNftMetadata: React.FC = ({ }; const imageUrl = useImageFileOrUrl(watch("image") as File | string); + const animationUrlFormValue = watch("animation_url"); + const imageUrlFormValue = watch("image"); + const mediaFileUrl = watch("animation_url") instanceof File ? watch("animation_url") @@ -190,11 +187,8 @@ export const UpdateNftMetadata: React.FC = ({ try { const newMetadata = parseAttributes({ ...data, - image: data.image || data.customImage || nft.metadata.image, - animation_url: - data.animation_url || - data.customAnimationUrl || - nft.metadata.animation_url, + image: data.image || nft.metadata.image, + animation_url: data.animation_url || nft.metadata.animation_url, }); const transaction = useUpdateMetadata @@ -249,10 +243,6 @@ export const UpdateNftMetadata: React.FC = ({ } })} > -
- Metadata - -
Name @@ -263,22 +253,34 @@ export const UpdateNftMetadata: React.FC = ({
{nft?.metadata && !mediaFileUrl && ( )} +
+ You can upload image, audio, video, html, text, pdf, and 3d model files here. @@ -319,6 +321,7 @@ export const UpdateNftMetadata: React.FC = ({ register={register} setValue={setValue} /> + = ({ Advanced Options - + Background Color @@ -357,26 +360,40 @@ export const UpdateNftMetadata: React.FC = ({ )} - + Image URL - + { + setValue("image", e.target.value); + }} + /> - If you already have your NFT image pre-uploaded, you can set the - URL or URI here. + If you already have your NFT image pre-uploaded to a URL, you + can specify it here instead of uploading the media file - - {errors?.customImage?.message} - + {errors?.image?.message} - + Animation URL - + { + setValue("animation_url", e.target.value); + }} + /> - If you already have your NFT Animation URL pre-uploaded, you can - set the URL or URI here. + If you already have your NFT Animation URL pre-uploaded to a + URL, you can specify it here instead of uploading the media file - {errors?.customAnimationUrl?.message} + {errors?.animation_url?.message} diff --git a/apps/dashboard/src/app/(dashboard)/(chain)/[chain_id]/[contractAddress]/nfts/[tokenId]/components/update-metadata-tab.tsx b/apps/dashboard/src/app/(dashboard)/(chain)/[chain_id]/[contractAddress]/nfts/[tokenId]/components/update-metadata-tab.tsx index 44b49fd90af..e8fca48a11b 100644 --- a/apps/dashboard/src/app/(dashboard)/(chain)/[chain_id]/[contractAddress]/nfts/[tokenId]/components/update-metadata-tab.tsx +++ b/apps/dashboard/src/app/(dashboard)/(chain)/[chain_id]/[contractAddress]/nfts/[tokenId]/components/update-metadata-tab.tsx @@ -36,8 +36,8 @@ const UpdateMetadataTab: React.FC = ({ - - Mint NFT + + Update NFT Metadata = ({ watch, handleSubmit, formState: { errors, isDirty }, - } = useForm< - NFTMetadataInputLimited & { - supply: number; - customImage: string; - customAnimationUrl: string; - } - >(); + } = useForm(); const setFile = (file: File) => { if (file.type.includes("image")) { @@ -108,6 +102,9 @@ export const LazyMintNftForm: React.FC = ({ }; const imageUrl = useImageFileOrUrl(watch("image") as File | string); + const animationUrlFormValue = watch("animation_url"); + const imageUrlFormValue = watch("image"); + const mediaFileUrl = watch("animation_url") instanceof File ? watch("animation_url") @@ -261,7 +258,7 @@ export const LazyMintNftForm: React.FC = ({ Advanced Options - + Background Color @@ -290,26 +287,45 @@ export const LazyMintNftForm: React.FC = ({ )} - + Image URL - + { + setValue("image", e.target.value); + }} + /> - If you already have your NFT image pre-uploaded, you can set - the URL or URI here. + If you already have your NFT image pre-uploaded to a URL, you + can specify it here instead of uploading the media file - - {errors?.customImage?.message} - + {errors?.image?.message} - + Animation URL - + { + setValue("animation_url", e.target.value); + }} + /> - If you already have your NFT Animation URL pre-uploaded, you - can set the URL or URI here. + If you already have your NFT Animation URL pre-uploaded to a + URL, you can specify it here instead of uploading the media + file - {errors?.customAnimationUrl?.message} + {errors?.animation_url?.message} diff --git a/apps/dashboard/src/app/(dashboard)/(chain)/[chain_id]/[contractAddress]/nfts/components/mint-form.tsx b/apps/dashboard/src/app/(dashboard)/(chain)/[chain_id]/[contractAddress]/nfts/components/mint-form.tsx index 6eb3bd6f01b..720f18143e9 100644 --- a/apps/dashboard/src/app/(dashboard)/(chain)/[chain_id]/[contractAddress]/nfts/components/mint-form.tsx +++ b/apps/dashboard/src/app/(dashboard)/(chain)/[chain_id]/[contractAddress]/nfts/components/mint-form.tsx @@ -63,8 +63,6 @@ export const NFTMintForm: React.FC = ({ } = useForm< NFTMetadataInputLimited & { supply: number; - customImage: string; - customAnimationUrl: string; } >(); @@ -106,6 +104,8 @@ export const NFTMintForm: React.FC = ({ }; const imageUrl = useImageFileOrUrl(watch("image") as File | string); + const animationUrlFormValue = watch("animation_url"); + const imageUrlFormValue = watch("image"); const mediaFileUrl = watch("animation_url") instanceof File ? watch("animation_url") @@ -144,7 +144,7 @@ export const NFTMintForm: React.FC = ({
{ + onSubmit={handleSubmit(async ({ supply, ...data }) => { if (!address) { toast.error("Please connect your wallet to mint."); return; @@ -153,8 +153,8 @@ export const NFTMintForm: React.FC = ({ try { const dataWithCustom = { ...data, - image: data.image || data.customImage, - animation_url: data.animation_url || data.customAnimationUrl, + image: data.image, + animation_url: data.animation_url, }; trackEvent({ @@ -169,7 +169,7 @@ export const NFTMintForm: React.FC = ({ contract, to: address, nft, - supply: BigInt(data.supply), + supply: BigInt(supply), }); await sendAndConfirmTx.mutateAsync(transaction, { onSuccess: () => { @@ -216,7 +216,7 @@ export const NFTMintForm: React.FC = ({ showUploadButton showPreview={true} setValue={setFile} - className="rounded border border-border transition-all duration-200" + className="shrink-0 rounded border border-border transition-all duration-200" selectOrUpload="Upload" helperText="Media" /> @@ -238,7 +238,7 @@ export const NFTMintForm: React.FC = ({ value={imageUrl} showUploadButton setValue={(file) => setValue("image", file)} - className="rounded border border-border transition-all" + className="shrink-0 rounded border border-border transition-all" /> You can optionally upload an image as the cover of your NFT. @@ -313,26 +313,42 @@ export const NFTMintForm: React.FC = ({ )} - + Image URL - + { + setValue("image", e.target.value); + }} + /> - If you already have your NFT image pre-uploaded, you can set - the URL or URI here. + If you already have your NFT image pre-uploaded to a URL, you + can specify it here instead of uploading the asset - - {errors?.customImage?.message} - + {errors?.image?.message} - + Animation URL - + { + setValue("animation_url", e.target.value); + }} + /> - If you already have your NFT Animation URL pre-uploaded, you - can set the URL or URI here. + If you already have your NFT Animation URL pre-uploaded to a + URL, you can specify it here instead of uploading the asset - {errors?.customAnimationUrl?.message} + {errors?.animation_url?.message} diff --git a/apps/dashboard/src/app/(dashboard)/(chain)/[chain_id]/[contractAddress]/nfts/components/shared-metadata-form.tsx b/apps/dashboard/src/app/(dashboard)/(chain)/[chain_id]/[contractAddress]/nfts/components/shared-metadata-form.tsx index 0c434351e18..43ed8339d0f 100644 --- a/apps/dashboard/src/app/(dashboard)/(chain)/[chain_id]/[contractAddress]/nfts/components/shared-metadata-form.tsx +++ b/apps/dashboard/src/app/(dashboard)/(chain)/[chain_id]/[contractAddress]/nfts/components/shared-metadata-form.tsx @@ -49,13 +49,7 @@ export const SharedMetadataForm: React.FC<{ watch, handleSubmit, formState: { errors, isDirty }, - } = useForm< - NFTMetadataInputLimited & { - supply: number; - customImage: string; - customAnimationUrl: string; - } - >(); + } = useForm(); const setFile = (file: File) => { if (file.type.includes("image")) { @@ -95,6 +89,8 @@ export const SharedMetadataForm: React.FC<{ }; const imageUrl = useImageFileOrUrl(watch("image") as File | string); + const animationUrlFormValue = watch("animation_url"); + const imageUrlFormValue = watch("image"); const mediaFileUrl = watch("animation_url") instanceof File ? watch("animation_url") @@ -135,8 +131,8 @@ export const SharedMetadataForm: React.FC<{ const dataWithCustom = { ...data, - image: data.image || data.customImage, - animation_url: data.animation_url || data.customAnimationUrl, + image: data.image, + animation_url: data.animation_url, }; trackEvent({ @@ -194,7 +190,7 @@ export const SharedMetadataForm: React.FC<{ showUploadButton showPreview={true} setValue={setFile} - className="rounded border border-border transition-all duration-200" + className="shrink-0 rounded border border-border transition-all duration-200" selectOrUpload="Upload" helperText="Media" /> @@ -216,7 +212,7 @@ export const SharedMetadataForm: React.FC<{ value={imageUrl} showUploadButton setValue={(file) => setValue("image", file)} - className="rounded border border-border transition-all" + className="shrink-0 rounded border border-border transition-all" /> You can optionally upload an image as the cover of your NFT. @@ -243,26 +239,42 @@ export const SharedMetadataForm: React.FC<{ - + Image URL - + { + setValue("image", e.target.value); + }} + /> If you already have your NFT image pre-uploaded, you can set the URL or URI here. - - {errors?.customImage?.message} - + {errors?.image?.message} - + Animation URL - + { + setValue("animation_url", e.target.value); + }} + /> If you already have your NFT Animation URL pre-uploaded, you can set the URL or URI here. - {errors?.customAnimationUrl?.message} + {errors?.animation_url?.message} diff --git a/apps/dashboard/src/components/shared/FileInput.tsx b/apps/dashboard/src/components/shared/FileInput.tsx index 2afc529d7c2..0194292d426 100644 --- a/apps/dashboard/src/components/shared/FileInput.tsx +++ b/apps/dashboard/src/components/shared/FileInput.tsx @@ -174,7 +174,7 @@ export const FileInput: React.FC = ({ ))} {showUploadButton || noDisplay ? ( -
+
{showUploadButton && ( )} {noDisplay && ( - - - + + )}
) : null}