Commit 558f514c authored by tom's avatar tom

skeleton for token details

parent 842d9465
import type { NextPage } from 'next'; import type { NextPage } from 'next';
import dynamic from 'next/dynamic';
import Head from 'next/head'; import Head from 'next/head';
import React from 'react'; import React from 'react';
import type { PageParams } from 'lib/next/token/types'; import type { PageParams } from 'lib/next/token/types';
import getSeo from 'lib/next/token/getSeo'; import getSeo from 'lib/next/token/getSeo';
import Token from 'ui/pages/Token'; import Page from 'ui/shared/Page/Page';
const Token = dynamic(() => import('ui/pages/Token'), { ssr: false });
const TokenPage: NextPage<PageParams> = ({ hash }: PageParams) => { const TokenPage: NextPage<PageParams> = ({ hash }: PageParams) => {
const { title, description } = getSeo({ hash }); const { title, description } = getSeo({ hash });
...@@ -16,7 +19,9 @@ const TokenPage: NextPage<PageParams> = ({ hash }: PageParams) => { ...@@ -16,7 +19,9 @@ const TokenPage: NextPage<PageParams> = ({ hash }: PageParams) => {
<title>{ title }</title> <title>{ title }</title>
<meta name="description" content={ description }/> <meta name="description" content={ description }/>
</Head> </Head>
<Token/> <Page>
<Token/>
</Page>
</> </>
); );
}; };
......
import type { TokenInfo } from 'types/api/token'; import type { TokenCounters, TokenInfo } from 'types/api/token';
export const TOKEN_INFO: TokenInfo<'ERC-20'> = { export const TOKEN_INFO: TokenInfo<'ERC-20'> = {
address: '0x2B51Ae4412F79c3c1cB12AA40Ea4ECEb4e80511a', address: '0x2B51Ae4412F79c3c1cB12AA40Ea4ECEb4e80511a',
...@@ -10,3 +10,8 @@ export const TOKEN_INFO: TokenInfo<'ERC-20'> = { ...@@ -10,3 +10,8 @@ export const TOKEN_INFO: TokenInfo<'ERC-20'> = {
total_supply: '6000000000000000', total_supply: '6000000000000000',
type: 'ERC-20', type: 'ERC-20',
}; };
export const TOKEN_COUNTERS: TokenCounters = {
token_holders_count: '123456',
transfers_count: '123456',
};
...@@ -14,7 +14,6 @@ import trimTokenSymbol from 'lib/token/trimTokenSymbol'; ...@@ -14,7 +14,6 @@ import trimTokenSymbol from 'lib/token/trimTokenSymbol';
import * as stubs from 'stubs/token'; import * as stubs from 'stubs/token';
import AddressContract from 'ui/address/AddressContract'; import AddressContract from 'ui/address/AddressContract';
import TextAd from 'ui/shared/ad/TextAd'; import TextAd from 'ui/shared/ad/TextAd';
import Page from 'ui/shared/Page/Page';
import PageTitle from 'ui/shared/Page/PageTitle'; import PageTitle from 'ui/shared/Page/PageTitle';
import type { Props as PaginationProps } from 'ui/shared/Pagination'; import type { Props as PaginationProps } from 'ui/shared/Pagination';
import Pagination from 'ui/shared/Pagination'; import Pagination from 'ui/shared/Pagination';
...@@ -154,7 +153,7 @@ const TokenPageContent = () => { ...@@ -154,7 +153,7 @@ const TokenPageContent = () => {
}, [ isMobile ]); }, [ isMobile ]);
return ( return (
<Page> <>
<TextAd mb={ 6 }/> <TextAd mb={ 6 }/>
<PageTitle <PageTitle
isLoading={ tokenQuery.isPlaceholderData } isLoading={ tokenQuery.isPlaceholderData }
...@@ -181,7 +180,7 @@ const TokenPageContent = () => { ...@@ -181,7 +180,7 @@ const TokenPageContent = () => {
) } ) }
{ !tokenQuery.isLoading && !tokenQuery.isError && <Box h={{ base: 0, lg: '40vh' }}/> } { !tokenQuery.isLoading && !tokenQuery.isError && <Box h={{ base: 0, lg: '40vh' }}/> }
</Page> </>
); );
}; };
......
import { GridItem, Flex, Text } from '@chakra-ui/react'; import { GridItem, Flex, Text, Skeleton } from '@chakra-ui/react';
import type { HTMLChakraProps } from '@chakra-ui/system'; import type { HTMLChakraProps } from '@chakra-ui/system';
import React from 'react'; import React from 'react';
...@@ -9,18 +9,21 @@ interface Props extends Omit<HTMLChakraProps<'div'>, 'title'> { ...@@ -9,18 +9,21 @@ interface Props extends Omit<HTMLChakraProps<'div'>, 'title'> {
hint: string; hint: string;
children: React.ReactNode; children: React.ReactNode;
note?: string; note?: string;
isLoading?: boolean;
} }
const DetailsInfoItem = ({ title, hint, note, children, id, ...styles }: Props) => { const DetailsInfoItem = ({ title, hint, note, children, id, isLoading, ...styles }: Props) => {
return ( return (
<> <>
<GridItem py={{ base: 1, lg: 2 }} id={ id } lineHeight={ 5 } { ...styles } whiteSpace="nowrap" _notFirst={{ mt: { base: 3, lg: 0 } }}> <GridItem py={{ base: 1, lg: 2 }} id={ id } lineHeight={ 5 } { ...styles } whiteSpace="nowrap" _notFirst={{ mt: { base: 3, lg: 0 } }}>
<Flex columnGap={ 2 } alignItems="flex-start"> <Flex columnGap={ 2 } alignItems="flex-start">
<Hint label={ hint }/> <Hint label={ hint } isLoading={ isLoading }/>
<Text fontWeight={{ base: 700, lg: 500 }}> <Skeleton isLoaded={ !isLoading }>
{ title } <Text fontWeight={{ base: 700, lg: 500 }}>
{ note && <Text fontWeight={ 500 } variant="secondary" fontSize="xs" className="note" align="right">{ note }</Text> } { title }
</Text> { note && <Text fontWeight={ 500 } variant="secondary" fontSize="xs" className="note" align="right">{ note }</Text> }
</Text>
</Skeleton>
</Flex> </Flex>
</GridItem> </GridItem>
<GridItem <GridItem
......
import type { TooltipProps } from '@chakra-ui/react'; import type { TooltipProps } from '@chakra-ui/react';
import { chakra, IconButton, Tooltip, useDisclosure } from '@chakra-ui/react'; import { chakra, IconButton, Tooltip, useDisclosure, Skeleton } from '@chakra-ui/react';
import React from 'react'; import React from 'react';
import InfoIcon from 'icons/info.svg'; import InfoIcon from 'icons/info.svg';
...@@ -8,9 +8,10 @@ interface Props { ...@@ -8,9 +8,10 @@ interface Props {
label: string | React.ReactNode; label: string | React.ReactNode;
className?: string; className?: string;
tooltipProps?: Partial<TooltipProps>; tooltipProps?: Partial<TooltipProps>;
isLoading?: boolean;
} }
const Hint = ({ label, className, tooltipProps }: Props) => { const Hint = ({ label, className, tooltipProps, isLoading }: Props) => {
// have to implement controlled tooltip because of the issue - https://github.com/chakra-ui/chakra-ui/issues/7107 // have to implement controlled tooltip because of the issue - https://github.com/chakra-ui/chakra-ui/issues/7107
const { isOpen, onOpen, onToggle, onClose } = useDisclosure(); const { isOpen, onOpen, onToggle, onClose } = useDisclosure();
...@@ -19,6 +20,10 @@ const Hint = ({ label, className, tooltipProps }: Props) => { ...@@ -19,6 +20,10 @@ const Hint = ({ label, className, tooltipProps }: Props) => {
onToggle(); onToggle();
}, [ onToggle ]); }, [ onToggle ]);
if (isLoading) {
return <Skeleton boxSize={ 5 } borderRadius="sm"/>;
}
return ( return (
<Tooltip <Tooltip
label={ label } label={ label }
......
...@@ -8,11 +8,11 @@ import type { TokenInfo } from 'types/api/token'; ...@@ -8,11 +8,11 @@ import type { TokenInfo } from 'types/api/token';
import useApiQuery from 'lib/api/useApiQuery'; import useApiQuery from 'lib/api/useApiQuery';
import getCurrencyValue from 'lib/getCurrencyValue'; import getCurrencyValue from 'lib/getCurrencyValue';
import { TOKEN_COUNTERS } from 'stubs/token';
import type { TokenTabs } from 'ui/pages/Token'; import type { TokenTabs } from 'ui/pages/Token';
import DetailsInfoItem from 'ui/shared/DetailsInfoItem'; import DetailsInfoItem from 'ui/shared/DetailsInfoItem';
import DetailsSponsoredItem from 'ui/shared/DetailsSponsoredItem'; import DetailsSponsoredItem from 'ui/shared/DetailsSponsoredItem';
import HashStringShortenDynamic from 'ui/shared/HashStringShortenDynamic'; import HashStringShortenDynamic from 'ui/shared/HashStringShortenDynamic';
import DetailsSkeletonRow from 'ui/shared/skeletons/DetailsSkeletonRow';
interface Props { interface Props {
tokenQuery: UseQueryResult<TokenInfo>; tokenQuery: UseQueryResult<TokenInfo>;
...@@ -23,7 +23,7 @@ const TokenDetails = ({ tokenQuery }: Props) => { ...@@ -23,7 +23,7 @@ const TokenDetails = ({ tokenQuery }: Props) => {
const tokenCountersQuery = useApiQuery('token_counters', { const tokenCountersQuery = useApiQuery('token_counters', {
pathParams: { hash: router.query.hash?.toString() }, pathParams: { hash: router.query.hash?.toString() },
queryOptions: { enabled: Boolean(router.query.hash) }, queryOptions: { enabled: Boolean(router.query.hash), placeholderData: TOKEN_COUNTERS },
}); });
const changeUrlAndScroll = useCallback((tab: TokenTabs) => () => { const changeUrlAndScroll = useCallback((tab: TokenTabs) => () => {
...@@ -56,32 +56,19 @@ const TokenDetails = ({ tokenQuery }: Props) => { ...@@ -56,32 +56,19 @@ const TokenDetails = ({ tokenQuery }: Props) => {
throw Error('Token fetch error', { cause: tokenQuery.error as unknown as Error }); throw Error('Token fetch error', { cause: tokenQuery.error as unknown as Error });
} }
if (tokenQuery.isLoading) {
return (
<Grid mt={ 10 } columnGap={ 8 } rowGap={{ base: 5, lg: 7 }} templateColumns={{ base: '1fr', lg: '210px 1fr' }} maxW="1000px">
<DetailsSkeletonRow w="10%"/>
<DetailsSkeletonRow w="30%"/>
<DetailsSkeletonRow w="30%"/>
<DetailsSkeletonRow w="20%"/>
<DetailsSkeletonRow w="20%"/>
<DetailsSkeletonRow w="10%"/>
</Grid>
);
}
const { const {
exchange_rate: exchangeRate, exchange_rate: exchangeRate,
total_supply: totalSupply, total_supply: totalSupply,
decimals, decimals,
symbol, symbol,
type, type,
} = tokenQuery.data; } = tokenQuery.data || {};
let marketcap; let marketcap;
let totalSupplyValue; let totalSupplyValue;
if (type === 'ERC-20') { if (type === 'ERC-20') {
const totalValue = totalSupply !== null ? getCurrencyValue({ value: totalSupply, accuracy: 3, accuracyUsd: 2, exchangeRate, decimals }) : undefined; const totalValue = totalSupply ? getCurrencyValue({ value: totalSupply, accuracy: 3, accuracyUsd: 2, exchangeRate, decimals }) : undefined;
marketcap = totalValue?.usd; marketcap = totalValue?.usd;
totalSupplyValue = totalValue?.valueStr; totalSupplyValue = totalValue?.valueStr;
} else { } else {
...@@ -119,37 +106,47 @@ const TokenDetails = ({ tokenQuery }: Props) => { ...@@ -119,37 +106,47 @@ const TokenDetails = ({ tokenQuery }: Props) => {
alignSelf="center" alignSelf="center"
wordBreak="break-word" wordBreak="break-word"
whiteSpace="pre-wrap" whiteSpace="pre-wrap"
isLoading={ tokenQuery.isPlaceholderData }
> >
<Flex w="100%"> <Skeleton isLoaded={ !tokenQuery.isPlaceholderData }>
<Box whiteSpace="nowrap" overflow="hidden"> <Flex w="100%">
<HashStringShortenDynamic hash={ totalSupplyValue || '0' }/> <Box whiteSpace="nowrap" overflow="hidden">
</Box> <HashStringShortenDynamic hash={ totalSupplyValue || '0' }/>
<Box flexShrink={ 0 }> { symbol || '' }</Box> </Box>
</Flex> <Box flexShrink={ 0 }> { symbol || '' }</Box>
</Flex>
</Skeleton>
</DetailsInfoItem> </DetailsInfoItem>
<DetailsInfoItem <DetailsInfoItem
title="Holders" title="Holders"
hint="Number of accounts holding the token" hint="Number of accounts holding the token"
alignSelf="center" alignSelf="center"
isLoading={ tokenQuery.isPlaceholderData }
> >
{ tokenCountersQuery.isLoading && <Skeleton w={ 20 } h={ 4 }/> } <Skeleton isLoaded={ !tokenCountersQuery.isPlaceholderData }>
{ !tokenCountersQuery.isLoading && countersItem('token_holders_count') } { countersItem('token_holders_count') }
</Skeleton>
</DetailsInfoItem> </DetailsInfoItem>
<DetailsInfoItem <DetailsInfoItem
title="Transfers" title="Transfers"
hint="Number of transfer for the token" hint="Number of transfer for the token"
alignSelf="center" alignSelf="center"
isLoading={ tokenQuery.isPlaceholderData }
> >
{ tokenCountersQuery.isLoading && <Skeleton w={ 20 } h={ 4 }/> } <Skeleton isLoaded={ !tokenCountersQuery.isPlaceholderData }>
{ !tokenCountersQuery.isLoading && countersItem('transfers_count') } { countersItem('transfers_count') }
</Skeleton>
</DetailsInfoItem> </DetailsInfoItem>
{ decimals && ( { decimals && (
<DetailsInfoItem <DetailsInfoItem
title="Decimals" title="Decimals"
hint="Number of digits that come after the decimal place when displaying token value" hint="Number of digits that come after the decimal place when displaying token value"
alignSelf="center" alignSelf="center"
isLoading={ tokenQuery.isPlaceholderData }
> >
{ decimals } <Skeleton isLoaded={ !tokenQuery.isPlaceholderData } minW={ 6 }>
{ decimals }
</Skeleton>
</DetailsInfoItem> </DetailsInfoItem>
) } ) }
<DetailsSponsoredItem/> <DetailsSponsoredItem/>
......
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