diff --git a/components/collections/creation/RoyaltyDetails.tsx b/components/collections/creation/RoyaltyDetails.tsx index d0db2bc..4ef4454 100644 --- a/components/collections/creation/RoyaltyDetails.tsx +++ b/components/collections/creation/RoyaltyDetails.tsx @@ -1,6 +1,7 @@ +import { Conditional } from 'components/Conditional' import { FormGroup } from 'components/FormGroup' import { useInputState, useNumberInputState } from 'components/forms/FormInput.hooks' -import React, { useEffect } from 'react' +import React, { useEffect, useState } from 'react' import { NumberInput, TextInput } from '../../forms/FormInput' @@ -9,11 +10,16 @@ interface RoyaltyDetailsProps { } export interface RoyaltyDetailsDataProps { + royaltyType: RoyaltyState paymentAddress: string share: number } +type RoyaltyState = 'none' | 'new' + export const RoyaltyDetails = ({ onChange }: RoyaltyDetailsProps) => { + const [royaltyState, setRoyaltyState] = useState('none') + const royaltyPaymentAddressState = useInputState({ id: 'royalty-payment-address', name: 'royaltyPaymentAddress', @@ -32,6 +38,7 @@ export const RoyaltyDetails = ({ onChange }: RoyaltyDetailsProps) => { useEffect(() => { const data: RoyaltyDetailsDataProps = { + royaltyType: royaltyState, paymentAddress: royaltyPaymentAddressState.value, share: royaltyShareState.value, } @@ -40,11 +47,47 @@ export const RoyaltyDetails = ({ onChange }: RoyaltyDetailsProps) => { }, [royaltyPaymentAddressState.value, royaltyShareState.value]) return ( -
- - - - +
+
+
+ { + setRoyaltyState('none') + }} + type="radio" + value="None" + /> + +
+
+ { + setRoyaltyState('new') + }} + type="radio" + value="Existing" + /> + +
+
+ + + + + +
) } diff --git a/components/collections/creation/UploadDetails.tsx b/components/collections/creation/UploadDetails.tsx index 68e7d74..e4069e9 100644 --- a/components/collections/creation/UploadDetails.tsx +++ b/components/collections/creation/UploadDetails.tsx @@ -187,170 +187,197 @@ export const UploadDetails = ({ onChange }: UploadDetailsProps) => { }, [uploadMethod]) return ( -
-
-
-
- { - setUploadMethod('existing') - }} - type="radio" - value="Existing" - /> - -
- -
- { - setUploadMethod('new') - }} - type="radio" - value="New" - /> - -
+
+
+
+ { + setUploadMethod('existing') + }} + type="radio" + value="Existing" + /> +
- {baseTokenURI && ( - - - Base Token URI: {baseTokenURI} - - - )} +
+ { + setUploadMethod('new') + }} + type="radio" + value="New" + /> + +
+
-
- -
-

- Though Stargaze's sg721 contract allows for off-chain metadata storage, it is recommended to use a - decentralized storage solution, such as IPFS.
You may head over to{' '} - - NFT Storage - {' '} - or{' '} - - Pinata - {' '} - and upload your assets & metadata manually to get a base URI for your collection. -

-
- - + + Base Token URI: {baseTokenURI} + + + )} + +
+ +
+

+ Though Stargaze's sg721 contract allows for off-chain metadata storage, it is recommended to use a + decentralized storage solution, such as IPFS.
You may head over to{' '} + + NFT Storage + {' '} + or{' '} + + Pinata + {' '} + and upload your assets & metadata manually to get a base URI for your collection. +

+
+ + + id="coverImage" + onChange={handleChangeImage} + placeholder="ipfs://bafybeigi3bwpvyvsmnbj46ra4hyffcxdeaj6ntfk5jpic5mx27x6ih2qvq/images/1.png" + /> +
+
+ + +
+
+
+ +
+
+
+
+ { + setUploadService('nft-storage') + }} + type="radio" + value="nft-storage" + /> + +
+ +
+ { + setUploadService('pinata') + }} + type="radio" + value="pinata" + /> + +
-
- - + +
+ + + + + +
+ +
- - -
-
-
-
- { - setUploadService('nft-storage') - }} - type="radio" - value="nft-storage" - /> - -
-
- { - setUploadService('pinata') - }} - type="radio" - value="pinata" - /> - -
-
- -
- - +
+
+
+ 0 && + metadataFilesArray.length > 0 && + assetFilesArray.length !== metadataFilesArray.length + } + > + + The number of assets and metadata files should match. + - - -
- - -
-
-
-
-
- 0 && - metadataFilesArray.length > 0 && - assetFilesArray.length !== metadataFilesArray.length - } +
+ +
+ +
+
+ {assetFilesArray.length > 0 && (
{ )} >
+ )} - {assetFilesArray.length > 0 && ( -
- -
- -
-
- )} - - -
+ +
0}>
@@ -455,10 +454,12 @@ export const UploadDetails = ({ onChange }: UploadDetailsProps) => {
+ +
-
-
+
+
) diff --git a/components/collections/creation/WhitelistDetails.tsx b/components/collections/creation/WhitelistDetails.tsx index 7ebaabe..f555c1d 100644 --- a/components/collections/creation/WhitelistDetails.tsx +++ b/components/collections/creation/WhitelistDetails.tsx @@ -1,11 +1,11 @@ import { FormControl } from 'components/FormControl' import { FormGroup } from 'components/FormGroup' -import { useNumberInputState } from 'components/forms/FormInput.hooks' +import { useInputState, useNumberInputState } from 'components/forms/FormInput.hooks' import { InputDateTime } from 'components/InputDateTime' import React, { useEffect, useState } from 'react' import { Conditional } from '../../Conditional' -import { NumberInput } from '../../forms/FormInput' +import { AddressInput, NumberInput } from '../../forms/FormInput' import { JsonPreview } from '../../JsonPreview' import { WhitelistUpload } from '../../WhitelistUpload' @@ -14,7 +14,7 @@ interface WhitelistDetailsProps { } export interface WhitelistDetailsDataProps { - isContractAddress: boolean + whitelistType: WhitelistState contractAddress?: string members?: string[] unitPrice?: string @@ -24,11 +24,20 @@ export interface WhitelistDetailsDataProps { memberLimit?: number } +type WhitelistState = 'none' | 'existing' | 'new' + export const WhitelistDetails = ({ onChange }: WhitelistDetailsProps) => { + const [whitelistState, setWhitelistState] = useState('none') const [startDate, setStartDate] = useState(undefined) const [endDate, setEndDate] = useState(undefined) const [whitelistArray, setWhitelistArray] = useState([]) + const whitelistAddressState = useInputState({ + id: 'whitelist-address', + name: 'whitelistAddress', + title: 'Whitelist Address', + }) + const uniPriceState = useNumberInputState({ id: 'unit-price', name: 'unitPrice', @@ -59,8 +68,8 @@ export const WhitelistDetails = ({ onChange }: WhitelistDetailsProps) => { useEffect(() => { const data: WhitelistDetailsDataProps = { - isContractAddress: false, - contractAddress: '', + whitelistType: whitelistState, + contractAddress: whitelistAddressState.value, members: whitelistArray, unitPrice: uniPriceState.value ? (Number(uniPriceState.value) * 1_000_000).toString() : '', startTime: startDate ? (startDate.getTime() * 1_000_000).toString() : '', @@ -73,24 +82,85 @@ export const WhitelistDetails = ({ onChange }: WhitelistDetailsProps) => { }, [uniPriceState.value, memberLimitState.value, perAddressLimitState.value, startDate, endDate, whitelistArray]) return ( -
- - - - - - - - setStartDate(date)} value={startDate} /> - - - setEndDate(date)} value={endDate} /> - - - 0}> - - - +
+
+
+ { + setWhitelistState('none') + }} + type="radio" + value="None" + /> + +
+
+ { + setWhitelistState('existing') + }} + type="radio" + value="Existing" + /> + +
+
+ { + setWhitelistState('new') + }} + type="radio" + value="New" + /> + +
+
+ + + + + + +
+ + + + + + setStartDate(date)} value={startDate} /> + + + setEndDate(date)} value={endDate} /> + + +
+ + + + 0}> + + +
+
+
) } diff --git a/pages/collections/create.tsx b/pages/collections/create.tsx index 9741469..a1ef073 100644 --- a/pages/collections/create.tsx +++ b/pages/collections/create.tsx @@ -65,9 +65,9 @@ const CollectionCreationPage: NextPage = () => { uploadDetails?.pinataSecretKey as string, ) - const whitelist = whitelistDetails?.isContractAddress - ? whitelistDetails.contractAddress - : await instantiateWhitelist() + let whitelist: string | undefined + if (whitelistDetails?.whitelistType === 'existing') whitelist = whitelistDetails.contractAddress + else if (whitelistDetails?.whitelistType === 'new') whitelist = await instantiateWhitelist() await instantate(baseUri, coverImageUri, whitelist) @@ -105,7 +105,7 @@ const CollectionCreationPage: NextPage = () => { if (!minterContract) throw new Error('Contract not found') let royaltyInfo = null - if (royaltyDetails?.paymentAddress && royaltyDetails.share) { + if (royaltyDetails?.royaltyType === 'new') { royaltyInfo = { paymentAddress: royaltyDetails.paymentAddress, share: royaltyDetails.share, @@ -225,8 +225,8 @@ const CollectionCreationPage: NextPage = () => { const checkWhitelistDetails = () => { if (!whitelistDetails) throw new Error('Please fill out the whitelist details') - if (whitelistDetails.isContractAddress) { - if (whitelistDetails.contractAddress === '') throw new Error('Contract address is required') + if (whitelistDetails.whitelistType === 'existing') { + if (whitelistDetails.contractAddress === '') throw new Error('Whitelist contract address is required') } else { if (whitelistDetails.members?.length === 0) throw new Error('Whitelist member list cannot be empty') if (whitelistDetails.unitPrice === '') throw new Error('Whitelist unit price is required') @@ -239,8 +239,10 @@ const CollectionCreationPage: NextPage = () => { const checkRoyaltyDetails = () => { if (!royaltyDetails) throw new Error('Please fill out the royalty details') - if (royaltyDetails.share === 0) throw new Error('Royalty share is required') - if (royaltyDetails.paymentAddress === '') throw new Error('Royalty payment address is required') + if (royaltyDetails.royaltyType === 'new') { + if (royaltyDetails.share === 0) throw new Error('Royalty share is required') + if (royaltyDetails.paymentAddress === '') throw new Error('Royalty payment address is required') + } } return ( @@ -259,28 +261,28 @@ const CollectionCreationPage: NextPage = () => {

- +
+ -
- - -
+
+ + +
-
- -
+
+ + +
-
- - -
- -
- +
+ +
+ +
)