Isolate Base & Vending Minter creation UI
This commit is contained in:
parent
637294c9b6
commit
5c6c87eb9e
@ -46,7 +46,7 @@ export const Sidebar = () => {
|
|||||||
!router.asPath.substring(0, router.asPath.lastIndexOf('/') + 1).includes(href) && isChild,
|
!router.asPath.substring(0, router.asPath.lastIndexOf('/') + 1).includes(href) && isChild,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
'text-plumbus': router.asPath.substring(0, router.asPath.lastIndexOf('/') + 1).includes(href) && isChild,
|
'text-stargaze': router.asPath.substring(0, router.asPath.lastIndexOf('/') + 1).includes(href) && isChild,
|
||||||
}, // active route styling
|
}, // active route styling
|
||||||
// { 'text-gray-500 pointer-events-none': disabled }, // disabled route styling
|
// { 'text-gray-500 pointer-events-none': disabled }, // disabled route styling
|
||||||
)}
|
)}
|
||||||
|
199
components/collections/creation/MinterDetails.tsx
Normal file
199
components/collections/creation/MinterDetails.tsx
Normal file
@ -0,0 +1,199 @@
|
|||||||
|
/* eslint-disable eslint-comments/disable-enable-pair */
|
||||||
|
/* eslint-disable @typescript-eslint/no-unsafe-call */
|
||||||
|
/* eslint-disable @typescript-eslint/no-unsafe-member-access */
|
||||||
|
/* eslint-disable @typescript-eslint/no-unsafe-assignment */
|
||||||
|
import { toUtf8 } from '@cosmjs/encoding'
|
||||||
|
import axios from 'axios'
|
||||||
|
import { useInputState } from 'components/forms/FormInput.hooks'
|
||||||
|
import { useWallet } from 'contexts/wallet'
|
||||||
|
import React, { useCallback, useEffect, useState } from 'react'
|
||||||
|
import { toast } from 'react-hot-toast'
|
||||||
|
import { API_URL } from 'utils/constants'
|
||||||
|
|
||||||
|
import { useDebounce } from '../../../utils/debounce'
|
||||||
|
import { TextInput } from '../../forms/FormInput'
|
||||||
|
import type { MinterType } from '../actions/Combobox'
|
||||||
|
|
||||||
|
export type MinterAcquisitionMethod = 'existing' | 'new'
|
||||||
|
|
||||||
|
export interface MinterInfo {
|
||||||
|
name: string
|
||||||
|
minter: string
|
||||||
|
}
|
||||||
|
|
||||||
|
interface MinterDetailsProps {
|
||||||
|
onChange: (data: MinterDetailsDataProps) => void
|
||||||
|
minterType: MinterType
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface MinterDetailsDataProps {
|
||||||
|
minterAcquisitionMethod: MinterAcquisitionMethod
|
||||||
|
existingMinter: string | undefined
|
||||||
|
}
|
||||||
|
|
||||||
|
export const MinterDetails = ({ onChange, minterType }: MinterDetailsProps) => {
|
||||||
|
const wallet = useWallet()
|
||||||
|
|
||||||
|
const [myBaseMinterContracts, setMyBaseMinterContracts] = useState<MinterInfo[]>([])
|
||||||
|
const [minterAcquisitionMethod, setMinterAcquisitionMethod] = useState<MinterAcquisitionMethod>('existing')
|
||||||
|
|
||||||
|
const existingMinterState = useInputState({
|
||||||
|
id: 'existingMinter',
|
||||||
|
name: 'existingMinter',
|
||||||
|
title: 'Existing Base Minter Contract Address',
|
||||||
|
subtitle: '',
|
||||||
|
placeholder: 'stars1...',
|
||||||
|
})
|
||||||
|
|
||||||
|
const fetchMinterContracts = async (): Promise<MinterInfo[]> => {
|
||||||
|
const contracts: MinterInfo[] = await axios
|
||||||
|
.get(`${API_URL}/api/v1beta/collections/${wallet.address}`)
|
||||||
|
.then((response) => {
|
||||||
|
const collectionData = response.data
|
||||||
|
const minterContracts = collectionData.map((collection: any) => {
|
||||||
|
return { name: collection.name, minter: collection.minter }
|
||||||
|
})
|
||||||
|
return minterContracts
|
||||||
|
})
|
||||||
|
.catch(console.error)
|
||||||
|
console.log(contracts)
|
||||||
|
return contracts
|
||||||
|
}
|
||||||
|
|
||||||
|
async function getMinterContractType(minterContractAddress: string) {
|
||||||
|
if (wallet.client && minterContractAddress.length > 0) {
|
||||||
|
const client = wallet.client
|
||||||
|
const data = await client.queryContractRaw(
|
||||||
|
minterContractAddress,
|
||||||
|
toUtf8(Buffer.from(Buffer.from('contract_info').toString('hex'), 'hex').toString()),
|
||||||
|
)
|
||||||
|
const contractType: string = JSON.parse(new TextDecoder().decode(data as Uint8Array)).contract
|
||||||
|
return contractType
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const filterBaseMinterContracts = async () => {
|
||||||
|
setMyBaseMinterContracts([])
|
||||||
|
await fetchMinterContracts()
|
||||||
|
.then((minterContracts) =>
|
||||||
|
minterContracts.map(async (minterContract: any) => {
|
||||||
|
await getMinterContractType(minterContract.minter)
|
||||||
|
.then((contractType) => {
|
||||||
|
if (contractType?.includes('sg-minter')) {
|
||||||
|
setMyBaseMinterContracts((prevState) => [...prevState, minterContract])
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.catch((err) => {
|
||||||
|
console.log(err)
|
||||||
|
console.log('Unable to retrieve contract type')
|
||||||
|
})
|
||||||
|
}),
|
||||||
|
)
|
||||||
|
.catch((err) => {
|
||||||
|
console.log(err)
|
||||||
|
console.log('Unable to fetch base minter contracts')
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
const debouncedMyBaseMinterContracts = useDebounce(myBaseMinterContracts, 500)
|
||||||
|
|
||||||
|
const renderMinterContracts = useCallback(() => {
|
||||||
|
return myBaseMinterContracts.map((minterContract, index) => {
|
||||||
|
return (
|
||||||
|
<option key={index} className="mt-2 text-lg bg-[#1A1A1A]">
|
||||||
|
{`${minterContract.name} - ${minterContract.minter}`}
|
||||||
|
</option>
|
||||||
|
)
|
||||||
|
})
|
||||||
|
}, [debouncedMyBaseMinterContracts])
|
||||||
|
|
||||||
|
const debouncedWalletAddress = useDebounce(wallet.address, 500)
|
||||||
|
|
||||||
|
const displayToast = async () => {
|
||||||
|
await toast.promise(filterBaseMinterContracts(), {
|
||||||
|
loading: 'Fetching Base Minter contracts...',
|
||||||
|
success: 'Base Minter contracts retrieved.',
|
||||||
|
error: 'Unable to retrieve Base Minter contracts.',
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (debouncedWalletAddress && minterAcquisitionMethod === 'existing') {
|
||||||
|
void displayToast()
|
||||||
|
}
|
||||||
|
}, [debouncedWalletAddress, minterAcquisitionMethod])
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const data: MinterDetailsDataProps = {
|
||||||
|
minterAcquisitionMethod,
|
||||||
|
existingMinter: existingMinterState.value,
|
||||||
|
}
|
||||||
|
onChange(data)
|
||||||
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||||
|
}, [existingMinterState.value, minterAcquisitionMethod])
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="mx-10 mb-4 rounded border-2 border-white/20">
|
||||||
|
<div className="flex justify-center mb-2">
|
||||||
|
<div className="mt-3 ml-4 font-bold form-check form-check-inline">
|
||||||
|
<input
|
||||||
|
checked={minterAcquisitionMethod === 'new'}
|
||||||
|
className="peer sr-only"
|
||||||
|
id="inlineRadio5"
|
||||||
|
name="inlineRadioOptions5"
|
||||||
|
onClick={() => {
|
||||||
|
setMinterAcquisitionMethod('new')
|
||||||
|
}}
|
||||||
|
type="radio"
|
||||||
|
value="New"
|
||||||
|
/>
|
||||||
|
<label
|
||||||
|
className="inline-block py-1 px-2 text-gray peer-checked:text-white hover:text-white peer-checked:bg-black peer-checked:border-b-2 hover:border-b-2 peer-checked:border-plumbus hover:border-plumbus cursor-pointer form-check-label"
|
||||||
|
htmlFor="inlineRadio5"
|
||||||
|
>
|
||||||
|
Create a New Base Minter Contract
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
<div className="mt-3 ml-2 font-bold form-check form-check-inline">
|
||||||
|
<input
|
||||||
|
checked={minterAcquisitionMethod === 'existing'}
|
||||||
|
className="peer sr-only"
|
||||||
|
id="inlineRadio6"
|
||||||
|
name="inlineRadioOptions6"
|
||||||
|
onClick={() => {
|
||||||
|
setMinterAcquisitionMethod('existing')
|
||||||
|
}}
|
||||||
|
type="radio"
|
||||||
|
value="Existing"
|
||||||
|
/>
|
||||||
|
<label
|
||||||
|
className="inline-block py-1 px-2 text-gray peer-checked:text-white hover:text-white peer-checked:bg-black peer-checked:border-b-2 hover:border-b-2 peer-checked:border-plumbus hover:border-plumbus cursor-pointer form-check-label"
|
||||||
|
htmlFor="inlineRadio6"
|
||||||
|
>
|
||||||
|
Use an Existing Base Minter Contract
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{minterAcquisitionMethod === 'existing' && (
|
||||||
|
<div>
|
||||||
|
<div className="grid grid-cols-2 grid-flow-col my-4 mx-10">
|
||||||
|
<select
|
||||||
|
className="mt-8 w-full max-w-lg text-sm bg-white/10 select select-bordered"
|
||||||
|
onChange={(e) => {
|
||||||
|
existingMinterState.onChange(e.target.value.slice(e.target.value.indexOf('-') + 2))
|
||||||
|
e.preventDefault()
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<option className="mt-2 text-lg bg-[#1A1A1A]" disabled selected>
|
||||||
|
Select a Base Minter Contract
|
||||||
|
</option>
|
||||||
|
{renderMinterContracts()}
|
||||||
|
</select>
|
||||||
|
<TextInput defaultValue={existingMinterState.value} {...existingMinterState} isRequired />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
@ -233,7 +233,7 @@ export const UploadDetails = ({ onChange }: UploadDetailsProps) => {
|
|||||||
}, [uploadMethod])
|
}, [uploadMethod])
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="justify-items-start mt-5 mb-3 rounded border border-2 border-white/20 flex-column">
|
<div className="justify-items-start mb-3 rounded border-2 border-white/20 flex-column">
|
||||||
<div className="flex justify-center">
|
<div className="flex justify-center">
|
||||||
<div className="mt-3 ml-4 font-bold form-check form-check-inline">
|
<div className="mt-3 ml-4 font-bold form-check form-check-inline">
|
||||||
<input
|
<input
|
||||||
|
@ -14,7 +14,7 @@ const nextConfig = {
|
|||||||
NEXT_PUBLIC_WEBSITE_URL:
|
NEXT_PUBLIC_WEBSITE_URL:
|
||||||
process.env.NODE_ENV === 'development' ? LOCALHOST_URL : process.env.NEXT_PUBLIC_WEBSITE_URL,
|
process.env.NODE_ENV === 'development' ? LOCALHOST_URL : process.env.NEXT_PUBLIC_WEBSITE_URL,
|
||||||
},
|
},
|
||||||
reactStrictMode: true,
|
reactStrictMode: false,
|
||||||
trailingSlash: true,
|
trailingSlash: true,
|
||||||
webpack(config, { dev, webpack }) {
|
webpack(config, { dev, webpack }) {
|
||||||
// svgr integration
|
// svgr integration
|
||||||
|
@ -39,7 +39,8 @@
|
|||||||
"react-datetime-picker": "^3",
|
"react-datetime-picker": "^3",
|
||||||
"react-dom": "^18",
|
"react-dom": "^18",
|
||||||
"react-hook-form": "^7",
|
"react-hook-form": "^7",
|
||||||
"react-hot-toast": "^2",
|
"react-hot-toast": "2.4.0",
|
||||||
|
"react-toastify": "9.1.1",
|
||||||
"react-icons": "^4",
|
"react-icons": "^4",
|
||||||
"react-popper": "^2",
|
"react-popper": "^2",
|
||||||
"react-query": "^3",
|
"react-query": "^3",
|
||||||
|
@ -4,6 +4,7 @@
|
|||||||
/* eslint-disable @typescript-eslint/no-unsafe-member-access */
|
/* eslint-disable @typescript-eslint/no-unsafe-member-access */
|
||||||
|
|
||||||
import { coin } from '@cosmjs/proto-signing'
|
import { coin } from '@cosmjs/proto-signing'
|
||||||
|
import clsx from 'clsx'
|
||||||
import { Alert } from 'components/Alert'
|
import { Alert } from 'components/Alert'
|
||||||
import { Anchor } from 'components/Anchor'
|
import { Anchor } from 'components/Anchor'
|
||||||
import { Button } from 'components/Button'
|
import { Button } from 'components/Button'
|
||||||
@ -15,6 +16,8 @@ import {
|
|||||||
WhitelistDetails,
|
WhitelistDetails,
|
||||||
} from 'components/collections/creation'
|
} from 'components/collections/creation'
|
||||||
import type { CollectionDetailsDataProps } from 'components/collections/creation/CollectionDetails'
|
import type { CollectionDetailsDataProps } from 'components/collections/creation/CollectionDetails'
|
||||||
|
import type { MinterDetailsDataProps } from 'components/collections/creation/MinterDetails'
|
||||||
|
import { MinterDetails } from 'components/collections/creation/MinterDetails'
|
||||||
import type { MintingDetailsDataProps } from 'components/collections/creation/MintingDetails'
|
import type { MintingDetailsDataProps } from 'components/collections/creation/MintingDetails'
|
||||||
import type { RoyaltyDetailsDataProps } from 'components/collections/creation/RoyaltyDetails'
|
import type { RoyaltyDetailsDataProps } from 'components/collections/creation/RoyaltyDetails'
|
||||||
import type { UploadDetailsDataProps } from 'components/collections/creation/UploadDetails'
|
import type { UploadDetailsDataProps } from 'components/collections/creation/UploadDetails'
|
||||||
@ -42,6 +45,7 @@ import {
|
|||||||
import { withMetadata } from 'utils/layout'
|
import { withMetadata } from 'utils/layout'
|
||||||
import { links } from 'utils/links'
|
import { links } from 'utils/links'
|
||||||
|
|
||||||
|
import type { MinterType } from '../../components/collections/actions/Combobox'
|
||||||
import type { UploadMethod } from '../../components/collections/creation/UploadDetails'
|
import type { UploadMethod } from '../../components/collections/creation/UploadDetails'
|
||||||
import { ConfirmationModal } from '../../components/ConfirmationModal'
|
import { ConfirmationModal } from '../../components/ConfirmationModal'
|
||||||
import { getAssetType } from '../../utils/getAssetType'
|
import { getAssetType } from '../../utils/getAssetType'
|
||||||
@ -62,13 +66,17 @@ const CollectionCreationPage: NextPage = () => {
|
|||||||
|
|
||||||
const [uploadDetails, setUploadDetails] = useState<UploadDetailsDataProps | null>(null)
|
const [uploadDetails, setUploadDetails] = useState<UploadDetailsDataProps | null>(null)
|
||||||
const [collectionDetails, setCollectionDetails] = useState<CollectionDetailsDataProps | null>(null)
|
const [collectionDetails, setCollectionDetails] = useState<CollectionDetailsDataProps | null>(null)
|
||||||
|
const [minterDetails, setMinterDetails] = useState<MinterDetailsDataProps | null>(null)
|
||||||
const [mintingDetails, setMintingDetails] = useState<MintingDetailsDataProps | null>(null)
|
const [mintingDetails, setMintingDetails] = useState<MintingDetailsDataProps | null>(null)
|
||||||
const [whitelistDetails, setWhitelistDetails] = useState<WhitelistDetailsDataProps | null>(null)
|
const [whitelistDetails, setWhitelistDetails] = useState<WhitelistDetailsDataProps | null>(null)
|
||||||
const [royaltyDetails, setRoyaltyDetails] = useState<RoyaltyDetailsDataProps | null>(null)
|
const [royaltyDetails, setRoyaltyDetails] = useState<RoyaltyDetailsDataProps | null>(null)
|
||||||
|
const [minterType, setMinterType] = useState<MinterType>('vending')
|
||||||
|
|
||||||
const [uploading, setUploading] = useState(false)
|
const [uploading, setUploading] = useState(false)
|
||||||
const [creatingCollection, setCreatingCollection] = useState(false)
|
const [creatingCollection, setCreatingCollection] = useState(false)
|
||||||
const [readyToCreate, setReadyToCreate] = useState(false)
|
const [readyToCreateVm, setReadyToCreateVm] = useState(false)
|
||||||
|
const [readyToCreateBm, setReadyToCreateBm] = useState(false)
|
||||||
|
const [readyToUploadAndMint, setReadyToUploadAndMint] = useState(false)
|
||||||
const [vendingMinterContractAddress, setVendingMinterContractAddress] = useState<string | null>(null)
|
const [vendingMinterContractAddress, setVendingMinterContractAddress] = useState<string | null>(null)
|
||||||
const [sg721ContractAddress, setSg721ContractAddress] = useState<string | null>(null)
|
const [sg721ContractAddress, setSg721ContractAddress] = useState<string | null>(null)
|
||||||
const [whitelistContractAddress, setWhitelistContractAddress] = useState<string | null | undefined>(null)
|
const [whitelistContractAddress, setWhitelistContractAddress] = useState<string | null | undefined>(null)
|
||||||
@ -76,20 +84,20 @@ const CollectionCreationPage: NextPage = () => {
|
|||||||
const [coverImageUrl, setCoverImageUrl] = useState<string | null>(null)
|
const [coverImageUrl, setCoverImageUrl] = useState<string | null>(null)
|
||||||
const [transactionHash, setTransactionHash] = useState<string | null>(null)
|
const [transactionHash, setTransactionHash] = useState<string | null>(null)
|
||||||
|
|
||||||
const performChecks = () => {
|
const performVendingMinterChecks = () => {
|
||||||
try {
|
try {
|
||||||
setReadyToCreate(false)
|
setReadyToCreateVm(false)
|
||||||
checkUploadDetails()
|
checkUploadDetails()
|
||||||
checkCollectionDetails()
|
checkCollectionDetails()
|
||||||
checkMintingDetails()
|
checkMintingDetails()
|
||||||
checkRoyaltyDetails()
|
checkRoyaltyDetails()
|
||||||
checkWhitelistDetails()
|
checkWhitelistDetails()
|
||||||
.then(() => {
|
.then(() => {
|
||||||
setReadyToCreate(true)
|
setReadyToCreateVm(true)
|
||||||
})
|
})
|
||||||
.catch((err) => {
|
.catch((err) => {
|
||||||
toast.error(`Error in Whitelist Configuration: ${err.message}`, { style: { maxWidth: 'none' } })
|
toast.error(`Error in Whitelist Configuration: ${err.message}`, { style: { maxWidth: 'none' } })
|
||||||
setReadyToCreate(false)
|
setReadyToCreateVm(false)
|
||||||
})
|
})
|
||||||
} catch (error: any) {
|
} catch (error: any) {
|
||||||
toast.error(error.message, { style: { maxWidth: 'none' } })
|
toast.error(error.message, { style: { maxWidth: 'none' } })
|
||||||
@ -97,7 +105,157 @@ const CollectionCreationPage: NextPage = () => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const createCollection = async () => {
|
const performBaseMinterChecks = () => {
|
||||||
|
try {
|
||||||
|
setReadyToCreateBm(false)
|
||||||
|
checkUploadDetails()
|
||||||
|
checkCollectionDetails()
|
||||||
|
checkMintingDetails()
|
||||||
|
checkRoyaltyDetails()
|
||||||
|
checkWhitelistDetails()
|
||||||
|
.then(() => {
|
||||||
|
setReadyToCreateBm(true)
|
||||||
|
})
|
||||||
|
.catch((err) => {
|
||||||
|
toast.error(`Error in Whitelist Configuration: ${err.message}`, { style: { maxWidth: 'none' } })
|
||||||
|
setReadyToCreateBm(false)
|
||||||
|
})
|
||||||
|
} catch (error: any) {
|
||||||
|
toast.error(error.message, { style: { maxWidth: 'none' } })
|
||||||
|
setUploading(false)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const performUploadAndMintChecks = () => {
|
||||||
|
try {
|
||||||
|
setReadyToUploadAndMint(false)
|
||||||
|
checkUploadDetails()
|
||||||
|
checkCollectionDetails()
|
||||||
|
checkMintingDetails()
|
||||||
|
checkRoyaltyDetails()
|
||||||
|
checkWhitelistDetails()
|
||||||
|
.then(() => {
|
||||||
|
setReadyToUploadAndMint(true)
|
||||||
|
})
|
||||||
|
.catch((err) => {
|
||||||
|
toast.error(`Error in Whitelist Configuration: ${err.message}`, { style: { maxWidth: 'none' } })
|
||||||
|
setReadyToUploadAndMint(false)
|
||||||
|
})
|
||||||
|
} catch (error: any) {
|
||||||
|
toast.error(error.message, { style: { maxWidth: 'none' } })
|
||||||
|
setUploading(false)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const createVendingMinterCollection = async () => {
|
||||||
|
try {
|
||||||
|
setCreatingCollection(true)
|
||||||
|
setBaseTokenUri(null)
|
||||||
|
setCoverImageUrl(null)
|
||||||
|
setVendingMinterContractAddress(null)
|
||||||
|
setSg721ContractAddress(null)
|
||||||
|
setWhitelistContractAddress(null)
|
||||||
|
setTransactionHash(null)
|
||||||
|
if (uploadDetails?.uploadMethod === 'new') {
|
||||||
|
setUploading(true)
|
||||||
|
|
||||||
|
const baseUri = await uploadFiles()
|
||||||
|
//upload coverImageUri and append the file name
|
||||||
|
const coverImageUri = await upload(
|
||||||
|
collectionDetails?.imageFile as File[],
|
||||||
|
uploadDetails.uploadService,
|
||||||
|
'cover',
|
||||||
|
uploadDetails.nftStorageApiKey as string,
|
||||||
|
uploadDetails.pinataApiKey as string,
|
||||||
|
uploadDetails.pinataSecretKey as string,
|
||||||
|
)
|
||||||
|
|
||||||
|
setUploading(false)
|
||||||
|
|
||||||
|
setBaseTokenUri(baseUri)
|
||||||
|
setCoverImageUrl(coverImageUri)
|
||||||
|
|
||||||
|
let whitelist: string | undefined
|
||||||
|
if (whitelistDetails?.whitelistType === 'existing') whitelist = whitelistDetails.contractAddress
|
||||||
|
else if (whitelistDetails?.whitelistType === 'new') whitelist = await instantiateWhitelist()
|
||||||
|
setWhitelistContractAddress(whitelist as string)
|
||||||
|
|
||||||
|
await instantiate(baseUri, coverImageUri, whitelist)
|
||||||
|
} else {
|
||||||
|
setBaseTokenUri(uploadDetails?.baseTokenURI as string)
|
||||||
|
setCoverImageUrl(uploadDetails?.imageUrl as string)
|
||||||
|
|
||||||
|
let whitelist: string | undefined
|
||||||
|
if (whitelistDetails?.whitelistType === 'existing') whitelist = whitelistDetails.contractAddress
|
||||||
|
else if (whitelistDetails?.whitelistType === 'new') whitelist = await instantiateWhitelist()
|
||||||
|
setWhitelistContractAddress(whitelist as string)
|
||||||
|
|
||||||
|
await instantiate(baseTokenUri as string, coverImageUrl as string, whitelist)
|
||||||
|
}
|
||||||
|
setCreatingCollection(false)
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||||
|
} catch (error: any) {
|
||||||
|
toast.error(error.message, { style: { maxWidth: 'none' } })
|
||||||
|
setCreatingCollection(false)
|
||||||
|
setUploading(false)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const createBaseMinterCollection = async () => {
|
||||||
|
try {
|
||||||
|
setCreatingCollection(true)
|
||||||
|
setBaseTokenUri(null)
|
||||||
|
setCoverImageUrl(null)
|
||||||
|
setVendingMinterContractAddress(null)
|
||||||
|
setSg721ContractAddress(null)
|
||||||
|
setWhitelistContractAddress(null)
|
||||||
|
setTransactionHash(null)
|
||||||
|
if (uploadDetails?.uploadMethod === 'new') {
|
||||||
|
setUploading(true)
|
||||||
|
|
||||||
|
const baseUri = await uploadFiles()
|
||||||
|
//upload coverImageUri and append the file name
|
||||||
|
const coverImageUri = await upload(
|
||||||
|
collectionDetails?.imageFile as File[],
|
||||||
|
uploadDetails.uploadService,
|
||||||
|
'cover',
|
||||||
|
uploadDetails.nftStorageApiKey as string,
|
||||||
|
uploadDetails.pinataApiKey as string,
|
||||||
|
uploadDetails.pinataSecretKey as string,
|
||||||
|
)
|
||||||
|
|
||||||
|
setUploading(false)
|
||||||
|
|
||||||
|
setBaseTokenUri(baseUri)
|
||||||
|
setCoverImageUrl(coverImageUri)
|
||||||
|
|
||||||
|
let whitelist: string | undefined
|
||||||
|
if (whitelistDetails?.whitelistType === 'existing') whitelist = whitelistDetails.contractAddress
|
||||||
|
else if (whitelistDetails?.whitelistType === 'new') whitelist = await instantiateWhitelist()
|
||||||
|
setWhitelistContractAddress(whitelist as string)
|
||||||
|
|
||||||
|
await instantiate(baseUri, coverImageUri, whitelist)
|
||||||
|
} else {
|
||||||
|
setBaseTokenUri(uploadDetails?.baseTokenURI as string)
|
||||||
|
setCoverImageUrl(uploadDetails?.imageUrl as string)
|
||||||
|
|
||||||
|
let whitelist: string | undefined
|
||||||
|
if (whitelistDetails?.whitelistType === 'existing') whitelist = whitelistDetails.contractAddress
|
||||||
|
else if (whitelistDetails?.whitelistType === 'new') whitelist = await instantiateWhitelist()
|
||||||
|
setWhitelistContractAddress(whitelist as string)
|
||||||
|
|
||||||
|
await instantiate(baseTokenUri as string, coverImageUrl as string, whitelist)
|
||||||
|
}
|
||||||
|
setCreatingCollection(false)
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||||
|
} catch (error: any) {
|
||||||
|
toast.error(error.message, { style: { maxWidth: 'none' } })
|
||||||
|
setCreatingCollection(false)
|
||||||
|
setUploading(false)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const uploadAndMint = async () => {
|
||||||
try {
|
try {
|
||||||
setCreatingCollection(true)
|
setCreatingCollection(true)
|
||||||
setBaseTokenUri(null)
|
setBaseTokenUri(null)
|
||||||
@ -513,36 +671,142 @@ const CollectionCreationPage: NextPage = () => {
|
|||||||
</Alert>
|
</Alert>
|
||||||
</Conditional>
|
</Conditional>
|
||||||
</div>
|
</div>
|
||||||
|
<div>
|
||||||
|
<div
|
||||||
|
className={clsx(
|
||||||
|
'mx-10 mt-5',
|
||||||
|
'grid before:absolute relative grid-cols-2 grid-flow-col items-stretch rounded',
|
||||||
|
'before:inset-x-0 before:bottom-0 before:border-white/25',
|
||||||
|
)}
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
className={clsx(
|
||||||
|
'isolate space-y-1 border-2',
|
||||||
|
'first-of-type:rounded-tl-md last-of-type:rounded-tr-md',
|
||||||
|
minterType === 'vending' ? 'border-stargaze' : 'border-transparent',
|
||||||
|
minterType !== 'vending' ? 'bg-stargaze/5 hover:bg-stargaze/80' : 'hover:bg-white/5',
|
||||||
|
)}
|
||||||
|
>
|
||||||
|
<button
|
||||||
|
className="p-4 w-full h-full text-left bg-transparent"
|
||||||
|
onClick={() => setMinterType('vending')}
|
||||||
|
type="button"
|
||||||
|
>
|
||||||
|
<h4 className="font-bold">Vending Minter</h4>
|
||||||
|
<span className="text-sm text-white/80 line-clamp-2">
|
||||||
|
Vending Minter contract facilitates primary market vending machine style minting
|
||||||
|
</span>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
className={clsx(
|
||||||
|
'isolate space-y-1 border-2',
|
||||||
|
'first-of-type:rounded-tl-md last-of-type:rounded-tr-md',
|
||||||
|
minterType === 'base' ? 'border-stargaze' : 'border-transparent',
|
||||||
|
minterType !== 'base' ? 'bg-stargaze/5 hover:bg-stargaze/80' : 'hover:bg-white/5',
|
||||||
|
)}
|
||||||
|
>
|
||||||
|
<button
|
||||||
|
className="p-4 w-full h-full text-left bg-transparent"
|
||||||
|
onClick={() => setMinterType('base')}
|
||||||
|
type="button"
|
||||||
|
>
|
||||||
|
<h4 className="font-bold">Base Minter</h4>
|
||||||
|
<span className="text-sm text-white/80 line-clamp-2">Base Minter contract enables 1/1 minting</span>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{minterType === 'base' && (
|
||||||
|
<div>
|
||||||
|
<MinterDetails minterType={minterType} onChange={setMinterDetails} />
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
|
||||||
<div className="mx-10">
|
<div className="mx-10">
|
||||||
<UploadDetails onChange={setUploadDetails} />
|
<UploadDetails onChange={setUploadDetails} />
|
||||||
|
|
||||||
<div className="flex justify-between py-3 px-8 rounded border-2 border-white/20 grid-col-2">
|
<Conditional
|
||||||
<CollectionDetails
|
test={minterType === 'vending' || (minterType === 'base' && minterDetails?.minterAcquisitionMethod === 'new')}
|
||||||
coverImageUrl={coverImageUrl as string}
|
>
|
||||||
onChange={setCollectionDetails}
|
<div className="flex justify-between py-3 px-8 rounded border-2 border-white/20 grid-col-2">
|
||||||
uploadMethod={uploadDetails?.uploadMethod as UploadMethod}
|
<Conditional
|
||||||
/>
|
test={
|
||||||
<MintingDetails
|
minterType === 'vending' || (minterType === 'base' && minterDetails?.minterAcquisitionMethod === 'new')
|
||||||
numberOfTokens={uploadDetails?.assetFiles.length}
|
}
|
||||||
onChange={setMintingDetails}
|
>
|
||||||
uploadMethod={uploadDetails?.uploadMethod as UploadMethod}
|
<CollectionDetails
|
||||||
/>
|
coverImageUrl={coverImageUrl as string}
|
||||||
</div>
|
onChange={setCollectionDetails}
|
||||||
<div className="my-6">
|
uploadMethod={uploadDetails?.uploadMethod as UploadMethod}
|
||||||
<WhitelistDetails onChange={setWhitelistDetails} />
|
/>
|
||||||
<div className="my-6" />
|
</Conditional>
|
||||||
<RoyaltyDetails onChange={setRoyaltyDetails} />
|
<Conditional test={minterType === 'vending'}>
|
||||||
</div>
|
<MintingDetails
|
||||||
{readyToCreate && <ConfirmationModal confirm={createCollection} />}
|
numberOfTokens={uploadDetails?.assetFiles.length}
|
||||||
|
onChange={setMintingDetails}
|
||||||
|
uploadMethod={uploadDetails?.uploadMethod as UploadMethod}
|
||||||
|
/>
|
||||||
|
</Conditional>
|
||||||
|
</div>
|
||||||
|
</Conditional>
|
||||||
|
|
||||||
|
<Conditional
|
||||||
|
test={minterType === 'vending' || (minterType === 'base' && minterDetails?.minterAcquisitionMethod === 'new')}
|
||||||
|
>
|
||||||
|
<div className="my-6">
|
||||||
|
<Conditional test={minterType === 'vending'}>
|
||||||
|
<WhitelistDetails onChange={setWhitelistDetails} />
|
||||||
|
<div className="my-6" />
|
||||||
|
</Conditional>
|
||||||
|
<RoyaltyDetails onChange={setRoyaltyDetails} />
|
||||||
|
</div>
|
||||||
|
</Conditional>
|
||||||
|
<Conditional test={readyToCreateVm && minterType === 'vending'}>
|
||||||
|
<ConfirmationModal confirm={createVendingMinterCollection} />
|
||||||
|
</Conditional>
|
||||||
|
<Conditional
|
||||||
|
test={readyToCreateBm && minterType === 'base' && minterDetails?.minterAcquisitionMethod === 'new'}
|
||||||
|
>
|
||||||
|
<ConfirmationModal confirm={createBaseMinterCollection} />
|
||||||
|
</Conditional>
|
||||||
|
<Conditional
|
||||||
|
test={readyToUploadAndMint && minterType === 'base' && minterDetails?.minterAcquisitionMethod === 'existing'}
|
||||||
|
>
|
||||||
|
<ConfirmationModal confirm={uploadAndMint} />
|
||||||
|
</Conditional>
|
||||||
<div className="flex justify-end w-full">
|
<div className="flex justify-end w-full">
|
||||||
<Button
|
<Conditional test={minterType === 'vending'}>
|
||||||
className="relative justify-center p-2 mb-6 max-h-12 text-white bg-plumbus hover:bg-plumbus-light border-0"
|
<Button
|
||||||
isLoading={creatingCollection}
|
className="relative justify-center p-2 mb-6 max-h-12 text-white bg-plumbus hover:bg-plumbus-light border-0"
|
||||||
onClick={performChecks}
|
isLoading={creatingCollection}
|
||||||
variant="solid"
|
onClick={performVendingMinterChecks}
|
||||||
>
|
variant="solid"
|
||||||
Create Collection
|
>
|
||||||
</Button>
|
Create Collection
|
||||||
|
</Button>
|
||||||
|
</Conditional>
|
||||||
|
<Conditional test={minterType === 'base' && minterDetails?.minterAcquisitionMethod === 'new'}>
|
||||||
|
<Button
|
||||||
|
className="relative justify-center p-2 mb-6 max-h-12 text-white bg-plumbus hover:bg-plumbus-light border-0"
|
||||||
|
isLoading={creatingCollection}
|
||||||
|
onClick={performBaseMinterChecks}
|
||||||
|
variant="solid"
|
||||||
|
>
|
||||||
|
Create BM Collection
|
||||||
|
</Button>
|
||||||
|
</Conditional>
|
||||||
|
<Conditional test={minterType === 'base' && minterDetails?.minterAcquisitionMethod === 'existing'}>
|
||||||
|
<Button
|
||||||
|
className="relative justify-center p-2 mb-6 max-h-12 text-white bg-plumbus hover:bg-plumbus-light border-0"
|
||||||
|
isLoading={creatingCollection}
|
||||||
|
onClick={performUploadAndMintChecks}
|
||||||
|
variant="solid"
|
||||||
|
>
|
||||||
|
Upload & Mint Token
|
||||||
|
</Button>
|
||||||
|
</Conditional>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
30
yarn.lock
30
yarn.lock
@ -3704,6 +3704,11 @@ clsx@^1:
|
|||||||
resolved "https://registry.npmjs.org/clsx/-/clsx-1.1.1.tgz"
|
resolved "https://registry.npmjs.org/clsx/-/clsx-1.1.1.tgz"
|
||||||
integrity sha512-6/bPho624p3S2pMyvP5kKBPXnI3ufHLObBFCfgx+LkeR5lg2XYy2hqZqUf45ypD8COn2bhgGJSUE+l5dhNBieA==
|
integrity sha512-6/bPho624p3S2pMyvP5kKBPXnI3ufHLObBFCfgx+LkeR5lg2XYy2hqZqUf45ypD8COn2bhgGJSUE+l5dhNBieA==
|
||||||
|
|
||||||
|
clsx@^1.1.1:
|
||||||
|
version "1.2.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/clsx/-/clsx-1.2.1.tgz#0ddc4a20a549b59c93a4116bb26f5294ca17dc12"
|
||||||
|
integrity sha512-EcR6r5a8bj6pu3ycsa/E/cKVGuTgZJZdsyUYHOksG/UHIiKfjxzRxYJpyVBwYaQeOvghal9fcc4PidlgzugAQg==
|
||||||
|
|
||||||
color-convert@^1.9.0:
|
color-convert@^1.9.0:
|
||||||
version "1.9.3"
|
version "1.9.3"
|
||||||
resolved "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz"
|
resolved "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz"
|
||||||
@ -4922,10 +4927,10 @@ globby@^11.0.4:
|
|||||||
merge2 "^1.4.1"
|
merge2 "^1.4.1"
|
||||||
slash "^3.0.0"
|
slash "^3.0.0"
|
||||||
|
|
||||||
goober@^2.1.1:
|
goober@^2.1.10:
|
||||||
version "2.1.9"
|
version "2.1.11"
|
||||||
resolved "https://registry.npmjs.org/goober/-/goober-2.1.9.tgz"
|
resolved "https://registry.yarnpkg.com/goober/-/goober-2.1.11.tgz#bbd71f90d2df725397340f808dbe7acc3118e610"
|
||||||
integrity sha512-PAtnJbrWtHbfpJUIveG5PJIB6Mc9Kd0gimu9wZwPyA+wQUSeOeA4x4Ug16lyaaUUKZ/G6QEH1xunKOuXP1F4Vw==
|
integrity sha512-5SS2lmxbhqH0u9ABEWq7WPU69a4i2pYcHeCxqaNq6Cw3mnrF0ghWNM4tEGid4dKy8XNIAUbuThuozDHHKJVh3A==
|
||||||
|
|
||||||
hamt-sharding@^2.0.0:
|
hamt-sharding@^2.0.0:
|
||||||
version "2.0.1"
|
version "2.0.1"
|
||||||
@ -6806,12 +6811,12 @@ react-hook-form@^7:
|
|||||||
resolved "https://registry.npmjs.org/react-hook-form/-/react-hook-form-7.30.0.tgz"
|
resolved "https://registry.npmjs.org/react-hook-form/-/react-hook-form-7.30.0.tgz"
|
||||||
integrity sha512-DzjiM6o2vtDGNMB9I4yCqW8J21P314SboNG1O0obROkbg7KVS0I7bMtwSdKyapnCPjHgnxc3L7E5PEdISeEUcQ==
|
integrity sha512-DzjiM6o2vtDGNMB9I4yCqW8J21P314SboNG1O0obROkbg7KVS0I7bMtwSdKyapnCPjHgnxc3L7E5PEdISeEUcQ==
|
||||||
|
|
||||||
react-hot-toast@^2:
|
react-hot-toast@2.4.0:
|
||||||
version "2.2.0"
|
version "2.4.0"
|
||||||
resolved "https://registry.npmjs.org/react-hot-toast/-/react-hot-toast-2.2.0.tgz"
|
resolved "https://registry.yarnpkg.com/react-hot-toast/-/react-hot-toast-2.4.0.tgz#b91e7a4c1b6e3068fc599d3d83b4fb48668ae51d"
|
||||||
integrity sha512-248rXw13uhf/6TNDVzagX+y7R8J183rp7MwUMNkcrBRyHj/jWOggfXTGlM8zAOuh701WyVW+eUaWG2LeSufX9g==
|
integrity sha512-qnnVbXropKuwUpriVVosgo8QrB+IaPJCpL8oBI6Ov84uvHZ5QQcTp2qg6ku2wNfgJl6rlQXJIQU5q+5lmPOutA==
|
||||||
dependencies:
|
dependencies:
|
||||||
goober "^2.1.1"
|
goober "^2.1.10"
|
||||||
|
|
||||||
react-icons@^4:
|
react-icons@^4:
|
||||||
version "4.3.1"
|
version "4.3.1"
|
||||||
@ -6862,6 +6867,13 @@ react-time-picker@^4.5.0:
|
|||||||
react-fit "^1.4.0"
|
react-fit "^1.4.0"
|
||||||
update-input-width "^1.2.2"
|
update-input-width "^1.2.2"
|
||||||
|
|
||||||
|
react-toastify@9.1.1:
|
||||||
|
version "9.1.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/react-toastify/-/react-toastify-9.1.1.tgz#9280caea4a13dc1739c350d90660a630807bf10b"
|
||||||
|
integrity sha512-pkFCla1z3ve045qvjEmn2xOJOy4ZciwRXm1oMPULVkELi5aJdHCN/FHnuqXq8IwGDLB7PPk2/J6uP9D8ejuiRw==
|
||||||
|
dependencies:
|
||||||
|
clsx "^1.1.1"
|
||||||
|
|
||||||
react-tracked@^1:
|
react-tracked@^1:
|
||||||
version "1.7.9"
|
version "1.7.9"
|
||||||
resolved "https://registry.npmjs.org/react-tracked/-/react-tracked-1.7.9.tgz"
|
resolved "https://registry.npmjs.org/react-tracked/-/react-tracked-1.7.9.tgz"
|
||||||
|
Loading…
Reference in New Issue
Block a user