Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Highlight same addresses in table views #1463

Merged
merged 24 commits into from
Jan 17, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
60 changes: 60 additions & 0 deletions lib/contexts/addressHighlight.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
import React from 'react';

interface AddressHighlightProviderProps {
children: React.ReactNode;
}

interface TAddressHighlightContext {
highlightedAddress: string | null;
onMouseEnter: (event: React.MouseEvent) => void;
onMouseLeave: (event: React.MouseEvent) => void;
}

export const AddressHighlightContext = React.createContext<TAddressHighlightContext | null>(null);

export function AddressHighlightProvider({ children }: AddressHighlightProviderProps) {
const [ highlightedAddress, setHighlightedAddress ] = React.useState<string | null>(null);
const timeoutId = React.useRef<number | null>(null);

const onMouseEnter = React.useCallback((event: React.MouseEvent) => {
const hash = event.currentTarget.getAttribute('data-hash');
if (hash) {
timeoutId.current = window.setTimeout(() => {
setHighlightedAddress(hash);
}, 100);
}
}, []);

const onMouseLeave = React.useCallback(() => {
setHighlightedAddress(null);
typeof timeoutId.current === 'number' && window.clearTimeout(timeoutId.current);
}, []);

const value = React.useMemo(() => {
return {
highlightedAddress,
onMouseEnter,
onMouseLeave,
};
}, [ highlightedAddress, onMouseEnter, onMouseLeave ]);

React.useEffect(() => {
return () => {
typeof timeoutId.current === 'number' && window.clearTimeout(timeoutId.current);
};
}, []);

return (
<AddressHighlightContext.Provider value={ value }>
{ children }
</AddressHighlightContext.Provider>
);
}

