From 88b9c1ec2463f5dde0766f3c2f8f52a6e2c05ad5 Mon Sep 17 00:00:00 2001 From: Nikita Yutanov Date: Fri, 29 Mar 2024 17:22:13 +0300 Subject: [PATCH] Optimize backend performance: drop subscriptions (#34) * Disable subscriptions * Log marketplace address * Drop cache and subscriptions --- frontend/src/context/indexer.tsx | 55 +------------ frontend/src/context/marketplace/context.tsx | 4 + .../collection-card/collection-card.tsx | 2 +- .../mint-limit-info-card.tsx | 2 +- .../components/mint-nft/mint-nft.tsx | 9 ++- frontend/src/graphql/gql.ts | 18 +---- frontend/src/graphql/graphql.ts | 36 ++------- .../src/hooks/use-send-message-with-reply.ts | 23 +++--- frontend/src/main.tsx | 4 +- frontend/src/pages/collection/collection.tsx | 29 ++----- frontend/src/pages/collection/consts.ts | 6 +- frontend/src/pages/collection/hooks.ts | 17 ++-- frontend/src/pages/create-collection/hooks.ts | 8 +- frontend/src/pages/lists/consts.ts | 52 ------------- frontend/src/pages/lists/hooks.ts | 78 ++++--------------- frontend/src/pages/nft/consts.ts | 2 +- frontend/src/pages/nft/hooks.ts | 4 +- 17 files changed, 75 insertions(+), 274 deletions(-) diff --git a/frontend/src/context/indexer.tsx b/frontend/src/context/indexer.tsx index 01900ac..7a6921d 100644 --- a/frontend/src/context/indexer.tsx +++ b/frontend/src/context/indexer.tsx @@ -6,7 +6,6 @@ import { Kind, OperationTypeNode } from 'graphql'; import { createClient } from 'graphql-ws'; import { ADDRESS } from '@/consts'; -import { CollectionsQueryQuery } from '@/graphql/graphql'; const httpLink = new HttpLink({ uri: ADDRESS.INDEXER }); const wsLink = new GraphQLWsLink(createClient({ url: ADDRESS.INDEXER_WS })); @@ -22,60 +21,10 @@ const splitLink = split( const client = new ApolloClient({ link: splitLink, - cache: new InMemoryCache({ - typePolicies: { - Query: { - fields: { - nfts: { - keyArgs: ['where', ['owner_eq', 'collection', ['id_eq']]], - merge: (existing: unknown[] = [], incoming: unknown[], { args }: { args: unknown }) => { - // eslint-disable-next-line @typescript-eslint/ban-ts-comment - // @ts-ignore - const offset = args.offset as number; - - // Slicing is necessary because the existing data is - // immutable, and frozen in development. - const merged = existing ? existing.slice(0) : []; - - for (let i = 0; i < incoming.length; ++i) { - merged[offset + i] = incoming[i]; - } - - return merged; - }, - }, - - // TODO: make it less mess - collections: { - keyArgs: ['where', ['admin_contains', 'admin_eq']], // admin_eq is for create collection page - merge: ( - existing: CollectionsQueryQuery['collections'] = [], - incoming: CollectionsQueryQuery['collections'], - { args }: { args: unknown }, - ) => { - // eslint-disable-next-line @typescript-eslint/ban-ts-comment - // @ts-ignore - const offset = args.offset as number; - - // Slicing is necessary because the existing data is - // immutable, and frozen in development. - const merged = existing ? existing.slice(0) : []; - - for (let i = 0; i < incoming.length; ++i) { - merged[offset + i] = incoming[i]; - } - - return merged; - }, - }, - }, - }, - }, - }), + cache: new InMemoryCache(), defaultOptions: { - query: { notifyOnNetworkStatusChange: true }, - watchQuery: { notifyOnNetworkStatusChange: true }, + watchQuery: { notifyOnNetworkStatusChange: true, fetchPolicy: 'network-only' }, }, }); diff --git a/frontend/src/context/marketplace/context.tsx b/frontend/src/context/marketplace/context.tsx index 7c25f5a..bfff3fa 100644 --- a/frontend/src/context/marketplace/context.tsx +++ b/frontend/src/context/marketplace/context.tsx @@ -3,6 +3,7 @@ import { ProgramMetadata } from '@gear-js/api'; import { ProviderProps, useAlert } from '@gear-js/react-hooks'; import { createContext, useContext, useEffect, useState } from 'react'; +import { ADDRESS } from '@/consts'; import { getIpfsLink } from '@/utils'; import { DEFAULT_VALUE, MARKETPLACE_QUERY } from './consts'; @@ -21,8 +22,11 @@ function MarketplaceProvider({ children }: ProviderProps) { const [marketplaceMetadata, setMarketplaceMetadata] = useState(); const [collectionsMetadata, setCollectionsMetadata] = useState(); + const logPublicEnvs = () => console.log('public envs: ', { ...ADDRESS, CONTRACT: marketplace?.address }); + useEffect(() => { if (!marketplace) return; + logPublicEnvs(); const { metadata, collectionTypes } = marketplace; const collectionURLs = collectionTypes.map(({ metaUrl }) => fetch(getIpfsLink(metaUrl))); diff --git a/frontend/src/features/collections/components/collection-card/collection-card.tsx b/frontend/src/features/collections/components/collection-card/collection-card.tsx index ea32c2b..52fe26f 100644 --- a/frontend/src/features/collections/components/collection-card/collection-card.tsx +++ b/frontend/src/features/collections/components/collection-card/collection-card.tsx @@ -14,7 +14,7 @@ import styles from './collection-card.module.scss'; type Props = Pick & { nfts: Pick[]; } & { - nftsCount: string | undefined; + nftsCount: number | undefined; }; const PREVIEW_NFTS_COUNT = 5; diff --git a/frontend/src/features/collections/components/mint-limit-info-card/mint-limit-info-card.tsx b/frontend/src/features/collections/components/mint-limit-info-card/mint-limit-info-card.tsx index 8da56b0..3da8c59 100644 --- a/frontend/src/features/collections/components/mint-limit-info-card/mint-limit-info-card.tsx +++ b/frontend/src/features/collections/components/mint-limit-info-card/mint-limit-info-card.tsx @@ -4,7 +4,7 @@ import LandscapeSVG from '../../assets/landscape.svg?react'; type Props = Omit & { heading: string | null | undefined; - text: string | number | undefined; + text: number | undefined; }; function MintLimitInfoCard({ heading, text, ...props }: Props) { diff --git a/frontend/src/features/collections/components/mint-nft/mint-nft.tsx b/frontend/src/features/collections/components/mint-nft/mint-nft.tsx index ca88f51..805806c 100644 --- a/frontend/src/features/collections/components/mint-nft/mint-nft.tsx +++ b/frontend/src/features/collections/components/mint-nft/mint-nft.tsx @@ -11,9 +11,10 @@ type Props = Pick< 'id' | 'tokensLimit' | 'paymentForMint' | 'userMintLimit' | 'permissionToMint' | 'admin' > & { nfts: Pick[]; + refetch: () => void; }; -function Component({ id, tokensLimit, paymentForMint, userMintLimit, permissionToMint, admin, nfts }: Props) { +function Component({ id, tokensLimit, paymentForMint, userMintLimit, permissionToMint, admin, nfts, refetch }: Props) { const sendMessage = useMarketplaceMessage(); const alert = useAlert(); const [isLoading, enableLoading, disableLoading] = useLoading(); @@ -42,7 +43,11 @@ function Component({ id, tokensLimit, paymentForMint, userMintLimit, permissionT const percentage = (BigInt(paymentForMint) * BigInt(200)) / BigInt(FEE_MULTIPLIER); const value = (BigInt(paymentForMint) + percentage).toString(); - const onSuccess = () => alert.success('NFT minted'); + const onSuccess = () => { + refetch(); + alert.success('NFT minted'); + }; + const onFinally = disableLoading; sendMessage({ payload, value, onSuccess, onFinally }); diff --git a/frontend/src/graphql/gql.ts b/frontend/src/graphql/gql.ts index 0710bdb..082360b 100644 --- a/frontend/src/graphql/gql.ts +++ b/frontend/src/graphql/gql.ts @@ -14,16 +14,14 @@ import { TypedDocumentNode as DocumentNode } from '@graphql-typed-document-node/ */ const documents = { "\n query MarketplaceQuery {\n marketplaceById(id: \"1\") {\n address\n collectionTypes {\n description\n metaUrl\n type\n }\n metadata\n config {\n feePerUploadedFile\n minimumValueForTrade\n royaltyToMarketplaceForMint\n royaltyToMarketplaceForTrade\n timeBetweenCreateCollections\n }\n admins\n }\n }\n": types.MarketplaceQueryDocument, - "\n subscription CollectionSub($id: String!) {\n collectionById(id: $id) {\n id\n name\n description\n collectionBanner\n collectionLogo\n admin\n tokensLimit\n permissionToMint\n userMintLimit\n paymentForMint\n transferable\n sellable\n\n additionalLinks {\n discord\n externalUrl\n medium\n xcom\n telegram\n }\n }\n }\n": types.CollectionSubDocument, + "\n query CollectionQuery($id: String!) {\n collectionById(id: $id) {\n id\n name\n description\n collectionBanner\n collectionLogo\n admin\n tokensLimit\n permissionToMint\n userMintLimit\n paymentForMint\n transferable\n sellable\n\n additionalLinks {\n discord\n externalUrl\n medium\n xcom\n telegram\n }\n }\n }\n": types.CollectionQueryDocument, "\n query LastCreatedCollectionQuery($admin: String!) {\n collections(where: { admin_eq: $admin }, orderBy: [createdAt_DESC, name_DESC, id_DESC], limit: 1) {\n createdAt\n }\n }\n": types.LastCreatedCollectionQueryDocument, "\n query CollectionsConnectionQuery($where: CollectionWhereInput!) {\n collectionsConnection(orderBy: [createdAt_DESC, name_DESC, id_DESC], where: $where) {\n totalCount\n }\n }\n": types.CollectionsConnectionQueryDocument, "\n query CollectionsQuery($limit: Int!, $offset: Int!, $where: CollectionWhereInput!) {\n collections(limit: $limit, offset: $offset, orderBy: [createdAt_DESC, name_DESC, id_DESC], where: $where) {\n id\n name\n description\n collectionBanner\n collectionLogo\n admin\n tokensLimit\n\n nfts(limit: 5) {\n id\n mediaUrl\n }\n }\n }\n": types.CollectionsQueryDocument, - "\n subscription CollectionsSub($limit: Int!, $offset: Int!, $where: CollectionWhereInput!) {\n collections(limit: $limit, offset: $offset, orderBy: [createdAt_DESC, name_DESC, id_DESC], where: $where) {\n id\n name\n description\n collectionBanner\n collectionLogo\n admin\n tokensLimit\n\n nfts(limit: 5) {\n id\n mediaUrl\n }\n }\n }\n": types.CollectionsSubDocument, "\n query CollectionsNFTsCountQuery($ids: [String!]) {\n nftsInCollection(collections: $ids) {\n collection\n count\n }\n }\n": types.CollectionsNfTsCountQueryDocument, "\n query NFTsConnectionQuery($where: NftWhereInput!) {\n nftsConnection(orderBy: [createdAt_DESC, name_DESC, id_DESC], where: $where) {\n totalCount\n }\n }\n": types.NfTsConnectionQueryDocument, "\n query NFTsQuery($limit: Int!, $offset: Int!, $where: NftWhereInput!) {\n nfts(limit: $limit, offset: $offset, orderBy: [createdAt_DESC, name_DESC, id_DESC], where: $where) {\n id\n idInCollection\n name\n mediaUrl\n owner\n\n mintedBy\n\n collection {\n id\n name\n transferable\n sellable\n }\n\n sales(where: { status_eq: \"open\" }) {\n price\n }\n\n auctions(where: { status_eq: \"open\" }) {\n minPrice\n lastPrice\n endTimestamp\n }\n }\n }\n": types.NfTsQueryDocument, - "\n subscription NFTsSubscription($limit: Int!, $offset: Int!, $where: NftWhereInput!) {\n nfts(limit: $limit, offset: $offset, orderBy: [createdAt_DESC, name_DESC, id_DESC], where: $where) {\n id\n idInCollection\n name\n mediaUrl\n owner\n\n mintedBy\n\n collection {\n id\n name\n transferable\n sellable\n }\n\n sales(where: { status_eq: \"open\" }) {\n price\n }\n\n auctions(where: { status_eq: \"open\" }) {\n minPrice\n lastPrice\n endTimestamp\n }\n }\n }\n": types.NfTsSubscriptionDocument, - "\n subscription NFTQuery($id: String!) {\n nftById(id: $id) {\n id\n idInCollection\n name\n description\n mediaUrl\n owner\n createdAt\n\n collection {\n id\n name\n royalty\n sellable\n transferable\n\n type {\n type\n }\n }\n\n sales(where: { status_eq: \"open\" }) {\n price\n }\n\n auctions(where: { status_eq: \"open\" }) {\n minPrice\n lastPrice\n endTimestamp\n }\n }\n }\n": types.NftQueryDocument, + "\n query NFTQuery($id: String!) {\n nftById(id: $id) {\n id\n idInCollection\n name\n description\n mediaUrl\n owner\n createdAt\n\n collection {\n id\n name\n royalty\n sellable\n transferable\n\n type {\n type\n }\n }\n\n sales(where: { status_eq: \"open\" }) {\n price\n }\n\n auctions(where: { status_eq: \"open\" }) {\n minPrice\n lastPrice\n endTimestamp\n }\n }\n }\n": types.NftQueryDocument, }; /** @@ -47,7 +45,7 @@ export function graphql(source: "\n query MarketplaceQuery {\n marketplaceBy /** * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. */ -export function graphql(source: "\n subscription CollectionSub($id: String!) {\n collectionById(id: $id) {\n id\n name\n description\n collectionBanner\n collectionLogo\n admin\n tokensLimit\n permissionToMint\n userMintLimit\n paymentForMint\n transferable\n sellable\n\n additionalLinks {\n discord\n externalUrl\n medium\n xcom\n telegram\n }\n }\n }\n"): (typeof documents)["\n subscription CollectionSub($id: String!) {\n collectionById(id: $id) {\n id\n name\n description\n collectionBanner\n collectionLogo\n admin\n tokensLimit\n permissionToMint\n userMintLimit\n paymentForMint\n transferable\n sellable\n\n additionalLinks {\n discord\n externalUrl\n medium\n xcom\n telegram\n }\n }\n }\n"]; +export function graphql(source: "\n query CollectionQuery($id: String!) {\n collectionById(id: $id) {\n id\n name\n description\n collectionBanner\n collectionLogo\n admin\n tokensLimit\n permissionToMint\n userMintLimit\n paymentForMint\n transferable\n sellable\n\n additionalLinks {\n discord\n externalUrl\n medium\n xcom\n telegram\n }\n }\n }\n"): (typeof documents)["\n query CollectionQuery($id: String!) {\n collectionById(id: $id) {\n id\n name\n description\n collectionBanner\n collectionLogo\n admin\n tokensLimit\n permissionToMint\n userMintLimit\n paymentForMint\n transferable\n sellable\n\n additionalLinks {\n discord\n externalUrl\n medium\n xcom\n telegram\n }\n }\n }\n"]; /** * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. */ @@ -60,10 +58,6 @@ export function graphql(source: "\n query CollectionsConnectionQuery($where: Co * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. */ export function graphql(source: "\n query CollectionsQuery($limit: Int!, $offset: Int!, $where: CollectionWhereInput!) {\n collections(limit: $limit, offset: $offset, orderBy: [createdAt_DESC, name_DESC, id_DESC], where: $where) {\n id\n name\n description\n collectionBanner\n collectionLogo\n admin\n tokensLimit\n\n nfts(limit: 5) {\n id\n mediaUrl\n }\n }\n }\n"): (typeof documents)["\n query CollectionsQuery($limit: Int!, $offset: Int!, $where: CollectionWhereInput!) {\n collections(limit: $limit, offset: $offset, orderBy: [createdAt_DESC, name_DESC, id_DESC], where: $where) {\n id\n name\n description\n collectionBanner\n collectionLogo\n admin\n tokensLimit\n\n nfts(limit: 5) {\n id\n mediaUrl\n }\n }\n }\n"]; -/** - * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. - */ -export function graphql(source: "\n subscription CollectionsSub($limit: Int!, $offset: Int!, $where: CollectionWhereInput!) {\n collections(limit: $limit, offset: $offset, orderBy: [createdAt_DESC, name_DESC, id_DESC], where: $where) {\n id\n name\n description\n collectionBanner\n collectionLogo\n admin\n tokensLimit\n\n nfts(limit: 5) {\n id\n mediaUrl\n }\n }\n }\n"): (typeof documents)["\n subscription CollectionsSub($limit: Int!, $offset: Int!, $where: CollectionWhereInput!) {\n collections(limit: $limit, offset: $offset, orderBy: [createdAt_DESC, name_DESC, id_DESC], where: $where) {\n id\n name\n description\n collectionBanner\n collectionLogo\n admin\n tokensLimit\n\n nfts(limit: 5) {\n id\n mediaUrl\n }\n }\n }\n"]; /** * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. */ @@ -79,11 +73,7 @@ export function graphql(source: "\n query NFTsQuery($limit: Int!, $offset: Int! /** * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. */ -export function graphql(source: "\n subscription NFTsSubscription($limit: Int!, $offset: Int!, $where: NftWhereInput!) {\n nfts(limit: $limit, offset: $offset, orderBy: [createdAt_DESC, name_DESC, id_DESC], where: $where) {\n id\n idInCollection\n name\n mediaUrl\n owner\n\n mintedBy\n\n collection {\n id\n name\n transferable\n sellable\n }\n\n sales(where: { status_eq: \"open\" }) {\n price\n }\n\n auctions(where: { status_eq: \"open\" }) {\n minPrice\n lastPrice\n endTimestamp\n }\n }\n }\n"): (typeof documents)["\n subscription NFTsSubscription($limit: Int!, $offset: Int!, $where: NftWhereInput!) {\n nfts(limit: $limit, offset: $offset, orderBy: [createdAt_DESC, name_DESC, id_DESC], where: $where) {\n id\n idInCollection\n name\n mediaUrl\n owner\n\n mintedBy\n\n collection {\n id\n name\n transferable\n sellable\n }\n\n sales(where: { status_eq: \"open\" }) {\n price\n }\n\n auctions(where: { status_eq: \"open\" }) {\n minPrice\n lastPrice\n endTimestamp\n }\n }\n }\n"]; -/** - * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. - */ -export function graphql(source: "\n subscription NFTQuery($id: String!) {\n nftById(id: $id) {\n id\n idInCollection\n name\n description\n mediaUrl\n owner\n createdAt\n\n collection {\n id\n name\n royalty\n sellable\n transferable\n\n type {\n type\n }\n }\n\n sales(where: { status_eq: \"open\" }) {\n price\n }\n\n auctions(where: { status_eq: \"open\" }) {\n minPrice\n lastPrice\n endTimestamp\n }\n }\n }\n"): (typeof documents)["\n subscription NFTQuery($id: String!) {\n nftById(id: $id) {\n id\n idInCollection\n name\n description\n mediaUrl\n owner\n createdAt\n\n collection {\n id\n name\n royalty\n sellable\n transferable\n\n type {\n type\n }\n }\n\n sales(where: { status_eq: \"open\" }) {\n price\n }\n\n auctions(where: { status_eq: \"open\" }) {\n minPrice\n lastPrice\n endTimestamp\n }\n }\n }\n"]; +export function graphql(source: "\n query NFTQuery($id: String!) {\n nftById(id: $id) {\n id\n idInCollection\n name\n description\n mediaUrl\n owner\n createdAt\n\n collection {\n id\n name\n royalty\n sellable\n transferable\n\n type {\n type\n }\n }\n\n sales(where: { status_eq: \"open\" }) {\n price\n }\n\n auctions(where: { status_eq: \"open\" }) {\n minPrice\n lastPrice\n endTimestamp\n }\n }\n }\n"): (typeof documents)["\n query NFTQuery($id: String!) {\n nftById(id: $id) {\n id\n idInCollection\n name\n description\n mediaUrl\n owner\n createdAt\n\n collection {\n id\n name\n royalty\n sellable\n transferable\n\n type {\n type\n }\n }\n\n sales(where: { status_eq: \"open\" }) {\n price\n }\n\n auctions(where: { status_eq: \"open\" }) {\n minPrice\n lastPrice\n endTimestamp\n }\n }\n }\n"]; export function graphql(source: string) { return (documents as any)[source] ?? {}; diff --git a/frontend/src/graphql/graphql.ts b/frontend/src/graphql/graphql.ts index 403254c..45dcd90 100644 --- a/frontend/src/graphql/graphql.ts +++ b/frontend/src/graphql/graphql.ts @@ -2095,7 +2095,7 @@ export type NftsConnection = { export type NftsInCollection = { __typename?: 'NftsInCollection'; collection: Scalars['String']['output']; - count: Scalars['String']['output']; + count: Scalars['Float']['output']; }; export type Offer = { @@ -3274,12 +3274,12 @@ export type MarketplaceQueryQueryVariables = Exact<{ [key: string]: never; }>; export type MarketplaceQueryQuery = { __typename?: 'Query', marketplaceById: { __typename?: 'Marketplace', address: string, metadata: string, admins: Array, collectionTypes: Array<{ __typename?: 'CollectionType', description: string, metaUrl: string, type: string }>, config: { __typename?: 'MarketplaceConfig', feePerUploadedFile: string, minimumValueForTrade: string, royaltyToMarketplaceForMint: number, royaltyToMarketplaceForTrade: number, timeBetweenCreateCollections: string } } | null }; -export type CollectionSubSubscriptionVariables = Exact<{ +export type CollectionQueryQueryVariables = Exact<{ id: Scalars['String']['input']; }>; -export type CollectionSubSubscription = { __typename?: 'Subscription', collectionById: { __typename?: 'Collection', id: string, name: string, description: string, collectionBanner: string, collectionLogo: string, admin: string, tokensLimit: string | null, permissionToMint: Array | null, userMintLimit: string | null, paymentForMint: string, transferable: string | null, sellable: string | null, additionalLinks: { __typename?: 'AdditionalLinks', discord: string | null, externalUrl: string | null, medium: string | null, xcom: string | null, telegram: string | null } | null } | null }; +export type CollectionQueryQuery = { __typename?: 'Query', collectionById: { __typename?: 'Collection', id: string, name: string, description: string, collectionBanner: string, collectionLogo: string, admin: string, tokensLimit: string | null, permissionToMint: Array | null, userMintLimit: string | null, paymentForMint: string, transferable: string | null, sellable: string | null, additionalLinks: { __typename?: 'AdditionalLinks', discord: string | null, externalUrl: string | null, medium: string | null, xcom: string | null, telegram: string | null } | null } | null }; export type LastCreatedCollectionQueryQueryVariables = Exact<{ admin: Scalars['String']['input']; @@ -3304,21 +3304,12 @@ export type CollectionsQueryQueryVariables = Exact<{ export type CollectionsQueryQuery = { __typename?: 'Query', collections: Array<{ __typename?: 'Collection', id: string, name: string, description: string, collectionBanner: string, collectionLogo: string, admin: string, tokensLimit: string | null, nfts: Array<{ __typename?: 'Nft', id: string, mediaUrl: string }> }> }; -export type CollectionsSubSubscriptionVariables = Exact<{ - limit: Scalars['Int']['input']; - offset: Scalars['Int']['input']; - where: CollectionWhereInput; -}>; - - -export type CollectionsSubSubscription = { __typename?: 'Subscription', collections: Array<{ __typename?: 'Collection', id: string, name: string, description: string, collectionBanner: string, collectionLogo: string, admin: string, tokensLimit: string | null, nfts: Array<{ __typename?: 'Nft', id: string, mediaUrl: string }> }> }; - export type CollectionsNfTsCountQueryQueryVariables = Exact<{ ids: InputMaybe | Scalars['String']['input']>; }>; -export type CollectionsNfTsCountQueryQuery = { __typename?: 'Query', nftsInCollection: Array<{ __typename?: 'NftsInCollection', collection: string, count: string }> }; +export type CollectionsNfTsCountQueryQuery = { __typename?: 'Query', nftsInCollection: Array<{ __typename?: 'NftsInCollection', collection: string, count: number }> }; export type NfTsConnectionQueryQueryVariables = Exact<{ where: NftWhereInput; @@ -3336,31 +3327,20 @@ export type NfTsQueryQueryVariables = Exact<{ export type NfTsQueryQuery = { __typename?: 'Query', nfts: Array<{ __typename?: 'Nft', id: string, idInCollection: number, name: string, mediaUrl: string, owner: string, mintedBy: string, collection: { __typename?: 'Collection', id: string, name: string, transferable: string | null, sellable: string | null }, sales: Array<{ __typename?: 'Sale', price: string }>, auctions: Array<{ __typename?: 'Auction', minPrice: string, lastPrice: string | null, endTimestamp: string | null }> }> }; -export type NfTsSubscriptionSubscriptionVariables = Exact<{ - limit: Scalars['Int']['input']; - offset: Scalars['Int']['input']; - where: NftWhereInput; -}>; - - -export type NfTsSubscriptionSubscription = { __typename?: 'Subscription', nfts: Array<{ __typename?: 'Nft', id: string, idInCollection: number, name: string, mediaUrl: string, owner: string, mintedBy: string, collection: { __typename?: 'Collection', id: string, name: string, transferable: string | null, sellable: string | null }, sales: Array<{ __typename?: 'Sale', price: string }>, auctions: Array<{ __typename?: 'Auction', minPrice: string, lastPrice: string | null, endTimestamp: string | null }> }> }; - -export type NftQuerySubscriptionVariables = Exact<{ +export type NftQueryQueryVariables = Exact<{ id: Scalars['String']['input']; }>; -export type NftQuerySubscription = { __typename?: 'Subscription', nftById: { __typename?: 'Nft', id: string, idInCollection: number, name: string, description: string, mediaUrl: string, owner: string, createdAt: string, collection: { __typename?: 'Collection', id: string, name: string, royalty: number, sellable: string | null, transferable: string | null, type: { __typename?: 'CollectionType', type: string } }, sales: Array<{ __typename?: 'Sale', price: string }>, auctions: Array<{ __typename?: 'Auction', minPrice: string, lastPrice: string | null, endTimestamp: string | null }> } | null }; +export type NftQueryQuery = { __typename?: 'Query', nftById: { __typename?: 'Nft', id: string, idInCollection: number, name: string, description: string, mediaUrl: string, owner: string, createdAt: string, collection: { __typename?: 'Collection', id: string, name: string, royalty: number, sellable: string | null, transferable: string | null, type: { __typename?: 'CollectionType', type: string } }, sales: Array<{ __typename?: 'Sale', price: string }>, auctions: Array<{ __typename?: 'Auction', minPrice: string, lastPrice: string | null, endTimestamp: string | null }> } | null }; export const MarketplaceQueryDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"MarketplaceQuery"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"marketplaceById"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"id"},"value":{"kind":"StringValue","value":"1","block":false}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"address"}},{"kind":"Field","name":{"kind":"Name","value":"collectionTypes"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"description"}},{"kind":"Field","name":{"kind":"Name","value":"metaUrl"}},{"kind":"Field","name":{"kind":"Name","value":"type"}}]}},{"kind":"Field","name":{"kind":"Name","value":"metadata"}},{"kind":"Field","name":{"kind":"Name","value":"config"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"feePerUploadedFile"}},{"kind":"Field","name":{"kind":"Name","value":"minimumValueForTrade"}},{"kind":"Field","name":{"kind":"Name","value":"royaltyToMarketplaceForMint"}},{"kind":"Field","name":{"kind":"Name","value":"royaltyToMarketplaceForTrade"}},{"kind":"Field","name":{"kind":"Name","value":"timeBetweenCreateCollections"}}]}},{"kind":"Field","name":{"kind":"Name","value":"admins"}}]}}]}}]} as unknown as DocumentNode; -export const CollectionSubDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"subscription","name":{"kind":"Name","value":"CollectionSub"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"id"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"collectionById"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"id"},"value":{"kind":"Variable","name":{"kind":"Name","value":"id"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"description"}},{"kind":"Field","name":{"kind":"Name","value":"collectionBanner"}},{"kind":"Field","name":{"kind":"Name","value":"collectionLogo"}},{"kind":"Field","name":{"kind":"Name","value":"admin"}},{"kind":"Field","name":{"kind":"Name","value":"tokensLimit"}},{"kind":"Field","name":{"kind":"Name","value":"permissionToMint"}},{"kind":"Field","name":{"kind":"Name","value":"userMintLimit"}},{"kind":"Field","name":{"kind":"Name","value":"paymentForMint"}},{"kind":"Field","name":{"kind":"Name","value":"transferable"}},{"kind":"Field","name":{"kind":"Name","value":"sellable"}},{"kind":"Field","name":{"kind":"Name","value":"additionalLinks"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"discord"}},{"kind":"Field","name":{"kind":"Name","value":"externalUrl"}},{"kind":"Field","name":{"kind":"Name","value":"medium"}},{"kind":"Field","name":{"kind":"Name","value":"xcom"}},{"kind":"Field","name":{"kind":"Name","value":"telegram"}}]}}]}}]}}]} as unknown as DocumentNode; +export const CollectionQueryDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"CollectionQuery"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"id"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"collectionById"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"id"},"value":{"kind":"Variable","name":{"kind":"Name","value":"id"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"description"}},{"kind":"Field","name":{"kind":"Name","value":"collectionBanner"}},{"kind":"Field","name":{"kind":"Name","value":"collectionLogo"}},{"kind":"Field","name":{"kind":"Name","value":"admin"}},{"kind":"Field","name":{"kind":"Name","value":"tokensLimit"}},{"kind":"Field","name":{"kind":"Name","value":"permissionToMint"}},{"kind":"Field","name":{"kind":"Name","value":"userMintLimit"}},{"kind":"Field","name":{"kind":"Name","value":"paymentForMint"}},{"kind":"Field","name":{"kind":"Name","value":"transferable"}},{"kind":"Field","name":{"kind":"Name","value":"sellable"}},{"kind":"Field","name":{"kind":"Name","value":"additionalLinks"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"discord"}},{"kind":"Field","name":{"kind":"Name","value":"externalUrl"}},{"kind":"Field","name":{"kind":"Name","value":"medium"}},{"kind":"Field","name":{"kind":"Name","value":"xcom"}},{"kind":"Field","name":{"kind":"Name","value":"telegram"}}]}}]}}]}}]} as unknown as DocumentNode; export const LastCreatedCollectionQueryDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"LastCreatedCollectionQuery"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"admin"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"collections"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"where"},"value":{"kind":"ObjectValue","fields":[{"kind":"ObjectField","name":{"kind":"Name","value":"admin_eq"},"value":{"kind":"Variable","name":{"kind":"Name","value":"admin"}}}]}},{"kind":"Argument","name":{"kind":"Name","value":"orderBy"},"value":{"kind":"ListValue","values":[{"kind":"EnumValue","value":"createdAt_DESC"},{"kind":"EnumValue","value":"name_DESC"},{"kind":"EnumValue","value":"id_DESC"}]}},{"kind":"Argument","name":{"kind":"Name","value":"limit"},"value":{"kind":"IntValue","value":"1"}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"createdAt"}}]}}]}}]} as unknown as DocumentNode; export const CollectionsConnectionQueryDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"CollectionsConnectionQuery"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"where"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"CollectionWhereInput"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"collectionsConnection"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"orderBy"},"value":{"kind":"ListValue","values":[{"kind":"EnumValue","value":"createdAt_DESC"},{"kind":"EnumValue","value":"name_DESC"},{"kind":"EnumValue","value":"id_DESC"}]}},{"kind":"Argument","name":{"kind":"Name","value":"where"},"value":{"kind":"Variable","name":{"kind":"Name","value":"where"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"totalCount"}}]}}]}}]} as unknown as DocumentNode; export const CollectionsQueryDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"CollectionsQuery"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"limit"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"Int"}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"offset"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"Int"}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"where"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"CollectionWhereInput"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"collections"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"limit"},"value":{"kind":"Variable","name":{"kind":"Name","value":"limit"}}},{"kind":"Argument","name":{"kind":"Name","value":"offset"},"value":{"kind":"Variable","name":{"kind":"Name","value":"offset"}}},{"kind":"Argument","name":{"kind":"Name","value":"orderBy"},"value":{"kind":"ListValue","values":[{"kind":"EnumValue","value":"createdAt_DESC"},{"kind":"EnumValue","value":"name_DESC"},{"kind":"EnumValue","value":"id_DESC"}]}},{"kind":"Argument","name":{"kind":"Name","value":"where"},"value":{"kind":"Variable","name":{"kind":"Name","value":"where"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"description"}},{"kind":"Field","name":{"kind":"Name","value":"collectionBanner"}},{"kind":"Field","name":{"kind":"Name","value":"collectionLogo"}},{"kind":"Field","name":{"kind":"Name","value":"admin"}},{"kind":"Field","name":{"kind":"Name","value":"tokensLimit"}},{"kind":"Field","name":{"kind":"Name","value":"nfts"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"limit"},"value":{"kind":"IntValue","value":"5"}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"mediaUrl"}}]}}]}}]}}]} as unknown as DocumentNode; -export const CollectionsSubDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"subscription","name":{"kind":"Name","value":"CollectionsSub"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"limit"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"Int"}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"offset"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"Int"}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"where"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"CollectionWhereInput"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"collections"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"limit"},"value":{"kind":"Variable","name":{"kind":"Name","value":"limit"}}},{"kind":"Argument","name":{"kind":"Name","value":"offset"},"value":{"kind":"Variable","name":{"kind":"Name","value":"offset"}}},{"kind":"Argument","name":{"kind":"Name","value":"orderBy"},"value":{"kind":"ListValue","values":[{"kind":"EnumValue","value":"createdAt_DESC"},{"kind":"EnumValue","value":"name_DESC"},{"kind":"EnumValue","value":"id_DESC"}]}},{"kind":"Argument","name":{"kind":"Name","value":"where"},"value":{"kind":"Variable","name":{"kind":"Name","value":"where"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"description"}},{"kind":"Field","name":{"kind":"Name","value":"collectionBanner"}},{"kind":"Field","name":{"kind":"Name","value":"collectionLogo"}},{"kind":"Field","name":{"kind":"Name","value":"admin"}},{"kind":"Field","name":{"kind":"Name","value":"tokensLimit"}},{"kind":"Field","name":{"kind":"Name","value":"nfts"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"limit"},"value":{"kind":"IntValue","value":"5"}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"mediaUrl"}}]}}]}}]}}]} as unknown as DocumentNode; export const CollectionsNfTsCountQueryDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"CollectionsNFTsCountQuery"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"ids"}},"type":{"kind":"ListType","type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"nftsInCollection"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"collections"},"value":{"kind":"Variable","name":{"kind":"Name","value":"ids"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"collection"}},{"kind":"Field","name":{"kind":"Name","value":"count"}}]}}]}}]} as unknown as DocumentNode; export const NfTsConnectionQueryDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"NFTsConnectionQuery"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"where"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"NftWhereInput"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"nftsConnection"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"orderBy"},"value":{"kind":"ListValue","values":[{"kind":"EnumValue","value":"createdAt_DESC"},{"kind":"EnumValue","value":"name_DESC"},{"kind":"EnumValue","value":"id_DESC"}]}},{"kind":"Argument","name":{"kind":"Name","value":"where"},"value":{"kind":"Variable","name":{"kind":"Name","value":"where"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"totalCount"}}]}}]}}]} as unknown as DocumentNode; export const NfTsQueryDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"NFTsQuery"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"limit"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"Int"}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"offset"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"Int"}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"where"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"NftWhereInput"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"nfts"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"limit"},"value":{"kind":"Variable","name":{"kind":"Name","value":"limit"}}},{"kind":"Argument","name":{"kind":"Name","value":"offset"},"value":{"kind":"Variable","name":{"kind":"Name","value":"offset"}}},{"kind":"Argument","name":{"kind":"Name","value":"orderBy"},"value":{"kind":"ListValue","values":[{"kind":"EnumValue","value":"createdAt_DESC"},{"kind":"EnumValue","value":"name_DESC"},{"kind":"EnumValue","value":"id_DESC"}]}},{"kind":"Argument","name":{"kind":"Name","value":"where"},"value":{"kind":"Variable","name":{"kind":"Name","value":"where"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"idInCollection"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"mediaUrl"}},{"kind":"Field","name":{"kind":"Name","value":"owner"}},{"kind":"Field","name":{"kind":"Name","value":"mintedBy"}},{"kind":"Field","name":{"kind":"Name","value":"collection"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"transferable"}},{"kind":"Field","name":{"kind":"Name","value":"sellable"}}]}},{"kind":"Field","name":{"kind":"Name","value":"sales"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"where"},"value":{"kind":"ObjectValue","fields":[{"kind":"ObjectField","name":{"kind":"Name","value":"status_eq"},"value":{"kind":"StringValue","value":"open","block":false}}]}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"price"}}]}},{"kind":"Field","name":{"kind":"Name","value":"auctions"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"where"},"value":{"kind":"ObjectValue","fields":[{"kind":"ObjectField","name":{"kind":"Name","value":"status_eq"},"value":{"kind":"StringValue","value":"open","block":false}}]}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"minPrice"}},{"kind":"Field","name":{"kind":"Name","value":"lastPrice"}},{"kind":"Field","name":{"kind":"Name","value":"endTimestamp"}}]}}]}}]}}]} as unknown as DocumentNode; -export const NfTsSubscriptionDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"subscription","name":{"kind":"Name","value":"NFTsSubscription"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"limit"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"Int"}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"offset"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"Int"}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"where"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"NftWhereInput"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"nfts"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"limit"},"value":{"kind":"Variable","name":{"kind":"Name","value":"limit"}}},{"kind":"Argument","name":{"kind":"Name","value":"offset"},"value":{"kind":"Variable","name":{"kind":"Name","value":"offset"}}},{"kind":"Argument","name":{"kind":"Name","value":"orderBy"},"value":{"kind":"ListValue","values":[{"kind":"EnumValue","value":"createdAt_DESC"},{"kind":"EnumValue","value":"name_DESC"},{"kind":"EnumValue","value":"id_DESC"}]}},{"kind":"Argument","name":{"kind":"Name","value":"where"},"value":{"kind":"Variable","name":{"kind":"Name","value":"where"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"idInCollection"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"mediaUrl"}},{"kind":"Field","name":{"kind":"Name","value":"owner"}},{"kind":"Field","name":{"kind":"Name","value":"mintedBy"}},{"kind":"Field","name":{"kind":"Name","value":"collection"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"transferable"}},{"kind":"Field","name":{"kind":"Name","value":"sellable"}}]}},{"kind":"Field","name":{"kind":"Name","value":"sales"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"where"},"value":{"kind":"ObjectValue","fields":[{"kind":"ObjectField","name":{"kind":"Name","value":"status_eq"},"value":{"kind":"StringValue","value":"open","block":false}}]}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"price"}}]}},{"kind":"Field","name":{"kind":"Name","value":"auctions"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"where"},"value":{"kind":"ObjectValue","fields":[{"kind":"ObjectField","name":{"kind":"Name","value":"status_eq"},"value":{"kind":"StringValue","value":"open","block":false}}]}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"minPrice"}},{"kind":"Field","name":{"kind":"Name","value":"lastPrice"}},{"kind":"Field","name":{"kind":"Name","value":"endTimestamp"}}]}}]}}]}}]} as unknown as DocumentNode; -export const NftQueryDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"subscription","name":{"kind":"Name","value":"NFTQuery"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"id"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"nftById"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"id"},"value":{"kind":"Variable","name":{"kind":"Name","value":"id"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"idInCollection"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"description"}},{"kind":"Field","name":{"kind":"Name","value":"mediaUrl"}},{"kind":"Field","name":{"kind":"Name","value":"owner"}},{"kind":"Field","name":{"kind":"Name","value":"createdAt"}},{"kind":"Field","name":{"kind":"Name","value":"collection"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"royalty"}},{"kind":"Field","name":{"kind":"Name","value":"sellable"}},{"kind":"Field","name":{"kind":"Name","value":"transferable"}},{"kind":"Field","name":{"kind":"Name","value":"type"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"type"}}]}}]}},{"kind":"Field","name":{"kind":"Name","value":"sales"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"where"},"value":{"kind":"ObjectValue","fields":[{"kind":"ObjectField","name":{"kind":"Name","value":"status_eq"},"value":{"kind":"StringValue","value":"open","block":false}}]}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"price"}}]}},{"kind":"Field","name":{"kind":"Name","value":"auctions"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"where"},"value":{"kind":"ObjectValue","fields":[{"kind":"ObjectField","name":{"kind":"Name","value":"status_eq"},"value":{"kind":"StringValue","value":"open","block":false}}]}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"minPrice"}},{"kind":"Field","name":{"kind":"Name","value":"lastPrice"}},{"kind":"Field","name":{"kind":"Name","value":"endTimestamp"}}]}}]}}]}}]} as unknown as DocumentNode; \ No newline at end of file +export const NftQueryDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"NFTQuery"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"id"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"nftById"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"id"},"value":{"kind":"Variable","name":{"kind":"Name","value":"id"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"idInCollection"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"description"}},{"kind":"Field","name":{"kind":"Name","value":"mediaUrl"}},{"kind":"Field","name":{"kind":"Name","value":"owner"}},{"kind":"Field","name":{"kind":"Name","value":"createdAt"}},{"kind":"Field","name":{"kind":"Name","value":"collection"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"royalty"}},{"kind":"Field","name":{"kind":"Name","value":"sellable"}},{"kind":"Field","name":{"kind":"Name","value":"transferable"}},{"kind":"Field","name":{"kind":"Name","value":"type"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"type"}}]}}]}},{"kind":"Field","name":{"kind":"Name","value":"sales"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"where"},"value":{"kind":"ObjectValue","fields":[{"kind":"ObjectField","name":{"kind":"Name","value":"status_eq"},"value":{"kind":"StringValue","value":"open","block":false}}]}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"price"}}]}},{"kind":"Field","name":{"kind":"Name","value":"auctions"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"where"},"value":{"kind":"ObjectValue","fields":[{"kind":"ObjectField","name":{"kind":"Name","value":"status_eq"},"value":{"kind":"StringValue","value":"open","block":false}}]}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"minPrice"}},{"kind":"Field","name":{"kind":"Name","value":"lastPrice"}},{"kind":"Field","name":{"kind":"Name","value":"endTimestamp"}}]}}]}}]}}]} as unknown as DocumentNode; \ No newline at end of file diff --git a/frontend/src/hooks/use-send-message-with-reply.ts b/frontend/src/hooks/use-send-message-with-reply.ts index 70a8a92..8453ada 100644 --- a/frontend/src/hooks/use-send-message-with-reply.ts +++ b/frontend/src/hooks/use-send-message-with-reply.ts @@ -58,6 +58,7 @@ const useSendMessageWithReply = (programId: HexString, metadata: ProgramMetadata if (!account) throw new Error('Account is not found'); let unsub: UnsubscribePromise | undefined = undefined; + let replyPayload: Reply | undefined = undefined; const _onFinally = () => { onFinally(); @@ -68,6 +69,13 @@ const useSendMessageWithReply = (programId: HexString, metadata: ProgramMetadata unsub.then((unsubCallback) => unsubCallback()).catch((error: Error) => alert.error(error.message)); }; + const _onSuccess = () => { + _onFinally(); + + if (!replyPayload) return; + onSuccess(replyPayload); + }; + const handleUserMessageSent = ({ data }: UserMessageSent) => { try { if (!metadata) throw new Error('Failed to get transaction result: metadata is not found'); @@ -87,25 +95,20 @@ const useSendMessageWithReply = (programId: HexString, metadata: ProgramMetadata const decodedPayload = metadata.createType(typeIndex, payload).toJSON(); if (!isObject(decodedPayload)) throw new Error('Failed to get transaction result: payload is not an object'); + if ('err' in decodedPayload) throw new Error(decodedPayload.err?.toString()); + if (!('ok' in decodedPayload)) throw new Error('Failed to get transaction result: ok property is not found'); - const isErrorPayload = Object.prototype.hasOwnProperty.call(decodedPayload, 'err'); - if (isErrorPayload) throw new Error(decodedPayload.err?.toString()); - - const isSuccessPayload = Object.prototype.hasOwnProperty.call(decodedPayload, 'ok'); - if (!isSuccessPayload) throw new Error('Failed to get transaction result: ok property is not found'); - - onSuccess(decodedPayload.ok as Reply); + replyPayload = decodedPayload.ok as Reply; } catch (error) { const errorMessage = error instanceof Error ? error.message : String(error); alert.error(errorMessage); + _onFinally(); } - - _onFinally(); }; unsub = api.gearEvents.subscribeToGearEvent('UserMessageSent', handleUserMessageSent); - sendMessage({ ...sendMessageArgs, onError: _onFinally }); + sendMessage({ ...sendMessageArgs, onError: _onFinally, onSuccess: _onSuccess }); }; }; diff --git a/frontend/src/main.tsx b/frontend/src/main.tsx index b5247a4..7752d9e 100644 --- a/frontend/src/main.tsx +++ b/frontend/src/main.tsx @@ -5,12 +5,10 @@ import { RouterProvider, createBrowserRouter } from 'react-router-dom'; import { App } from './App'; import { PrivateRoute } from './components'; -import { ADDRESS, ROUTE } from './consts'; +import { ROUTE } from './consts'; import { Collection, CreateCollection, NFT, Lists, NotFound } from './pages'; import './index.scss'; -console.log('public envs: ', ADDRESS); - const PRIVATE_ROUTES = [ { path: ROUTE.CREATE_COLLECTION, diff --git a/frontend/src/pages/collection/collection.tsx b/frontend/src/pages/collection/collection.tsx index 3a39228..fa6f42f 100644 --- a/frontend/src/pages/collection/collection.tsx +++ b/frontend/src/pages/collection/collection.tsx @@ -8,20 +8,13 @@ import NFTCardSkeletonSVG from '@/features/collections/assets/nft-card-skeleton. import { AccountFilter, GRID_SIZE, GridSize, useAccountFilter, useGridSize } from '@/features/lists'; import { getIpfsLink } from '@/utils'; +import { useNFTs } from '../lists/hooks'; // TODO: shared folder + import UserSVG from './assets/user.svg?react'; import styles from './collection.module.scss'; import { SOCIAL_ICON } from './consts'; import { useCollection } from './hooks'; -// function useSearchQuery() { -// const { handleSubmit, register } = useForm({ defaultValues: { query: '' } }); -// const [query, setQuery] = useState(''); - -// const onSubmit = handleSubmit((values) => setQuery(values.query.trim().toLocaleLowerCase())); - -// return { query, onSubmit, register }; -// } - type Params = { id: string; }; @@ -32,10 +25,9 @@ function Collection() { const { gridSize, setGridSize } = useGridSize(); const { accountFilterValue, accountFilterAddress, setAccountFilterValue } = useAccountFilter(); - const [collection, nfts, totalNFTsCount, hasMoreNFTs, isCollectionQueryReady, fetchNFTs] = useCollection( - id, - accountFilterAddress, - ); + const [nfts, nftsCount, hasMoreNFTs, isNFTsQueryReady, fetchNFTs, refetchNFTs] = useNFTs(accountFilterAddress, id); + + const collection = useCollection(id); const { name, additionalLinks } = collection || {}; const socialEntries = Object.entries(additionalLinks || {}).filter(([key]) => !key.startsWith('__')); @@ -67,7 +59,7 @@ function Collection() {
- +
@@ -80,7 +72,7 @@ function Collection() {
    {renderSocials()}
- +
@@ -92,11 +84,6 @@ function Collection() {
- {/* TODO: search */} - {/*
- - */} -
@@ -112,7 +99,7 @@ function Collection() { isMoreItems={hasMoreNFTs} skeleton={{ rowsCount: 2, - isVisible: !isCollectionQueryReady, + isVisible: !isNFTsQueryReady, renderItem: (index) => (
  • diff --git a/frontend/src/pages/collection/consts.ts b/frontend/src/pages/collection/consts.ts index e20f499..7583be4 100644 --- a/frontend/src/pages/collection/consts.ts +++ b/frontend/src/pages/collection/consts.ts @@ -13,8 +13,8 @@ const SOCIAL_ICON = { discord: DiscordSVG, }; -const COLLECTION_SUBSCRIPTION = graphql(` - subscription CollectionSub($id: String!) { +const COLLECTION_QUERY = graphql(` + query CollectionQuery($id: String!) { collectionById(id: $id) { id name @@ -40,4 +40,4 @@ const COLLECTION_SUBSCRIPTION = graphql(` } `); -export { SOCIAL_ICON, COLLECTION_SUBSCRIPTION }; +export { SOCIAL_ICON, COLLECTION_QUERY }; diff --git a/frontend/src/pages/collection/hooks.ts b/frontend/src/pages/collection/hooks.ts index 028519b..298bc6c 100644 --- a/frontend/src/pages/collection/hooks.ts +++ b/frontend/src/pages/collection/hooks.ts @@ -1,19 +1,12 @@ -import { useSubscription } from '@apollo/client'; +import { useQuery } from '@apollo/client'; -// TODO: reusing temporary solution for nfts subscriptiption -import { useNFTs } from '../lists/hooks'; +import { COLLECTION_QUERY } from './consts'; -import { COLLECTION_SUBSCRIPTION } from './consts'; - -function useCollection(id: string, owner: string) { - const [nfts, nftsCount, hasMoreNFTs, isNFTsQueryReady, fetchNFTs] = useNFTs(owner, id); - - // subscription to handle update in case of newly created collection - const { data, loading } = useSubscription(COLLECTION_SUBSCRIPTION, { variables: { id } }); +function useCollection(id: string) { + const { data } = useQuery(COLLECTION_QUERY, { variables: { id } }); const collection = data?.collectionById; - const isCollectionQueryReady = !loading && isNFTsQueryReady; - return [collection, nfts, nftsCount, hasMoreNFTs, isCollectionQueryReady, fetchNFTs] as const; + return collection; } export { useCollection }; diff --git a/frontend/src/pages/create-collection/hooks.ts b/frontend/src/pages/create-collection/hooks.ts index df8946e..01778bb 100644 --- a/frontend/src/pages/create-collection/hooks.ts +++ b/frontend/src/pages/create-collection/hooks.ts @@ -10,13 +10,7 @@ function useLastCollection() { const { account } = useAccount(); const admin = account?.decodedAddress || ''; - const { data, loading } = useQuery(LAST_CREATED_COLLECTION_QUERY, { - variables: { admin }, - // TODO: better to use cache-and-network, but result.fetching is not getting updated immediately - // maybe should be easy to fix via result.stale - // ref: https://github.com/urql-graphql/urql/issues/2002 - fetchPolicy: 'network-only', - }); + const { data, loading } = useQuery(LAST_CREATED_COLLECTION_QUERY, { variables: { admin } }); const lastCollection = data?.collections[0]; const isLastCollectionReady = !loading; diff --git a/frontend/src/pages/lists/consts.ts b/frontend/src/pages/lists/consts.ts index 2e56c49..fc48609 100644 --- a/frontend/src/pages/lists/consts.ts +++ b/frontend/src/pages/lists/consts.ts @@ -27,25 +27,6 @@ const COLLECTIONS_QUERY = graphql(` } `); -const COLLECTIONS_SUBSCRIPTION = graphql(` - subscription CollectionsSub($limit: Int!, $offset: Int!, $where: CollectionWhereInput!) { - collections(limit: $limit, offset: $offset, orderBy: [createdAt_DESC, name_DESC, id_DESC], where: $where) { - id - name - description - collectionBanner - collectionLogo - admin - tokensLimit - - nfts(limit: 5) { - id - mediaUrl - } - } - } -`); - const COLLECTIONS_NFTS_COUNT_QUERY = graphql(` query CollectionsNFTsCountQuery($ids: [String!]) { nftsInCollection(collections: $ids) { @@ -96,37 +77,6 @@ const NFTS_QUERY = graphql(` } `); -const NFTS_SUBSCRIPTION = graphql(` - subscription NFTsSubscription($limit: Int!, $offset: Int!, $where: NftWhereInput!) { - nfts(limit: $limit, offset: $offset, orderBy: [createdAt_DESC, name_DESC, id_DESC], where: $where) { - id - idInCollection - name - mediaUrl - owner - - mintedBy - - collection { - id - name - transferable - sellable - } - - sales(where: { status_eq: "open" }) { - price - } - - auctions(where: { status_eq: "open" }) { - minPrice - lastPrice - endTimestamp - } - } - } -`); - const DEFAULT_VARIABLES = { COLLECTIONS: { limit: 12, @@ -142,10 +92,8 @@ const DEFAULT_VARIABLES = { export { COLLECTIONS_CONNECTION_QUERY, COLLECTIONS_QUERY, - COLLECTIONS_SUBSCRIPTION, COLLECTIONS_NFTS_COUNT_QUERY, NFTS_CONNECTION_QUERY, NFTS_QUERY, - NFTS_SUBSCRIPTION, DEFAULT_VARIABLES, }; diff --git a/frontend/src/pages/lists/hooks.ts b/frontend/src/pages/lists/hooks.ts index da59441..53f2511 100644 --- a/frontend/src/pages/lists/hooks.ts +++ b/frontend/src/pages/lists/hooks.ts @@ -1,5 +1,5 @@ import { useQuery } from '@apollo/client'; -import { useCallback, useEffect, useMemo } from 'react'; +import { useCallback, useMemo } from 'react'; import { CollectionWhereInput, NftWhereInput } from '@/graphql/graphql'; @@ -7,11 +7,9 @@ import { COLLECTIONS_CONNECTION_QUERY, COLLECTIONS_NFTS_COUNT_QUERY, COLLECTIONS_QUERY, - COLLECTIONS_SUBSCRIPTION, DEFAULT_VARIABLES, NFTS_CONNECTION_QUERY, NFTS_QUERY, - NFTS_SUBSCRIPTION, } from './consts'; import { getCollectionFilters, getNftFilters } from './utils'; @@ -35,7 +33,7 @@ function useCollections(admin: string) { const where = useMemo(() => getCollectionFilters(admin), [admin]); const [totalCount, isTotalCountReady] = useTotalCollectionsCount(where); - const { data, loading, fetchMore, subscribeToMore } = useQuery(COLLECTIONS_QUERY, { + const { data, loading, fetchMore } = useQuery(COLLECTIONS_QUERY, { variables: { ...DEFAULT_VARIABLES.COLLECTIONS, where }, }); @@ -56,36 +54,15 @@ function useCollections(admin: string) { const isReady = !loading && isTotalCountReady; const hasMore = totalCount && collectionsCount ? collectionsCount < totalCount : false; - useEffect(() => { - if (loading) return; - - const limit = collectionsCount || 1; // 1 fallback, cuz in case of empty list with limit 0, subscription won't work - const offset = 0; - - // same solution as for nfts, but for newly created collections - const unsubscribe = subscribeToMore({ - document: COLLECTIONS_SUBSCRIPTION, - variables: { limit, offset, where }, - updateQuery: (prev = { collections: [] }, { subscriptionData }) => { - if (!subscriptionData.data) return { collections: [] }; - - const newCollections = subscriptionData.data.collections.filter( - (subCollection) => !prev.collections.some((collection) => collection.id === subCollection.id), - ); - - return { collections: [...newCollections, ...prev.collections] }; - }, - }); - - return () => { - unsubscribe(); - }; - }, [subscribeToMore, collectionsCount, where, loading]); - const fetchCollections = useCallback(() => { const offset = collectionsCount; - fetchMore({ variables: { offset } }).catch(console.error); + fetchMore({ + variables: { offset }, + updateQuery: (prevResult, { fetchMoreResult }) => ({ + collections: [...prevResult.collections, ...fetchMoreResult.collections], + }), + }).catch(console.error); }, [collectionsCount, fetchMore]); return [collectionsWithCounts, totalCount, hasMore, isReady, fetchCollections] as const; @@ -103,7 +80,7 @@ function useNFTs(owner: string, collectionId?: string) { const where = useMemo(() => getNftFilters(owner, collectionId), [owner, collectionId]); const [totalCount, isTotalCountReady] = useTotalNFTsCount(where); - const { data, loading, fetchMore, subscribeToMore } = useQuery(NFTS_QUERY, { + const { data, loading, fetchMore, refetch } = useQuery(NFTS_QUERY, { variables: { ...DEFAULT_VARIABLES.NFTS, where }, }); @@ -114,43 +91,16 @@ function useNFTs(owner: string, collectionId?: string) { const hasMoreNFTs = totalCount && nftsCount ? nftsCount < totalCount : false; const isNFTsQueryReady = !loading && isTotalCountReady; - useEffect(() => { - if (loading) return; - - const limit = nftsCount || 1; // 1 fallback, cuz in case of empty list with limit 0, subscription won't work - const offset = 0; - - // kinda tricky subscription to handle live interaction, - // works for now, but worth to reconsider them later. - // maybe would be better to use connection's cursor pagination? - const unsubscribe = subscribeToMore({ - document: NFTS_SUBSCRIPTION, - variables: { limit, offset, where }, - updateQuery: (prev = { nfts: [] }, { subscriptionData }) => { - // extracting newly minted nfts, merge type policy should handle the rest - if (!subscriptionData.data) return { nfts: [] }; - - // important to preserve consistent sorting of nfts, otherwise results will be inaccurate - const mintedNfts = subscriptionData.data.nfts.filter( - (subNft) => !prev.nfts.some((nft) => nft.id === subNft.id), - ); - - return { nfts: [...mintedNfts, ...prev.nfts] }; - }, - }); - - return () => { - unsubscribe(); - }; - }, [subscribeToMore, nftsCount, where, loading]); - const fetchNFTs = useCallback(() => { const offset = nftsCount; - fetchMore({ variables: { offset } }).catch(console.error); + fetchMore({ + variables: { offset }, + updateQuery: (prevResult, { fetchMoreResult }) => ({ nfts: [...prevResult.nfts, ...fetchMoreResult.nfts] }), + }).catch(console.error); }, [fetchMore, nftsCount]); - return [nfts, totalCount, hasMoreNFTs, isNFTsQueryReady, fetchNFTs] as const; + return [nfts, totalCount, hasMoreNFTs, isNFTsQueryReady, fetchNFTs, refetch] as const; } export { useNFTs, useCollections }; diff --git a/frontend/src/pages/nft/consts.ts b/frontend/src/pages/nft/consts.ts index f7bd34f..8804162 100644 --- a/frontend/src/pages/nft/consts.ts +++ b/frontend/src/pages/nft/consts.ts @@ -1,7 +1,7 @@ import { graphql } from '@/graphql'; const NFT_QUERY = graphql(` - subscription NFTQuery($id: String!) { + query NFTQuery($id: String!) { nftById(id: $id) { id idInCollection diff --git a/frontend/src/pages/nft/hooks.ts b/frontend/src/pages/nft/hooks.ts index 7c55f86..a322141 100644 --- a/frontend/src/pages/nft/hooks.ts +++ b/frontend/src/pages/nft/hooks.ts @@ -1,10 +1,10 @@ -import { useSubscription } from '@apollo/client'; +import { useQuery, useSubscription } from '@apollo/client'; import { NFT_QUERY } from './consts'; function useNFT(collectionId: string, idInCollection: string) { const id = `${collectionId}-${idInCollection}`; - const { data } = useSubscription(NFT_QUERY, { variables: { id } }); + const { data } = useQuery(NFT_QUERY, { variables: { id } }); return data?.nftById; }