kodadot/nft-gallery

View on GitHub
components/migrate/steps/SignLoader3.vue

Summary

Maintainability
Test Coverage
<template>
  <div class="mb-5">
    <div class="flex items-center mb-4">
      <div class="mr-5">
        <NeoIcon
          v-if="fromNfts?.length === nextNfts?.length"
          v-bind="iconSuccess"
          class="fa-2x"
        />
        <NeoIcon
          v-else
          v-bind="iconIdle"
          class="fa-2x"
        />
      </div>
      <div>
        <p class="font-bold text-xl">
          Comprehensive Collection Scan
        </p>
        <p class="text-k-grey">
          Verifying your collection on the destination chain.
        </p>
      </div>
    </div>
    <div class="flex mb-4">
      <div class="v-border" />
      <div>
        <p class="text-k-grey italic">
          no action needed
        </p>
      </div>
    </div>

    <div class="flex items-center mb-4">
      <div class="mr-5">
        <NeoIcon
          v-bind="whichIcon()"
          class="fa-2x"
        />
      </div>
      <div>
        <p class="font-bold text-xl">
          {{ $t('migrate.signStep.finalization') }}
        </p>
        <p class="text-k-grey">
          {{ $t('migrate.signStep.authorize') }}
        </p>
      </div>
    </div>
    <div class="flex">
      <div class="v-border" />
      <div class="mb-4">
        1/1 {{ $t('migrate.signStep.left') }}
      </div>
    </div>
    <div class="flex">
      <div class="v-border" />
      <div class="mb-4 flex w-full">
        <NeoIcon
          v-bind="whichIcon()"
          class="mr-4"
        />
        <div :class="whichIcon().textColor">
          <p>{{ $t('migrate.signStep.finalizingItems', [itemCount]) }}</p>
        </div>
        <div
          v-if="isError || status === TransactionStatus.Cancelled"
          class="flex-1 text-right"
        >
          <NeoButton
            variant="outlined-rounded"
            size="small"
            @click="burnItems()"
          >
            {{ $t('helper.tryAgain') }}
          </NeoButton>
        </div>
      </div>
    </div>
  </div>
</template>

<script setup lang="ts">
import type { Prefix } from '@kodadot1/static'
import { Interaction } from '@kodadot1/minimark/v1'
import { NeoButton, NeoIcon } from '@kodadot1/brick'
import { Collections } from '@/composables/transaction/types'
import { TransactionStatus } from '@/composables/useTransactionStatus'
import {
  type Steps,
  iconIdle,
  iconLoading,
  iconSuccess,
} from '@/composables/useMigrate'
import nftIdListByCollection from '@/queries/subsquid/general/nftIdListByCollection.graphql'

const route = useRoute()
const { transaction, status, isError } = useTransaction()
const { urlPrefix } = usePrefix()
const { accountId } = useAuth()
const { $consola } = useNuxtApp()

const from = route.query.source as Prefix
const fromAccountId = route.query.accountId?.toString()
const fromCollectionId = route.query.collectionId?.toString()
const nextCollectionId = computed(() =>
  route.query.nextCollectionId?.toString(),
)

const itemCount = route.query.itemCount?.toString()

type NftIds = {
  nfts?: {
    id: string
  }[]
}

const { steps, updateSteps } = inject('steps') as {
  steps: Ref<Steps>
  updateSteps: (step: Steps) => void
}

const whichIcon = () => {
  if (isError.value || status.value === TransactionStatus.Cancelled) {
    return iconError
  }

  if (steps.value === 'step4') {
    return iconSuccess
  }

  if (steps.value === 'step3-burn' || steps.value === 'step3-burn-collection') {
    return iconLoading
  }

  return iconIdle
}

const { data: getFromNfts } = useGraphql({
  queryName: 'nftIdListByCollection',
  clientName: from,
  variables: {
    id: fromCollectionId,
    search: [{ currentOwner_eq: fromAccountId }],
  },
})
const fromNfts = computed(() => (getFromNfts.value as NftIds)?.nfts)

const nextNfts = ref()
const checkNextNfts = async () => {
  const { data } = await useAsyncQuery({
    query: nftIdListByCollection,
    variables: {
      id: nextCollectionId.value,
      search: [{ currentOwner_eq: accountId.value }],
    },
    clientId: urlPrefix.value,
  })

  nextNfts.value = (data.value as NftIds)?.nfts
}

const burnItems = async () => {
  const ids = fromNfts.value?.map(item => item.id) || []

  await transaction(
    {
      interaction: Interaction.CONSUME,
      nftIds: ids,
      urlPrefix: from,
    },
    from,
  )
  updateSteps('step3-burn')
}

const burnCollection = async () => {
  if (fromCollectionId) {
    await transaction(
      {
        interaction: Collections.DELETE,
        collectionId: fromCollectionId,
        urlPrefix: from,
      },
      from,
    )
    updateSteps('step3-burn-collection')
  }
}

const congratsPage = () => {
  updateSteps('step4')
  navigateTo({
    path: '/migrate/congrats',
    query: {
      ...route.query,
    },
  })
}

// check next nfts
watchDebounced(
  [steps, nextCollectionId, nextNfts],
  async () => {
    if (
      steps.value === 'step3'
      && nextCollectionId.value
      && fromNfts.value?.length !== nextNfts.value?.length
    ) {
      await checkNextNfts()
    }
  },
  { debounce: 1000 },
)

watchEffect(async () => {
  $consola.info(
    'SignLoader3',
    steps.value,
    toRaw(fromNfts.value),
    nextNfts.value,
  )

  // burn items
  if (
    steps.value === 'step3'
    && fromNfts.value?.length === nextNfts.value?.length
  ) {
    burnItems()
  }

  // ensure to burn items
  if (
    steps.value === 'step3-burn'
    && status.value === TransactionStatus.Finalized
  ) {
    burnCollection()
  }

  // ensure to burn collection
  if (
    steps.value === 'step3-burn-collection'
    && status.value === TransactionStatus.Finalized
  ) {
    congratsPage()
  }
})
</script>