How to get and display NFTs and collections

To getting collections or NFTs use Apollo client for react. The Apollo Client API reference can be found at:
https://www.apollographql.com/docs/react/api/apollo-client/open in new window

First, create two files:

_types.ts_
// QueryResponse interface
export interface QueryResponse<T = void> {
  [key: string]: {
    data?: T[];
  };
}

// Collection's full interface
export interface Collection {
  collection_id: number; // Id of collection
  collection_name: string; // Collection name
  collection_cover: string; // Cover image
  date_of_creation: number; // Creation date
  description: string; // Description text
  owner: string; // Owner's address
  owner_mormalized: string; // Same as owner's address
  owner_can_destroy: boolean; // Shows if collection can be burned
  token_prefix: string; // Token prefix (up to 4 characters)
  tokens_count: number; // Number of tokens in the each collection
  token_limit: number; // Number of tokens limit
  name: string; // Collection name
  sponsorship: string; // Sponsor's address
}

export interface Token {
  token_id: number; // Token id
  token_name: string; // Token name
  token_prefix: number; // Token prefix (up to 4 characters)
  owner: string; // Owner's address
  owner_mormalized: string; // Same as owner's address
  attributes: Record<string, Attribute>; // Token attributes
  date_of_creation: number; // Creation date
  // Token image
  image?: {
    fullUrl: string | null;
    ipfsCid: string | null;
  };

  collection_id: number; // Id of the collection containing the token
  collection_name: string; // The name of the collection containing the token
  collection_cover: string; // Cover image of the collection containing the token
  collection_description: string; // Description of the collection containing the token
}

and

_utils.ts_
// Utilite for getting image path

/* Data image cover different formats:
 * 1) 'QmbuyQebXVQcZbaGmP4maWUqRiKYeAAyYZEiqL3rnev8i4'
 * 2) https://www.ipfs-server/QmbuyQebXVQcZbaGmP4maWUqRiKYeAAyYZEiqL3rnev8i4
 * 3) "{\"ipfs\":\"QmZCuWx72x1ukhehLsg1qNjKhVj3d1feJjadUPJbyYfmpY\",\"type\":\"image\"}"
 * */
export const formatCoverSrc = (
  imagePath: string | null | undefined,
): string | undefined => {
  if (!imagePath) {
    return undefined;
  }

  const buildPath = (url: string) => {
    if (isValidHttpUrl(url)) {
      return url;
    }
    return `https://ipfs.uniquenetwork.dev/ipfs/${url}`;
  };

  try {
    const deserializedImagePath: unknown = JSON.parse(imagePath);

    if (IPFSGateway && isImagePath(deserializedImagePath) && deserializedImagePath.ipfs) {
      return buildPath(deserializedImagePath.ipfs);
    }
  } catch {
    return buildPath(imagePath);
  }

  return undefined;
};

Get NFTs

Create useGqlTokens.ts:

import { gql, useQuery } from '@apollo/client';
import { QueryResponse, Token } from 'types';

// gql request
const OWNER_TOKENS_QUERY = gql`
  query owner_tokens_query(
    $where: TokenWhereParams
  ) {
    tokens(
      where: $where
      order_by: { token_id: "asc" }
    ) {

      # You can add keys from Token interface above
      data {
        token_id
        token_name
        collection_name
        collection_id
        image
      }
    }
  }
`;

// hook
export const useGqlTokens = (
  ownerAddress: string | undefined
) => {
  const {
    data: response,
    error,
  } = useQuery<QueryResponse<Token>>(OWNER_TOKENS_QUERY, {
    skip: !ownerAddress,
    fetchPolicy: 'network-only',
    nextFetchPolicy: 'cache-first',
    notifyOnNetworkStatusChange: true,
    variables: {
      where: {
        _or: [
          { owner: { _eq: ownerAddress } },
          { owner_normalized: { _eq: ownerAddress } },
        ]
      },
    },
  });

  return {
    tokens: response?.tokens.data || [],
    error,
  };
};

Display NFTs

Create tokens.ts:

import { formatCoverSrc } from 'utils';
import { useGqlTokens } from './hooks/useGqlCollections';
import { Token } from 'types';

// NFTs list component
export const TokensList = ({ ownerAddress } : {
  ownerAddress: string | undefined
}) => {
  const { tokens } = useGqlTokens('5HNUuEAYMWEo4cuBW7tuL9mLHR9zSA8H7SdNKsNnYRB9M5TX');
  
  if (!tokens) {
    return <p>No data to display</p>;
  }
  
  return (
    <>
      <h1>List of NFTs</h1>
      <ul>
        {tokens.map((item: Token) => (
          <li key={item.token_id}>
            <h4>{item.token_name} [{item.token_id}]</h4>
            <img
              src={item.image?.fullUrl || undefined}
              alt={item.token_name}
            />
            <p>
              Collection: {item.collection_name} [{item.collection_id}]
            </p>
          </li>
        ))}
      </ul>
    </>
  );
};

Get collections

Create file hooks/useGqlCollections.ts:

import { gql, useQuery } from '@apollo/client';
import { Collection, QueryResponse } from 'types';

// gql request
const COLLECTIONS_BY_ACCOUNT_QUERY = gql`
  query collections_by_account_query(
    $where: CollectionWhereParams
  ) {
    collections(order_by: { collection_id: "asc" }, where: $where) {

      # You can add keys from Collection interface above
      data {
        name
        description
        collection_cover
        collection_id
        owner_normalized
        tokens_count
      }
    }
  }
`;

// hook
export const useGqlCollections = (
  accountAddress: string | undefined
) => {
  const {
    data: response,
    error,
  } = useQuery<QueryResponse<Collection>>(COLLECTIONS_BY_ACCOUNT_QUERY, {
    skip: !accountAddress,
    fetchPolicy: 'network-only',
    nextFetchPolicy: 'network-only',
    notifyOnNetworkStatusChange: true,
    variables: {
      where: {
        _or: [
          { owner: { _eq: accountAddress } },
          { owner_normalized: { _eq: accountAddress } },
        ],
      },
    },
  });

  return {
    collections: response?.collections.data ?? [],
    error,
  };
};

Display collections

Create collections.tsx:

import { formatCoverSrc } from 'utils';
import { useGqlCollections } from './hooks/useGqlCollections';
import { Collection } from 'types';

// Create some functional component for displaying collections list:
export const CollectionsList = () => {
  const { collections } = useGqlCollections('5HNUuEAYMWEo4cuBW7tuL9mLHR9zSA8H7SdNKsNnYRB9M5TX');

  if (!collections) {
    return <p>Nothing to show</p>;
  }

  return (
    <>
      <h1>List of collections</h1>
      <ul>
        {collections.map((item: Collection) => (
          <li key={item.collection_id}>
            <h4>{item.name} [{item.collection_id}]</h4>
            <img
              src={formatCoverSrc(item.collection_cover)}
              alt={item.name}
            />
            <p>{item.description}</p>
            <p>
              Owner: {item.owner_normalized}<br/>
              Tokens count: {item.tokens_count}
            </p>
          </li>
        ))}
      </ul>
    </>
  );
}