Commit 8b4ee616 authored by tom's avatar tom

skeleton for token holders

parent 558f514c
import type { TokenCounters, TokenInfo } from 'types/api/token';
import type { TokenCounters, TokenHolder, TokenInfo } from 'types/api/token';
export const TOKEN_INFO: TokenInfo<'ERC-20'> = {
address: '0x2B51Ae4412F79c3c1cB12AA40Ea4ECEb4e80511a',
......@@ -15,3 +15,17 @@ export const TOKEN_COUNTERS: TokenCounters = {
token_holders_count: '123456',
transfers_count: '123456',
};
export const TOKEN_HOLDER: TokenHolder = {
address: {
hash: '0x2B51Ae4412F79c3c1cB12AA40Ea4ECEb4e80511a',
implementation_name: null,
is_contract: false,
is_verified: null,
name: null,
private_tags: [],
public_tags: [],
watchlist_names: [],
},
value: '1021378038331138520668',
};
......@@ -22,7 +22,7 @@ export type TokenInfoGeneric<Type extends TokenType> = Omit<TokenInfo, 'type'> &
export interface TokenHolders {
items: Array<TokenHolder>;
next_page_params: TokenHoldersPagination;
next_page_params: TokenHoldersPagination | null;
}
export type TokenHolder = {
......
......@@ -75,6 +75,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 },
},
});
......
import { Box, Flex, Text, chakra, useColorModeValue } from '@chakra-ui/react';
import { Box, Flex, Text, chakra, useColorModeValue, Skeleton } from '@chakra-ui/react';
import clamp from 'lodash/clamp';
import React from 'react';
......@@ -6,21 +6,26 @@ interface Props {
className?: string;
value: number;
colorScheme?: 'green' | 'gray';
isLoading?: boolean;
}
const WIDTH = 50;
const Utilization = ({ className, value, colorScheme = 'green' }: Props) => {
const Utilization = ({ className, value, colorScheme = 'green', isLoading }: Props) => {
const valueString = (clamp(value * 100 || 0, 0, 100)).toLocaleString('en', { maximumFractionDigits: 2 }) + '%';
const colorGrayScheme = useColorModeValue('gray.500', 'gray.400');
const color = colorScheme === 'gray' ? colorGrayScheme : 'green.500';
return (
<Flex className={ className } alignItems="center">
<Box bg={ useColorModeValue('blackAlpha.200', 'whiteAlpha.200') } w={ `${ WIDTH }px` } h="4px" borderRadius="full" overflow="hidden">
<Box bg={ color } w={ valueString } h="100%"/>
</Box>
<Text color={ color } ml="10px" fontWeight="bold">{ valueString }</Text>
<Flex className={ className } alignItems="center" columnGap="10px">
<Skeleton isLoaded={ !isLoading }>
<Box bg={ useColorModeValue('blackAlpha.200', 'whiteAlpha.200') } w={ `${ WIDTH }px` } h="4px" borderRadius="full" overflow="hidden">
<Box bg={ color } w={ valueString } h="100%"/>
</Box>
</Skeleton>
<Skeleton isLoaded={ !isLoading }>
<Text color={ color } fontWeight="bold">{ valueString }</Text>
</Skeleton>
</Flex>
);
};
......
......@@ -38,15 +38,28 @@ const TokenHoldersContent = ({ holdersQuery, tokenQuery }: Props) => {
const content = items && tokenQuery.data ? (
<>
{ !isMobile && <TokenHoldersTable data={ items } token={ tokenQuery.data } top={ holdersQuery.isPaginationVisible ? 80 : 0 }/> }
{ isMobile && <TokenHoldersList data={ items } token={ tokenQuery.data }/> }
{ !isMobile && (
<TokenHoldersTable
data={ items }
token={ tokenQuery.data }
top={ holdersQuery.isPaginationVisible ? 80 : 0 }
isLoading={ tokenQuery.isPlaceholderData || holdersQuery.isPlaceholderData }
/>
) }
{ isMobile && (
<TokenHoldersList
data={ items }
token={ tokenQuery.data }
isLoading={ tokenQuery.isPlaceholderData || holdersQuery.isPlaceholderData }
/>
) }
</>
) : null;
return (
<DataListDisplay
isError={ holdersQuery.isError || tokenQuery.isError }
isLoading={ holdersQuery.isLoading || tokenQuery.isLoading }
isLoading={ false }
items={ holdersQuery.data?.items }
skeletonProps={{ skeletonDesktopColumns: [ '100%', '300px', '175px' ] }}
emptyText="There are no holders for this token."
......
......@@ -8,16 +8,18 @@ import TokenHoldersListItem from './TokenHoldersListItem';
interface Props {
data: Array<TokenHolder>;
token: TokenInfo;
isLoading?: boolean;
}
const TokenHoldersList = ({ data, token }: Props) => {
const TokenHoldersList = ({ data, token, isLoading }: Props) => {
return (
<Box>
{ data.map((item) => (
{ data.map((item, index) => (
<TokenHoldersListItem
key={ item.address.hash }
key={ item.address.hash + (isLoading ? index : '') }
token={ token }
holder={ item }
isLoading={ isLoading }
/>
)) }
</Box>
......
import { Flex } from '@chakra-ui/react';
import { Flex, Skeleton } from '@chakra-ui/react';
import BigNumber from 'bignumber.js';
import React from 'react';
......@@ -13,24 +13,36 @@ import Utilization from 'ui/shared/Utilization/Utilization';
interface Props {
holder: TokenHolder;
token: TokenInfo;
isLoading?: boolean;
}
const TokenHoldersListItem = ({ holder, token }: Props) => {
const TokenHoldersListItem = ({ holder, token, isLoading }: Props) => {
const quantity = BigNumber(holder.value).div(BigNumber(10 ** Number(token.decimals))).dp(6).toFormat();
return (
<ListItemMobile rowGap={ 3 }>
<Address display="inline-flex" maxW="100%" lineHeight="30px">
<AddressIcon address={ holder.address }/>
<AddressLink type="address" ml={ 2 } fontWeight="700" hash={ holder.address.hash } alias={ holder.address.name } flexGrow={ 1 }/>
<Address display="inline-flex" maxW="100%">
<AddressIcon address={ holder.address } isLoading={ isLoading }/>
<AddressLink
type="address"
ml={ 2 }
fontWeight="700"
hash={ holder.address.hash }
alias={ holder.address.name }
flexGrow={ 1 }
isLoading={ isLoading }
/>
</Address>
<Flex justifyContent="space-between" alignItems="center" width="100%">
{ quantity }
<Skeleton isLoaded={ !isLoading } display="inline-block">
{ quantity }
</Skeleton>
{ token.total_supply && (
<Utilization
value={ BigNumber(holder.value).div(BigNumber(token.total_supply)).dp(4).toNumber() }
colorScheme="green"
ml={ 6 }
isLoading={ isLoading }
/>
) }
</Flex>
......
......@@ -10,9 +10,10 @@ interface Props {
data: Array<TokenHolder>;
token: TokenInfo;
top: number;
isLoading?: boolean;
}
const TokenHoldersTable = ({ data, token, top }: Props) => {
const TokenHoldersTable = ({ data, token, top, isLoading }: Props) => {
return (
<Table variant="simple" size="sm">
<Thead top={ top }>
......@@ -23,8 +24,8 @@ const TokenHoldersTable = ({ data, token, top }: Props) => {
</Tr>
</Thead>
<Tbody>
{ data.map((item) => (
<TokenHoldersTableItem key={ item.address.hash } holder={ item } token={ token }/>
{ data.map((item, index) => (
<TokenHoldersTableItem key={ item.address.hash + (isLoading ? index : '') } holder={ item } token={ token } isLoading={ isLoading }/>
)) }
</Tbody>
</Table>
......
import { Tr, Td } from '@chakra-ui/react';
import { Tr, Td, Skeleton } from '@chakra-ui/react';
import BigNumber from 'bignumber.js';
import React from 'react';
......@@ -12,28 +12,40 @@ import Utilization from 'ui/shared/Utilization/Utilization';
type Props = {
holder: TokenHolder;
token: TokenInfo;
isLoading?: boolean;
}
const TokenTransferTableItem = ({ holder, token }: Props) => {
const TokenTransferTableItem = ({ holder, token, isLoading }: Props) => {
const quantity = BigNumber(holder.value).div(BigNumber(10 ** Number(token.decimals))).toFormat();
return (
<Tr>
<Td>
<Address display="inline-flex" maxW="100%" lineHeight="30px">
<AddressIcon address={ holder.address }/>
<AddressLink type="address" ml={ 2 } fontWeight="700" hash={ holder.address.hash } alias={ holder.address.name } flexGrow={ 1 }/>
<Td verticalAlign="middle">
<Address display="inline-flex" maxW="100%">
<AddressIcon address={ holder.address } isLoading={ isLoading }/>
<AddressLink
type="address"
ml={ 2 }
fontWeight="700"
hash={ holder.address.hash }
alias={ holder.address.name }
flexGrow={ 1 }
isLoading={ isLoading }
/>
</Address>
</Td>
<Td isNumeric>
{ quantity }
<Td verticalAlign="middle" isNumeric>
<Skeleton isLoaded={ !isLoading } display="inline-block">
{ quantity }
</Skeleton>
</Td>
{ token.total_supply && (
<Td isNumeric>
<Td verticalAlign="middle" isNumeric>
<Utilization
value={ BigNumber(holder.value).div(BigNumber(token.total_supply)).dp(4).toNumber() }
colorScheme="green"
display="inline-flex"
isLoading={ isLoading }
/>
</Td>
) }
......
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