kodadot/nft-gallery

View on GitHub
components/collection/drop/MintButton.vue

Summary

Maintainability
Test Coverage
<template>
  <NeoButton
    ref="root"
    variant="primary"
    expanded
    no-shadow
    size="large"
    data-testid="drop-mint-button"
    :loading="loading"
    :disabled="!enabled || loading"
    :loading-with-label="
      isCheckingMintRequirements
        || dropStore.walletConnecting
        || dropStore.loading
    "
    :label="label"
    @click="handleMint"
  />
</template>

<script setup lang="ts">
import { NeoButton } from '@kodadot1/brick'
import useGenerativeDropMint from '@/composables/drop/useGenerativeDropMint'
import { useDropStore } from '@/stores/drop'
import { useDropMinimumFunds } from '@/components/drops/useDrops'
import {
  calculateBalanceUsdValue,
  formatAmountWithRound,
} from '@/utils/format/balance'
import useHolderOfCollection from '@/composables/drop/useHolderOfCollection'
import { parseCETDate } from '@/components/drops/utils'
import { doAfterCheckCurrentChainVM } from '@/components/common/ConnectWallet/openReconnectWalletModal'

const emit = defineEmits(['mint'])

const { $i18n } = useNuxtApp()
const { urlPrefix } = usePrefix()
const { isLogIn } = useAuth()
const { chainSymbol, decimals } = useChain()
const dropStore = useDropStore()
const { hasCurrentChainBalance } = useMultipleBalance()
const now = useNow()
const { mintCountAvailable } = useGenerativeDropMint()
const { amountToMint, previewItem, userMintsCount, drop, getIsLoadingMaxCount } = storeToRefs(dropStore)

const { hasMinimumFunds } = useDropMinimumFunds()
const { holderOfCollection } = useHolderOfCollection()
const priceUsd = ref()

const isHolderAndEligible = computed(
  () =>
    holderOfCollection.value.isHolder
    && drop.value.max
    && drop.value.max > drop.value.minted
    && hasMinimumFunds.value
    && holderOfCollection.value.hasAvailable,
)

watch(drop, async () => {
  const tokenPrice = await getApproximatePriceOf(chainSymbol.value)
  const tokenAmount = calculateBalanceUsdValue(
    Number(drop.value.price),
    decimals.value,
  )
  priceUsd.value = tokenAmount * tokenPrice
})

const mintForLabel = computed(() =>
  $i18n.t('drops.mintForPaid', [
    `${formatAmountWithRound(drop.value?.price ? Number(drop.value?.price) * amountToMint.value : '', decimals.value, drop.value.chain)} ${
      chainSymbol.value
    } ${priceUsd.value ? '/ ' + (priceUsd.value * amountToMint.value).toFixed(2) + ' ' + $i18n.t('general.usd') : ''}`,
  ]),
)

const label = computed(() => {
  if (drop.value.max && (drop.value.max === drop.value.minted)) {
    return $i18n.t('mint.unlockable.seeListings')
  }
  if (!isLogIn.value) {
    return $i18n.t('general.connect_wallet')
  }
  if (dropStore.walletConnecting) {
    return $i18n.t('shoppingCart.wallet')
  }
  if (dropStore.loading) {
    // TODO: listen to transaction status and update label accordingly
    return $i18n.t('loader.ipfs')
  }
  if (isCheckingMintRequirements.value) {
    return $i18n.t('checking')
  }

  if (isMintNotLive.value) {
    return $i18n.t('mint.unlockable.mintingNotLive')
  }

  switch (drop.value.type) {
    case 'free':
      return $i18n.t('drops.mintForFree')
    case 'holder':
      return isHolderAndEligible.value
        ? mintForLabel.value
        : $i18n.t('mint.unlockable.notEligibility')
    case 'paid':
      return mintForLabel.value
    default:
      return $i18n.t('general.connect_wallet')
  }
})

const isMintNotLive = computed(() => {
  const startAt = drop.value.start_at
  return startAt ? parseCETDate(startAt) > now.value : false
})

const enabled = computed(() => {
  if (!isLogIn.value) {
    return true
  }
  if (!mintCountAvailable.value) {
    return true
  }
  if (
    !amountToMint.value // number of drop to be mint is 0
    || Boolean(drop.value.disabled) // drop is disabled
    || isMintNotLive.value // drop start time is greater than now
    || !previewItem.value // no image
    || isCheckingMintRequirements.value // still checking requirements
    || loading.value // still loading
  ) {
    return false
  }

  switch (drop.value.type) {
    case 'free':
      return true
    case 'holder':
      return isHolderAndEligible.value
    case 'paid':
      return drop.value.max && drop.value.max > userMintsCount.value
    default:
      return false
  }
})

const loading = computed(
  () =>
    dropStore.isCapturingImage
    || dropStore.walletConnecting
    || dropStore.loading
    || getIsLoadingMaxCount.value,
)

const showHolderOfCollection = computed(() =>
  Boolean(holderOfCollection.value.id),
)

const isCheckingMintRequirements = computed(
  () =>
    showHolderOfCollection.value
    && isLogIn.value
    && (holderOfCollection.value.isLoading || !hasCurrentChainBalance.value),
)

const handleMint = () => {
  if (!mintCountAvailable.value) {
    return navigateTo(
      `/${urlPrefix.value}/collection/${drop.value.collection}?listed=true`,
    )
  }

  doAfterCheckCurrentChainVM(() => {
    emit('mint')
  })
}
</script>