Commit 3c3e22ea authored by tom's avatar tom

skeletons for internal txs

parent e9297935
import type { InternalTransaction, InternalTransactionsResponse } from 'types/api/internalTransaction';
import { ADDRESS_PARAMS } from './addressParams';
import { TX_HASH } from './tx';
export const INTERNAL_TX: InternalTransaction = {
block: 9006105,
created_contract: null,
error: null,
from: ADDRESS_PARAMS,
gas_limit: '754278',
index: 1,
success: true,
timestamp: '2023-05-15T20:14:00.000000Z',
to: ADDRESS_PARAMS,
transaction_hash: TX_HASH,
type: 'staticcall',
value: '22324344900000000',
};
export const INTERNAL_TXS: InternalTransactionsResponse = {
items: Array(3).fill(INTERNAL_TX),
next_page_params: null,
};
......@@ -6,6 +6,7 @@ import type { InternalTransaction } from 'types/api/internalTransaction';
import { SECOND } from 'lib/consts';
import useQueryWithPages from 'lib/hooks/useQueryWithPages';
// import { apos } from 'lib/html-entities';
import { INTERNAL_TXS } from 'stubs/internalTx';
import ActionBar from 'ui/shared/ActionBar';
import DataListDisplay from 'ui/shared/DataListDisplay';
// import FilterInput from 'ui/shared/filters/FilterInput';
......@@ -70,11 +71,12 @@ const TxInternals = () => {
// const [ searchTerm, setSearchTerm ] = React.useState<string>('');
const [ sort, setSort ] = React.useState<Sort>();
const txInfo = useFetchTxInfo({ updateDelay: 5 * SECOND });
const { data, isLoading, isError, pagination, isPaginationVisible } = useQueryWithPages({
const { data, isPlaceholderData, isError, pagination, isPaginationVisible } = useQueryWithPages({
resourceName: 'tx_internal_txs',
pathParams: { hash: txInfo.data?.hash },
options: {
enabled: Boolean(txInfo.data?.hash) && Boolean(txInfo.data?.status),
enabled: !txInfo.isPlaceholderData && Boolean(txInfo.data?.hash) && Boolean(txInfo.data?.status),
placeholderData: INTERNAL_TXS,
},
});
......@@ -84,11 +86,14 @@ const TxInternals = () => {
const handleSortToggle = React.useCallback((field: SortField) => {
return () => {
if (isPlaceholderData) {
return;
}
setSort(getNextSortValue(field));
};
}, []);
}, [ isPlaceholderData ]);
if (!txInfo.isLoading && !txInfo.isError && !txInfo.data.status) {
if (!txInfo.isPlaceholderData && !txInfo.isError && !txInfo.data?.status) {
return txInfo.socketStatus ? <TxSocketAlert status={ txInfo.socketStatus }/> : <TxPendingAlert/>;
}
......@@ -100,9 +105,15 @@ const TxInternals = () => {
const content = filteredData ? (
<>
<Show below="lg" ssr={ false }><TxInternalsList data={ filteredData }/></Show>
<Show below="lg" ssr={ false }><TxInternalsList data={ filteredData } isLoading={ isPlaceholderData }/></Show>
<Hide below="lg" ssr={ false }>
<TxInternalsTable data={ filteredData } sort={ sort } onSortToggle={ handleSortToggle } top={ isPaginationVisible ? 80 : 0 }/>
<TxInternalsTable
data={ filteredData }
sort={ sort }
onSortToggle={ handleSortToggle }
top={ isPaginationVisible ? 80 : 0 }
isLoading={ isPlaceholderData }
/>
</Hide>
</>
) : null;
......@@ -118,7 +129,7 @@ const TxInternals = () => {
return (
<DataListDisplay
isError={ isError || txInfo.isError }
isLoading={ isLoading || txInfo.isLoading }
isLoading={ false }
items={ data?.items }
skeletonProps={{ skeletonDesktopColumns: [ '28%', '20%', '24px', '20%', '16%', '16%' ] }}
emptyText="There are no internal transactions for this transaction."
......
......@@ -5,10 +5,10 @@ import type { InternalTransaction } from 'types/api/internalTransaction';
import TxInternalsListItem from 'ui/tx/internals/TxInternalsListItem';
const TxInternalsList = ({ data }: { data: Array<InternalTransaction>}) => {
const TxInternalsList = ({ data, isLoading }: { data: Array<InternalTransaction>; isLoading?: boolean }) => {
return (
<Box>
{ data.map((item) => <TxInternalsListItem key={ item.transaction_hash } { ...item }/>) }
{ data.map((item, index) => <TxInternalsListItem key={ item.transaction_hash + (isLoading ? index : '') } { ...item } isLoading={ isLoading }/>) }
</Box>
);
};
......
import { Flex, Tag, Icon, Box, HStack, Text } from '@chakra-ui/react';
import { Flex, Icon, Box, HStack, Skeleton } from '@chakra-ui/react';
import BigNumber from 'bignumber.js';
import React from 'react';
......@@ -9,47 +9,50 @@ import eastArrowIcon from 'icons/arrows/east.svg';
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';
import TxStatus from 'ui/shared/TxStatus';
import { TX_INTERNALS_ITEMS } from 'ui/tx/internals/utils';
type Props = InternalTransaction;
type Props = InternalTransaction & { isLoading: boolean };
const TxInternalsListItem = ({ type, from, to, value, success, error, gas_limit: gasLimit, created_contract: createdContract }: Props) => {
const TxInternalsListItem = ({ type, from, to, value, success, error, gas_limit: gasLimit, created_contract: createdContract, isLoading }: Props) => {
const typeTitle = TX_INTERNALS_ITEMS.find(({ id }) => id === type)?.title;
const toData = to ? to : createdContract;
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>
<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 }/>
<CopyToClipboard text={ from.hash }/>
<AddressIcon address={ from } isLoading={ isLoading }/>
<AddressLink type="address" ml={ 2 } fontWeight="500" hash={ from.hash } isLoading={ isLoading }/>
<CopyToClipboard text={ from.hash } isLoading={ isLoading }/>
</Address>
<Icon as={ eastArrowIcon } boxSize={ 6 } color="gray.500"/>
<Skeleton isLoaded={ !isLoading } boxSize={ 6 }>
<Icon as={ eastArrowIcon } boxSize={ 6 } color="gray.500"/>
</Skeleton>
{ toData && (
<Address width="calc((100% - 48px) / 2)">
<AddressIcon address={ toData }/>
<AddressLink type="address" ml={ 2 } fontWeight="500" hash={ toData.hash }/>
<CopyToClipboard text={ toData.hash }/>
<AddressIcon address={ toData } isLoading={ isLoading }/>
<AddressLink type="address" ml={ 2 } fontWeight="500" hash={ toData.hash } isLoading={ isLoading }/>
<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">
<Skeleton isLoaded={ !isLoading } fontSize="sm" fontWeight={ 500 }>Value { appConfig.network.currency.symbol }</Skeleton>
<Skeleton isLoaded={ !isLoading } fontSize="sm" variant="secondary">
{ BigNumber(value).div(BigNumber(10 ** appConfig.network.currency.decimals)).toFormat() }
</Text>
</Skeleton>
</HStack>
<HStack spacing={ 3 }>
<Text fontSize="sm" fontWeight={ 500 }>Gas limit</Text>
<Text fontSize="sm" variant="secondary">{ BigNumber(gasLimit).toFormat() }</Text>
<Skeleton isLoaded={ !isLoading } fontSize="sm" fontWeight={ 500 }>Gas limit</Skeleton>
<Skeleton isLoaded={ !isLoading } fontSize="sm" variant="secondary">{ BigNumber(gasLimit).toFormat() }</Skeleton>
</HStack>
</ListItemMobile>
);
......
......@@ -14,9 +14,10 @@ interface Props {
sort: Sort | undefined;
onSortToggle: (field: SortField) => () => void;
top: number;
isLoading?: boolean;
}
const TxInternalsTable = ({ data, sort, onSortToggle, top }: Props) => {
const TxInternalsTable = ({ data, sort, onSortToggle, top, isLoading }: Props) => {
const sortIconTransform = sort?.includes('asc') ? 'rotate(-90deg)' : 'rotate(90deg)';
return (
......@@ -42,8 +43,8 @@ const TxInternalsTable = ({ data, sort, onSortToggle, top }: Props) => {
</Tr>
</Thead>
<Tbody>
{ data.map((item) => (
<TxInternalsTableItem key={ item.transaction_hash } { ...item }/>
{ data.map((item, index) => (
<TxInternalsTableItem key={ item.transaction_hash + (isLoading ? index : '') } { ...item } isLoading={ isLoading }/>
)) }
</Tbody>
</Table>
......
import { Tr, Td, Tag, Icon, Box, Flex } from '@chakra-ui/react';
import { Tr, Td, Icon, Box, Flex, Skeleton } from '@chakra-ui/react';
import BigNumber from 'bignumber.js';
import React from 'react';
......@@ -9,13 +9,16 @@ import rightArrowIcon from 'icons/arrows/east.svg';
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 TxStatus from 'ui/shared/TxStatus';
import { TX_INTERNALS_ITEMS } from 'ui/tx/internals/utils';
type Props = InternalTransaction
type Props = InternalTransaction & {
isLoading?: boolean;
}
const TxInternalTableItem = ({ type, from, to, value, success, error, gas_limit: gasLimit, created_contract: createdContract }: Props) => {
const TxInternalTableItem = ({ type, from, to, value, success, error, gas_limit: gasLimit, created_contract: createdContract, isLoading }: Props) => {
const typeTitle = TX_INTERNALS_ITEMS.find(({ id }) => id === type)?.title;
const toData = to ? to : createdContract;
......@@ -25,36 +28,42 @@ const TxInternalTableItem = ({ type, from, to, value, success, error, gas_limit:
<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">
<Address display="inline-flex" maxW="100%">
<AddressIcon address={ from }/>
<AddressLink type="address" ml={ 2 } fontWeight="500" hash={ from.hash } alias={ from.name } flexGrow={ 1 }/>
<CopyToClipboard text={ from.hash }/>
<AddressIcon address={ from } isLoading={ isLoading }/>
<AddressLink type="address" ml={ 2 } fontWeight="500" hash={ from.hash } alias={ from.name } flexGrow={ 1 } isLoading={ isLoading }/>
<CopyToClipboard text={ from.hash } isLoading={ isLoading }/>
</Address>
</Td>
<Td px={ 0 } verticalAlign="middle">
<Icon as={ rightArrowIcon } boxSize={ 6 } color="gray.500"/>
<Skeleton isLoaded={ !isLoading } boxSize={ 6 }>
<Icon as={ rightArrowIcon } boxSize={ 6 } color="gray.500"/>
</Skeleton>
</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 }/>
<CopyToClipboard text={ toData.hash }/>
<AddressIcon address={ toData } isLoading={ isLoading }/>
<AddressLink type="address" hash={ toData.hash } alias={ toData.name } fontWeight="500" ml={ 2 } isLoading={ isLoading }/>
<CopyToClipboard text={ toData.hash } isLoading={ isLoading }/>
</Address>
) }
</Td>
<Td isNumeric verticalAlign="middle">
{ BigNumber(value).div(BigNumber(10 ** appConfig.network.currency.decimals)).toFormat() }
<Skeleton isLoaded={ !isLoading } display="inline-block">
{ BigNumber(value).div(BigNumber(10 ** appConfig.network.currency.decimals)).toFormat() }
</Skeleton>
</Td>
<Td isNumeric verticalAlign="middle">
{ BigNumber(gasLimit).toFormat() }
<Skeleton isLoaded={ !isLoading } display="inline-block">
{ BigNumber(gasLimit).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