Skip to content

Commit

Permalink
Merge pull request #8842 from kodadot/issue-8835
Browse files Browse the repository at this point in the history
feat: Implement paid drop
  • Loading branch information
vikiival authored Jan 4, 2024
2 parents 02f1897 + bb1c01b commit 49f6d8e
Show file tree
Hide file tree
Showing 10 changed files with 329 additions and 20 deletions.
2 changes: 1 addition & 1 deletion components/collection/drop/AddFundsModal.vue
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ const emit = defineEmits(['confirm', 'update:modelValue'])
const props = withDefaults(
defineProps<{
modelValue: boolean
minimumFunds: bigint
minimumFunds: number
formattedMinimumFunds: string
token: string
chain: string
Expand Down
4 changes: 3 additions & 1 deletion components/collection/drop/GenerativeLayout.vue
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
:max-count="maxCount"
:minted-count="mintedCount"
:mint-count-available="mintCountAvailable"
:disabled-by-backend="drop.disabled"
:mint-button="mintButton"
:holder-of-collection="holderOfCollection"
@mint="handleSubmitMint" />
Expand All @@ -43,6 +44,7 @@
:max-count="maxCount"
:minted-count="mintedCount"
:mint-count-available="mintCountAvailable"
:disabled-by-backend="drop.disabled"
:mint-button="mintButton"
:holder-of-collection="holderOfCollection"
@mint="handleSubmitMint" />
Expand Down Expand Up @@ -70,7 +72,7 @@ withDefaults(
mintedCount: number
mintCountAvailable: boolean
maxCount: number
minimumFunds: { amount: bigint; description: string }
minimumFunds: { amount: number; description: string }
isImageFetching: boolean
isWalletConnecting: boolean
isLoading: boolean
Expand Down
5 changes: 4 additions & 1 deletion components/collection/drop/MintSection.vue
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,9 @@
<div class="has-text-weight-bold is-size-5">
{{ $t('mint.unlockable.phase') }}
</div>
<div v-if="mintCountAvailable" class="flex items-center">
<div
v-if="mintCountAvailable && !disabledByBackend"
class="flex items-center">
<img src="/unlockable-pulse.svg" alt="open" />
{{ $t('mint.unlockable.open') }}
</div>
Expand Down Expand Up @@ -101,6 +103,7 @@ const props = withDefaults(
defineProps<{
mintedCount: number
mintCountAvailable: boolean
disabledByBackend: number
maxCount: number
minimumFunds: { amount: bigint; description: string }
isImageFetching: boolean
Expand Down
307 changes: 307 additions & 0 deletions components/collection/drop/PaidGenerative.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,307 @@
<template>
<Loader v-model="isLoading" :status="status" />

<CollectionDropGenerativeLayout
:collection-id="collectionId"
:description="description"
:drop="drop"
:user-minted-nft-id="userMintedNftId"
:is-wallet-connecting="isWalletConnecting"
:is-image-fetching="isImageFetching"
:is-loading="isLoading"
:minimum-funds="minimumFundsProps"
:max-count="maxCount"
:minted-count="mintedCount"
:mint-count-available="mintCountAvailable"
:mint-button="mintButtonProps"
:handle-select-image="handleSelectImage"
:handle-submit-mint="handleSubmitMint" />

<CollectionDropAddFundsModal
v-model="isAddFundModalActive"
:minimum-funds="minimumFunds"
:formatted-minimum-funds="formattedMinimumFunds"
:token="token"
:chain="chainName"
@close="closeAddFundModal"
@confirm="handleDropAddModalConfirm" />
</template>

<script setup lang="ts">
import { createUnlockableMetadata } from '../unlockable/utils'
import { DropItem } from '@/params/types'
import { claimDropItem } from '@/services/waifu'
import { useDropMinimumFunds, useDropStatus } from '@/components/drops/useDrops'
import { fetchNft } from '@/components/items/ItemsGrid/useNftActions'
import unlockableCollectionById from '@/queries/subsquid/general/unlockableCollectionById.graphql'
import Loader from '@/components/shared/Loader.vue'
import useGenerativeDropMint, {
type UnlockableCollectionById,
} from '@/composables/drop/useGenerativeDropMint'
import useGenerativeDropDetails from '@/composables/drop/useGenerativeDropDetails'
import formatBalance from '@/utils/format/balance'
const props = withDefaults(
defineProps<{
drop: DropItem
}>(),
{
drop: () => ({}) as DropItem,
},
)
const { fetchMultipleBalance } = useMultipleBalance()
const { chainSymbol, decimals } = useChain()
const { hasMinimumFunds, formattedMinimumFunds, minimumFunds } =
useDropMinimumFunds(props.drop)
const minimumFundsDescription = computed(() =>
$i18n.t('mint.unlockable.minimumFundsDescription', [
formattedMinimumFunds.value,
chainName.value,
]),
)
const minimumFundsProps = computed(() => ({
amount: minimumFunds.value,
description: minimumFundsDescription.value,
}))
const isWalletConnecting = ref(false)
const { currentAccountMintedToken, mintedDropCount, fetchDropStatus } =
useDropStatus(props.drop.alias)
const instance = getCurrentInstance()
const mintNftSN = ref('0')
const { doAfterLogin } = useDoAfterlogin(instance)
const { $i18n, $consola } = useNuxtApp()
const { urlPrefix } = usePrefix()
const { toast } = useToast()
const { accountId, isLogIn } = useAuth()
const { client } = usePrefix()
const isLoading = ref(false)
const isImageFetching = ref(false)
const isAddFundModalActive = ref(false)
const {
defaultName,
defaultImage,
defaultMax,
collectionId,
chainName,
disabledByBackend,
token,
price,
} = useGenerativeDropDetails(props.drop)
const {
howAboutToExecute,
isLoading: isTransactionLoading,
initTransactionLoader,
status,
} = useMetaTransaction()
const handleSelectImage = (image: string) => {
selectedImage.value = image
}
const { data: collectionData } = await useAsyncData(
'unlockableCollectionData',
async () =>
await useAsyncQuery<UnlockableCollectionById>({
clientId: client.value,
query: unlockableCollectionById,
variables: {
id: collectionId.value,
search: { currentOwner_eq: accountId.value },
},
}).then((res) => res.data.value),
{
watch: [accountId],
},
)
const {
maxCount,
mintedNft,
mintedNftWithMetadata,
userMintedNftId,
mintedCount,
mintCountAvailable,
selectedImage,
description,
collectionName,
tryCapture,
subscribeToMintedNft,
} = useGenerativeDropMint({
collectionData,
defaultMax,
currentAccountMintedToken,
collectionId,
mintedDropCount,
defaultImage,
})
const mintedAmountForCurrentUser = computed(
() => collectionData.value?.nftEntitiesConnection?.totalCount || 0, // todo: fetch from backend
)
const maxMintLimitForCurrentUser = computed(() => maxCount.value)
const mintButtonLabel = computed(() => {
return isWalletConnecting.value
? $i18n.t('shoppingCart.wallet')
: $i18n.t('mint.unlockable.claimPaidNft', [
`${formatBalance(price.value || '', decimals.value, '')} ${
chainSymbol.value
}`,
])
})
const mintButtonDisabled = computed(
() =>
isLogIn.value &&
Boolean(
!mintCountAvailable.value ||
!selectedImage.value ||
disabledByBackend.value ||
maxMintLimitForCurrentUser.value <= mintedAmountForCurrentUser.value,
),
)
const mintButtonProps = computed(() => ({
disabled: mintButtonDisabled.value,
label: mintButtonLabel.value,
}))
const mintNft = async () => {
try {
isLoading.value = true
const { apiInstance } = useApi()
const api = await apiInstance.value
const collectionRes = (
await api.query.nfts.collection(collectionId.value)
).toJSON() as {
items: string
}
initTransactionLoader()
const cb = api.tx.nfts.mint
const args = [
collectionId.value,
collectionRes.items,
accountId.value,
{
ownedItem: null,
mintPrice: price.value,
},
]
mintNftSN.value = collectionRes.items
howAboutToExecute(accountId.value, cb, args)
} catch (e) {
showNotification(`[MINT::ERR] ${e}`, notificationTypes.warn)
$consola.error(e)
isTransactionLoading.value = false
}
}
watch(status, (curStatus) => {
if (curStatus === TransactionStatus.Block) {
submitMint(mintNftSN.value)
}
})
const clearWalletConnecting = () => {
isWalletConnecting.value = false
}
const handleSubmitMint = async () => {
if (!isLogIn.value) {
isWalletConnecting.value = true
doAfterLogin({
onLoginSuccess: clearWalletConnecting,
onCancel: clearWalletConnecting,
})
return
}
if (isLoading.value || isImageFetching.value) {
return false
}
if (hasMinimumFunds.value) {
mintNft()
} else {
openAddFundModal()
}
}
const openAddFundModal = () => {
isAddFundModalActive.value = true
}
const closeAddFundModal = () => {
isAddFundModalActive.value = false
}
const submitMint = async (sn: string) => {
try {
isImageFetching.value = true
const imageHash = await tryCapture()
const hash = await createUnlockableMetadata(
imageHash,
description.value,
collectionName.value || defaultName.value,
'text/html',
selectedImage.value,
)
isImageFetching.value = false
const { result } = await claimDropItem(
{
account: accountId.value,
metadata: hash,
sn,
image: imageHash,
},
props.drop.id,
)
await fetchDropStatus()
const id = `${collectionId.value}-${result.sn}`
subscribeToMintedNft(id, async () => {
mintedNftWithMetadata.value = await fetchNft(id)
})
isLoading.value = false
mintedNft.value = {
...result,
id,
name: result.name,
collectionName: collectionName.value,
}
} catch (error) {
toast($i18n.t('drops.mintPerAddress'))
isImageFetching.value = false
throw error
}
}
const handleDropAddModalConfirm = () => {
closeAddFundModal()
fetchMultipleBalance([urlPrefix.value])
}
</script>

<style scoped lang="scss">
.order-1 {
order: 1;
}
</style>
16 changes: 3 additions & 13 deletions components/drops/DropCard.vue
Original file line number Diff line number Diff line change
Expand Up @@ -53,11 +53,7 @@
<div class="flex flex-col">
<span class="has-text-grey">{{ $t('price') }}</span>
<span v-if="isFreeDrop">{{ $t('free') }}</span>
<Money
v-else
:value="drop.price"
:prefix="correctUrlPrefix"
inline />
<Money v-else :value="drop.price" :prefix="drop.chain" inline />
</div>
</div>
</div>
Expand Down Expand Up @@ -117,16 +113,10 @@ const correctUrlPrefix = computed(() => {
})
const isFreeDrop = computed(() => {
return true // !Number(props.drop?.price)
return !Number(props.drop.price)
})
const availableCount = computed(() => {
if (isFreeDrop.value) {
return props.drop.max - props.drop.minted
} else {
return props.drop.minted
}
})
const availableCount = computed(() => props.drop.minted === props.drop.max)
onMounted(async () => {
if (!props.drop?.collection) {
Expand Down
Loading

0 comments on commit 49f6d8e

Please sign in to comment.