stargaze-studio/components/openEdition/MintingDetails.tsx
2024-02-02 16:34:17 +03:00

258 lines
9.7 KiB
TypeScript

/* eslint-disable eslint-comments/disable-enable-pair */
/* eslint-disable @typescript-eslint/no-unnecessary-condition */
/* eslint-disable no-nested-ternary */
import { Conditional } from 'components/Conditional'
import { FormControl } from 'components/FormControl'
import { FormGroup } from 'components/FormGroup'
import { useInputState, useNumberInputState } from 'components/forms/FormInput.hooks'
import { InputDateTime } from 'components/InputDateTime'
import { openEditionMinterList } from 'config/minter'
import type { TokenInfo } from 'config/token'
import { stars, tokensList } from 'config/token'
import { useGlobalSettings } from 'contexts/globalSettings'
import React, { useEffect, useState } from 'react'
import { resolveAddress } from 'utils/resolveAddress'
import { useWallet } from 'utils/wallet'
import { NumberInput, TextInput } from '../forms/FormInput'
import type { UploadMethod } from './OffChainMetadataUploadDetails'
export type LimitType = 'count_limited' | 'time_limited'
interface MintingDetailsProps {
onChange: (data: MintingDetailsDataProps) => void
uploadMethod: UploadMethod
minimumMintPrice: number
mintTokenFromFactory?: TokenInfo | undefined
importedMintingDetails?: MintingDetailsDataProps
}
export interface MintingDetailsDataProps {
unitPrice: string
perAddressLimit: number
startTime: string
endTime?: string
tokenCountLimit?: number
paymentAddress?: string
selectedMintToken?: TokenInfo
limitType: LimitType
}
export const MintingDetails = ({
onChange,
uploadMethod,
minimumMintPrice,
mintTokenFromFactory,
importedMintingDetails,
}: MintingDetailsProps) => {
const wallet = useWallet()
const [timestamp, setTimestamp] = useState<Date | undefined>()
const [endTimestamp, setEndTimestamp] = useState<Date | undefined>()
const [selectedMintToken, setSelectedMintToken] = useState<TokenInfo | undefined>(stars)
const [mintingDetailsImported, setMintingDetailsImported] = useState(false)
const [limitType, setLimitType] = useState<LimitType>('time_limited')
const { timezone } = useGlobalSettings()
const unitPriceState = useNumberInputState({
id: 'unitPrice',
name: 'unitPrice',
title: 'Mint Price',
subtitle: `Price of each token (min. ${minimumMintPrice} ${
mintTokenFromFactory ? mintTokenFromFactory.displayName : 'STARS'
})`,
placeholder: '50',
})
const perAddressLimitState = useNumberInputState({
id: 'peraddresslimit',
name: 'peraddresslimit',
title: 'Per Address Limit',
subtitle: '',
placeholder: '1',
})
const tokenCountLimitState = useNumberInputState({
id: 'tokencountlimit',
name: 'tokencountlimit',
title: 'Maximum Token Count',
subtitle: 'Total number of mintable tokens',
placeholder: '100',
})
const paymentAddressState = useInputState({
id: 'payment-address',
name: 'paymentAddress',
title: 'Payment Address (optional)',
subtitle: 'Address to receive minting revenues (defaults to current wallet address)',
placeholder: 'stars1234567890abcdefghijklmnopqrstuvwxyz...',
})
const resolvePaymentAddress = async () => {
await resolveAddress(paymentAddressState.value.trim(), wallet).then((resolvedAddress) => {
paymentAddressState.onChange(resolvedAddress)
})
}
useEffect(() => {
if (!importedMintingDetails || (importedMintingDetails && mintingDetailsImported)) {
void resolvePaymentAddress()
}
}, [paymentAddressState.value])
useEffect(() => {
const data: MintingDetailsDataProps = {
unitPrice: unitPriceState.value
? (Number(unitPriceState.value) * 1_000_000).toString()
: unitPriceState.value === 0
? '0'
: '',
perAddressLimit: perAddressLimitState.value,
startTime: timestamp ? (timestamp.getTime() * 1_000_000).toString() : '',
endTime: endTimestamp ? (endTimestamp.getTime() * 1_000_000).toString() : '',
paymentAddress: paymentAddressState.value.trim(),
selectedMintToken,
limitType,
tokenCountLimit: limitType === 'count_limited' ? tokenCountLimitState.value : undefined,
}
onChange(data)
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [
unitPriceState.value,
perAddressLimitState.value,
timestamp,
endTimestamp,
paymentAddressState.value,
selectedMintToken,
tokenCountLimitState.value,
limitType,
])
useEffect(() => {
if (importedMintingDetails) {
console.log('Selected Token ID: ', importedMintingDetails.selectedMintToken?.id)
unitPriceState.onChange(Number(importedMintingDetails.unitPrice) / 1000000)
perAddressLimitState.onChange(importedMintingDetails.perAddressLimit)
setLimitType(importedMintingDetails.limitType)
tokenCountLimitState.onChange(importedMintingDetails.tokenCountLimit ? importedMintingDetails.tokenCountLimit : 0)
setTimestamp(new Date(Number(importedMintingDetails.startTime) / 1_000_000))
setEndTimestamp(new Date(Number(importedMintingDetails.endTime) / 1_000_000))
paymentAddressState.onChange(importedMintingDetails.paymentAddress ? importedMintingDetails.paymentAddress : '')
setSelectedMintToken(tokensList.find((token) => token.id === importedMintingDetails.selectedMintToken?.id))
setMintingDetailsImported(true)
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [importedMintingDetails])
return (
<div className="border-l-[1px] border-gray-500 border-opacity-20">
<FormGroup subtitle="Information about your minting settings" title="Minting Details">
<div className="flex flex-row items-end">
<NumberInput {...unitPriceState} isRequired />
<select
className="py-[9px] px-4 ml-4 placeholder:text-white/50 bg-white/10 rounded border-2 border-white/20 focus:ring focus:ring-plumbus-20"
onChange={(e) => setSelectedMintToken(tokensList.find((t) => t.displayName === e.target.value))}
value={selectedMintToken?.displayName}
>
{openEditionMinterList
.filter((minter) => minter.factoryAddress !== undefined && minter.updatable === false)
.map((minter) => (
<option key={minter.id} className="bg-black" value={minter.supportedToken.displayName}>
{minter.supportedToken.displayName}
</option>
))}
</select>
</div>
<NumberInput {...perAddressLimitState} isRequired />
<FormControl
htmlId="timestamp"
isRequired
subtitle={`Minting start time ${timezone === 'Local' ? '(local)' : '(UTC)'}`}
title="Start Time"
>
<InputDateTime
minDate={
timezone === 'Local' ? new Date() : new Date(Date.now() + new Date().getTimezoneOffset() * 60 * 1000)
}
onChange={(date) =>
date
? setTimestamp(
timezone === 'Local' ? date : new Date(date.getTime() - new Date().getTimezoneOffset() * 60 * 1000),
)
: setTimestamp(undefined)
}
value={
timezone === 'Local'
? timestamp
: timestamp
? new Date(timestamp.getTime() + new Date().getTimezoneOffset() * 60 * 1000)
: undefined
}
/>
</FormControl>
<div className="flex-row mt-2 w-full form-control">
<h1 className="mt-2 font-bold text-md">Limit Type: </h1>
<label className="justify-start ml-6 cursor-pointer label">
<span className="mr-2">Time</span>
<input
checked={limitType === 'time_limited'}
className={`${limitType === 'time_limited' ? `bg-stargaze` : `bg-gray-600`} checkbox`}
onClick={() => {
setLimitType('time_limited' as LimitType)
}}
type="checkbox"
/>
</label>
<label className="justify-start ml-4 cursor-pointer label">
<span className="mr-2">Token Count</span>
<input
checked={limitType === 'count_limited'}
className={`${limitType === 'count_limited' ? `bg-stargaze` : `bg-gray-600`} checkbox`}
onClick={() => {
setLimitType('count_limited' as LimitType)
}}
type="checkbox"
/>
</label>
</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>
<TextInput className="pr-4 pl-4 mt-3" {...paymentAddressState} />
</div>
)
}