Commit 16467af8 authored by tom's avatar tom

skeletons for top accounts

parent f884b1f5
import type { NextPage } from 'next';
import dynamic from 'next/dynamic';
import Head from 'next/head';
import React from 'react';
import getNetworkTitle from 'lib/networks/getNetworkTitle';
import Accounts from 'ui/pages/Accounts';
import Page from 'ui/shared/Page/Page';
const Accounts = dynamic(() => import('ui/pages/Accounts'), { ssr: false });
const AccountsPage: NextPage = () => {
const title = `Top Accounts - ${ getNetworkTitle() }`;
return (
<>
<Head><title>{ title }</title></Head>
<Page>
<Accounts/>
</Page>
</>
);
};
......
import type { Address } from 'types/api/address';
import type { AddressesItem } from 'types/api/addresses';
import { ADDRESS_HASH } from './addressParams';
import { TOKEN_INFO_ERC_20 } from './token';
......@@ -32,3 +33,16 @@ export const ADDRESS_INFO: Address = {
watchlist_names: [],
watchlist_address_id: null,
};
export const TOP_ADDRESS: AddressesItem = {
coin_balance: '11886682377162664596540805',
tx_count: '1835',
hash: '0x4f7A67464B5976d7547c860109e4432d50AfB38e',
implementation_name: null,
is_contract: false,
is_verified: null,
name: null,
private_tags: [],
public_tags: [ ],
watchlist_names: [],
};
......@@ -77,11 +77,11 @@ export const TOKEN_TRANSFER_ERC_1155: TokenTransfer = {
export const getTokenTransfersStub = (type?: TokenType, pagination: TokenTransferPagination | null = null): TokenTransferResponse => {
switch (type) {
case 'ERC-721':
return generateListStub<'token_transfers'>(TOKEN_TRANSFER_ERC_721, 50, pagination);
return generateListStub<'token_transfers'>(TOKEN_TRANSFER_ERC_721, 50, { next_page_params: pagination });
case 'ERC-1155':
return generateListStub<'token_transfers'>(TOKEN_TRANSFER_ERC_1155, 50, pagination);
return generateListStub<'token_transfers'>(TOKEN_TRANSFER_ERC_1155, 50, { next_page_params: pagination });
default:
return generateListStub<'token_transfers'>(TOKEN_TRANSFER_ERC_20, 50, pagination);
return generateListStub<'token_transfers'>(TOKEN_TRANSFER_ERC_20, 50, { next_page_params: pagination });
}
};
......
......@@ -5,10 +5,10 @@ import type { PaginatedResources, PaginatedResponse } from 'lib/api/resources';
export function generateListStub<Resource extends PaginatedResources>(
stub: ArrayElement<PaginatedResponse<Resource>['items']>,
num = 50,
pagination: PaginatedResponse<Resource>['next_page_params'] = null,
rest: Omit<PaginatedResponse<Resource>, 'items'>,
) {
return {
items: Array(num).fill(stub),
next_page_params: pagination,
...rest,
};
}
......@@ -19,12 +19,12 @@ const AddressLogs = ({ scrollRef }: {scrollRef?: React.RefObject<HTMLDivElement>
pathParams: { hash },
scrollRef,
options: {
placeholderData: generateListStub<'address_logs'>(LOG, 3, {
placeholderData: generateListStub<'address_logs'>(LOG, 3, { next_page_params: {
block_number: 9005750,
index: 42,
items_count: 50,
transaction_index: 23,
}),
} }),
},
});
......
......@@ -44,11 +44,11 @@ const AddressTxs = ({ scrollRef }: {scrollRef?: React.RefObject<HTMLDivElement>}
filters: { filter: filterValue },
scrollRef,
options: {
placeholderData: generateListStub<'address_txs'>(TX, 50, {
placeholderData: generateListStub<'address_txs'>(TX, 50, { next_page_params: {
block_number: 9005713,
index: 5,
items_count: 50,
}),
} }),
},
});
......
......@@ -22,10 +22,10 @@ const AddressWithdrawals = ({ scrollRef }: {scrollRef?: React.RefObject<HTMLDivE
pathParams: { hash },
scrollRef,
options: {
placeholderData: generateListStub<'address_withdrawals'>(WITHDRAWAL, 50, {
placeholderData: generateListStub<'address_withdrawals'>(WITHDRAWAL, 50, { next_page_params: {
index: 5,
items_count: 50,
}),
} }),
},
});
const content = data?.items ? (
......
import { Flex, Tag, Text, HStack } from '@chakra-ui/react';
import { Flex, HStack, Skeleton } from '@chakra-ui/react';
import BigNumber from 'bignumber.js';
import React from 'react';
......@@ -8,18 +8,22 @@ import appConfig from 'configs/app/config';
import Address from 'ui/shared/address/Address';
import AddressIcon from 'ui/shared/address/AddressIcon';
import AddressLink from 'ui/shared/address/AddressLink';
import Tag from 'ui/shared/chakra/Tag';
import CopyToClipboard from 'ui/shared/CopyToClipboard';
import ListItemMobile from 'ui/shared/ListItemMobile/ListItemMobile';
type Props = {
item: AddressesItem;
index: number;
totalSupply: string;
isLoading?: boolean;
}
const AddressesListItem = ({
item,
index,
totalSupply,
isLoading,
}: Props) => {
const addressBalance = BigNumber(item.coin_balance).div(BigNumber(10 ** appConfig.network.currency.decimals));
......@@ -28,7 +32,7 @@ const AddressesListItem = ({
<ListItemMobile rowGap={ 3 }>
<Flex alignItems="center" justifyContent="space-between" w="100%">
<Address maxW="100%" mr={ 8 }>
<AddressIcon address={ item } mr={ 2 }/>
<AddressIcon address={ item } mr={ 2 } isLoading={ isLoading }/>
<AddressLink
fontWeight={ 700 }
flexGrow={ 1 }
......@@ -36,26 +40,36 @@ const AddressesListItem = ({
hash={ item.hash }
alias={ item.name }
type="address"
isLoading={ isLoading }
/>
<CopyToClipboard text={ item.hash } isLoading={ isLoading }/>
</Address>
<Text fontSize="sm" ml="auto" variant="secondary">{ index }</Text>
<Skeleton isLoaded={ !isLoading } fontSize="sm" ml="auto" minW={ 6 } color="text_secondary">
<span>{ index }</span>
</Skeleton>
</Flex>
{ item.public_tags !== null && item.public_tags.length > 0 && item.public_tags.map(tag => (
<Tag key={ tag.label }>{ tag.display_name }</Tag>
<Tag key={ tag.label } isLoading={ isLoading }>{ tag.display_name }</Tag>
)) }
<HStack spacing={ 3 }>
<Text fontSize="sm" fontWeight={ 500 }>{ `Balance ${ appConfig.network.currency.symbol }` }</Text>
<Text fontSize="sm" variant="secondary">{ addressBalance.dp(8).toFormat() }</Text>
<Skeleton isLoaded={ !isLoading } fontSize="sm" fontWeight={ 500 }>{ `Balance ${ appConfig.network.currency.symbol }` }</Skeleton>
<Skeleton isLoaded={ !isLoading } fontSize="sm" color="text_secondary">
<span>{ addressBalance.dp(8).toFormat() }</span>
</Skeleton>
</HStack>
{ totalSupply && totalSupply !== '0' && (
<HStack spacing={ 3 }>
<Text fontSize="sm" fontWeight={ 500 }>Percentage</Text>
<Text fontSize="sm" variant="secondary">{ addressBalance.div(BigNumber(totalSupply)).multipliedBy(100).dp(8).toFormat() + '%' }</Text>
<Skeleton isLoaded={ !isLoading } fontSize="sm" fontWeight={ 500 }>Percentage</Skeleton>
<Skeleton isLoaded={ !isLoading } fontSize="sm" color="text_secondary">
<span>{ addressBalance.div(BigNumber(totalSupply)).multipliedBy(100).dp(8).toFormat() + '%' }</span>
</Skeleton>
</HStack>
) }
<HStack spacing={ 3 }>
<Text fontSize="sm" fontWeight={ 500 }>Txn count</Text>
<Text fontSize="sm" variant="secondary">{ Number(item.tx_count).toLocaleString() }</Text>
<Skeleton isLoaded={ !isLoading } fontSize="sm" fontWeight={ 500 }>Txn count</Skeleton>
<Skeleton isLoaded={ !isLoading } fontSize="sm" color="text_secondary">
<span>{ Number(item.tx_count).toLocaleString() }</span>
</Skeleton>
</HStack>
</ListItemMobile>
);
......
......@@ -13,9 +13,10 @@ interface Props {
totalSupply: string;
pageStartIndex: number;
top: number;
isLoading?: boolean;
}
const AddressesTable = ({ items, totalSupply, pageStartIndex, top }: Props) => {
const AddressesTable = ({ items, totalSupply, pageStartIndex, top, isLoading }: Props) => {
const hasPercentage = Boolean(totalSupply && totalSupply !== '0');
return (
<Table variant="simple" size="sm">
......@@ -32,11 +33,12 @@ const AddressesTable = ({ items, totalSupply, pageStartIndex, top }: Props) => {
<Tbody>
{ items.map((item, index) => (
<AddressesTableItem
key={ item.hash }
key={ item.hash + (isLoading ? index : '') }
item={ item }
totalSupply={ totalSupply }
index={ pageStartIndex + index }
hasPercentage={ hasPercentage }
isLoading={ isLoading }
/>
)) }
</Tbody>
......
import { Tr, Td, Tag, Text } from '@chakra-ui/react';
import { Tr, Td, Text, Skeleton } from '@chakra-ui/react';
import BigNumber from 'bignumber.js';
import React from 'react';
......@@ -8,12 +8,15 @@ import appConfig from 'configs/app/config';
import Address from 'ui/shared/address/Address';
import AddressIcon from 'ui/shared/address/AddressIcon';
import AddressLink from 'ui/shared/address/AddressLink';
import Tag from 'ui/shared/chakra/Tag';
import CopyToClipboard from 'ui/shared/CopyToClipboard';
type Props = {
item: AddressesItem;
index: number;
totalSupply: string;
hasPercentage: boolean;
isLoading?: boolean;
}
const AddressesTableItem = ({
......@@ -21,6 +24,7 @@ const AddressesTableItem = ({
index,
totalSupply,
hasPercentage,
isLoading,
}: Props) => {
const addressBalance = BigNumber(item.coin_balance).div(BigNumber(10 ** appConfig.network.currency.decimals));
......@@ -29,11 +33,13 @@ const AddressesTableItem = ({
return (
<Tr>
<Td>
<Text lineHeight="24px">{ index }</Text>
<Skeleton isLoaded={ !isLoading } display="inline-block" minW={ 6 } lineHeight="24px">
{ index }
</Skeleton>
</Td>
<Td>
<Address display="inline-flex" maxW="100%">
<AddressIcon address={ item } mr={ 2 }/>
<AddressIcon address={ item } mr={ 2 } isLoading={ isLoading }/>
<AddressLink
fontWeight={ 700 }
flexGrow={ 1 }
......@@ -41,18 +47,22 @@ const AddressesTableItem = ({
hash={ item.hash }
alias={ item.name }
type="address"
isLoading={ isLoading }
/>
<CopyToClipboard text={ item.hash } isLoading={ isLoading }/>
</Address>
</Td>
<Td pl={ 10 }>
{ item.public_tags && item.public_tags.length ? item.public_tags.map(tag => (
<Tag key={ tag.label }>{ tag.display_name }</Tag>
)) : <Text lineHeight="24px">-</Text> }
<Tag key={ tag.label } isLoading={ isLoading } isTruncated>{ tag.display_name }</Tag>
)) : null }
</Td>
<Td isNumeric>
<Skeleton isLoaded={ !isLoading } display="inline-block">
<Text lineHeight="24px" as="span">{ addressBalanceChunks[0] }</Text>
{ addressBalanceChunks[1] && <Text lineHeight="24px" as="span">.</Text> }
<Text lineHeight="24px" variant="secondary" as="span">{ addressBalanceChunks[1] }</Text>
</Skeleton>
</Td>
{ hasPercentage && (
<Td isNumeric>
......@@ -60,7 +70,9 @@ const AddressesTableItem = ({
</Td>
) }
<Td isNumeric>
<Text lineHeight="24px">{ Number(item.tx_count).toLocaleString() }</Text>
<Skeleton isLoaded={ !isLoading } display="inline-block" lineHeight="24px">
{ Number(item.tx_count).toLocaleString() }
</Skeleton>
</Td>
</Tr>
);
......
......@@ -2,19 +2,34 @@ import { Hide, Show } from '@chakra-ui/react';
import React from 'react';
import useQueryWithPages from 'lib/hooks/useQueryWithPages';
import { TOP_ADDRESS } from 'stubs/address';
import { generateListStub } from 'stubs/utils';
import AddressesListItem from 'ui/addresses/AddressesListItem';
import AddressesTable from 'ui/addresses/AddressesTable';
import ActionBar from 'ui/shared/ActionBar';
import DataListDisplay from 'ui/shared/DataListDisplay';
import Page from 'ui/shared/Page/Page';
import PageTitle from 'ui/shared/Page/PageTitle';
import Pagination from 'ui/shared/Pagination';
const PAGE_SIZE = 50;
const Accounts = () => {
const { isError, isLoading, data, isPaginationVisible, pagination } = useQueryWithPages({
const { isError, isPlaceholderData, data, isPaginationVisible, pagination } = useQueryWithPages({
resourceName: 'addresses',
options: {
placeholderData: generateListStub<'addresses'>(
TOP_ADDRESS,
50,
{
next_page_params: {
fetched_coin_balance: '42',
hash: '0x99f0ec06548b086e46cb0019c78d0b9b9f36cd53',
items_count: 50,
},
total_supply: '0',
},
),
},
});
const actionBar = isPaginationVisible && (
......@@ -32,16 +47,18 @@ const Accounts = () => {
items={ data.items }
totalSupply={ data.total_supply }
pageStartIndex={ pageStartIndex }
isLoading={ isPlaceholderData }
/>
</Hide>
<Show below="lg" ssr={ false }>
{ data.items.map((item, index) => {
return (
<AddressesListItem
key={ item.hash }
key={ item.hash + (isPlaceholderData ? index : '') }
item={ item }
index={ pageStartIndex + index }
totalSupply={ data.total_supply }
isLoading={ isPlaceholderData }
/>
);
}) }
......@@ -50,18 +67,18 @@ const Accounts = () => {
) : null;
return (
<Page>
<>
<PageTitle title="Top accounts" withTextAd/>
<DataListDisplay
isError={ isError }
isLoading={ isLoading }
isLoading={ false }
items={ data?.items }
skeletonProps={{ skeletonDesktopColumns: [ '64px', '30%', '20%', '20%', '15%', '15%' ] }}
emptyText="There are no accounts."
content={ content }
actionBar={ actionBar }
/>
</Page>
</>
);
};
......
......@@ -50,11 +50,11 @@ const BlockPageContent = () => {
pathParams: { height },
options: {
enabled: Boolean(!blockQuery.isPlaceholderData && blockQuery.data?.height && tab === 'txs'),
placeholderData: generateListStub<'block_txs'>(TX, 50, {
placeholderData: generateListStub<'block_txs'>(TX, 50, { next_page_params: {
block_number: 9004925,
index: 49,
items_count: 50,
}),
} }),
},
});
......@@ -63,10 +63,10 @@ const BlockPageContent = () => {
pathParams: { height },
options: {
enabled: Boolean(!blockQuery.isPlaceholderData && blockQuery.data?.height && appConfig.beaconChain.hasBeaconChain && tab === 'withdrawals'),
placeholderData: generateListStub<'block_withdrawals'>(WITHDRAWAL, 50, {
placeholderData: generateListStub<'block_withdrawals'>(WITHDRAWAL, 50, { next_page_params: {
index: 5,
items_count: 50,
}),
} }),
},
});
......
......@@ -34,10 +34,10 @@ const BlocksPageContent = () => {
resourceName: 'blocks',
filters: { type },
options: {
placeholderData: generateListStub<'blocks'>(BLOCK, 50, {
placeholderData: generateListStub<'blocks'>(BLOCK, 50, { next_page_params: {
block_number: 8988686,
items_count: 50,
}),
} }),
},
});
......
......@@ -146,7 +146,7 @@ const TokenPageContent = () => {
scrollRef,
options: {
enabled: Boolean(router.query.hash && router.query.tab === 'inventory' && hasData),
placeholderData: generateListStub<'token_inventory'>(tokenStubs.TOKEN_INSTANCE),
placeholderData: generateListStub<'token_inventory'>(tokenStubs.TOKEN_INSTANCE, 50, { next_page_params: null }),
},
});
......
......@@ -31,12 +31,12 @@ const Transactions = () => {
filters: { filter: router.query.tab === 'pending' ? 'pending' : 'validated' },
options: {
enabled: !router.query.tab || router.query.tab === 'validated' || router.query.tab === 'pending',
placeholderData: generateListStub<'txs_validated'>(TX, 50, {
placeholderData: generateListStub<'txs_validated'>(TX, 50, { next_page_params: {
block_number: 9005713,
index: 5,
items_count: 50,
filter: 'validated',
}),
} }),
},
});
......
......@@ -21,10 +21,10 @@ const Withdrawals = () => {
const { data, isError, isPlaceholderData, isPaginationVisible, pagination } = useQueryWithPages({
resourceName: 'withdrawals',
options: {
placeholderData: generateListStub<'withdrawals'>(WITHDRAWAL, 50, {
placeholderData: generateListStub<'withdrawals'>(WITHDRAWAL, 50, { next_page_params: {
index: 5,
items_count: 50,
}),
} }),
},
});
......
......@@ -55,7 +55,7 @@ const CoinzillaTextAd = ({ className }: {className?: string}) => {
}
if (isLoading) {
return <Skeleton className={ className } h={{ base: 12, lg: 6 }} w="100%" maxW="1000px"/>;
return <Skeleton className={ className } h={{ base: 12, lg: 6 }} w={{ base: '100%', lg: 'auto' }} flexGrow={ 1 } maxW="1000px" display="inline-block"/>;
}
if (!adData) {
......
......@@ -36,12 +36,18 @@ const Tokens = () => {
resourceName: 'tokens',
filters: { q: debouncedFilter, type },
options: {
placeholderData: generateListStub<'tokens'>(TOKEN_INFO_ERC_20, 50, {
placeholderData: generateListStub<'tokens'>(
TOKEN_INFO_ERC_20,
50,
{
next_page_params: {
holder_count: 81528,
items_count: 50,
name: '',
market_cap: null,
}),
},
},
),
},
});
......
......@@ -77,7 +77,7 @@ const TxInternals = () => {
pathParams: { hash: txInfo.data?.hash },
options: {
enabled: !txInfo.isPlaceholderData && Boolean(txInfo.data?.hash) && Boolean(txInfo.data?.status),
placeholderData: generateListStub<'tx_internal_txs'>(INTERNAL_TX, 3),
placeholderData: generateListStub<'tx_internal_txs'>(INTERNAL_TX, 3, { next_page_params: null }),
},
});
......
......@@ -20,7 +20,7 @@ const TxLogs = () => {
pathParams: { hash: txInfo.data?.hash },
options: {
enabled: !txInfo.isPlaceholderData && Boolean(txInfo.data?.hash) && Boolean(txInfo.data?.status),
placeholderData: generateListStub<'tx_logs'>(LOG, 3),
placeholderData: generateListStub<'tx_logs'>(LOG, 3, { next_page_params: null }),
},
});
......
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