Commit f665a2a7 authored by tom's avatar tom

skeletons for tx state changes

parent a2cced29
import type { TxStateChange, TxStateChanges } from 'types/api/txStateChanges';
import { ADDRESS_PARAMS } from './addressParams';
import { TOKEN_INFO_ERC_721 } from './token';
export const STATE_CHANGE_MINER: TxStateChange = {
address: ADDRESS_PARAMS,
balance_after: '124280364215547113',
balance_before: '123405277440098758',
change: '875086775448355',
is_miner: true,
token: null,
type: 'coin',
};
export const STATE_CHANGE_COIN: TxStateChange = {
address: ADDRESS_PARAMS,
balance_after: '61659392141463351540',
balance_before: '61660292436225994690',
change: '-900294762600000',
is_miner: false,
token: null,
type: 'coin',
};
export const STATE_CHANGE_TOKEN: TxStateChange = {
address: ADDRESS_PARAMS,
balance_after: '43',
balance_before: '42',
change: [
{
direction: 'to',
total: {
token_id: '1621395',
},
},
],
is_miner: false,
token: TOKEN_INFO_ERC_721,
type: 'token',
};
export const TX_STATE_CHANGES: TxStateChanges = [
STATE_CHANGE_MINER,
STATE_CHANGE_COIN,
STATE_CHANGE_TOKEN,
];
import { Grid, chakra, GridItem } from '@chakra-ui/react';
import { Grid, chakra, GridItem, Skeleton } from '@chakra-ui/react';
import { motion } from 'framer-motion';
import React from 'react';
......@@ -38,13 +38,20 @@ const Container = chakra(({ isAnimated, children, className }: ContainerProps) =
interface LabelProps {
className?: string;
children: React.ReactNode;
isLoading?: boolean;
}
const Label = chakra(({ children, className }: LabelProps) => {
const Label = chakra(({ children, className, isLoading }: LabelProps) => {
return (
<GridItem className={ className } fontWeight={ 500 } lineHeight="20px" py="5px">
<Skeleton
className={ className }
isLoaded={ !isLoading }
fontWeight={ 500 }
lineHeight="20px"
my="5px"
>
{ children }
</GridItem>
</Skeleton>
);
});
......
import { Accordion, Hide, Show, Skeleton, Text } from '@chakra-ui/react';
import { Accordion, Hide, Show, Text } from '@chakra-ui/react';
import React from 'react';
import useApiQuery from 'lib/api/useApiQuery';
import { SECOND } from 'lib/consts';
import { TX_STATE_CHANGES } from 'stubs/txStateChanges';
import DataListDisplay from 'ui/shared/DataListDisplay';
import SkeletonList from 'ui/shared/skeletons/SkeletonList';
import SkeletonTable from 'ui/shared/skeletons/SkeletonTable';
import TxStateList from 'ui/tx/state/TxStateList';
import TxStateTable from 'ui/tx/state/TxStateTable';
import useFetchTxInfo from 'ui/tx/useFetchTxInfo';
......@@ -15,59 +14,44 @@ import TxSocketAlert from './TxSocketAlert';
const TxState = () => {
const txInfo = useFetchTxInfo({ updateDelay: 5 * SECOND });
const { data, isLoading, isError } = useApiQuery('tx_state_changes', {
const { data, isPlaceholderData, isError } = useApiQuery('tx_state_changes', {
pathParams: { hash: txInfo.data?.hash },
queryOptions: {
enabled: Boolean(txInfo.data?.hash) && Boolean(txInfo.data?.status),
placeholderData: TX_STATE_CHANGES,
},
});
if (!txInfo.isLoading && !txInfo.isError && !txInfo.data.status) {
if (!txInfo.isLoading && !txInfo.isPlaceholderData && !txInfo.isError && !txInfo.data.status) {
return txInfo.socketStatus ? <TxSocketAlert status={ txInfo.socketStatus }/> : <TxPendingAlert/>;
}
const skeleton = (
<>
<Show below="lg" ssr={ false }>
<Skeleton h={ 4 } borderRadius="full" w="100%"/>
<Skeleton h={ 4 } borderRadius="full" w="100%" mt={ 2 }/>
<Skeleton h={ 4 } borderRadius="full" w="100%" mt={ 2 }/>
<Skeleton h={ 4 } borderRadius="full" w="50%" mt={ 2 } mb={ 6 }/>
<SkeletonList/>
</Show>
const content = data ? (
<Accordion allowMultiple defaultIndex={ [] }>
<Hide below="lg" ssr={ false }>
<Skeleton h={ 6 } borderRadius="full" w="90%" mb={ 6 }/>
<SkeletonTable columns={ [ '140px', '146px', '33%', '33%', '33%', '150px' ] }/>
<TxStateTable data={ data } isLoading={ isPlaceholderData }/>
</Hide>
</>
);
<Show below="lg" ssr={ false }>
<TxStateList data={ data } isLoading={ isPlaceholderData }/>
</Show>
</Accordion>
) : null;
const content = data ? (
return (
<>
<Text>
A set of information that represents the current state is updated when a transaction takes place on the network.
The below is a summary of those changes.
</Text>
<Accordion allowMultiple defaultIndex={ [] }>
<Hide below="lg" ssr={ false }>
<TxStateTable data={ data }/>
</Hide>
<Show below="lg" ssr={ false }>
<TxStateList data={ data }/>
</Show>
</Accordion>
<DataListDisplay
isError={ isError }
isLoading={ false }
items={ data }
emptyText="There are no state changes for this transaction."
content={ content }
skeletonProps={{ customSkeleton: null }}
/>
</>
) : null;
return (
<DataListDisplay
isError={ isError }
isLoading={ isLoading }
items={ data }
emptyText="There are no state changes for this transaction."
content={ content }
skeletonProps={{ customSkeleton: skeleton }}
/>
);
};
......
......@@ -7,12 +7,13 @@ import TxStateListItem from 'ui/tx/state/TxStateListItem';
interface Props {
data: TxStateChanges;
isLoading?: boolean;
}
const TxStateList = ({ data }: Props) => {
const TxStateList = ({ data, isLoading }: Props) => {
return (
<Box mt={ 6 }>
{ data.map((item, index) => <TxStateListItem key={ index } data={ item }/>) }
{ data.map((item, index) => <TxStateListItem key={ index } data={ item } isLoading={ isLoading }/>) }
</Box>
);
};
......
......@@ -11,48 +11,49 @@ import { getStateElements } from './utils';
interface Props {
data: TxStateChange;
isLoading?: boolean;
}
const TxStateListItem = ({ data }: Props) => {
const TxStateListItem = ({ data, isLoading }: Props) => {
const { before, after, change, tag, tokenId } = getStateElements(data);
const { before, after, change, tag, tokenId } = getStateElements(data, isLoading);
return (
<ListItemMobileGrid.Container>
<ListItemMobileGrid.Label>Address</ListItemMobileGrid.Label>
<ListItemMobileGrid.Label isLoading={ isLoading }>Address</ListItemMobileGrid.Label>
<ListItemMobileGrid.Value py="3px">
<Address flexGrow={ 1 } w="100%" alignSelf="center">
<AddressIcon address={ data.address }/>
<AddressLink type="address" hash={ data.address.hash } ml={ 2 } truncation="constant" mr={ 3 }/>
<AddressIcon address={ data.address } isLoading={ isLoading }/>
<AddressLink type="address" hash={ data.address.hash } ml={ 2 } truncation="constant" mr={ 3 } isLoading={ isLoading }/>
{ tag }
</Address>
</ListItemMobileGrid.Value>
{ before && (
<>
<ListItemMobileGrid.Label>Before</ListItemMobileGrid.Label>
<ListItemMobileGrid.Label isLoading={ isLoading }>Before</ListItemMobileGrid.Label>
<ListItemMobileGrid.Value>{ before }</ListItemMobileGrid.Value>
</>
) }
{ after && (
<>
<ListItemMobileGrid.Label>After</ListItemMobileGrid.Label>
<ListItemMobileGrid.Label isLoading={ isLoading }>After</ListItemMobileGrid.Label>
<ListItemMobileGrid.Value>{ after }</ListItemMobileGrid.Value>
</>
) }
{ change && (
<>
<ListItemMobileGrid.Label>Change</ListItemMobileGrid.Label>
<ListItemMobileGrid.Label isLoading={ isLoading }>Change</ListItemMobileGrid.Label>
<ListItemMobileGrid.Value>{ change }</ListItemMobileGrid.Value>
</>
) }
{ tokenId && (
<>
<ListItemMobileGrid.Label>Token ID</ListItemMobileGrid.Label>
<ListItemMobileGrid.Label isLoading={ isLoading }>Token ID</ListItemMobileGrid.Label>
<ListItemMobileGrid.Value py="0">{ tokenId }</ListItemMobileGrid.Value>
</>
) }
......
......@@ -13,9 +13,10 @@ import TxStateTableItem from 'ui/tx/state/TxStateTableItem';
interface Props {
data: TxStateChanges;
isLoading?: boolean;
}
const TxStateTable = ({ data }: Props) => {
const TxStateTable = ({ data, isLoading }: Props) => {
return (
<Table variant="simple" minWidth="1000px" size="sm" w="auto" mt={ 6 }>
<Thead top={ 0 }>
......@@ -29,7 +30,7 @@ const TxStateTable = ({ data }: Props) => {
</Tr>
</Thead>
<Tbody>
{ data.map((item, index) => <TxStateTableItem data={ item } key={ index }/>) }
{ data.map((item, index) => <TxStateTableItem data={ item } key={ index } isLoading={ isLoading }/>) }
</Tbody>
</Table>
);
......
import { Tr, Td } from '@chakra-ui/react';
import { Tr, Td, Box } from '@chakra-ui/react';
import React from 'react';
import type { TxStateChange } from 'types/api/txStateChanges';
......@@ -11,26 +11,37 @@ import { getStateElements } from './utils';
interface Props {
data: TxStateChange;
isLoading?: boolean;
}
const TxStateTableItem = ({ data }: Props) => {
const { before, after, change, tag, tokenId } = getStateElements(data);
const TxStateTableItem = ({ data, isLoading }: Props) => {
const { before, after, change, tag, tokenId } = getStateElements(data, isLoading);
return (
<Tr>
<Td lineHeight="30px">
{ tag }
<Td>
<Box py="3px">
{ tag }
</Box>
</Td>
<Td>
<Address height="30px">
<AddressIcon address={ data.address }/>
<AddressLink type="address" hash={ data.address.hash } alias={ data.address.name } fontWeight="500" truncation="constant" ml={ 2 }/>
<Address py="3px">
<AddressIcon address={ data.address } isLoading={ isLoading }/>
<AddressLink
type="address"
hash={ data.address.hash }
alias={ data.address.name }
fontWeight="500"
truncation="constant"
ml={ 2 }
isLoading={ isLoading }
/>
</Address>
</Td>
<Td isNumeric lineHeight="30px">{ before }</Td>
<Td isNumeric lineHeight="30px">{ after }</Td>
<Td isNumeric lineHeight="30px"> { change } </Td>
<Td lineHeight="30px">{ tokenId }</Td>
<Td isNumeric><Box py="7px">{ before }</Box></Td>
<Td isNumeric><Box py="7px">{ after }</Box></Td>
<Td isNumeric><Box py="7px">{ change }</Box></Td>
<Td>{ tokenId }</Td>
</Tr>
);
};
......
......@@ -8,9 +8,10 @@ import type { TxStateChangeNftItemFlatten } from './utils';
interface Props {
items: Array<TxStateChangeNftItemFlatten>;
tokenAddress: string;
isLoading?: boolean;
}
const TxStateTokenIdList = ({ items, tokenAddress }: Props) => {
const TxStateTokenIdList = ({ items, tokenAddress, isLoading }: Props) => {
const [ isCut, setIsCut ] = useBoolean(true);
return (
......@@ -22,6 +23,7 @@ const TxStateTokenIdList = ({ items, tokenAddress }: Props) => {
id={ item.total.token_id }
w="auto"
truncation="constant"
isLoading={ isLoading }
/>
)) }
{ items.length > 3 && (
......
import { Box, Flex, Tag, Tooltip } from '@chakra-ui/react';
import { Flex, Skeleton, Tooltip } from '@chakra-ui/react';
import BigNumber from 'bignumber.js';
import React from 'react';
......@@ -7,19 +7,22 @@ import type { ArrayElement } from 'types/utils';
import appConfig from 'configs/app/config';
import { ZERO_ADDRESS } from 'lib/consts';
import { nbsp } from 'lib/html-entities';
import { nbsp, space } from 'lib/html-entities';
import getNetworkValidatorTitle from 'lib/networks/getNetworkValidatorTitle';
import trimTokenSymbol from 'lib/token/trimTokenSymbol';
import AddressLink from 'ui/shared/address/AddressLink';
import Tag from 'ui/shared/chakra/Tag';
import TxStateTokenIdList from './TxStateTokenIdList';
export function getStateElements(data: TxStateChange) {
export function getStateElements(data: TxStateChange, isLoading?: boolean) {
const tag = (() => {
if (data.is_miner) {
return (
<Tooltip label="A block producer who successfully included the block into the blockchain">
<Tag textTransform="capitalize" colorScheme="yellow">{ getNetworkValidatorTitle() }</Tag>
<Tag textTransform="capitalize" colorScheme="yellow" isLoading={ isLoading }>
{ getNetworkValidatorTitle() }
</Tag>
</Tooltip>
);
}
......@@ -37,7 +40,7 @@ export function getStateElements(data: TxStateChange) {
const text = changeDirection === 'from' ? 'Mint' : 'Burn';
return (
<Tooltip label="Address used in tokens mintings and burnings">
<Tag textTransform="capitalize" colorScheme="yellow">{ text } address</Tag>
<Tag textTransform="capitalize" colorScheme="yellow" isLoading={ isLoading }>{ text } address</Tag>
</Tooltip>
);
}
......@@ -55,14 +58,25 @@ export function getStateElements(data: TxStateChange) {
const changeSign = beforeBn.lte(afterBn) ? '+' : '-';
return {
before: <Box>{ beforeBn.toFormat() } { appConfig.network.currency.symbol }</Box>,
after: <Box>{ afterBn.toFormat() } { appConfig.network.currency.symbol }</Box>,
change: <Box color={ changeColor }>{ changeSign }{ nbsp }{ differenceBn.abs().toFormat() }</Box>,
before: <Skeleton isLoaded={ !isLoading } display="inline-block">{ beforeBn.toFormat() } { appConfig.network.currency.symbol }</Skeleton>,
after: <Skeleton isLoaded={ !isLoading } display="inline-block">{ afterBn.toFormat() } { appConfig.network.currency.symbol }</Skeleton>,
change: (
<Skeleton isLoaded={ !isLoading } display="inline-block" color={ changeColor }>
<span>{ changeSign }{ nbsp }{ differenceBn.abs().toFormat() }</span>
</Skeleton>
),
tag,
};
}
case 'token': {
const tokenLink = <AddressLink type="token" hash={ data.token.address } alias={ trimTokenSymbol(data.token?.symbol || data.token.address) }/>;
const tokenLink = (
<AddressLink
type="token"
hash={ data.token.address }
alias={ trimTokenSymbol(data.token?.symbol || data.token.address) }
isLoading={ isLoading }
/>
);
const before = Number(data.balance_before);
const after = Number(data.balance_after);
const change = (() => {
......@@ -75,7 +89,11 @@ export function getStateElements(data: TxStateChange) {
const changeColor = difference >= 0 ? 'green.500' : 'red.500';
const changeSign = difference >= 0 ? '+' : '-';
return <Box color={ changeColor }>{ changeSign }{ nbsp }{ Math.abs(difference).toLocaleString() }</Box>;
return (
<Skeleton isLoaded={ !isLoading } display="inline-block" color={ changeColor }>
<span>{ changeSign }{ nbsp }{ Math.abs(difference).toLocaleString() }</span>
</Skeleton>
);
})();
const tokenId = (() => {
......@@ -84,19 +102,21 @@ export function getStateElements(data: TxStateChange) {
}
const items = (data.change as Array<TxStateChangeNftItem>).reduce(flattenTotal, []);
return <TxStateTokenIdList items={ items } tokenAddress={ data.token.address }/>;
return <TxStateTokenIdList items={ items } tokenAddress={ data.token.address } isLoading={ isLoading }/>;
})();
return {
before: data.balance_before ? (
<Flex whiteSpace="pre-wrap" justifyContent={{ base: 'flex-start', lg: 'flex-end' }}>
<span>{ before.toLocaleString() } </span>
<Skeleton isLoaded={ !isLoading }>{ before.toLocaleString() }</Skeleton>
<span>{ space }</span>
{ tokenLink }
</Flex>
) : null,
after: data.balance_after ? (
<Flex whiteSpace="pre-wrap" justifyContent={{ base: 'flex-start', lg: 'flex-end' }}>
<span>{ after.toLocaleString() } </span>
<Skeleton isLoaded={ !isLoading }>{ after.toLocaleString() }</Skeleton>
<span>{ space }</span>
{ tokenLink }
</Flex>
) : 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