Commit 05bc3818 authored by tom's avatar tom

skeletons for verified contracts

parent 8d1de2c4
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 VerifiedContracts from 'ui/pages/VerifiedContracts';
import Page from 'ui/shared/Page/Page';
const VerifiedContracts = dynamic(() => import('ui/pages/VerifiedContracts'), { ssr: false });
const VerifiedContractsPage: NextPage = () => {
const title = getNetworkTitle();
......
import type { SmartContract } from 'types/api/contract';
import type { VerifiedContract } from 'types/api/contracts';
import { ADDRESS_PARAMS } from './addressParams';
export const CONTRACT_CODE_UNVERIFIED = {
creation_bytecode: '0x60806040526e',
......@@ -38,3 +41,15 @@ export const CONTRACT_CODE_VERIFIED = {
source_code: 'source_code',
verified_at: '2023-02-21T14:39:16.906760Z',
} as unknown as SmartContract;
export const VERIFIED_CONTRACT_INFO: VerifiedContract = {
address: { ...ADDRESS_PARAMS, name: 'StubContract' },
coin_balance: '30319033612988277',
compiler_version: 'v0.8.17+commit.8df45f5f',
has_constructor_args: true,
language: 'solidity',
market_cap: null,
optimization_enabled: false,
tx_count: 565058,
verified_at: '2023-04-10T13:16:33.884921Z',
};
......@@ -9,6 +9,8 @@ import useIsMobile from 'lib/hooks/useIsMobile';
import useQueryWithPages from 'lib/hooks/useQueryWithPages';
import { apos } from 'lib/html-entities';
import getQueryParamString from 'lib/router/getQueryParamString';
import { VERIFIED_CONTRACT_INFO } from 'stubs/contract';
import { generateListStub } from 'stubs/utils';
import ActionBar from 'ui/shared/ActionBar';
import DataListDisplay from 'ui/shared/DataListDisplay';
import FilterInput from 'ui/shared/filters/FilterInput';
......@@ -32,9 +34,21 @@ const VerifiedContracts = () => {
const isMobile = useIsMobile();
const { isError, isLoading, data, isPaginationVisible, pagination, onFilterChange } = useQueryWithPages({
const { isError, isPlaceholderData, data, isPaginationVisible, pagination, onFilterChange } = useQueryWithPages({
resourceName: 'verified_contracts',
filters: { q: debouncedSearchTerm, filter: type },
options: {
placeholderData: generateListStub<'verified_contracts'>(
VERIFIED_CONTRACT_INFO,
50,
{
next_page_params: {
items_count: '50',
smart_contract_id: '50',
},
},
),
},
});
const handleSearchTermChange = React.useCallback((value: string) => {
......@@ -107,10 +121,10 @@ const VerifiedContracts = () => {
const content = sortedData ? (
<>
<Show below="lg" ssr={ false }>
<VerifiedContractsList data={ sortedData }/>
<VerifiedContractsList data={ sortedData } isLoading={ isPlaceholderData }/>
</Show>
<Hide below="lg" ssr={ false }>
<VerifiedContractsTable data={ sortedData } sort={ sort } onSortToggle={ handleSortToggle }/>
<VerifiedContractsTable data={ sortedData } sort={ sort } onSortToggle={ handleSortToggle } isLoading={ isPlaceholderData }/>
</Hide>
</>
) : null;
......@@ -121,7 +135,7 @@ const VerifiedContracts = () => {
<VerifiedContractsCounters/>
<DataListDisplay
isError={ isError }
isLoading={ isLoading }
isLoading={ false }
items={ data?.items }
skeletonProps={{ skeletonDesktopColumns: [ '50%', '130px', '130px', '50%', '80px', '110px' ] }}
emptyText="There are no verified contracts."
......
......@@ -5,10 +5,16 @@ import type { VerifiedContract } from 'types/api/contracts';
import VerifiedContractsListItem from './VerifiedContractsListItem';
const VerifiedContractsList = ({ data }: { data: Array<VerifiedContract>}) => {
const VerifiedContractsList = ({ data, isLoading }: { data: Array<VerifiedContract>; isLoading: boolean }) => {
return (
<Box>
{ data.map((item) => <VerifiedContractsListItem key={ item.address.hash } data={ item }/>) }
{ data.map((item, index) => (
<VerifiedContractsListItem
key={ item.address.hash + (isLoading ? index : '') }
data={ item }
isLoading={ isLoading }
/>
)) }
</Box>
);
};
......
import { Box, Flex, Icon } from '@chakra-ui/react';
import { Box, Flex, Skeleton } from '@chakra-ui/react';
import BigNumber from 'bignumber.js';
import React from 'react';
......@@ -12,14 +12,16 @@ import dayjs from 'lib/date/dayjs';
import Address from 'ui/shared/address/Address';
import AddressIcon from 'ui/shared/address/AddressIcon';
import AddressLink from 'ui/shared/address/AddressLink';
import Icon from 'ui/shared/chakra/Icon';
import HashStringShorten from 'ui/shared/HashStringShorten';
import ListItemMobile from 'ui/shared/ListItemMobile/ListItemMobile';
interface Props {
data: VerifiedContract;
isLoading?: boolean;
}
const VerifiedContractsListItem = ({ data }: Props) => {
const VerifiedContractsListItem = ({ data, isLoading }: Props) => {
const balance = data.coin_balance && data.coin_balance !== '0' ?
BigNumber(data.coin_balance).div(10 ** appConfig.network.currency.decimals).dp(6).toFormat() :
'0';
......@@ -27,50 +29,50 @@ const VerifiedContractsListItem = ({ data }: Props) => {
return (
<ListItemMobile rowGap={ 3 }>
<Address columnGap={ 2 } overflow="hidden" w="100%">
<AddressIcon address={ data.address }/>
<AddressLink hash={ data.address.hash } type="address" alias={ data.address.name }/>
<Box color="text_secondary" ml="auto">
<AddressIcon address={ data.address } isLoading={ isLoading }/>
<AddressLink hash={ data.address.hash } type="address" alias={ data.address.name } isLoading={ isLoading }/>
<Skeleton isLoaded={ !isLoading } color="text_secondary" ml="auto">
<HashStringShorten hash={ data.address.hash } isTooltipDisabled/>
</Box>
</Skeleton>
</Address>
<Flex columnGap={ 3 }>
<Box fontWeight={ 500 }>Balance { appConfig.network.currency.symbol }</Box>
<Box color="text_secondary">
{ balance }
</Box>
<Skeleton isLoaded={ !isLoading } fontWeight={ 500 }>Balance { appConfig.network.currency.symbol }</Skeleton>
<Skeleton isLoaded={ !isLoading } color="text_secondary">
<span>{ balance }</span>
</Skeleton>
</Flex>
<Flex columnGap={ 3 }>
<Box fontWeight={ 500 }>Txs count</Box>
<Box color="text_secondary">
{ data.tx_count ? data.tx_count.toLocaleString() : '0' }
</Box>
<Skeleton isLoaded={ !isLoading } fontWeight={ 500 }>Txs count</Skeleton>
<Skeleton isLoaded={ !isLoading } color="text_secondary">
<span>{ data.tx_count ? data.tx_count.toLocaleString() : '0' }</span>
</Skeleton>
</Flex>
<Flex columnGap={ 3 }>
<Box fontWeight={ 500 } flexShrink="0">Compiler</Box>
<Flex flexWrap="wrap">
<Skeleton isLoaded={ !isLoading } fontWeight={ 500 } flexShrink="0">Compiler</Skeleton>
<Skeleton isLoaded={ !isLoading } display="flex" flexWrap="wrap">
<Box textTransform="capitalize">{ data.language }</Box>
<Box color="text_secondary" wordBreak="break-all" whiteSpace="pre-wrap"> ({ data.compiler_version })</Box>
</Flex>
</Skeleton>
</Flex>
<Flex columnGap={ 3 }>
<Box fontWeight={ 500 }>Optimization</Box>
<Skeleton isLoaded={ !isLoading } fontWeight={ 500 }>Optimization</Skeleton>
{ data.optimization_enabled ?
<Icon as={ iconCheck } boxSize={ 6 } color="green.500" cursor="pointer"/> :
<Icon as={ iconCross } boxSize={ 6 } color="red.600" cursor="pointer"/> }
<Icon as={ iconCheck } boxSize={ 6 } color="green.500" cursor="pointer" isLoading={ isLoading }/> :
<Icon as={ iconCross } boxSize={ 6 } color="red.600" cursor="pointer" isLoading={ isLoading }/> }
</Flex>
<Flex columnGap={ 3 }>
<Box fontWeight={ 500 }>Constructor args</Box>
<Skeleton isLoaded={ !isLoading } fontWeight={ 500 }>Constructor args</Skeleton>
{ data.has_constructor_args ?
<Icon as={ iconCheck } boxSize={ 6 } color="green.500" cursor="pointer"/> :
<Icon as={ iconCross } boxSize={ 6 } color="red.600" cursor="pointer"/> }
<Icon as={ iconCheck } boxSize={ 6 } color="green.500" cursor="pointer" isLoading={ isLoading }/> :
<Icon as={ iconCross } boxSize={ 6 } color="red.600" cursor="pointer" isLoading={ isLoading }/> }
</Flex>
<Flex columnGap={ 3 }>
<Box fontWeight={ 500 }>Verified</Box>
<Skeleton isLoaded={ !isLoading } fontWeight={ 500 }>Verified</Skeleton>
<Flex alignItems="center" columnGap={ 2 }>
<Icon as={ iconSuccess } boxSize={ 4 } color="green.500"/>
<Box color="text_secondary">
{ dayjs(data.verified_at).fromNow() }
</Box>
<Icon as={ iconSuccess } boxSize={ 4 } color="green.500" isLoading={ isLoading }/>
<Skeleton isLoaded={ !isLoading } color="text_secondary">
<span>{ dayjs(data.verified_at).fromNow() }</span>
</Skeleton>
</Flex>
</Flex>
{ /* <Flex columnGap={ 3 }>
......
......@@ -14,9 +14,10 @@ interface Props {
data: Array<VerifiedContract>;
sort: Sort | undefined;
onSortToggle: (field: SortField) => () => void;
isLoading?: boolean;
}
const VerifiedContractsTable = ({ data, sort, onSortToggle }: Props) => {
const VerifiedContractsTable = ({ data, sort, onSortToggle, isLoading }: Props) => {
const sortIconTransform = sort?.includes('asc') ? 'rotate(-90deg)' : 'rotate(90deg)';
return (
......@@ -25,13 +26,13 @@ const VerifiedContractsTable = ({ data, sort, onSortToggle }: Props) => {
<Tr>
<Th width="50%">Contract</Th>
<Th width="130px" isNumeric>
<Link display="flex" alignItems="center" justifyContent="flex-end" onClick={ onSortToggle('balance') } columnGap={ 1 }>
<Link display="flex" alignItems="center" justifyContent="flex-end" onClick={ isLoading ? undefined : onSortToggle('balance') } columnGap={ 1 }>
{ sort?.includes('balance') && <Icon as={ arrowIcon } boxSize={ 4 } transform={ sortIconTransform }/> }
Balance { appConfig.network.currency.symbol }
</Link>
</Th>
<Th width="130px" isNumeric>
<Link display="flex" alignItems="center" justifyContent="flex-end" onClick={ onSortToggle('txs') } columnGap={ 1 }>
<Link display="flex" alignItems="center" justifyContent="flex-end" onClick={ isLoading ? undefined : onSortToggle('txs') } columnGap={ 1 }>
{ sort?.includes('txs') && <Icon as={ arrowIcon } boxSize={ 4 } transform={ sortIconTransform }/> }
Txs
</Link>
......@@ -43,7 +44,12 @@ const VerifiedContractsTable = ({ data, sort, onSortToggle }: Props) => {
</Tr>
</Thead>
<Tbody>
{ data.map((item) => <VerifiedContractsTableItem key={ item.address.hash } data={ item }/>) }
{ data.map((item, index) => (
<VerifiedContractsTableItem
key={ item.address.hash + (isLoading ? index : '') }
data={ item }
isLoading={ isLoading }/>
)) }
</Tbody>
</Table>
);
......
import { Tr, Td, Icon, Box, Flex, chakra, Tooltip } from '@chakra-ui/react';
import { Tr, Td, Flex, chakra, Tooltip, Skeleton } from '@chakra-ui/react';
import BigNumber from 'bignumber.js';
import React from 'react';
......@@ -11,13 +11,15 @@ import iconSuccess from 'icons/status/success.svg';
import dayjs from 'lib/date/dayjs';
import AddressIcon from 'ui/shared/address/AddressIcon';
import AddressLink from 'ui/shared/address/AddressLink';
import Icon from 'ui/shared/chakra/Icon';
import HashStringShorten from 'ui/shared/HashStringShorten';
interface Props {
data: VerifiedContract;
isLoading?: boolean;
}
const VerifiedContractsTableItem = ({ data }: Props) => {
const VerifiedContractsTableItem = ({ data, isLoading }: Props) => {
const balance = data.coin_balance && data.coin_balance !== '0' ?
BigNumber(data.coin_balance).div(10 ** appConfig.network.currency.decimals).dp(6).toFormat() :
'0';
......@@ -26,52 +28,58 @@ const VerifiedContractsTableItem = ({ data }: Props) => {
<Tr>
<Td>
<Flex columnGap={ 2 }>
<AddressIcon address={ data.address }/>
<Flex columnGap={ 2 } flexWrap="wrap" lineHeight={ 6 } w="calc(100% - 32px)">
<AddressLink hash={ data.address.hash } type="address" alias={ data.address.name }/>
<Box color="text_secondary">
<AddressIcon address={ data.address } isLoading={ isLoading }/>
<Flex columnGap={ 2 } flexWrap="wrap" w="calc(100% - 32px)">
<AddressLink hash={ data.address.hash } type="address" alias={ data.address.name } isLoading={ isLoading } my={ 1 }/>
<Skeleton isLoaded={ !isLoading } color="text_secondary" my={ 1 }>
<HashStringShorten hash={ data.address.hash } isTooltipDisabled/>
</Box>
</Skeleton>
</Flex>
</Flex>
</Td>
<Td isNumeric lineHeight={ 6 }>
{ balance }
<Td isNumeric>
<Skeleton isLoaded={ !isLoading } display="inline-block" my={ 1 }>
{ balance }
</Skeleton>
</Td>
<Td isNumeric lineHeight={ 6 }>
{ data.tx_count ? data.tx_count.toLocaleString() : '0' }
<Td isNumeric>
<Skeleton isLoaded={ !isLoading } display="inline-block" my={ 1 }>
{ data.tx_count ? data.tx_count.toLocaleString() : '0' }
</Skeleton>
</Td>
<Td lineHeight={ 6 }>
<Td>
<Flex flexWrap="wrap" columnGap={ 2 }>
<chakra.span textTransform="capitalize">{ data.language }</chakra.span>
<chakra.span color="text_secondary" wordBreak="break-all">{ data.compiler_version }</chakra.span>
<Skeleton isLoaded={ !isLoading } textTransform="capitalize" my={ 1 }>{ data.language }</Skeleton>
<Skeleton isLoaded={ !isLoading } color="text_secondary" wordBreak="break-all" my={ 1 }>
<span>{ data.compiler_version }</span>
</Skeleton>
</Flex>
</Td>
<Td>
<Tooltip label="Optimization">
<span>
<Tooltip label={ isLoading ? undefined : 'Optimization' }>
<chakra.span display="inline-block">
{ data.optimization_enabled ?
<Icon as={ iconCheck } boxSize={ 6 } color="green.500" cursor="pointer"/> :
<Icon as={ iconCross } boxSize={ 6 } color="red.600" cursor="pointer"/> }
</span>
<Icon as={ iconCheck } boxSize={ 6 } color="green.500" cursor="pointer" isLoading={ isLoading }/> :
<Icon as={ iconCross } boxSize={ 6 } color="red.600" cursor="pointer" isLoading={ isLoading }/> }
</chakra.span>
</Tooltip>
<Tooltip label="Constructor args">
<chakra.span ml={ 3 }>
<Tooltip label={ isLoading ? undefined : 'Constructor args' }>
<chakra.span display="inline-block" ml={ 3 }>
{ data.has_constructor_args ?
<Icon as={ iconCheck } boxSize={ 6 } color="green.500" cursor="pointer"/> :
<Icon as={ iconCross } boxSize={ 6 } color="red.600" cursor="pointer"/> }
<Icon as={ iconCheck } boxSize={ 6 } color="green.500" cursor="pointer" isLoading={ isLoading }/> :
<Icon as={ iconCross } boxSize={ 6 } color="red.600" cursor="pointer" isLoading={ isLoading }/> }
</chakra.span>
</Tooltip>
</Td>
<Td lineHeight={ 6 }>
<Flex alignItems="center" columnGap={ 2 }>
<Icon as={ iconSuccess } boxSize={ 4 } color="green.500"/>
<chakra.span color="text_secondary">
{ dayjs(data.verified_at).fromNow() }
</chakra.span>
<Td>
<Flex alignItems="center" columnGap={ 2 } my={ 1 }>
<Icon as={ iconSuccess } boxSize={ 4 } color="green.500" isLoading={ isLoading }/>
<Skeleton isLoaded={ !isLoading } color="text_secondary">
<span>{ dayjs(data.verified_at).fromNow() }</span>
</Skeleton>
</Flex>
</Td>
{ /* <Td lineHeight={ 6 }>
{ /* <Td>
N/A
</Td> */ }
</Tr>
......
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