stargaze-studio/components/MetadataModal.tsx

194 lines
6.3 KiB
TypeScript

/* eslint-disable eslint-comments/disable-enable-pair */
/* eslint-disable @typescript-eslint/no-unnecessary-condition */
/* eslint-disable @typescript-eslint/no-unsafe-call */
import { useMetadataAttributesState } from 'components/forms/MetadataAttributes.hooks'
import { useEffect, useState } from 'react'
import toast from 'react-hot-toast'
import { Alert } from './Alert'
import { Button } from './Button'
import { Conditional } from './Conditional'
import { TextInput } from './forms/FormInput'
import { useInputState } from './forms/FormInput.hooks'
import { MetadataAttributes } from './forms/MetadataAttributes'
import { MetadataFormGroup } from './MetadataFormGroup'
export interface MetadataModalProps {
assetFile: File
metadataFile: File
updateMetadata: (metadataFile: File) => void
refresher: boolean
}
export const MetadataModal = (props: MetadataModalProps) => {
const metadataFile: File = props.metadataFile
const [metadata, setMetadata] = useState<any>(null)
let parsedMetadata: any
const parseMetadata = async () => {
if (metadataFile) {
attributesState.reset()
parsedMetadata = JSON.parse(await metadataFile.text())
if (!parsedMetadata.attributes || parsedMetadata.attributes.length === 0) {
attributesState.add({
trait_type: '',
value: '',
})
} else {
for (let i = 0; i < parsedMetadata.attributes.length; i++) {
attributesState.add({
trait_type: parsedMetadata.attributes[i].trait_type,
value: parsedMetadata.attributes[i].value,
})
}
}
if (!parsedMetadata.name) {
nameState.onChange('')
} else {
nameState.onChange(parsedMetadata.name)
}
if (!parsedMetadata.description) {
descriptionState.onChange('')
} else {
descriptionState.onChange(parsedMetadata.description)
}
if (!parsedMetadata.external_url) {
externalUrlState.onChange('')
} else {
externalUrlState.onChange(parsedMetadata.external_url)
}
if (!parsedMetadata.youtube_url) {
youtubeUrlState.onChange('')
} else {
youtubeUrlState.onChange(parsedMetadata.youtube_url)
}
setMetadata(parsedMetadata)
} else {
attributesState.reset()
nameState.onChange('')
descriptionState.onChange('')
externalUrlState.onChange('')
youtubeUrlState.onChange('')
setMetadata(null)
}
}
const nameState = useInputState({
id: 'name',
name: 'name',
title: 'Name',
placeholder: 'Token name',
defaultValue: metadata?.name,
})
const descriptionState = useInputState({
id: 'description',
name: 'description',
title: 'Description',
placeholder: 'Token description',
defaultValue: metadata?.description,
})
const externalUrlState = useInputState({
id: 'externalUrl',
name: 'externalUrl',
title: 'External URL',
placeholder: 'https://',
defaultValue: metadata?.external_url,
})
const youtubeUrlState = useInputState({
id: 'youtubeUrl',
name: 'youtubeUrl',
title: 'Youtube URL',
placeholder: 'https://',
defaultValue: metadata?.youtube_url,
})
const attributesState = useMetadataAttributesState()
const generateUpdatedMetadata = () => {
metadata.attributes = Object.values(attributesState)[1]
metadata.attributes = metadata.attributes.filter((attribute: { trait_type: string }) => attribute.trait_type !== '')
if (nameState.value === '') delete metadata.name
else metadata.name = nameState.value
if (descriptionState.value === '') delete metadata.description
else metadata.description = descriptionState.value
if (externalUrlState.value === '') delete metadata.external_url
else metadata.external_url = externalUrlState.value
if (youtubeUrlState.value === '') delete metadata.youtube_url
else metadata.youtube_url = youtubeUrlState.value
const metadataFileBlob = new Blob([JSON.stringify(metadata)], {
type: 'application/json',
})
const editedMetadataFile = new File([metadataFileBlob], metadataFile.name, { type: 'application/json' })
props.updateMetadata(editedMetadataFile)
toast.success('Metadata updated successfully.')
}
useEffect(() => {
void parseMetadata()
}, [props.metadataFile, props.refresher])
return (
<div>
<input className="modal-toggle" id="my-modal-4" type="checkbox" />
<label className="cursor-pointer modal" htmlFor="my-modal-4">
<label
className="absolute top-5 bottom-5 w-full max-w-5xl max-h-full border-2 no-scrollbar modal-box"
htmlFor="temp"
>
<MetadataFormGroup
relatedAsset={props.assetFile}
subtitle={`Asset filename: ${props.assetFile?.name}`}
title="Update Metadata"
>
<TextInput
{...nameState}
disabled={!props.metadataFile}
onChange={(e) => nameState.onChange(e.target.value)}
/>
<TextInput
{...descriptionState}
disabled={!props.metadataFile}
onChange={(e) => descriptionState.onChange(e.target.value)}
/>
<TextInput
{...externalUrlState}
disabled={!props.metadataFile}
onChange={(e) => externalUrlState.onChange(e.target.value)}
/>
<TextInput
{...youtubeUrlState}
disabled={!props.metadataFile}
onChange={(e) => youtubeUrlState.onChange(e.target.value)}
/>
<Conditional test={props.metadataFile !== null}>
<MetadataAttributes
attributes={attributesState.entries}
onAdd={attributesState.add}
onChange={attributesState.update}
onRemove={attributesState.remove}
subtitle="Enter trait types and values"
title="Attributes"
/>
</Conditional>
<Button isDisabled={!props.metadataFile} onClick={generateUpdatedMetadata}>
Update Metadata
</Button>
<Conditional test={Boolean(!props.metadataFile)}>
<Alert type="info">No metadata file to preview. Please select metadata files.</Alert>
</Conditional>
</MetadataFormGroup>
</label>
</label>
</div>
)
}