Commit 40109a61 authored by tom's avatar tom

skeletons for internal txs

parent c0834be6
......@@ -9,6 +9,8 @@ import getFilterValueFromQuery from 'lib/getFilterValueFromQuery';
import useQueryWithPages from 'lib/hooks/useQueryWithPages';
import { apos } from 'lib/html-entities';
import getQueryParamString from 'lib/router/getQueryParamString';
import { INTERNAL_TX } from 'stubs/internalTx';
import { generateListStub } from 'stubs/utils';
import AddressIntTxsTable from 'ui/address/internals/AddressIntTxsTable';
import ActionBar from 'ui/shared/ActionBar';
import DataListDisplay from 'ui/shared/DataListDisplay';
......@@ -26,15 +28,28 @@ const AddressInternalTxs = ({ scrollRef }: {scrollRef?: React.RefObject<HTMLDivE
const hash = getQueryParamString(router.query.hash);
const { data, isLoading, isError, pagination, onFilterChange, isPaginationVisible } = useQueryWithPages({
const { data, isPlaceholderData, isError, pagination, onFilterChange, isPaginationVisible } = useQueryWithPages({
resourceName: 'address_internal_txs',
pathParams: { hash },
filters: { filter: filterValue },
scrollRef,
options: {
placeholderData: generateListStub<'address_internal_txs'>(
INTERNAL_TX,
50,
{
next_page_params: {
block_number: 8987561,
index: 2,
items_count: 50,
transaction_index: 67,
},
},
),
},
});
const handleFilterChange = React.useCallback((val: string | Array<string>) => {
const newVal = getFilterValue(val);
setFilterValue(newVal);
onFilterChange({ filter: newVal });
......@@ -43,22 +58,23 @@ const AddressInternalTxs = ({ scrollRef }: {scrollRef?: React.RefObject<HTMLDivE
const content = data?.items ? (
<>
<Show below="lg" ssr={ false }>
<AddressIntTxsList data={ data.items } currentAddress={ hash }/>
<AddressIntTxsList data={ data.items } currentAddress={ hash } isLoading={ isPlaceholderData }/>
</Show>
<Hide below="lg" ssr={ false }>
<AddressIntTxsTable data={ data.items } currentAddress={ hash }/>
<AddressIntTxsTable data={ data.items } currentAddress={ hash } isLoading={ isPlaceholderData }/>
</Hide>
</>
) : null ;
const actionBar = (
<ActionBar mt={ -6 } justifyContent="left" showShadow={ isLoading }>
<ActionBar mt={ -6 } justifyContent="left">
<AddressTxsFilter
defaultFilter={ filterValue }
onFilterChange={ handleFilterChange }
isActive={ Boolean(filterValue) }
isLoading={ pagination.isLoading }
/>
<AddressCsvExportLink address={ hash } type="internal-transactions" ml={{ base: 2, lg: 'auto' }}/>
<AddressCsvExportLink address={ hash } isLoading={ pagination.isLoading } type="internal-transactions" ml={{ base: 2, lg: 'auto' }}/>
{ isPaginationVisible && <Pagination ml={{ base: 'auto', lg: 8 }} { ...pagination }/> }
</ActionBar>
);
......@@ -66,7 +82,7 @@ const AddressInternalTxs = ({ scrollRef }: {scrollRef?: React.RefObject<HTMLDivE
return (
<DataListDisplay
isError={ isError }
isLoading={ isLoading }
isLoading={ false }
items={ data?.items }
skeletonProps={{ isLongSkeleton: true, skeletonDesktopColumns: [ '15%', '15%', '10%', '20%', '20%', '20%' ] }}
filterProps={{ emptyFilteredText: `Couldn${ apos }t find any transaction that matches your query.`, hasActiveFilters: Boolean(filterValue) }}
......
......@@ -8,12 +8,20 @@ import AddressIntTxsListItem from 'ui/address/internals/AddressIntTxsListItem';
type Props = {
data: Array<InternalTransaction>;
currentAddress: string;
isLoading?: boolean;
}
const AddressIntTxsList = ({ data, currentAddress }: Props) => {
const AddressIntTxsList = ({ data, currentAddress, isLoading }: Props) => {
return (
<Box>
{ data.map((item) => <AddressIntTxsListItem key={ item.transaction_hash } { ...item } currentAddress={ currentAddress }/>) }
{ data.map((item, index) => (
<AddressIntTxsListItem
key={ item.transaction_hash + '_' + index }
{ ...item }
currentAddress={ currentAddress }
isLoading={ isLoading }
/>
)) }
</Box>
);
};
......
import { Flex, Tag, Icon, Box, HStack, Text } from '@chakra-ui/react';
import { Flex, Box, HStack, Skeleton } from '@chakra-ui/react';
import BigNumber from 'bignumber.js';
import { route } from 'nextjs-routes';
import React from 'react';
......@@ -11,6 +11,8 @@ 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 Tag from 'ui/shared/chakra/Tag';
import CopyToClipboard from 'ui/shared/CopyToClipboard';
import InOutTag from 'ui/shared/InOutTag';
import LinkInternal from 'ui/shared/LinkInternal';
......@@ -18,7 +20,7 @@ import ListItemMobile from 'ui/shared/ListItemMobile/ListItemMobile';
import TxStatus from 'ui/shared/TxStatus';
import { TX_INTERNALS_ITEMS } from 'ui/tx/internals/utils';
type Props = InternalTransaction & { currentAddress: string };
type Props = InternalTransaction & { currentAddress: string; isLoading?: boolean };
const TxInternalsListItem = ({
type,
......@@ -32,6 +34,7 @@ const TxInternalsListItem = ({
block,
timestamp,
currentAddress,
isLoading,
}: Props) => {
const typeTitle = TX_INTERNALS_ITEMS.find(({ id }) => id === type)?.title;
const toData = to ? to : createdContract;
......@@ -41,41 +44,45 @@ const TxInternalsListItem = ({
return (
<ListItemMobile rowGap={ 3 }>
<Flex>
{ typeTitle && <Tag colorScheme="cyan" mr={ 2 }>{ typeTitle }</Tag> }
<TxStatus status={ success ? 'ok' : 'error' } errorText={ error }/>
<Flex columnGap={ 2 }>
{ typeTitle && <Tag colorScheme="cyan" isLoading={ isLoading }>{ typeTitle }</Tag> }
<TxStatus status={ success ? 'ok' : 'error' } errorText={ error } isLoading={ isLoading }/>
</Flex>
<Flex justifyContent="space-between" width="100%">
<AddressLink fontWeight="700" hash={ txnHash } truncation="constant" type="transaction"/>
<Text variant="secondary" fontWeight="400" fontSize="sm">{ dayjs(timestamp).fromNow() }</Text>
<AddressLink fontWeight="700" hash={ txnHash } truncation="constant" type="transaction" isLoading={ isLoading }/>
<Skeleton isLoaded={ !isLoading } color="text_secondary" fontWeight="400" fontSize="sm">
<span>{ dayjs(timestamp).fromNow() }</span>
</Skeleton>
</Flex>
<HStack spacing={ 1 }>
<Text fontSize="sm" fontWeight={ 500 }>Block</Text>
<Skeleton isLoaded={ !isLoading } fontSize="sm" fontWeight={ 500 }>Block</Skeleton>
<Skeleton isLoaded={ !isLoading }>
<LinkInternal href={ route({ pathname: '/block/[height]', query: { height: block.toString() } }) }>{ block }</LinkInternal>
</Skeleton>
</HStack>
<Box w="100%" display="flex" columnGap={ 3 }>
<Address width="calc((100% - 48px) / 2)">
<AddressIcon address={ from }/>
<AddressLink type="address" ml={ 2 } fontWeight="500" hash={ from.hash } isDisabled={ isOut }/>
{ isIn && <CopyToClipboard text={ from.hash }/> }
<AddressIcon address={ from } isLoading={ isLoading }/>
<AddressLink type="address" ml={ 2 } fontWeight="500" hash={ from.hash } isDisabled={ isOut } isLoading={ isLoading }/>
{ isIn && <CopyToClipboard text={ from.hash } isLoading={ isLoading }/> }
</Address>
{ (isIn || isOut) ?
<InOutTag isIn={ isIn } isOut={ isOut }/> :
<Icon as={ eastArrowIcon } boxSize={ 6 } color="gray.500"/>
<InOutTag isIn={ isIn } isOut={ isOut } isLoading={ isLoading }/> :
<Icon as={ eastArrowIcon } boxSize={ 6 } color="gray.500" isLoading={ isLoading }/>
}
{ toData && (
<Address width="calc((100% - 48px) / 2)">
<AddressIcon address={ toData }/>
<AddressLink type="address" ml={ 2 } fontWeight="500" hash={ toData.hash } isDisabled={ isIn }/>
{ isOut && <CopyToClipboard text={ toData.hash }/> }
<AddressIcon address={ toData } isLoading={ isLoading }/>
<AddressLink type="address" ml={ 2 } fontWeight="500" hash={ toData.hash } isDisabled={ isIn } isLoading={ isLoading }/>
{ isOut && <CopyToClipboard text={ toData.hash } isLoading={ isLoading }/> }
</Address>
) }
</Box>
<HStack spacing={ 3 }>
<Text fontSize="sm" fontWeight={ 500 }>Value { appConfig.network.currency.symbol }</Text>
<Text fontSize="sm" variant="secondary">
{ BigNumber(value).div(BigNumber(10 ** appConfig.network.currency.decimals)).toFormat() }
</Text>
<Skeleton isLoaded={ !isLoading } fontSize="sm" fontWeight={ 500 }>Value { appConfig.network.currency.symbol }</Skeleton>
<Skeleton isLoaded={ !isLoading } fontSize="sm" color="text_secondary" minW={ 6 }>
<span>{ BigNumber(value).div(BigNumber(10 ** appConfig.network.currency.decimals)).toFormat() }</span>
</Skeleton>
</HStack>
</ListItemMobile>
);
......
......@@ -11,9 +11,10 @@ import AddressIntTxsTableItem from './AddressIntTxsTableItem';
interface Props {
data: Array<InternalTransaction>;
currentAddress: string;
isLoading?: boolean;
}
const AddressIntTxsTable = ({ data, currentAddress }: Props) => {
const AddressIntTxsTable = ({ data, currentAddress, isLoading }: Props) => {
return (
<Table variant="simple" size="sm">
<Thead top={ 80 }>
......@@ -30,8 +31,13 @@ const AddressIntTxsTable = ({ data, currentAddress }: Props) => {
</Tr>
</Thead>
<Tbody>
{ data.map((item) => (
<AddressIntTxsTableItem key={ item.transaction_hash } { ...item } currentAddress={ currentAddress }/>
{ data.map((item, index) => (
<AddressIntTxsTableItem
key={ item.transaction_hash + '_' + index }
{ ...item }
currentAddress={ currentAddress }
isLoading={ isLoading }
/>
)) }
</Tbody>
</Table>
......
import { Tr, Td, Tag, Icon, Box, Flex, Text } from '@chakra-ui/react';
import { Tr, Td, Box, Flex, Skeleton } from '@chakra-ui/react';
import BigNumber from 'bignumber.js';
import { route } from 'nextjs-routes';
import React from 'react';
......@@ -11,13 +11,15 @@ import useTimeAgoIncrement from 'lib/hooks/useTimeAgoIncrement';
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 Tag from 'ui/shared/chakra/Tag';
import CopyToClipboard from 'ui/shared/CopyToClipboard';
import InOutTag from 'ui/shared/InOutTag';
import LinkInternal from 'ui/shared/LinkInternal';
import TxStatus from 'ui/shared/TxStatus';
import { TX_INTERNALS_ITEMS } from 'ui/tx/internals/utils';
type Props = InternalTransaction & { currentAddress: string }
type Props = InternalTransaction & { currentAddress: string; isLoading?: boolean }
const AddressIntTxsTableItem = ({
type,
......@@ -31,6 +33,7 @@ const AddressIntTxsTableItem = ({
block,
timestamp,
currentAddress,
isLoading,
}: Props) => {
const typeTitle = TX_INTERNALS_ITEMS.find(({ id }) => id === type)?.title;
const toData = to ? to : createdContract;
......@@ -44,47 +47,66 @@ const AddressIntTxsTableItem = ({
<Tr alignItems="top">
<Td verticalAlign="middle">
<Flex rowGap={ 3 } flexWrap="wrap">
<AddressLink fontWeight="700" hash={ txnHash } type="transaction"/>
{ timestamp && <Text variant="secondary" fontWeight="400" fontSize="sm">{ timeAgo }</Text> }
<AddressLink fontWeight="700" hash={ txnHash } type="transaction" isLoading={ isLoading }/>
{ timestamp && (
<Skeleton isLoaded={ !isLoading } color="text_secondary" fontWeight="400" fontSize="sm">
<span>{ timeAgo }</span>
</Skeleton>
) }
</Flex>
</Td>
<Td verticalAlign="middle">
<Flex rowGap={ 2 } flexWrap="wrap">
{ typeTitle && (
<Box w="126px" display="inline-block">
<Tag colorScheme="cyan" mr={ 5 }>{ typeTitle }</Tag>
<Tag colorScheme="cyan" mr={ 5 } isLoading={ isLoading }>{ typeTitle }</Tag>
</Box>
) }
<TxStatus status={ success ? 'ok' : 'error' } errorText={ error }/>
<TxStatus status={ success ? 'ok' : 'error' } errorText={ error } isLoading={ isLoading }/>
</Flex>
</Td>
<Td verticalAlign="middle">
<LinkInternal href={ route({ pathname: '/block/[height]', query: { height: block.toString() } }) }>{ block }</LinkInternal>
<Skeleton isLoaded={ !isLoading } display="inline-block">
<LinkInternal href={ route({ pathname: '/block/[height]', query: { height: block.toString() } }) }>
{ block }
</LinkInternal>
</Skeleton>
</Td>
<Td verticalAlign="middle">
<Address display="inline-flex" maxW="100%">
<AddressIcon address={ from }/>
<AddressLink type="address" ml={ 2 } fontWeight="500" hash={ from.hash } alias={ from.name } flexGrow={ 1 } isDisabled={ isOut }/>
{ isIn && <CopyToClipboard text={ from.hash }/> }
<AddressIcon address={ from } isLoading={ isLoading }/>
<AddressLink
type="address"
ml={ 2 }
fontWeight="500"
hash={ from.hash }
alias={ from.name }
flexGrow={ 1 }
isDisabled={ isOut }
isLoading={ isLoading }
/>
{ isIn && <CopyToClipboard text={ from.hash } isLoading={ isLoading }/> }
</Address>
</Td>
<Td px={ 0 } verticalAlign="middle">
{ (isIn || isOut) ?
<InOutTag isIn={ isIn } isOut={ isOut }/> :
<Icon as={ rightArrowIcon } boxSize={ 6 } color="gray.500"/>
<InOutTag isIn={ isIn } isOut={ isOut } isLoading={ isLoading }/> :
<Icon as={ rightArrowIcon } boxSize={ 6 } color="gray.500" isLoading={ isLoading }/>
}
</Td>
<Td verticalAlign="middle">
{ toData && (
<Address display="inline-flex" maxW="100%">
<AddressIcon address={ toData }/>
<AddressLink type="address" hash={ toData.hash } alias={ toData.name } fontWeight="500" ml={ 2 } isDisabled={ isIn }/>
{ isOut && <CopyToClipboard text={ toData.hash }/> }
<AddressIcon address={ toData } isLoading={ isLoading }/>
<AddressLink type="address" hash={ toData.hash } alias={ toData.name } fontWeight="500" ml={ 2 } isDisabled={ isIn } isLoading={ isLoading }/>
{ isOut && <CopyToClipboard text={ toData.hash } isLoading={ isLoading }/> }
</Address>
) }
</Td>
<Td isNumeric verticalAlign="middle">
<Skeleton isLoaded={ !isLoading } display="inline-block" minW={ 6 }>
{ BigNumber(value).div(BigNumber(10 ** appConfig.network.currency.decimals)).toFormat() }
</Skeleton>
</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