kodadot/nft-gallery

View on GitHub
components/drops/calendar/DropPreviewModal.vue

Summary

Maintainability
Test Coverage
<template>
  <div>
    <NeoModal
      :value="isModalActive"
      append-to-body
      no-shadow
      content-class="!p-10 h-full !absolute top-0 right-0 !border-y-0 max-md:!border-0 !border-r-0 md:!w-2/3 "
      max-height="100vh"
      @close="emit('close')"
    >
      <template v-if="dropCalendar">
        <header class="flex justify-between items-center">
          <span class="text-3xl font-bold">
            {{ dropCalendar.name }}
          </span>
          <NeoButton
            class="py-1 px-2"
            variant="text"
            no-shadow
            icon="xmark"
            size="large"
            @click="emit('close')"
          />
        </header>

        <div class="!mt-6 flex flex-wrap gap-6">
          <NeoButton
            v-if="dropCalendar.dropStartTime"
            no-shadow
            rounded
            @click="isCreateEventModalActive = true"
          >
            {{ $t('scheduled') }}<span class="text-neutral-5 mx-2">•</span>{{ formattedDate }}
          </NeoButton>

          <NeoButton
            v-if="dropCalendar.alias"
            variant="secondary-rounded"
            icon-left="sparkles"
            :tag="NuxtLink"
            :to="`/${chain}/drops/${dropCalendar.alias}`"
          >
            {{ $t('drops.goToDropPage') }}
          </NeoButton>
        </div>

        <div class="flex justify-between !mt-6">
          <div>
            <span :class="{ 'text-k-grey': !dropCalendar.twitter_handle }">{{ $t('artist') }}:
            </span>
            <a
              v-if="dropCalendar.twitter_handle"
              v-safe-href="`https://twitter.com/${dropCalendar.twitter_handle}`"
              class="has-text-link"
              target="_blank"
              rel="nofollow noopener noreferrer"
            >{{ dropCalendar.twitter_handle }}</a>
            <span v-else> {{ placeholder }}</span>
          </div>

          <div v-if="dropCalendar.royalty">
            <p class="capitalize text-k-grey">
              {{ dropCalendar.royalty }}% {{ $t('royalty') }}
            </p>
          </div>
        </div>

        <CarouselModuleCarouselAgnostic
          v-if="dropCalendar.items.length"
          v-slot="{ item }"
          class="!mt-10"
          :items="dropCalendar.items"
          :config="config"
        >
          <BaseMediaItem
            class="border border-k-shade"
            :src="sanitizeIpfsUrl(item.image)"
            preview
            is-detail
          />
        </CarouselModuleCarouselAgnostic>

        <div class="!mt-10">
          <h2 class="text-xl font-bold">
            {{ $t('drops.dropInformation') }}
          </h2>

          <div class="!mt-6 flex gap-16">
            <div>
              <span class="text-k-grey !mr-3">{{ $t('price') }}:</span>
              <span>{{ price }}</span>
            </div>

            <div>
              <span class="text-k-grey !mr-3">{{ $t('supply') }}:</span>
              <span>{{
                withPlaceholder(
                  dropCalendar.supply,
                  dropCalendar.supply || $t('helper.unlimited'),
                )
              }}</span>
            </div>

            <div class="flex gap-3 items-center">
              <span class="text-k-grey">{{ $t('chain') }}:</span>
              <DropsChainPill
                v-if="dropCalendar?.chain"
                :prefix="dropCalendar?.chain"
              />
              <span v-else>{{ placeholder }}</span>
            </div>
          </div>
        </div>

        <div
          v-if="dropCalendar.holder_of || dropCalendar.location"
          class="!mt-6"
        >
          <h2 class="text-lg font-bold">
            {{ $t('requirements') }}
          </h2>

          <ul class="list-disc !mt-4">
            <li
              v-if="dropCalendar.holder_of && collection"
              class="ml-4"
            >
              Holder Of
              <nuxt-link
                class="has-text-link"
                :to="`/ahp/collection/${collection.id}`"
              >{{ collection.name }}</nuxt-link>
              NFT
            </li>
            <li
              v-if="dropCalendar.location"
              class="ml-4"
            >
              Geolocation of {{ dropCalendar.location }}
            </li>
          </ul>
        </div>

        <hr class="!my-10">

        <Markdown :source="dropCalendar.description ?? ''" />
      </template>
    </NeoModal>

    <DropsCreateCalendarEventModal
      v-if="dropCalendar"
      v-model="isCreateEventModalActive"
      :title="`Drop: ${dropCalendar.name}`"
      :drop-start-time="dropCalendar.dropStartTime ?? undefined"
      use-time-from-date
      @close="isCreateEventModalActive = false"
    />
  </div>
</template>

<script lang="ts" setup>
import { NeoButton, NeoModal } from '@kodadot1/brick'
import { format } from 'date-fns'
import type { InternalDropCalendar } from './DropsCalendar.vue'
import { useCollectionMinimal } from '@/components/collection/utils/useCollectionDetails'
import { chainPropListOf } from '@/utils/config/chain.config'
import { isTBA } from '@/components/drops/utils'

const NuxtLink = resolveComponent('NuxtLink')
const placeholder = 'TBA'
const MOBILE_BREAKPOINT = 768

const emit = defineEmits(['close'])
const props = defineProps<{ dropCalendar?: InternalDropCalendar }>()

const { $i18n } = useNuxtApp()
const { width } = useWindowSize()
const { urlPrefix } = usePrefix()

const chain = computed(() => props.dropCalendar?.chain ?? urlPrefix.value)

const { formatted: formattedPrice } = useAmount(
  computed(() => props.dropCalendar?.price || ''),
  computed(() => chainPropListOf(chain.value)?.tokenDecimals),
  computed(() => chainPropListOf(chain.value)?.tokenSymbol),
)

const { collection } = useCollectionMinimal({
  collectionId: computed(() => props.dropCalendar?.holder_of ?? ''),
})

const isCreateEventModalActive = ref(false)

const config = computed(() => ({
  slides: { perView: width.value > MOBILE_BREAKPOINT ? 2 : 1.2, spacing: 16 },
}))

const price = computed(() =>
  withPlaceholder(
    props.dropCalendar?.price,
    props.dropCalendar?.price ? formattedPrice.value : $i18n.t('free'),
  ),
)

const isModalActive = computed(() => Boolean(props.dropCalendar))

const formattedDate = computed(() =>
  props.dropCalendar?.dropStartTime
    ? `${format(props.dropCalendar.dropStartTime, 'd. MMMM h:mm aa')}`
    : '',
)

const withPlaceholder = (nullableValue: unknown, or: unknown) =>
  isTBA(nullableValue) ? placeholder : or
</script>