kodadot/nft-gallery

View on GitHub
components/items/ItemsGrid/useNftActions.ts

Summary

Maintainability
A
1 hr
Test Coverage
import nftById from '@/queries/subsquid/general/nftById.graphql'
import nftListWithSearch from '@/queries/subsquid/ahk/nftListWithSearch.graphql'
import type { TokenId } from '@/types'

export type NFTWitToken = NFTWithMetadata & TokenId
export const isStack = (entity: TokenEntity) => entity.supply > 1

export const isAvailableToBuy = (entity: TokenEntity) =>
  Number(entity.cheapest.price) > 0

const tokensNftsCache = new Map<string, NFTWithMetadata[]>()

export const fetchNft = async (nftId: string): Promise<NFTWithMetadata> => {
  const { client } = usePrefix()

  const { data } = await useAsyncQuery<{ nftEntity: NFTWithMetadata }>({
    query: nftById,
    variables: {
      id: nftId,
    },
    clientId: client.value,
  })

  return data.value.nftEntity
}

export const prepareListingQuery = (
  entities: TokenEntity[],
) => {
  const { accountId } = useAuth()
  const variables = {
    first: 10000, // some large number
    search: [
      {
        token: { id_in: entities.map(n => n.id) },
        currentOwner_eq: accountId.value,
        burned_eq: false,
      },
    ],
  }

  return {
    query: nftListWithSearch,
    variables,
  }
}

const getCachedAndMissingEntities = (
  entities: TokenEntity[],
): { cachedResults: NFTWithMetadata[], missingEntities: TokenEntity[] } => {
  const cachedResults: NFTWithMetadata[] = []
  const missingEntities: TokenEntity[] = []

  entities.forEach((entity) => {
    if (tokensNftsCache.has(entity.id)) {
      cachedResults.push(...tokensNftsCache.get(entity.id)!)
    }
    else {
      missingEntities.push(entity)
    }
  })

  return { cachedResults, missingEntities }
}

const fetchMissingEntities = async (
  missingEntities: TokenEntity[],
): Promise<NFTWitToken[]> => {
  const { query, variables } = prepareListingQuery(missingEntities)
  const { client } = usePrefix()

  const { data } = await useAsyncQuery<{ nFTEntities: NFTWitToken[] }>({
    query: query,
    variables: variables,
    clientId: client.value,
  })

  return data.value.nFTEntities
}

const groupFetchedResults = (
  fetchedResults: NFTWitToken[],
): { [entityId: string]: NFTWitToken[] } => {
  const grouped: { [entityId: string]: NFTWitToken[] } = {}

  fetchedResults.forEach((fetchedResult) => {
    const entityId = fetchedResult.token?.id
    if (entityId) {
      if (!grouped[entityId]) {
        grouped[entityId] = []
      }
      grouped[entityId].push(fetchedResult)
    }
  })

  return grouped
}

export const getTokensNfts = async (
  entities: TokenEntity[],
): Promise<NFTWithMetadata[]> => {
  const { cachedResults, missingEntities }
    = getCachedAndMissingEntities(entities)

  if (missingEntities.length === 0) {
    return cachedResults
  }

  const fetchedResults = await fetchMissingEntities(missingEntities)

  const groupedResults = groupFetchedResults(fetchedResults)

  Object.entries(groupedResults).forEach(([entityId, nfts]) => {
    const existingDataForEntity = tokensNftsCache.get(entityId) ?? []
    tokensNftsCache.set(entityId, [...existingDataForEntity, ...nfts])
  })

  return [...cachedResults, ...fetchedResults]
}

export const checkIfAnythingToList = async (entities: TokenEntity[]) => {
  const { accountId } = useAuth()

  const count = await getNftCount({
    token: { id_in: entities.map(n => n.id) },
    currentOwner_eq: accountId.value,
    price_eq: 0,
  })

  return count > 0
}

export function useNftActions(entity: TokenEntity) {
  const { isCurrentOwner } = useAuth()

  const cheapestNFT = ref<NFTWithMetadata>()

  const fetchCheapestNFT = async () => {
    cheapestNFT.value = await fetchNft(entity.cheapest.id)
    return cheapestNFT.value
  }

  const isThereAnythingToList = ref<boolean>()
  const isStackComputed = computed(() => isStack(entity))
  const isOwner = computed(() => isCurrentOwner(entity.cheapest.currentOwner))
  const isAvailableToBuyComputed = computed(() => isAvailableToBuy(entity))
  const nftForShoppingCart = computed(() =>
    isTokenEntity(entity) ? entity.cheapest : entity,
  )

  const getNFTForBuying = async () => cheapestNFT.value ?? fetchCheapestNFT()

  onMounted(async () => {
    if (isStackComputed.value && isThereAnythingToList.value === undefined) {
      isThereAnythingToList.value = await checkIfAnythingToList([entity])
    }
  })

  return {
    isOwner,
    isAvailableToBuy: isAvailableToBuyComputed,
    getNFTForBuying,
    nftForShoppingCart,
    isStack: isStackComputed,
    isThereAnythingToList,
  }
}