Fixes and improvements (#28)

* Update collection creation error messages

* Update minimum unit price

* Update .env.example

* Fix double ustars conversion for whitelist & minter unit_price

* Add minimum unit price for whitelisted addresses

* Fix: Invalid baseTokenURI error during collection instantiation

* Collection cover image URI update

* Minimum unit price update - 2

* Fix: nonfunctional existing whitelist option

* Check matching asset and metadata file arrays before creating a collection

* Mark minting detail inputs as required

* Fix: collection creation with the specified royalty preference

* Fix: whitelistType change problem

* Fix creation logic

* Automate number of tokens input & check per address limit

* Automate number of tokens input & check per address limit - 2

* Metadata files should have .json extensions

* Check royalty percentage

* Upload service related changes now trigger state updates

Co-authored-by: findolor <anakisci@gmail.com>
This commit is contained in:
Serkan Reis
2022-08-09 14:42:55 +03:00
committed by GitHub
co-authored by findolor
parent 986777b73d
commit 0f0e68a285
7 changed files with 77 additions and 47 deletions
@@ -8,6 +8,7 @@ import { NumberInput } from '../../forms/FormInput'
interface MintingDetailsProps {
onChange: (data: MintingDetailsDataProps) => void
numberOfTokens: number | undefined
}
export interface MintingDetailsDataProps {
@@ -17,7 +18,7 @@ export interface MintingDetailsDataProps {
startTime: string
}
export const MintingDetails = ({ onChange }: MintingDetailsProps) => {
export const MintingDetails = ({ onChange, numberOfTokens }: MintingDetailsProps) => {
const [timestamp, setTimestamp] = useState<Date | undefined>()
const numberOfTokensState = useNumberInputState({
@@ -45,6 +46,7 @@ export const MintingDetails = ({ onChange }: MintingDetailsProps) => {
})
useEffect(() => {
if (numberOfTokens) numberOfTokensState.onChange(numberOfTokens)
const data: MintingDetailsDataProps = {
numTokens: numberOfTokensState.value,
unitPrice: unitPriceState.value ? (Number(unitPriceState.value) * 1_000_000).toString() : '',
@@ -53,14 +55,14 @@ export const MintingDetails = ({ onChange }: MintingDetailsProps) => {
}
onChange(data)
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [numberOfTokensState.value, unitPriceState.value, perAddressLimitState.value, timestamp])
}, [numberOfTokens, numberOfTokensState.value, unitPriceState.value, perAddressLimitState.value, timestamp])
return (
<div>
<FormGroup subtitle="Information about your minting settings" title="Minting Details">
<NumberInput {...numberOfTokensState} />
<NumberInput {...unitPriceState} />
<NumberInput {...perAddressLimitState} />
<NumberInput {...numberOfTokensState} disabled isRequired value={numberOfTokens} />
<NumberInput {...unitPriceState} isRequired />
<NumberInput {...perAddressLimitState} isRequired />
<FormControl htmlId="timestamp" isRequired subtitle="Start time for the minting" title="Start Time">
<InputDateTime minDate={new Date()} onChange={(date) => setTimestamp(date)} value={timestamp} />
</FormControl>
@@ -44,7 +44,7 @@ export const RoyaltyDetails = ({ onChange }: RoyaltyDetailsProps) => {
}
onChange(data)
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [royaltyPaymentAddressState.value, royaltyShareState.value])
}, [royaltyState, royaltyPaymentAddressState.value, royaltyShareState.value])
return (
<div className="py-3 px-8 rounded border-2 border-white/20">
@@ -78,7 +78,7 @@ export const RoyaltyDetails = ({ onChange }: RoyaltyDetailsProps) => {
value="Existing"
/>
<label className="inline-block text-white cursor-pointer form-check-label" htmlFor="royaltyRadio2">
New royalty
Configure royalty details
</label>
</div>
</div>
@@ -98,11 +98,9 @@ export const UploadDetails = ({ onChange }: UploadDetailsProps) => {
if (event.target.files === null) return toast.error('No files selected.')
for (let i = 0; i < event.target.files.length; i++) {
reader = new FileReader()
reader.onload = async (e) => {
reader.onload = (e) => {
if (!e.target?.result) return toast.error('Error parsing file.')
if (!event.target.files) return toast.error('No files selected.')
if (!JSON.parse(await event.target.files[i].text()).attributes)
return toast.error(`The file with name '${event.target.files[i].name}' doesn't have an attributes list!`)
const metadataFile = new File([e.target.result], event.target.files[i].name, { type: 'application/json' })
setMetadataFilesArray((prev) => [...prev, metadataFile])
}
@@ -126,16 +124,6 @@ export const UploadDetails = ({ onChange }: UploadDetailsProps) => {
console.log(JSON.parse(await metadataFilesArray[metadataFileArrayIndex]?.text()))
}
const checkAssetMetadataMatch = () => {
const metadataFileNames = metadataFilesArray.map((file) => file.name)
const assetFileNames = assetFilesArray.map((file) => file.name.substring(0, file.name.lastIndexOf('.')))
// Compare the two arrays to make sure they are the same
const areArraysEqual = metadataFileNames.every((val, index) => val === assetFileNames[index])
if (!areArraysEqual) {
throw new Error('Asset and metadata file names do not match.')
}
}
const videoPreviewElements = useMemo(() => {
const tempArray: JSX.Element[] = []
assetFilesArray.forEach((assetFile) => {
@@ -163,7 +151,6 @@ export const UploadDetails = ({ onChange }: UploadDetailsProps) => {
useEffect(() => {
try {
checkAssetMetadataMatch()
const data: UploadDetailsDataProps = {
assetFiles: assetFilesArray,
metadataFiles: metadataFilesArray,
@@ -176,7 +163,14 @@ export const UploadDetails = ({ onChange }: UploadDetailsProps) => {
} catch (error: any) {
toast.error(error.message)
}
}, [assetFilesArray, metadataFilesArray])
}, [
assetFilesArray,
metadataFilesArray,
uploadService,
nftStorageApiKeyState.value,
pinataApiKeyState.value,
pinataSecretKeyState.value,
])
useEffect(() => {
setAssetFilesArray([])
@@ -383,7 +377,7 @@ export const UploadDetails = ({ onChange }: UploadDetailsProps) => {
)}
>
<input
accept=""
accept="application/json"
className={clsx(
'file:py-2 file:px-4 file:mr-4 file:bg-plumbus-light file:rounded file:border-0 cursor-pointer',
'before:absolute before:inset-0 before:hover:bg-white/5 before:transition',
@@ -36,6 +36,7 @@ export const WhitelistDetails = ({ onChange }: WhitelistDetailsProps) => {
id: 'whitelist-address',
name: 'whitelistAddress',
title: 'Whitelist Address',
defaultValue: '',
})
const uniPriceState = useNumberInputState({
@@ -79,7 +80,16 @@ export const WhitelistDetails = ({ onChange }: WhitelistDetailsProps) => {
}
onChange(data)
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [uniPriceState.value, memberLimitState.value, perAddressLimitState.value, startDate, endDate, whitelistArray])
}, [
whitelistAddressState.value,
uniPriceState.value,
memberLimitState.value,
perAddressLimitState.value,
startDate,
endDate,
whitelistArray,
whitelistState,
])
return (
<div className="py-3 px-8 rounded border-2 border-white/20">
@@ -135,7 +145,11 @@ export const WhitelistDetails = ({ onChange }: WhitelistDetailsProps) => {
</div>
<Conditional test={whitelistState === 'existing'}>
<AddressInput {...whitelistAddressState} className="pb-5" />
<AddressInput
{...whitelistAddressState}
className="pb-5"
onChange={(e) => whitelistAddressState.onChange(e.target.value)}
/>
</Conditional>
<Conditional test={whitelistState === 'new'}>