export function useAddressHighlightContext() {
const context = React.useContext(AddressHighlightContext);
if (context === undefined) {
return null;
}
return context;
}
4 changes: 2 additions & 2 deletions ui/address/AddressTxsFilter.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -38,8 +38,8 @@ const AddressTxsFilter = ({ onFilterChange, defaultFilter, isActive, isLoading }
<MenuList zIndex={ 2 }>
<MenuOptionGroup defaultValue={ defaultFilter || 'all' } title="Address" type="radio" onChange={ onFilterChange }>
<MenuItemOption value="all">All</MenuItemOption>
<MenuItemOption value="from">From</MenuItemOption>
<MenuItemOption value="to">To</MenuItemOption>
<MenuItemOption value="from">Outgoing transactions</MenuItemOption>
<MenuItemOption value="to">Incoming transactions</MenuItemOption>
</MenuOptionGroup>
</MenuList>
</Menu>
Expand Down
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
38 changes: 9 additions & 29 deletions ui/address/internals/AddressIntTxsListItem.tsx
Original file line number Diff line number Diff line change
@@ -1,17 +1,15 @@
import { Flex, Box, HStack, Skeleton } from '@chakra-ui/react';
import { Flex, HStack, Skeleton } from '@chakra-ui/react';
import BigNumber from 'bignumber.js';
import React from 'react';

import type { InternalTransaction } from 'types/api/internalTransaction';

import config from 'configs/app';
import dayjs from 'lib/date/dayjs';
import AddressFromTo from 'ui/shared/address/AddressFromTo';
import Tag from 'ui/shared/chakra/Tag';
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 IconSvg from 'ui/shared/IconSvg';
import InOutTag from 'ui/shared/InOutTag';
import ListItemMobile from 'ui/shared/ListItemMobile/ListItemMobile';
import TxStatus from 'ui/shared/statusTag/TxStatus';
import { TX_INTERNALS_ITEMS } from 'ui/tx/internals/utils';
Expand All @@ -35,9 +33,6 @@ const TxInternalsListItem = ({
const typeTitle = TX_INTERNALS_ITEMS.find(({ id }) => id === type)?.title;
const toData = to ? to : createdContract;

const isOut = Boolean(currentAddress && currentAddress === from.hash);
const isIn = Boolean(currentAddress && currentAddress === toData?.hash);

return (
<ListItemMobile rowGap={ 3 }>
<Flex columnGap={ 2 }>
Expand Down Expand Up @@ -65,28 +60,13 @@ const TxInternalsListItem = ({
lineHeight={ 5 }
/>
</HStack>
<Box w="100%" display="flex" columnGap={ 3 }>
<AddressEntity
address={ from }
isLoading={ isLoading }
noLink={ isOut }
noCopy={ isOut }
width="calc((100% - 48px) / 2)"
/>
{ (isIn || isOut) ?
<InOutTag isIn={ isIn } isOut={ isOut } isLoading={ isLoading }/> :
<IconSvg name="arrows/east" boxSize={ 6 } color="gray.500" isLoading={ isLoading }/>
}
{ toData && (
<AddressEntity
address={ toData }
isLoading={ isLoading }
noLink={ isIn }
noCopy={ isIn }
width="calc((100% - 48px) / 2)"
/>
) }
</Box>
<AddressFromTo
from={ from }
to={ toData }
current={ currentAddress }
isLoading={ isLoading }
w="100%"
/>
<HStack spacing={ 3 }>
<Skeleton isLoaded={ !isLoading } fontSize="sm" fontWeight={ 500 }>Value { config.chain.currency.symbol }</Skeleton>
<Skeleton isLoaded={ !isLoading } fontSize="sm" color="text_secondary" minW={ 6 }>
Expand Down
52 changes: 27 additions & 25 deletions ui/address/internals/AddressIntTxsTable.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import React from 'react';
import type { InternalTransaction } from 'types/api/internalTransaction';

import config from 'configs/app';
import { AddressHighlightProvider } from 'lib/contexts/addressHighlight';
import { default as Thead } from 'ui/shared/TheadSticky';

import AddressIntTxsTableItem from './AddressIntTxsTableItem';
Expand All @@ -16,31 +17,32 @@ interface Props {

const AddressIntTxsTable = ({ data, currentAddress, isLoading }: Props) => {
return (
<Table variant="simple" size="sm">
<Thead top={ 80 }>
<Tr>
<Th width="15%">Parent txn hash</Th>
<Th width="15%">Type</Th>
<Th width="10%">Block</Th>
<Th width="20%">From</Th>
<Th width="48px" px={ 0 }/>
<Th width="20%">To</Th>
<Th width="20%" isNumeric>
Value { config.chain.currency.symbol }
</Th>
</Tr>
</Thead>
<Tbody>
{ data.map((item, index) => (
<AddressIntTxsTableItem
key={ item.transaction_hash + '_' + index }
{ ...item }
currentAddress={ currentAddress }
isLoading={ isLoading }
/>
)) }
</Tbody>
</Table>
<AddressHighlightProvider>
<Table variant="simple" size="sm">
<Thead top={ 80 }>
<Tr>
<Th width="15%">Parent txn hash</Th>
<Th width="15%">Type</Th>
<Th width="10%">Block</Th>
<Th width="40%">From/To</Th>
<Th width="20%" isNumeric>
Value { config.chain.currency.symbol }
</Th>
</Tr>
</Thead>
<Tbody>
{ data.map((item, index) => (
<AddressIntTxsTableItem
key={ item.transaction_hash + '_' + index }
{ ...item }
currentAddress={ currentAddress }
isLoading={ isLoading }
/>
)) }
</Tbody>
</Table>
</AddressHighlightProvider>

);
};

Expand Down
31 changes: 5 additions & 26 deletions ui/address/internals/AddressIntTxsTableItem.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,10 @@ import type { InternalTransaction } from 'types/api/internalTransaction';

import config from 'configs/app';
import useTimeAgoIncrement from 'lib/hooks/useTimeAgoIncrement';
import AddressFromTo from 'ui/shared/address/AddressFromTo';
import Tag from 'ui/shared/chakra/Tag';
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 IconSvg from 'ui/shared/IconSvg';
import InOutTag from 'ui/shared/InOutTag';
import TxStatus from 'ui/shared/statusTag/TxStatus';
import { TX_INTERNALS_ITEMS } from 'ui/tx/internals/utils';

Expand All @@ -34,9 +32,6 @@ const AddressIntTxsTableItem = ({
const typeTitle = TX_INTERNALS_ITEMS.find(({ id }) => id === type)?.title;
const toData = to ? to : createdContract;

const isOut = Boolean(currentAddress && currentAddress === from.hash);
const isIn = Boolean(currentAddress && currentAddress === toData?.hash);

const timeAgo = useTimeAgoIncrement(timestamp, true);

return (
Expand Down Expand Up @@ -77,29 +72,13 @@ const AddressIntTxsTableItem = ({
/>
</Td>
<Td verticalAlign="middle">
<AddressEntity
address={ from }
<AddressFromTo
from={ from }
to={ toData }
current={ currentAddress }
isLoading={ isLoading }
noLink={ isOut }
noCopy={ isOut }
/>
</Td>
<Td px={ 0 } verticalAlign="middle">
{ (isIn || isOut) ?
<InOutTag isIn={ isIn } isOut={ isOut } isLoading={ isLoading } w="100%"/> :
<IconSvg name="arrows/east" boxSize={ 6 } color="gray.500" isLoading={ isLoading }/>
}
</Td>
<Td verticalAlign="middle">
{ toData && (
<AddressEntity
address={ toData }
isLoading={ isLoading }
noLink={ isIn }
noCopy={ isIn }
/>
) }
</Td>
<Td isNumeric verticalAlign="middle">
<Skeleton isLoaded={ !isLoading } display="inline-block" minW={ 6 }>
{ BigNumber(value).div(BigNumber(10 ** config.chain.currency.decimals)).toFormat() }
Expand Down
67 changes: 35 additions & 32 deletions ui/blocks/BlocksTable.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import React from 'react';
import type { Block } from 'types/api/block';

import config from 'configs/app';
import { AddressHighlightProvider } from 'lib/contexts/addressHighlight';
import getNetworkValidatorTitle from 'lib/networks/getNetworkValidatorTitle';
import BlocksTableItem from 'ui/blocks/BlocksTableItem';
import * as SocketNewItemsNotice from 'ui/shared/SocketNewItemsNotice';
Expand Down Expand Up @@ -37,43 +38,45 @@ const BlocksTable = ({ data, isLoading, top, page, showSocketInfo, socketInfoNum
(!isRollup && !config.UI.views.block.hiddenFields?.burnt_fees ? FEES_COL_WEIGHT : 0);

return (
<Table variant="simple" minWidth="1040px" size="md" fontWeight={ 500 }>
<Thead top={ top }>
<Tr>
<Th width="125px">Block</Th>
<Th width="120px">Size, bytes</Th>
{ !config.UI.views.block.hiddenFields?.miner &&
<AddressHighlightProvider>
<Table variant="simple" minWidth="1040px" size="md" fontWeight={ 500 }>
<Thead top={ top }>
<Tr>
<Th width="125px">Block</Th>
<Th width="120px">Size, bytes</Th>
{ !config.UI.views.block.hiddenFields?.miner &&
<Th width={ `${ VALIDATOR_COL_WEIGHT / widthBase * 100 }%` } minW="160px">{ capitalize(getNetworkValidatorTitle()) }</Th> }
<Th width="64px" isNumeric>Txn</Th>
<Th width={ `${ GAS_COL_WEIGHT / widthBase * 100 }%` }>Gas used</Th>
{ !isRollup && !config.UI.views.block.hiddenFields?.total_reward &&
<Th width="64px" isNumeric>Txn</Th>
<Th width={ `${ GAS_COL_WEIGHT / widthBase * 100 }%` }>Gas used</Th>
{ !isRollup && !config.UI.views.block.hiddenFields?.total_reward &&
<Th width={ `${ REWARD_COL_WEIGHT / widthBase * 100 }%` }>Reward { config.chain.currency.symbol }</Th> }
{ !isRollup && !config.UI.views.block.hiddenFields?.burnt_fees &&
{ !isRollup && !config.UI.views.block.hiddenFields?.burnt_fees &&
<Th width={ `${ FEES_COL_WEIGHT / widthBase * 100 }%` }>Burnt fees { config.chain.currency.symbol }</Th> }
</Tr>
</Thead>
<Tbody>
{ showSocketInfo && (
<SocketNewItemsNotice.Desktop
url={ window.location.href }
alert={ socketInfoAlert }
num={ socketInfoNum }
type="block"
isLoading={ isLoading }
/>
) }
<AnimatePresence initial={ false }>
{ data.map((item, index) => (
<BlocksTableItem
key={ item.height + (isLoading ? `${ index }_${ page }` : '') }
data={ item }
enableTimeIncrement={ page === 1 && !isLoading }
</Tr>
</Thead>
<Tbody>
{ showSocketInfo && (
<SocketNewItemsNotice.Desktop
url={ window.location.href }
alert={ socketInfoAlert }
num={ socketInfoNum }
type="block"
isLoading={ isLoading }
/>
)) }
</AnimatePresence>
</Tbody>
</Table>
) }
<AnimatePresence initial={ false }>
{ data.map((item, index) => (
<BlocksTableItem
key={ item.height + (isLoading ? `${ index }_${ page }` : '') }
data={ item }
enableTimeIncrement={ page === 1 && !isLoading }
isLoading={ isLoading }
/>
)) }
</AnimatePresence>
</Tbody>
</Table>
</AddressHighlightProvider>
);
};

Expand Down
21 changes: 12 additions & 9 deletions ui/home/LatestTxs.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import React from 'react';
import { route } from 'nextjs-routes';

import useApiQuery from 'lib/api/useApiQuery';
import { AddressHighlightProvider } from 'lib/contexts/addressHighlight';
import useIsMobile from 'lib/hooks/useIsMobile';
import useNewTxsSocket from 'lib/hooks/useNewTxsSocket';
import { TX } from 'stubs/tx';
Expand Down Expand Up @@ -42,15 +43,17 @@ const LatestTransactions = () => {
/>
))) }
</Box>
<Box mb={ 4 } display={{ base: 'none', lg: 'block' }}>
{ data.slice(0, txsCount).map(((tx, index) => (
<LatestTxsItem
key={ tx.hash + (isPlaceholderData ? index : '') }
tx={ tx }
isLoading={ isPlaceholderData }
/>
))) }
</Box>
<AddressHighlightProvider>
<Box mb={ 4 } display={{ base: 'none', lg: 'block' }}>
{ data.slice(0, txsCount).map(((tx, index) => (
<LatestTxsItem
key={ tx.hash + (isPlaceholderData ? index : '') }
tx={ tx }
isLoading={ isPlaceholderData }
/>
))) }
</Box>
</AddressHighlightProvider>
<Flex justifyContent="center">
<LinkInternal fontSize="sm" href={ txsUrl }>View all transactions</LinkInternal>
</Flex>
Expand Down
Loading
Loading