Commit eae41d10 authored by tom goriunov's avatar tom goriunov Committed by GitHub

Show tags for watch list txs (#1289)

watchlist - show private tag

Fixes #1209
parent 3b49f1d1
......@@ -68,8 +68,25 @@ export const base: Transaction = {
has_error_in_internal_txs: false,
};
export const withWatchListNames: Transaction = {
...base,
hash: '0x62d597ebcf3e8d60096dd0363bc2f0f5e2df27ba1dacd696c51aa7c9409f3194',
from: {
...base.from,
watchlist_names: [
{ label: 'from #1', display_name: 'from utka' },
{ label: 'kitty', display_name: 'kitty kitty kitty cat where are you' },
],
},
to: {
...base.to,
watchlist_names: [ { label: 'to #1', display_name: 'to utka' } ],
} as Transaction['to'],
};
export const withContractCreation: Transaction = {
...base,
hash: '0x62d597ebcf3e8d60096dd0363bc2f0f5e2df27ba1dacd696c51aa7c9409f3195',
to: null,
created_contract: {
hash: '0xdda21946FF3FAa027104b15BE6970CA756439F5a',
......@@ -88,6 +105,7 @@ export const withContractCreation: Transaction = {
export const withTokenTransfer: Transaction = {
...base,
hash: '0x62d597ebcf3e8d60096dd0363bc2f0f5e2df27ba1dacd696c51aa7c9409f3196',
to: {
hash: '0xd789a607CEac2f0E14867de4EB15b15C9FFB5859',
implementation_name: null,
......
......@@ -21,6 +21,7 @@ test.describe('mobile', () => {
txMock.base,
txMock.withContractCreation,
txMock.withTokenTransfer,
txMock.withWatchListNames,
]),
}));
......@@ -41,6 +42,7 @@ test('default view +@dark-mode', async({ mount, page }) => {
txMock.base,
txMock.withContractCreation,
txMock.withTokenTransfer,
txMock.withWatchListNames,
]),
}));
......
......@@ -17,6 +17,7 @@ import useTimeAgoIncrement from 'lib/hooks/useTimeAgoIncrement';
import Icon from 'ui/shared/chakra/Icon';
import AddressEntity from 'ui/shared/entities/address/AddressEntity';
import TxEntity from 'ui/shared/entities/tx/TxEntity';
import TxWatchListTags from 'ui/shared/tx/TxWatchListTags';
import TxStatus from 'ui/shared/TxStatus';
import TxAdditionalInfo from 'ui/txs/TxAdditionalInfo';
import TxType from 'ui/txs/TxType';
......@@ -32,89 +33,92 @@ const LatestTxsItem = ({ tx, isLoading }: Props) => {
const columnNum = config.UI.views.tx.hiddenFields?.value && config.UI.views.tx.hiddenFields?.tx_fee ? 2 : 3;
return (
<Box
<Grid
gridTemplateColumns={ columnNum === 2 ? '3fr 2fr' : '3fr 2fr 150px' }
gridGap={ 8 }
width="100%"
minW="700px"
borderTop="1px solid"
borderColor="divider"
p={ 4 }
_last={{ borderBottom: '1px solid', borderColor: 'divider' }}
display={{ base: 'none', lg: 'block' }}
display={{ base: 'none', lg: 'grid' }}
>
<Grid width="100%" gridTemplateColumns={ columnNum === 2 ? '3fr 2fr' : '3fr 2fr 150px' } gridGap={ 8 }>
<Flex overflow="hidden" w="100%">
<TxAdditionalInfo tx={ tx } isLoading={ isLoading }/>
<Box ml={ 3 } w="calc(100% - 40px)">
<HStack>
<TxType types={ tx.tx_types } isLoading={ isLoading }/>
<TxStatus status={ tx.status } errorText={ tx.status === 'error' ? tx.result : undefined } isLoading={ isLoading }/>
</HStack>
<Flex
mt={ 2 }
alignItems="center"
>
<TxEntity
isLoading={ isLoading }
hash={ tx.hash }
fontWeight="700"
/>
{ tx.timestamp && (
<Skeleton
isLoaded={ !isLoading }
color="text_secondary"
fontWeight="400"
fontSize="sm"
flexShrink={ 0 }
ml={ 2 }
>
<span>{ timeAgo }</span>
</Skeleton>
) }
</Flex>
</Box>
</Flex>
<Grid alignItems="center" templateColumns="24px auto">
<Icon
as={ rightArrowIcon }
boxSize={ 6 }
color="gray.500"
transform="rotate(90deg)"
<Flex overflow="hidden" w="100%">
<TxAdditionalInfo tx={ tx } isLoading={ isLoading }/>
<Box ml={ 3 } w="calc(100% - 40px)">
<HStack flexWrap="wrap">
<TxType types={ tx.tx_types } isLoading={ isLoading }/>
<TxStatus status={ tx.status } errorText={ tx.status === 'error' ? tx.result : undefined } isLoading={ isLoading }/>
<TxWatchListTags tx={ tx } isLoading={ isLoading }/>
</HStack>
<Flex
mt={ 2 }
alignItems="center"
>
<TxEntity
isLoading={ isLoading }
hash={ tx.hash }
fontWeight="700"
/>
{ tx.timestamp && (
<Skeleton
isLoaded={ !isLoading }
color="text_secondary"
fontWeight="400"
fontSize="sm"
flexShrink={ 0 }
ml={ 2 }
>
<span>{ timeAgo }</span>
</Skeleton>
) }
</Flex>
</Box>
</Flex>
<Grid alignItems="center" alignSelf="flex-start" templateColumns="24px auto">
<Icon
as={ rightArrowIcon }
boxSize={ 6 }
color="gray.500"
transform="rotate(90deg)"
isLoading={ isLoading }
/>
<Box overflow="hidden" ml={ 1 }>
<AddressEntity
isLoading={ isLoading }
address={ tx.from }
fontSize="sm"
lineHeight={ 6 }
fontWeight="500"
mb={ 2 }
/>
<Box overflow="hidden" ml={ 1 }>
{ dataTo && (
<AddressEntity
isLoading={ isLoading }
address={ tx.from }
address={ dataTo }
fontSize="sm"
lineHeight={ 6 }
fontWeight="500"
mb={ 2 }
/>
{ dataTo && (
<AddressEntity
isLoading={ isLoading }
address={ dataTo }
fontSize="sm"
fontWeight="500"
/>
) }
</Box>
</Grid>
<Box>
{ !config.UI.views.tx.hiddenFields?.value && (
<Skeleton isLoaded={ !isLoading } mb={ 2 }>
<Text as="span" whiteSpace="pre">{ config.chain.currency.symbol } </Text>
<Text as="span" variant="secondary">{ getValueWithUnit(tx.value).dp(5).toFormat() }</Text>
</Skeleton>
) }
{ !config.UI.views.tx.hiddenFields?.tx_fee && (
<Skeleton isLoaded={ !isLoading }>
<Text as="span">Fee </Text>
<Text as="span" variant="secondary">{ getValueWithUnit(tx.fee.value).dp(5).toFormat() }</Text>
</Skeleton>
) }
</Box>
</Grid>
</Box>
<Box>
{ !config.UI.views.tx.hiddenFields?.value && (
<Skeleton isLoaded={ !isLoading } mb={ 2 }>
<Text as="span" whiteSpace="pre">{ config.chain.currency.symbol } </Text>
<Text as="span" variant="secondary">{ getValueWithUnit(tx.value).dp(5).toFormat() }</Text>
</Skeleton>
) }
{ !config.UI.views.tx.hiddenFields?.tx_fee && (
<Skeleton isLoaded={ !isLoading }>
<Text as="span">Fee </Text>
<Text as="span" variant="secondary">{ getValueWithUnit(tx.fee.value).dp(5).toFormat() }</Text>
</Skeleton>
) }
</Box>
</Grid>
);
};
......
......@@ -16,6 +16,7 @@ import useTimeAgoIncrement from 'lib/hooks/useTimeAgoIncrement';
import Icon from 'ui/shared/chakra/Icon';
import AddressEntity from 'ui/shared/entities/address/AddressEntity';
import TxEntity from 'ui/shared/entities/tx/TxEntity';
import TxWatchListTags from 'ui/shared/tx/TxWatchListTags';
import TxStatus from 'ui/shared/TxStatus';
import TxAdditionalInfo from 'ui/txs/TxAdditionalInfo';
import TxType from 'ui/txs/TxType';
......@@ -39,9 +40,10 @@ const LatestTxsItem = ({ tx, isLoading }: Props) => {
display={{ base: 'block', lg: 'none' }}
>
<Flex justifyContent="space-between">
<HStack>
<HStack flexWrap="wrap">
<TxType types={ tx.tx_types } isLoading={ isLoading }/>
<TxStatus status={ tx.status } errorText={ tx.status === 'error' ? tx.result : undefined } isLoading={ isLoading }/>
<TxWatchListTags tx={ tx } isLoading={ isLoading }/>
</HStack>
<TxAdditionalInfo tx={ tx } isMobile isLoading={ isLoading }/>
</Flex>
......
......@@ -10,6 +10,7 @@ import { TX } from 'stubs/tx';
import LinkInternal from 'ui/shared/LinkInternal';
import LatestTxsItem from './LatestTxsItem';
import LatestTxsItemMobile from './LatestTxsItemMobile';
const LatestWatchlistTxs = () => {
useRedirectForInvalidAuthToken();
......@@ -33,7 +34,16 @@ const LatestWatchlistTxs = () => {
const txsUrl = route({ pathname: '/txs', query: { tab: 'watchlist' } });
return (
<>
<Box mb={{ base: 3, lg: 4 }}>
<Box mb={ 3 } display={{ base: 'block', lg: 'none' }}>
{ data.slice(0, txsCount).map(((tx, index) => (
<LatestTxsItemMobile
key={ tx.hash + (isPlaceholderData ? index : '') }
tx={ tx }
isLoading={ isPlaceholderData }
/>
))) }
</Box>
<Box mb={ 4 } display={{ base: 'none', lg: 'block' }}>
{ data.slice(0, txsCount).map(((tx, index) => (
<LatestTxsItem
key={ tx.hash + (isPlaceholderData ? index : '') }
......
import { Flex } from '@chakra-ui/react';
import React from 'react';
import type { Transaction } from 'types/api/transaction';
import Tag from 'ui/shared/chakra/Tag';
interface Props {
tx: Transaction;
isLoading?: boolean;
}
const TxWatchListTags = ({ tx, isLoading }: Props) => {
const tags = [
...(tx.from?.watchlist_names || []),
...(tx.to?.watchlist_names || []),
].filter(Boolean);
if (tags.length === 0) {
return null;
}
return (
<Flex columnGap={ 2 } rowGap={ 2 } flexWrap="wrap" overflow="hidden" maxW="100%">
{ tags.map((tag) => (
<Tag
key={ tag.label }
isLoading={ isLoading }
isTruncated
// maxW={{ base: '115px', lg: 'initial' }}
colorScheme="gray"
variant="subtle"
>
{ tag.display_name }
</Tag>
)) }
</Flex>
);
};
export default React.memo(TxWatchListTags);
......@@ -11,7 +11,7 @@ test.use({ viewport: devices['iPhone 13 Pro'].viewport });
test('base view +@dark-mode', async({ mount }) => {
const component = await mount(
<TestApp>
<TxsListItem tx={ txMock.base } showBlockInfo/>
<TxsListItem tx={ txMock.withWatchListNames } showBlockInfo/>
</TestApp>,
);
......@@ -21,7 +21,7 @@ test('base view +@dark-mode', async({ mount }) => {
test('with base address', async({ mount }) => {
const component = await mount(
<TestApp>
<TxsListItem tx={ txMock.base } showBlockInfo currentAddress={ txMock.base.from.hash }/>
<TxsListItem tx={ txMock.withWatchListNames } showBlockInfo currentAddress={ txMock.base.from.hash }/>
</TestApp>,
);
......
......@@ -18,6 +18,7 @@ import BlockEntity from 'ui/shared/entities/block/BlockEntity';
import TxEntity from 'ui/shared/entities/tx/TxEntity';
import InOutTag from 'ui/shared/InOutTag';
import ListItemMobile from 'ui/shared/ListItemMobile/ListItemMobile';
import TxWatchListTags from 'ui/shared/tx/TxWatchListTags';
import TxStatus from 'ui/shared/TxStatus';
import TxAdditionalInfo from 'ui/txs/TxAdditionalInfo';
import TxType from 'ui/txs/TxType';
......@@ -44,9 +45,10 @@ const TxsListItem = ({ tx, isLoading, showBlockInfo, currentAddress, enableTimeI
return (
<ListItemMobile display="block" width="100%" isAnimated key={ tx.hash }>
<Flex justifyContent="space-between" mt={ 4 }>
<HStack>
<HStack flexWrap="wrap">
<TxType types={ tx.tx_types } isLoading={ isLoading }/>
<TxStatus status={ tx.status } errorText={ tx.status === 'error' ? tx.result : undefined } isLoading={ isLoading }/>
<TxWatchListTags tx={ tx } isLoading={ isLoading }/>
</HStack>
<TxAdditionalInfo tx={ tx } isMobile isLoading={ isLoading }/>
</Flex>
......
......@@ -13,7 +13,7 @@ test.describe('base view', () => {
const component = await mount(
<TestApp>
{ /* eslint-disable-next-line react/jsx-no-bind */ }
<TxsTable txs={ [ txMock.base, txMock.base ] } sort={ () => () => {} } top={ 0 } showBlockInfo showSocketInfo={ false }/>
<TxsTable txs={ [ txMock.base, txMock.withWatchListNames ] } sort={ () => () => {} } top={ 0 } showBlockInfo showSocketInfo={ false }/>
</TestApp>,
);
......@@ -27,7 +27,7 @@ test.describe('base view', () => {
const component = await mount(
<TestApp>
{ /* eslint-disable-next-line react/jsx-no-bind */ }
<TxsTable txs={ [ txMock.base, txMock.base ] } sort={ () => () => {} } top={ 0 } showBlockInfo showSocketInfo={ false }/>
<TxsTable txs={ [ txMock.base, txMock.withWatchListNames ] } sort={ () => () => {} } top={ 0 } showBlockInfo showSocketInfo={ false }/>
</TestApp>,
);
......
......@@ -23,6 +23,7 @@ import AddressEntity from 'ui/shared/entities/address/AddressEntity';
import BlockEntity from 'ui/shared/entities/block/BlockEntity';
import TxEntity from 'ui/shared/entities/tx/TxEntity';
import InOutTag from 'ui/shared/InOutTag';
import TxWatchListTags from 'ui/shared/tx/TxWatchListTags';
import TxStatus from 'ui/shared/TxStatus';
import TxAdditionalInfo from 'ui/txs/TxAdditionalInfo';
......@@ -95,6 +96,7 @@ const TxsTableItem = ({ tx, showBlockInfo, currentAddress, enableTimeIncrement,
<VStack alignItems="start">
<TxType types={ tx.tx_types } isLoading={ isLoading }/>
<TxStatus status={ tx.status } errorText={ tx.status === 'error' ? tx.result : undefined } isLoading={ isLoading }/>
<TxWatchListTags tx={ tx } isLoading={ isLoading }/>
</VStack>
</Td>
<Td whiteSpace="nowrap">
......
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