Merge pull request #342 from public-awesome/limited-edition-update

Limited edition collection update
This commit is contained in:
Serkan Reis 2024-02-14 22:37:02 +02:00 committed by GitHub
commit b3dea5e757
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 103 additions and 32 deletions

View File

@ -1,6 +1,7 @@
/* eslint-disable eslint-comments/disable-enable-pair */ /* eslint-disable eslint-comments/disable-enable-pair */
/* eslint-disable @typescript-eslint/no-unnecessary-condition */ /* eslint-disable @typescript-eslint/no-unnecessary-condition */
/* eslint-disable no-nested-ternary */ /* eslint-disable no-nested-ternary */
import { Conditional } from 'components/Conditional'
import { FormControl } from 'components/FormControl' import { FormControl } from 'components/FormControl'
import { FormGroup } from 'components/FormGroup' import { FormGroup } from 'components/FormGroup'
import { useInputState, useNumberInputState } from 'components/forms/FormInput.hooks' import { useInputState, useNumberInputState } from 'components/forms/FormInput.hooks'
@ -16,6 +17,8 @@ import { useWallet } from 'utils/wallet'
import { NumberInput, TextInput } from '../forms/FormInput' import { NumberInput, TextInput } from '../forms/FormInput'
import type { UploadMethod } from './OffChainMetadataUploadDetails' import type { UploadMethod } from './OffChainMetadataUploadDetails'
export type LimitType = 'count_limited' | 'time_limited'
interface MintingDetailsProps { interface MintingDetailsProps {
onChange: (data: MintingDetailsDataProps) => void onChange: (data: MintingDetailsDataProps) => void
uploadMethod: UploadMethod uploadMethod: UploadMethod
@ -28,9 +31,11 @@ export interface MintingDetailsDataProps {
unitPrice: string unitPrice: string
perAddressLimit: number perAddressLimit: number
startTime: string startTime: string
endTime: string endTime?: string
tokenCountLimit?: number
paymentAddress?: string paymentAddress?: string
selectedMintToken?: TokenInfo selectedMintToken?: TokenInfo
limitType: LimitType
} }
export const MintingDetails = ({ export const MintingDetails = ({
@ -46,6 +51,7 @@ export const MintingDetails = ({
const [endTimestamp, setEndTimestamp] = useState<Date | undefined>() const [endTimestamp, setEndTimestamp] = useState<Date | undefined>()
const [selectedMintToken, setSelectedMintToken] = useState<TokenInfo | undefined>(stars) const [selectedMintToken, setSelectedMintToken] = useState<TokenInfo | undefined>(stars)
const [mintingDetailsImported, setMintingDetailsImported] = useState(false) const [mintingDetailsImported, setMintingDetailsImported] = useState(false)
const [limitType, setLimitType] = useState<LimitType>('time_limited')
const { timezone } = useGlobalSettings() const { timezone } = useGlobalSettings()
const unitPriceState = useNumberInputState({ const unitPriceState = useNumberInputState({
@ -66,6 +72,14 @@ export const MintingDetails = ({
placeholder: '1', placeholder: '1',
}) })
const tokenCountLimitState = useNumberInputState({
id: 'tokencountlimit',
name: 'tokencountlimit',
title: 'Maximum Token Count',
subtitle: 'Total number of mintable tokens',
placeholder: '100',
})
const paymentAddressState = useInputState({ const paymentAddressState = useInputState({
id: 'payment-address', id: 'payment-address',
name: 'paymentAddress', name: 'paymentAddress',
@ -98,6 +112,8 @@ export const MintingDetails = ({
endTime: endTimestamp ? (endTimestamp.getTime() * 1_000_000).toString() : '', endTime: endTimestamp ? (endTimestamp.getTime() * 1_000_000).toString() : '',
paymentAddress: paymentAddressState.value.trim(), paymentAddress: paymentAddressState.value.trim(),
selectedMintToken, selectedMintToken,
limitType,
tokenCountLimit: limitType === 'count_limited' ? tokenCountLimitState.value : undefined,
} }
onChange(data) onChange(data)
// eslint-disable-next-line react-hooks/exhaustive-deps // eslint-disable-next-line react-hooks/exhaustive-deps
@ -108,6 +124,8 @@ export const MintingDetails = ({
endTimestamp, endTimestamp,
paymentAddressState.value, paymentAddressState.value,
selectedMintToken, selectedMintToken,
tokenCountLimitState.value,
limitType,
]) ])
useEffect(() => { useEffect(() => {
@ -115,6 +133,8 @@ export const MintingDetails = ({
console.log('Selected Token ID: ', importedMintingDetails.selectedMintToken?.id) console.log('Selected Token ID: ', importedMintingDetails.selectedMintToken?.id)
unitPriceState.onChange(Number(importedMintingDetails.unitPrice) / 1000000) unitPriceState.onChange(Number(importedMintingDetails.unitPrice) / 1000000)
perAddressLimitState.onChange(importedMintingDetails.perAddressLimit) perAddressLimitState.onChange(importedMintingDetails.perAddressLimit)
setLimitType(importedMintingDetails.limitType)
tokenCountLimitState.onChange(importedMintingDetails.tokenCountLimit ? importedMintingDetails.tokenCountLimit : 0)
setTimestamp(new Date(Number(importedMintingDetails.startTime) / 1_000_000)) setTimestamp(new Date(Number(importedMintingDetails.startTime) / 1_000_000))
setEndTimestamp(new Date(Number(importedMintingDetails.endTime) / 1_000_000)) setEndTimestamp(new Date(Number(importedMintingDetails.endTime) / 1_000_000))
paymentAddressState.onChange(importedMintingDetails.paymentAddress ? importedMintingDetails.paymentAddress : '') paymentAddressState.onChange(importedMintingDetails.paymentAddress ? importedMintingDetails.paymentAddress : '')
@ -171,32 +191,65 @@ export const MintingDetails = ({
} }
/> />
</FormControl> </FormControl>
<FormControl
htmlId="endTimestamp" <div className="flex-row mt-2 w-full form-control">
isRequired <h1 className="mt-2 font-bold text-md">Limit Type: </h1>
subtitle={`Minting end time ${timezone === 'Local' ? '(local)' : '(UTC)'}`} <label className="justify-start ml-6 cursor-pointer label">
title="End Time" <span className="mr-2">Time</span>
> <input
<InputDateTime checked={limitType === 'time_limited'}
minDate={ className={`${limitType === 'time_limited' ? `bg-stargaze` : `bg-gray-600`} checkbox`}
timezone === 'Local' ? new Date() : new Date(Date.now() + new Date().getTimezoneOffset() * 60 * 1000) onClick={() => {
} setLimitType('time_limited' as LimitType)
onChange={(date) => }}
date type="checkbox"
? setEndTimestamp( />
timezone === 'Local' ? date : new Date(date.getTime() - new Date().getTimezoneOffset() * 60 * 1000), </label>
) <label className="justify-start ml-4 cursor-pointer label">
: setEndTimestamp(undefined) <span className="mr-2">Token Count</span>
} <input
value={ checked={limitType === 'count_limited'}
timezone === 'Local' className={`${limitType === 'count_limited' ? `bg-stargaze` : `bg-gray-600`} checkbox`}
? endTimestamp onClick={() => {
: endTimestamp setLimitType('count_limited' as LimitType)
? new Date(endTimestamp.getTime() + new Date().getTimezoneOffset() * 60 * 1000) }}
: undefined type="checkbox"
} />
/> </label>
</FormControl> </div>
<Conditional test={limitType === 'time_limited'}>
<FormControl
htmlId="endTimestamp"
isRequired
subtitle={`Minting end time ${timezone === 'Local' ? '(local)' : '(UTC)'}`}
title="End Time"
>
<InputDateTime
minDate={
timezone === 'Local' ? new Date() : new Date(Date.now() + new Date().getTimezoneOffset() * 60 * 1000)
}
onChange={(date) =>
date
? setEndTimestamp(
timezone === 'Local'
? date
: new Date(date.getTime() - new Date().getTimezoneOffset() * 60 * 1000),
)
: setEndTimestamp(undefined)
}
value={
timezone === 'Local'
? endTimestamp
: endTimestamp
? new Date(endTimestamp.getTime() + new Date().getTimezoneOffset() * 60 * 1000)
: undefined
}
/>
</FormControl>
</Conditional>
<Conditional test={limitType === 'count_limited'}>
<NumberInput {...tokenCountLimitState} isRequired />
</Conditional>
</FormGroup> </FormGroup>
<TextInput className="pr-4 pl-4 mt-3" {...paymentAddressState} /> <TextInput className="pr-4 pl-4 mt-3" {...paymentAddressState} />
</div> </div>

View File

@ -37,7 +37,7 @@ import { useWallet } from 'utils/wallet'
import { type CollectionDetailsDataProps, CollectionDetails } from './CollectionDetails' import { type CollectionDetailsDataProps, CollectionDetails } from './CollectionDetails'
import type { ImageUploadDetailsDataProps } from './ImageUploadDetails' import type { ImageUploadDetailsDataProps } from './ImageUploadDetails'
import { ImageUploadDetails } from './ImageUploadDetails' import { ImageUploadDetails } from './ImageUploadDetails'
import type { MintingDetailsDataProps } from './MintingDetails' import type { LimitType, MintingDetailsDataProps } from './MintingDetails'
import { MintingDetails } from './MintingDetails' import { MintingDetails } from './MintingDetails'
import type { UploadMethod } from './OffChainMetadataUploadDetails' import type { UploadMethod } from './OffChainMetadataUploadDetails'
import { import {
@ -314,11 +314,27 @@ export const OpenEditionMinterCreator = ({
if (!mintingDetails.perAddressLimit || mintingDetails.perAddressLimit < 1 || mintingDetails.perAddressLimit > 50) if (!mintingDetails.perAddressLimit || mintingDetails.perAddressLimit < 1 || mintingDetails.perAddressLimit > 50)
throw new Error('Invalid limit for tokens per address') throw new Error('Invalid limit for tokens per address')
if (mintingDetails.startTime === '') throw new Error('Start time is required') if (mintingDetails.startTime === '') throw new Error('Start time is required')
if (mintingDetails.endTime === '') throw new Error('End time is required') if (mintingDetails.limitType === 'time_limited' && mintingDetails.endTime === '')
throw new Error('End time is required')
if (mintingDetails.limitType === 'count_limited' && mintingDetails.tokenCountLimit === undefined)
throw new Error('Token count limit is required')
if (
mintingDetails.limitType === 'count_limited' &&
mintingDetails.perAddressLimit > (mintingDetails.tokenCountLimit as number)
)
throw new Error('Per address limit cannot exceed maximum token count limit')
if (mintingDetails.limitType === 'count_limited' && (mintingDetails.tokenCountLimit as number) > 10000)
throw new Error('Maximum token count cannot exceed 10000')
if (Number(mintingDetails.startTime) < new Date().getTime() * 1000000) throw new Error('Invalid start time') if (Number(mintingDetails.startTime) < new Date().getTime() * 1000000) throw new Error('Invalid start time')
if (Number(mintingDetails.endTime) < Number(mintingDetails.startTime)) if (
mintingDetails.limitType === 'time_limited' &&
Number(mintingDetails.endTime) < Number(mintingDetails.startTime)
)
throw new Error('End time cannot be earlier than start time') throw new Error('End time cannot be earlier than start time')
if (Number(mintingDetails.endTime) === Number(mintingDetails.startTime)) if (
mintingDetails.limitType === 'time_limited' &&
Number(mintingDetails.endTime) === Number(mintingDetails.startTime)
)
throw new Error('End time cannot be equal to the start time') throw new Error('End time cannot be equal to the start time')
if ( if (
@ -603,12 +619,14 @@ export const OpenEditionMinterCreator = ({
: null, : null,
}, },
start_time: mintingDetails?.startTime, start_time: mintingDetails?.startTime,
end_time: mintingDetails?.endTime, end_time: mintingDetails?.limitType === ('time_limited' as LimitType) ? mintingDetails.endTime : null,
mint_price: { mint_price: {
amount: Number(mintingDetails?.unitPrice).toString(), amount: Number(mintingDetails?.unitPrice).toString(),
denom: (mintTokenFromFactory?.denom as string) || 'ustars', denom: (mintTokenFromFactory?.denom as string) || 'ustars',
}, },
per_address_limit: mintingDetails?.perAddressLimit, per_address_limit: mintingDetails?.perAddressLimit,
num_tokens:
mintingDetails?.limitType === ('count_limited' as LimitType) ? mintingDetails.tokenCountLimit : null,
payment_address: mintingDetails?.paymentAddress || null, payment_address: mintingDetails?.paymentAddress || null,
}, },
collection_params: { collection_params: {