Commit a6c5f0c4 authored by tom's avatar tom

skeleton for token inventory

parent 78c4fe54
import type { TokenCounters, TokenHolder, TokenInfo, TokenType } from 'types/api/token';
import type { TokenCounters, TokenHolder, TokenHolders, TokenInfo, TokenInstance, TokenInventoryResponse, TokenType } from 'types/api/token';
import type { TokenTransfer, TokenTransferResponse } from 'types/api/tokenTransfer';
const ADDRESS_PARAMS = {
......@@ -43,6 +43,8 @@ export const TOKEN_HOLDER: TokenHolder = {
value: '1021378038331138520668',
};
export const TOKEN_HOLDERS: TokenHolders = { items: Array(50).fill(TOKEN_HOLDER), next_page_params: null };
export const TOKEN_TRANSFER_ERC_20: TokenTransfer = {
block_hash: '0x8fa7b9e5e5e79deeb62d608db22ba9a5cb45388c7ebb9223ae77331c6080dc70',
from: ADDRESS_PARAMS,
......@@ -87,3 +89,26 @@ export const getTokenTransfersStub = (type?: TokenType): TokenTransferResponse =
return { items: Array(50).fill(TOKEN_TRANSFER_ERC_20), next_page_params: null };
}
};
export const TOKEN_INSTANCE: TokenInstance = {
animation_url: null,
external_app_url: 'https://vipsland.com/nft/collections/genesis/188882',
id: '188882',
image_url: 'https://ipfs.vipsland.com/nft/collections/genesis/188882.gif',
is_unique: true,
metadata: {
attributes: Array(3).fill({ trait_type: 'skin', value: '6' }),
description: '**GENESIS #188882**, **8a77ca1bcaa4036f** :: *844th* generation of *#57806 and #57809* :: **eGenetic Hash Code (eDNA)** = *2822355e953a462d*',
external_url: 'https://vipsland.com/nft/collections/genesis/188882',
image: 'https://ipfs.vipsland.com/nft/collections/genesis/188882.gif',
name: 'GENESIS #188882, 8a77ca1bcaa4036f. Blockchain pixel PFP NFT + "on music video" trait inspired by God',
},
owner: ADDRESS_PARAMS,
token: TOKEN_INFO_ERC_1155,
holder_address_hash: '0x2B51Ae4412F79c3c1cB12AA40Ea4ECEb4e80511a',
};
export const TOKEN_INSTANCES: TokenInventoryResponse = {
items: Array(50).fill(TOKEN_INSTANCE),
next_page_params: null,
};
......@@ -53,7 +53,7 @@ export interface TokenInstanceTransfersCount {
export interface TokenInventoryResponse {
items: Array<TokenInstance>;
next_page_params: TokenInventoryPagination;
next_page_params: TokenInventoryPagination | null;
}
export type TokenInventoryPagination = {
......
......@@ -76,7 +76,7 @@ const TokenPageContent = () => {
scrollRef,
options: {
enabled: Boolean(router.query.hash && router.query.tab === 'holders' && tokenQuery.data),
placeholderData: { items: Array(50).fill(stubs.TOKEN_HOLDER), next_page_params: null },
placeholderData: stubs.TOKEN_HOLDERS,
},
});
......@@ -86,6 +86,7 @@ const TokenPageContent = () => {
scrollRef,
options: {
enabled: Boolean(router.query.hash && router.query.tab === 'inventory' && tokenQuery.data),
placeholderData: stubs.TOKEN_INSTANCES,
},
});
......
......@@ -11,13 +11,14 @@ interface Props {
imageUrl: string | null;
animationUrl: string | null;
className?: string;
isLoading?: boolean;
}
const NftMedia = ({ imageUrl, animationUrl, className }: Props) => {
const NftMedia = ({ imageUrl, animationUrl, className, isLoading }: Props) => {
const [ type, setType ] = React.useState<MediaType | undefined>(!animationUrl ? 'image' : undefined);
React.useEffect(() => {
if (!animationUrl) {
if (!animationUrl || isLoading) {
return;
}
......@@ -45,9 +46,9 @@ const NftMedia = ({ imageUrl, animationUrl, className }: Props) => {
setType('image');
});
}, [ animationUrl ]);
}, [ animationUrl, isLoading ]);
if (!type) {
if (!type || isLoading) {
return (
<AspectRatio
className={ className }
......
import { Grid, Skeleton } from '@chakra-ui/react';
import { Grid } from '@chakra-ui/react';
import type { UseQueryResult } from '@tanstack/react-query';
import React from 'react';
......@@ -28,21 +28,6 @@ const TokenInventory = ({ inventoryQuery }: Props) => {
</ActionBar>
);
const skeleton = (
<Grid
w="100%"
columnGap={{ base: 3, lg: 6 }}
rowGap={{ base: 3, lg: 6 }}
gridTemplateColumns={{ base: 'repeat(2, calc((100% - 12px)/2))', lg: 'repeat(auto-fill, minmax(210px, 1fr))' }}
>
<Skeleton w={{ base: '100%', lg: '210px' }} h="272px"/>
<Skeleton w={{ base: '100%', lg: '210px' }} h="272px"/>
<Skeleton w={{ base: '100%', lg: '210px' }} h="272px"/>
<Skeleton w={{ base: '100%', lg: '210px' }} h="272px"/>
<Skeleton w={{ base: '100%', lg: '210px' }} h="272px"/>
</Grid>
);
const items = inventoryQuery.data?.items;
const content = items ? (
......@@ -52,19 +37,25 @@ const TokenInventory = ({ inventoryQuery }: Props) => {
rowGap={{ base: 3, lg: 6 }}
gridTemplateColumns={{ base: 'repeat(2, calc((100% - 12px)/2))', lg: 'repeat(auto-fill, minmax(210px, 1fr))' }}
>
{ items.map((item) => <TokenInventoryItem key={ item.token.address + '_' + item.id } item={ item }/>) }
{ items.map((item, index) => (
<TokenInventoryItem
key={ item.token.address + '_' + item.id + (inventoryQuery.isPlaceholderData ? '_' + index : '') }
item={ item }
isLoading={ inventoryQuery.isPlaceholderData }
/>
)) }
</Grid>
) : null;
return (
<DataListDisplay
isError={ inventoryQuery.isError }
isLoading={ inventoryQuery.isLoading }
isLoading={ false }
items={ items }
emptyText="There are no tokens."
content={ content }
actionBar={ actionBar }
skeletonProps={{ customSkeleton: skeleton }}
skeletonProps={{ customSkeleton: null }}
/>
);
};
......
import { Flex, Text, LinkBox, LinkOverlay, useColorModeValue, Hide } from '@chakra-ui/react';
import { Flex, Text, LinkBox, LinkOverlay, useColorModeValue, Hide, Skeleton } from '@chakra-ui/react';
import NextLink from 'next/link';
import React from 'react';
......@@ -11,9 +11,9 @@ import LinkInternal from 'ui/shared/LinkInternal';
import NftMedia from 'ui/shared/nft/NftMedia';
import TruncatedTextTooltip from 'ui/shared/TruncatedTextTooltip';
type Props = { item: TokenInstance };
type Props = { item: TokenInstance; isLoading: boolean };
const NFTItem = ({ item }: Props) => {
const NFTItem = ({ item, isLoading }: Props) => {
return (
<LinkBox
w={{ base: '100%', lg: '210px' }}
......@@ -32,6 +32,7 @@ const NFTItem = ({ item }: Props) => {
mb="18px"
imageUrl={ item.image_url }
animationUrl={ item.animation_url }
isLoading={ isLoading }
/>
</LinkOverlay>
</NextLink>
......@@ -44,7 +45,9 @@ const NFTItem = ({ item }: Props) => {
whiteSpace="nowrap"
textOverflow="ellipsis"
>
{ item.id }
<Skeleton isLoaded={ !isLoading }>
{ item.id }
</Skeleton>
</LinkInternal>
</TruncatedTextTooltip>
</Flex>
......@@ -53,8 +56,8 @@ const NFTItem = ({ item }: Props) => {
<Flex mb={ 2 } ml={ 1 }>
<Text whiteSpace="pre" variant="secondary" mr={ 2 } lineHeight="24px">Owner</Text>
<Address>
<Hide below="lg" ssr={ false }><AddressIcon address={ item.owner } mr={ 1 }/></Hide>
<AddressLink hash={ item.owner.hash } alias={ item.owner.name } type="address" truncation="constant"/>
<Hide below="lg" ssr={ false }><AddressIcon address={ item.owner } mr={ 1 } isLoading={ isLoading }/></Hide>
<AddressLink hash={ item.owner.hash } alias={ item.owner.name } type="address" truncation="constant" isLoading={ isLoading }/>
</Address>
</Flex>
) }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment