Commit f11218a1 authored by tom's avatar tom

token transfer table

parent 8e46f14d
This diff is collapsed.
......@@ -7,7 +7,7 @@ import React from 'react';
import infoIcon from 'icons/info.svg';
const TxAdditionalInfoButton = ({ isOpen, onClick }: {isOpen?: boolean; onClick?: () => void}, ref: React.ForwardedRef<HTMLDivElement>) => {
const AdditionalInfoButton = ({ isOpen, onClick }: {isOpen?: boolean; onClick?: () => void}, ref: React.ForwardedRef<HTMLDivElement>) => {
const infoBgColor = useColorModeValue('blue.50', 'gray.600');
const infoColor = useColorModeValue('blue.600', 'blue.300');
......@@ -24,4 +24,4 @@ const TxAdditionalInfoButton = ({ isOpen, onClick }: {isOpen?: boolean; onClick?
);
};
export default React.forwardRef(TxAdditionalInfoButton);
export default React.forwardRef(AdditionalInfoButton);
import { Tag, chakra } from '@chakra-ui/react';
import React from 'react';
interface Props {
baseAddress: string;
addressFrom: string;
className?: string;
}
const InOutTag = ({ baseAddress, addressFrom, className }: Props) => {
const isOut = addressFrom === baseAddress;
const colorScheme = isOut ? 'orange' : 'green';
return <Tag className={ className } colorScheme={ colorScheme }>{ isOut ? 'OUT' : 'IN' }</Tag>;
};
export default React.memo(chakra(InOutTag));
import { Center, Link, Text, chakra } from '@chakra-ui/react';
import { Flex, Text, chakra } from '@chakra-ui/react';
import React from 'react';
import link from 'lib/link/link';
import AddressLink from 'ui/shared/address/AddressLink';
import TokenLogo from 'ui/shared/TokenLogo';
interface Props {
......@@ -12,16 +12,12 @@ interface Props {
}
const TokenSnippet = ({ symbol, hash, name, className }: Props) => {
const url = link('token_index', { hash });
return (
<Center className={ className } columnGap={ 1 }>
<TokenLogo boxSize={ 5 } hash={ hash } name={ name }/>
<Link href={ url } target="_blank">
{ name }
</Link>
<Flex className={ className } alignItems="center" columnGap={ 1 } w="100%">
<TokenLogo boxSize={ 5 } borderRadius={ 2 } hash={ hash } name={ name }/>
<AddressLink hash={ hash } alias={ name } type="token"/>
{ symbol && <Text variant="secondary">({ symbol })</Text> }
</Center>
</Flex>
);
};
......
import { Box } from '@chakra-ui/react';
import { Alert, Show } from '@chakra-ui/react';
import type { QueryKey } from '@tanstack/react-query';
import { useQuery } from '@tanstack/react-query';
import React from 'react';
import { TokenTransfer } from 'types/api/tokenTransfer';
import type { TokenTransferResponse } from 'types/api/tokenTransfer';
import useFetch from 'lib/hooks/useFetch';
import DataFetchAlert from 'ui/shared/DataFetchAlert';
import SkeletonTable from 'ui/shared/SkeletonTable';
import TokenTransferTable from 'ui/shared/TokenTransfer/TokenTransferTable';
interface Props {
isLoading?: boolean;
isDisabled?: boolean;
path: string;
queryKey: QueryKey;
baseAddress?: string;
}
const TokenTransfer = ({ isLoading: isLoadingProp, isDisabled, queryKey, path }: Props) => {
const { isError, isLoading } = useQuery<unknown, unknown, TokenTransferResponse>(
const TokenTransfer = ({ isLoading: isLoadingProp, isDisabled, queryKey, path, baseAddress }: Props) => {
const fetch = useFetch();
const { isError, isLoading, data } = useQuery<unknown, unknown, TokenTransferResponse>(
queryKey,
async() => await fetch(path),
{
......@@ -24,14 +30,37 @@ const TokenTransfer = ({ isLoading: isLoadingProp, isDisabled, queryKey, path }:
);
if (isLoading || isLoadingProp) {
return <span>Loading...</span>;
return (
<>
<Show below="lg">loading...</Show>
<Show above="lg">
<SkeletonTable columns={ [ '44px', '185px', '160px', '25%', '25%', '25%', '25%' ] }/>
</Show>
</>
);
}
if (isError) {
return <DataFetchAlert/>;
}
return <Box>TokenTransfer</Box>;
if (!data.items?.length) {
return <Alert>There are no token transfers</Alert>;
}
const items = data.items.reduce((result, item) => {
if (Array.isArray(item.total)) {
item.total.forEach((total) => {
result.push({ ...item, total });
});
} else {
result.push(item);
}
return result;
}, [] as Array<TokenTransfer>);
return <TokenTransferTable data={ items } baseAddress={ baseAddress }/>;
};
export default React.memo(TokenTransfer);
import { Table, Tbody, Tr, Th } from '@chakra-ui/react';
import React from 'react';
import type { TokenTransfer } from 'types/api/tokenTransfer';
import { default as Thead } from 'ui/shared/TheadSticky';
import TokenTransferTableItem from 'ui/shared/TokenTransfer/TokenTransferTableItem';
interface Props {
data: Array<TokenTransfer>;
baseAddress?: string;
}
const TxInternalsTable = ({ data, baseAddress }: Props) => {
return (
<Table variant="simple" size="sm" mt={ 6 }>
<Thead top={ 0 }>
<Tr>
<Th width="44px"></Th>
<Th width="185px">Token</Th>
<Th width="160px">Token ID</Th>
<Th width="25%">Txn hash</Th>
<Th width="25%">From</Th>
{ baseAddress && <Th width="50px" px={ 0 }/> }
<Th width="25%">To</Th>
<Th width="25%">Value</Th>
</Tr>
</Thead>
<Tbody>
{ data.map((item, index) => (
<TokenTransferTableItem key={ index } { ...item } baseAddress={ baseAddress }/>
)) }
</Tbody>
</Table>
);
};
export default React.memo(TxInternalsTable);
import { Tr, Td, Tag, Icon, Flex } from '@chakra-ui/react';
import BigNumber from 'bignumber.js';
import React from 'react';
import type { TokenTransfer } from 'types/api/tokenTransfer';
import nftPlaceholder from 'icons/nft_placeholder.svg';
import AdditionalInfoButton from 'ui/shared/AdditionalInfoButton';
import Address from 'ui/shared/address/Address';
import AddressIcon from 'ui/shared/address/AddressIcon';
import AddressLink from 'ui/shared/address/AddressLink';
import InOutTag from 'ui/shared/InOutTag';
import TokenSnippet from 'ui/shared/TokenSnippet';
type Props = TokenTransfer & {
baseAddress?: string;
}
const TxInternalTableItem = ({ token, total, tx_hash: txHash, from, to, baseAddress }: Props) => {
const value = (() => {
if (!('value' in total)) {
return '-';
}
return BigNumber(total.value).div(BigNumber(10 ** Number(total.decimals))).dp(8).toFormat();
})();
return (
<Tr alignItems="top">
<Td>
<AdditionalInfoButton/>
</Td>
<Td>
<Flex flexDir="column" rowGap={ 3 } alignItems="flex-start">
<TokenSnippet hash={ token.address } name={ token.name || 'Unnamed token' }/>
<Tag>{ token.type }</Tag>
</Flex>
</Td>
<Td>
{ 'token_id' in total ? (
<Flex align="center">
<Icon as={ nftPlaceholder } boxSize="30px" mr={ 2 }/>
<AddressLink hash={ token.address } id={ total.token_id } type="token_instance_item"/>
</Flex>
) : '-' }
</Td>
<Td>
<Address display="inline-flex" maxW="100%" fontWeight={ 600 }>
<AddressLink type="transaction" hash={ txHash }/>
</Address>
</Td>
<Td>
<Address display="inline-flex" maxW="100%">
<AddressIcon hash={ from.hash }/>
<AddressLink ml={ 2 } fontWeight="500" hash={ from.hash } alias={ from.name } flexGrow={ 1 }/>
</Address>
</Td>
{ baseAddress && (
<Td px={ 0 }>
<InOutTag baseAddress={ baseAddress } addressFrom={ from.hash } w="50px" textAlign="center"/>
</Td>
) }
<Td>
<Address display="inline-flex" maxW="100%">
<AddressIcon hash={ to.hash }/>
<AddressLink ml={ 2 } fontWeight="500" hash={ to.hash } alias={ to.name } flexGrow={ 1 }/>
</Address>
</Td>
<Td isNumeric verticalAlign="top">
{ value }
</Td>
</Tr>
);
};
export default React.memo(TxInternalTableItem);
......@@ -7,7 +7,7 @@ import HashStringShorten from 'ui/shared/HashStringShorten';
import HashStringShortenDynamic from 'ui/shared/HashStringShortenDynamic';
interface Props {
type?: 'address' | 'transaction' | 'token' | 'block';
type?: 'address' | 'transaction' | 'token' | 'block' | 'token_instance_item';
alias?: string | null;
className?: string;
hash: string;
......@@ -23,6 +23,8 @@ const AddressLink = ({ alias, type, className, truncation = 'dynamic', hash, id,
url = link('tx', { id: id || hash });
} else if (type === 'token') {
url = link('token_index', { hash: id || hash });
} else if (type === 'token_instance_item') {
url = link('token_instance_item', { hash, id });
} else if (type === 'block') {
url = link('block', { id: id || hash });
} else {
......@@ -39,11 +41,11 @@ const AddressLink = ({ alias, type, className, truncation = 'dynamic', hash, id,
}
switch (truncation) {
case 'constant':
return <HashStringShorten hash={ hash }/>;
return <HashStringShorten hash={ id || hash }/>;
case 'dynamic':
return <HashStringShortenDynamic hash={ hash } fontWeight={ fontWeight }/>;
return <HashStringShortenDynamic hash={ id || hash } fontWeight={ fontWeight }/>;
case 'none':
return <span>{ hash }</span>;
return <span>{ id || hash }</span>;
}
})();
......
......@@ -23,7 +23,15 @@ const TxTokenTransfer = () => {
const queryKey = [ QueryKeys.txTokenTransfers, data?.hash ];
const path = `/node-api/transactions/${ data?.hash }/token-transfers`;
return <TokenTransfer isLoading={ isLoading } isDisabled={ !data?.status || !data?.hash } path={ path } queryKey={ queryKey }/>;
return (
<TokenTransfer
isLoading={ isLoading }
isDisabled={ !data?.status || !data?.hash }
path={ path }
queryKey={ queryKey }
// todo_tom delete me
baseAddress="0xd789a607CEac2f0E14867de4EB15b15C9FFB5859"/>
);
};
export default TxTokenTransfer;
......@@ -20,12 +20,12 @@ import transactionIcon from 'icons/transactions.svg';
import dayjs from 'lib/date/dayjs';
import getValueWithUnit from 'lib/getValueWithUnit';
import link from 'lib/link/link';
import AdditionalInfoButton from 'ui/shared/AdditionalInfoButton';
import Address from 'ui/shared/address/Address';
import AddressIcon from 'ui/shared/address/AddressIcon';
import AddressLink from 'ui/shared/address/AddressLink';
import TxStatus from 'ui/shared/TxStatus';
import TxAdditionalInfo from 'ui/txs/TxAdditionalInfo';
import TxAdditionalInfoButton from 'ui/txs/TxAdditionalInfoButton';
import TxType from 'ui/txs/TxType';
const TxsListItem = ({ tx }: {tx: Transaction}) => {
......@@ -42,7 +42,7 @@ const TxsListItem = ({ tx }: {tx: Transaction}) => {
{ tx.tx_types.map(item => <TxType key={ item } type={ item }/>) }
<TxStatus status={ tx.status } errorText={ tx.status === 'error' ? tx.result : undefined }/>
</HStack>
<TxAdditionalInfoButton onClick={ onOpen }/>
<AdditionalInfoButton onClick={ onOpen }/>
</Flex>
<Flex justifyContent="space-between" lineHeight="24px" mt={ 3 }>
<Flex>
......
......@@ -22,6 +22,7 @@ import type { Transaction } from 'types/api/transaction';
import rightArrowIcon from 'icons/arrows/east.svg';
import dayjs from 'lib/date/dayjs';
import link from 'lib/link/link';
import AdditionalInfoButton from 'ui/shared/AdditionalInfoButton';
import Address from 'ui/shared/address/Address';
import AddressIcon from 'ui/shared/address/AddressIcon';
import AddressLink from 'ui/shared/address/AddressLink';
......@@ -29,7 +30,6 @@ import CurrencyValue from 'ui/shared/CurrencyValue';
import TruncatedTextTooltip from 'ui/shared/TruncatedTextTooltip';
import TxStatus from 'ui/shared/TxStatus';
import TxAdditionalInfo from 'ui/txs/TxAdditionalInfo';
import TxAdditionalInfoButton from 'ui/txs/TxAdditionalInfoButton';
import TxType from './TxType';
......@@ -60,7 +60,7 @@ const TxsTableItem = ({ tx }: {tx: Transaction}) => {
{ ({ isOpen }) => (
<>
<PopoverTrigger>
<TxAdditionalInfoButton isOpen={ isOpen }/>
<AdditionalInfoButton isOpen={ isOpen }/>
</PopoverTrigger>
<PopoverContent border="1px solid" borderColor={ infoBorderColor }>
<PopoverBody>
......
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