Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[CFE-569]: Feat(pages): NFT details page #1033

Merged
merged 12 commits into from
Jul 23, 2024
6 changes: 3 additions & 3 deletions src/lib/components/nft/NftCard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,14 @@ import { AppLink } from "../AppLink";
import { AmpEvent, track } from "lib/amplitude";
import { NFT_IMAGE_PLACEHOLDER } from "lib/data";
import { useMetadata } from "lib/services/nft";
import type { HexAddr32, Option } from "lib/types";
import type { HexAddr32, Nullable } from "lib/types";

interface NftCardProps {
uri: string;
tokenId: string;
collectionName: string;
collectionName: Nullable<string>;
collectionAddress: HexAddr32;
nftAddress: Option<HexAddr32>;
nftAddress: Nullable<HexAddr32>;
showCollection?: boolean;
}

Expand Down
3 changes: 2 additions & 1 deletion src/lib/pages/account-details/components/nfts/FilterItem.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,10 @@ import { AmpEvent, track } from "lib/amplitude";
import { CustomIcon } from "lib/components/icon";
import { NFT_IMAGE_PLACEHOLDER } from "lib/data";
import { useMetadata } from "lib/services/nft";
import type { Nullable } from "lib/types";

interface FilterItemProps {
collectionName: string;
collectionName: Nullable<string>;
count: number;
onClick: () => void;
uri?: string;
Expand Down
36 changes: 10 additions & 26 deletions src/lib/pages/nft-details/index.tsx
Original file line number Diff line number Diff line change
@@ -1,21 +1,11 @@
import {
Divider,
Flex,
Image,
TabList,
TabPanel,
TabPanels,
Tabs,
Text,
} from "@chakra-ui/react";
import { Divider, Flex, Image, Text } from "@chakra-ui/react";
import { observer } from "mobx-react-lite";
import { useRouter } from "next/router";
import { useEffect } from "react";

import { AmpEvent, track } from "lib/amplitude";
import { useMobile, useTierConfig } from "lib/app-provider";
import { Breadcrumb } from "lib/components/Breadcrumb";
import { CustomTab } from "lib/components/CustomTab";
import { ExplorerLink } from "lib/components/ExplorerLink";
import { JsonLink } from "lib/components/JsonLink";
import { Loading } from "lib/components/Loading";
Expand All @@ -25,12 +15,7 @@ import { ErrorFetching, InvalidState } from "lib/components/state";
import { Tooltip } from "lib/components/Tooltip";
import { UserDocsLink } from "lib/components/UserDocsLink";
import { NFT_IMAGE_PLACEHOLDER } from "lib/data";
import {
useMetadata,
useNftByNftAddress,
useNftMutateEventsCount,
useNftTransactionsCount,
} from "lib/services/nft";
import { useMetadata, useNftByNftAddress } from "lib/services/nft";
import { useCollectionByCollectionAddress } from "lib/services/nft-collection";

import {
Expand All @@ -39,9 +24,7 @@ import {
DescriptionBox,
MintInfo,
NftInfoItem,
NftMutateEvents,
Title,
Txs,
ViewResourceButton,
} from "./components";
import type { NftDetailQueryParams } from "./types";
Expand All @@ -61,8 +44,9 @@ const NftDetailsBody = ({
collectionAddress,
nftAddress
);
const { data: txCount = 0 } = useNftTransactionsCount(nftAddress);
const { data: mutateEventsCount = 0 } = useNftMutateEventsCount(nftAddress);

// const { data: txCount = 0 } = useNftTransactionsCount(nftAddress);
// const { data: mutateEventsCount = 0 } = useNftMutateEventsCount(nftAddress);
const { data: metadata } = useMetadata(nft?.data?.uri ?? "");

if (isCollectionLoading || isNftLoading) return <Loading />;
Expand Down Expand Up @@ -103,7 +87,7 @@ const NftDetailsBody = ({
displayCollectionName={displayCollectionName}
tokenId={tokenId}
nftAddress={nftAddress}
isBurned={isBurned}
isBurned={!!isBurned}
/>
)}
<div
Expand Down Expand Up @@ -160,7 +144,7 @@ const NftDetailsBody = ({
displayCollectionName={displayCollectionName}
tokenId={tokenId}
nftAddress={nftAddress}
isBurned={isBurned}
isBurned={!!isBurned}
/>
)}
</Flex>
Expand Down Expand Up @@ -232,7 +216,7 @@ const NftDetailsBody = ({
</Flex>
</Flex>
<Divider width="100%" color="gray.700" />
<Tabs
{/* <Tabs
isLazy
lazyBehavior="keepMounted"
onChange={(tab) =>
Expand Down Expand Up @@ -266,7 +250,7 @@ const NftDetailsBody = ({
/>
</TabPanel>
</TabPanels>
</Tabs>
</Tabs> */}
<UserDocsLink
title="What is a NFT?"
cta="Read more about NFT"
Expand All @@ -278,7 +262,7 @@ const NftDetailsBody = ({
};

const NftDetails = observer(() => {
useTierConfig({ minTier: "full" });
useTierConfig({ minTier: "sequencer" });
const router = useRouter();
const validated = zNftDetailQueryParams.safeParse(router.query);

Expand Down
19 changes: 19 additions & 0 deletions src/lib/services/move/module/api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import {
zModuleTableCountsResponse,
zModuleTxsResponse,
zModuleVerificationInternal,
zMoveViewJsonResponse,
} from "lib/services/types";
import type {
AbiFormData,
Expand Down Expand Up @@ -180,3 +181,21 @@ export const getModuleRelatedProposals = async (
}
)
.then(({ data }) => parseWithError(zModuleRelatedProposalsResponse, data));

export const getMoveViewJson = async (
endpoint: string,
vmAddress: HexAddr,
moduleName: string,
functionName: string,
typeArgs: string[],
args: string[]
) =>
axios
.post(`${endpoint}/initia/move/v1/view/json`, {
address: vmAddress,
module_name: moduleName,
function_name: functionName,
type_args: typeArgs,
args,
})
.then(({ data }) => parseWithError(zMoveViewJsonResponse, data));
23 changes: 21 additions & 2 deletions src/lib/services/nft-collection/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,10 @@ import {
getCollectionsByAccount,
getCollectionUniqueHoldersCount,
} from "./gql";
import { getCollectionsByAccountSequencer } from "./sequencer";
import {
getCollectionByCollectionAddressSequence,
getCollectionsByAccountSequencer,
} from "./sequencer";

export const useCollections = (
limit: number,
Expand Down Expand Up @@ -58,14 +61,30 @@ export const useCollectionByCollectionAddress = (
collectionAddress: HexAddr32
) => {
const { chainConfig } = useCelatoneApp();
const { tier } = useTierConfig();
const lcdEndpoint = useLcdEndpoint();

return useQuery<CollectionByCollectionAddressResponse>(
[
CELATONE_QUERY_KEYS.NFT_COLLECTION_BY_COLLECTION_ADDRESS,
chainConfig.indexer,
collectionAddress,
],
async () =>
getCollectionByCollectionAddress(chainConfig.indexer, collectionAddress),
handleQueryByTier({
tier,
threshold: "sequencer",
queryFull: () =>
getCollectionByCollectionAddress(
chainConfig.indexer,
collectionAddress
),
querySequencer: () =>
getCollectionByCollectionAddressSequence(
lcdEndpoint,
collectionAddress
),
}),
{
retry: 1,
refetchOnWindowFocus: false,
Expand Down
19 changes: 17 additions & 2 deletions src/lib/services/nft-collection/sequencer.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
import axios from "axios";

import { zCollectionsByAccountResponseSequencer } from "../types";
import type { HexAddr } from "lib/types";
import {
zCollectionByCollectionAddressResponseSequencer,
zCollectionsByAccountResponseSequencer,
} from "../types";
import type { HexAddr, HexAddr32 } from "lib/types";
import { parseWithError } from "lib/utils";

export const getCollectionsByAccountSequencer = async (
Expand All @@ -21,3 +24,15 @@ export const getCollectionsByAccountSequencer = async (
.then(({ data }) =>
parseWithError(zCollectionsByAccountResponseSequencer, data)
);

export const getCollectionByCollectionAddressSequence = async (
endpoint: string,
collectionAddress: HexAddr32
) =>
axios
.get(
`${endpoint}/indexer/nft/v1/collections/${encodeURI(collectionAddress)}`
)
.then(({ data }) =>
parseWithError(zCollectionByCollectionAddressResponseSequencer, data)
);
51 changes: 45 additions & 6 deletions src/lib/services/nft/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,16 +4,18 @@ import { useQuery } from "@tanstack/react-query";
import type {
Metadata,
Nft,
NftByNftAddressResponse,
NftMintInfo,
NftsByAccountResponse,
NftTransactions,
} from "../types";
import { handleQueryByTier } from "../utils";
import {
CELATONE_QUERY_KEYS,
useCelatoneApp,
useCurrentChain,
useLcdEndpoint,
useNftConfig,
useTierConfig,
} from "lib/app-provider";
import type { HexAddr, HexAddr32, MutateEvent } from "lib/types";

Expand All @@ -29,7 +31,11 @@ import {
getNftTransactions,
getNftTransactionsCount,
} from "./gql";
import { getNftsByAccountSequencer } from "./sequencer";
import {
getNftByNftAddressSequencer,
getNftMintInfoSequencer,
getNftsByAccountSequencer,
} from "./sequencer";

export const useNfts = (
collectionAddress: HexAddr32,
Expand Down Expand Up @@ -62,16 +68,29 @@ export const useNftByNftAddress = (
nftAddress: HexAddr32
) => {
const { chainConfig } = useCelatoneApp();
const { tier } = useTierConfig();
const lcdEndpoint = useLcdEndpoint();

return useQuery<NftByNftAddressResponse>(
return useQuery(
[
CELATONE_QUERY_KEYS.NFT_BY_NFT_ADDRESS,
chainConfig.indexer,
collectionAddress,
nftAddress,
],
async () =>
getNftByNftAddress(chainConfig.indexer, collectionAddress, nftAddress),
handleQueryByTier({
tier,
threshold: "sequencer",
queryFull: () =>
getNftByNftAddress(
chainConfig.indexer,
collectionAddress,
nftAddress
),
querySequencer: () =>
getNftByNftAddressSequencer(lcdEndpoint, nftAddress),
}),
{
retry: 1,
refetchOnWindowFocus: false,
Expand All @@ -81,9 +100,29 @@ export const useNftByNftAddress = (

export const useNftMintInfo = (nftAddress: HexAddr32) => {
const { chainConfig } = useCelatoneApp();
const {
chain: { bech32_prefix: prefix },
} = useCurrentChain();
const { tier } = useTierConfig();
const lcdEndpoint = useLcdEndpoint();

return useQuery<NftMintInfo>(
[CELATONE_QUERY_KEYS.NFT_TOKEN_MINT_INFO, chainConfig.indexer, nftAddress],
async () => getNftMintInfo(chainConfig.indexer, nftAddress),
[
CELATONE_QUERY_KEYS.NFT_TOKEN_MINT_INFO,
chainConfig.indexer,
nftAddress,
tier,
prefix,
lcdEndpoint,
],
async () =>
handleQueryByTier({
tier,
threshold: "sequencer",
queryFull: () => getNftMintInfo(chainConfig.indexer, nftAddress),
querySequencer: () =>
getNftMintInfoSequencer(lcdEndpoint, prefix, nftAddress),
}),
{
retry: 1,
refetchOnWindowFocus: false,
Expand Down
Loading
Loading