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 6 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;
}
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.
52 changes: 28 additions & 24 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,34 @@ 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>
<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="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>
</Th>
</Tr>
</Thead>
<Tbody>
{ data.map((item, index) => (
<AddressIntTxsTableItem
key={ item.transaction_hash + '_' + index }
{ ...item }
currentAddress={ currentAddress }
isLoading={ isLoading }
/>
)) }
</Tbody>
</Table>
</AddressHighlightProvider>

);
};

Expand Down
4 changes: 4 additions & 0 deletions ui/address/internals/AddressIntTxsTableItem.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,8 @@ const AddressIntTxsTableItem = ({
isLoading={ isLoading }
noLink={ isOut }
noCopy={ isOut }
w="min-content"
maxW="100%"
/>
</Td>
<Td px={ 0 } verticalAlign="middle">
Expand All @@ -97,6 +99,8 @@ const AddressIntTxsTableItem = ({
isLoading={ isLoading }
noLink={ isIn }
noCopy={ isIn }
w="min-content"
maxW="100%"
/>
) }
</Td>
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
36 changes: 21 additions & 15 deletions ui/home/LatestTxsItem.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,10 @@ const LatestTxsItem = ({ tx, isLoading }: Props) => {

return (
<Grid
gridTemplateColumns={ columnNum === 2 ? '3fr 2fr' : '3fr 2fr 150px' }
gridTemplateColumns={{
lg: columnNum === 2 ? '3fr minmax(auto, 160px)' : '3fr minmax(auto, 160px) 150px',
xl: columnNum === 2 ? '3fr minmax(auto, 250px)' : '3fr minmax(auto, 275px) 150px',
}}
gridGap={ 8 }
width="100%"
minW="700px"
Expand All @@ -45,16 +48,17 @@ const LatestTxsItem = ({ tx, isLoading }: Props) => {
display={{ base: 'none', lg: 'grid' }}
>
<Flex overflow="hidden" w="100%">
<TxAdditionalInfo tx={ tx } isLoading={ isLoading }/>
<TxAdditionalInfo tx={ tx } isLoading={ isLoading } my="3px"/>
<Box ml={ 3 } w="calc(100% - 40px)">
<HStack flexWrap="wrap">
<HStack flexWrap="wrap" my="3px">
<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"
mt="7px"
mb="3px"
>
<TxEntity
isLoading={ isLoading }
Expand All @@ -76,43 +80,45 @@ const LatestTxsItem = ({ tx, isLoading }: Props) => {
</Flex>
</Box>
</Flex>
<Grid alignItems="center" alignSelf="flex-start" templateColumns="24px auto">
<Flex alignItems="center" alignSelf="flex-start">
<IconSvg
name="arrows/east"
boxSize={ 6 }
color="gray.500"
transform="rotate(90deg)"
isLoading={ isLoading }
flexShrink={ 0 }
/>
<Box overflow="hidden" ml={ 1 }>
<Flex ml={ 1 } maxW="calc(100% - 24px)" flexDir="column" rowGap="1px">
<AddressEntity
isLoading={ isLoading }
address={ tx.from }
fontSize="sm"
lineHeight={ 6 }
lineHeight={ 5 }
my="5px"
fontWeight="500"
mb={ 2 }
/>
{ dataTo && (
<AddressEntity
isLoading={ isLoading }
address={ dataTo }
fontSize="sm"
lineHeight={ 6 }
lineHeight={ 5 }
my="5px"
fontWeight="500"
/>
) }
</Box>
</Grid>
<Box>
</Flex>
</Flex>
<Flex flexDir="column">
{ !config.UI.views.tx.hiddenFields?.value && (
<Skeleton isLoaded={ !isLoading } mb={ 2 }>
<Skeleton isLoaded={ !isLoading } my="3px">
<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 } display="flex" whiteSpace="pre">
<Skeleton isLoaded={ !isLoading } display="flex" whiteSpace="pre" my="3px">
<Text as="span">Fee </Text>
{ tx.stability_fee ? (
<TxFeeStability data={ tx.stability_fee } accuracy={ 5 } color="text_secondary" hideUsd/>
Expand All @@ -121,7 +127,7 @@ const LatestTxsItem = ({ tx, isLoading }: Props) => {
) }
</Skeleton>
) }
</Box>
</Flex>
</Grid>
);
};
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
Loading