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
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

### Features

- [#1033](https://github.com/alleslabs/celatone-frontend/pull/1033) Add Sequencer for NFT details
- [#1015](https://github.com/alleslabs/celatone-frontend/pull/1015) New network selector
- [#1032](https://github.com/alleslabs/celatone-frontend/pull/1032) Search collection address on both full and sequencer tier
- [#1024](https://github.com/alleslabs/celatone-frontend/pull/1024) Add Sequencer for account detail NFTs
Expand Down
1 change: 1 addition & 0 deletions src/lib/app-provider/env.ts
Original file line number Diff line number Diff line change
Expand Up @@ -156,6 +156,7 @@ export enum CELATONE_QUERY_KEYS {
NFT_TOKEN_MINT_INFO = "CELATONE_QUERY_NFT_TOKEN_MINT_INFO",
NFT_METADATA = "CELATONE_QUERY_NFT_METADATA",
NFT_TRANSACTIONS = "CELATONE_QUERY_NFT_TRANSACTIONS",
NFT_TRANSACTIONS_SEQUENCER = "CELATONE_QUERY_NFT_TRANSACTIONS_SEQUENCER",
NFT_TRANSACTIONS_COUNT = "CELATONE_QUERY_NFT_TRANSACTIONS_COUNT",
NFT_MUTATE_EVENTS = "CELATONE_QUERY_NFT_MUTATE_EVENTS",
NFT_MUTATE_EVENTS_COUNT = "CELATONE_QUERY_NFT_MUTATE_EVENTS_COUNT",
Expand Down
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
4 changes: 2 additions & 2 deletions src/lib/pages/nft-details/components/Title.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { Alert, Flex, Heading, Text } from "@chakra-ui/react";

import { useMobile } from "lib/app-provider";
import { AppLink } from "lib/components/AppLink";
import type { HexAddr32 } from "lib/types";
import type { HexAddr32, Nullable } from "lib/types";

import { ViewResourceButton } from "./ViewResourceButton";

Expand All @@ -11,7 +11,7 @@ interface TitleProps {
nftAddress: HexAddr32;
displayCollectionName: string;
tokenId: string;
isBurned?: boolean;
isBurned: Nullable<boolean>;
}

export const Title = ({
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,12 @@ import type { HexAddr32 } from "lib/types";

import { TxsTable } from "./TxsTable";

interface TxsProps {
interface TxsFullProps {
nftAddress: HexAddr32;
totalData: number;
}

export const Txs = ({ nftAddress, totalData }: TxsProps) => {
export const TxsFull = ({ nftAddress, totalData }: TxsFullProps) => {
const {
pagesQuantity,
currentPage,
Expand Down
24 changes: 24 additions & 0 deletions src/lib/pages/nft-details/components/tables/txs/TxsSequencer.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import { EmptyState } from "lib/components/state";
import { useNftTransactionsSequencer } from "lib/services/nft";
import type { HexAddr32 } from "lib/types";

import { TxsTable } from "./TxsTable";

interface TxsSequencerProps {
nftAddress: HexAddr32;
}

export const TxsSequencer = ({ nftAddress }: TxsSequencerProps) => {
const { data: transactions, isLoading } =
useNftTransactionsSequencer(nftAddress);

return (
<TxsTable
txs={transactions}
isLoading={isLoading}
emptyState={
<EmptyState imageVariant="empty" message="Transactions not found." />
}
/>
);
};
2 changes: 2 additions & 0 deletions src/lib/pages/nft-details/components/tables/txs/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export * from "./TxsFull";
export * from "./TxsSequencer";
56 changes: 39 additions & 17 deletions src/lib/pages/nft-details/index.tsx
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
/* eslint-disable complexity */
import {
Divider,
Flex,
Expand All @@ -22,6 +23,7 @@ import { Loading } from "lib/components/Loading";
import PageContainer from "lib/components/PageContainer";
import { CelatoneSeo } from "lib/components/Seo";
import { ErrorFetching, InvalidState } from "lib/components/state";
import { TierSwitcher } from "lib/components/TierSwitcher";
import { Tooltip } from "lib/components/Tooltip";
import { UserDocsLink } from "lib/components/UserDocsLink";
import { NFT_IMAGE_PLACEHOLDER } from "lib/data";
Expand All @@ -30,6 +32,7 @@ import {
useNftByNftAddress,
useNftMutateEventsCount,
useNftTransactionsCount,
useNftTransactionsSequencer,
} from "lib/services/nft";
import { useCollectionByCollectionAddress } from "lib/services/nft-collection";

Expand All @@ -41,7 +44,8 @@ import {
NftInfoItem,
NftMutateEvents,
Title,
Txs,
TxsFull,
TxsSequencer,
ViewResourceButton,
} from "./components";
import type { NftDetailQueryParams } from "./types";
Expand All @@ -54,15 +58,26 @@ const NftDetailsBody = ({
nftAddress,
}: NftDetailQueryParams) => {
const isMobile = useMobile();
const { isFullTier, isSequencerTier } = useTierConfig();

const { data: collection, isLoading: isCollectionLoading } =
useCollectionByCollectionAddress(collectionAddress);
const { data: nft, isLoading: isNftLoading } = useNftByNftAddress(
collectionAddress,
nftAddress
);
const { data: txCount = 0 } = useNftTransactionsCount(nftAddress);
const { data: mutateEventsCount = 0 } = useNftMutateEventsCount(nftAddress);

const { data: txCount = 0 } = useNftTransactionsCount(nftAddress, isFullTier);
const { data: transactions } = useNftTransactionsSequencer(
nftAddress,
isSequencerTier
);
const totalTxs = isFullTier ? txCount : transactions?.length ?? 0;

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

if (isCollectionLoading || isNftLoading) return <Loading />;
Expand Down Expand Up @@ -247,24 +262,31 @@ const NftDetailsBody = ({
borderColor="gray.700"
overflowX="scroll"
>
<CustomTab count={txCount}>Transactions</CustomTab>
<CustomTab
count={mutateEventsCount}
isDisabled={!mutateEventsCount}
>
Mutate Events
</CustomTab>
<CustomTab count={totalTxs}>Transactions</CustomTab>
{isFullTier && (
<CustomTab
count={mutateEventsCount}
isDisabled={!mutateEventsCount}
>
Mutate Events
</CustomTab>
)}
</TabList>
<TabPanels>
<TabPanel p={0}>
<Txs nftAddress={nftAddress} totalData={txCount} />
</TabPanel>
<TabPanel p={0}>
<NftMutateEvents
nftAddress={nftAddress}
totalData={mutateEventsCount}
<TierSwitcher
full={<TxsFull nftAddress={nftAddress} totalData={txCount} />}
sequencer={<TxsSequencer nftAddress={nftAddress} />}
/>
</TabPanel>
{isFullTier && (
<TabPanel p={0}>
<NftMutateEvents
nftAddress={nftAddress}
totalData={mutateEventsCount}
/>
</TabPanel>
)}
</TabPanels>
</Tabs>
<UserDocsLink
Expand All @@ -278,7 +300,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));
12 changes: 6 additions & 6 deletions src/lib/services/nft-collection/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@ export const useCollectionByCollectionAddress = (
const { chainConfig } = useCelatoneApp();
const { tier } = useTierConfig();
const lcdEndpoint = useLcdEndpoint();

return useQuery<CollectionByCollectionAddressResponse>(
[
CELATONE_QUERY_KEYS.NFT_COLLECTION_BY_COLLECTION_ADDRESS,
Expand All @@ -76,18 +77,17 @@ export const useCollectionByCollectionAddress = (
handleQueryByTier({
tier,
threshold: "sequencer",
querySequencer: () =>
getCollectionByCollectionAddressSequencer(
lcdEndpoint,
collectionAddress
),
queryFull: () =>
getCollectionByCollectionAddress(
chainConfig.indexer,
collectionAddress
),
querySequencer: () =>
getCollectionByCollectionAddressSequencer(
lcdEndpoint,
collectionAddress
),
}),

{
retry: 1,
refetchOnWindowFocus: false,
Expand Down
Loading
Loading