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

Details page: fix line height for rows (#1949)

* refactor block page

* token details

* token instance details

* name domain details

* blob details

* user ops details

* zkEvm and zkSync batch details

* tx details

* address details

* update screenshots
parent 86e33cae
...@@ -10,7 +10,7 @@ import AddressCounterItem from 'ui/address/details/AddressCounterItem'; ...@@ -10,7 +10,7 @@ import AddressCounterItem from 'ui/address/details/AddressCounterItem';
import ServiceDegradationWarning from 'ui/shared/alerts/ServiceDegradationWarning'; import ServiceDegradationWarning from 'ui/shared/alerts/ServiceDegradationWarning';
import isCustomAppError from 'ui/shared/AppError/isCustomAppError'; import isCustomAppError from 'ui/shared/AppError/isCustomAppError';
import DataFetchAlert from 'ui/shared/DataFetchAlert'; import DataFetchAlert from 'ui/shared/DataFetchAlert';
import DetailsInfoItem from 'ui/shared/DetailsInfoItem'; import * as DetailsInfoItem from 'ui/shared/DetailsInfoItem';
import DetailsSponsoredItem from 'ui/shared/DetailsSponsoredItem'; import DetailsSponsoredItem from 'ui/shared/DetailsSponsoredItem';
import AddressEntity from 'ui/shared/entities/address/AddressEntity'; import AddressEntity from 'ui/shared/entities/address/AddressEntity';
import BlockEntity from 'ui/shared/entities/block/BlockEntity'; import BlockEntity from 'ui/shared/entities/block/BlockEntity';
...@@ -92,12 +92,16 @@ const AddressDetails = ({ addressQuery, scrollRef }: Props) => { ...@@ -92,12 +92,16 @@ const AddressDetails = ({ addressQuery, scrollRef }: Props) => {
templateColumns={{ base: 'minmax(0, 1fr)', lg: 'auto minmax(0, 1fr)' }} overflow="hidden" templateColumns={{ base: 'minmax(0, 1fr)', lg: 'auto minmax(0, 1fr)' }} overflow="hidden"
> >
<AddressNameInfo data={ data } isLoading={ addressQuery.isPlaceholderData }/> <AddressNameInfo data={ data } isLoading={ addressQuery.isPlaceholderData }/>
{ data.is_contract && data.creation_tx_hash && data.creator_address_hash && ( { data.is_contract && data.creation_tx_hash && data.creator_address_hash && (
<DetailsInfoItem <>
title="Creator" <DetailsInfoItem.Label
hint="Transaction and address of creation" hint="Transaction and address of creation"
isLoading={ addressQuery.isPlaceholderData } isLoading={ addressQuery.isPlaceholderData }
> >
Creator
</DetailsInfoItem.Label>
<DetailsInfoItem.Value>
<AddressEntity <AddressEntity
address={{ hash: data.creator_address_hash }} address={{ hash: data.creator_address_hash }}
truncation="constant" truncation="constant"
...@@ -105,48 +109,63 @@ const AddressDetails = ({ addressQuery, scrollRef }: Props) => { ...@@ -105,48 +109,63 @@ const AddressDetails = ({ addressQuery, scrollRef }: Props) => {
/> />
<Text whiteSpace="pre"> at txn </Text> <Text whiteSpace="pre"> at txn </Text>
<TxEntity hash={ data.creation_tx_hash } truncation="constant" noIcon noCopy={ false }/> <TxEntity hash={ data.creation_tx_hash } truncation="constant" noIcon noCopy={ false }/>
</DetailsInfoItem> </DetailsInfoItem.Value>
</>
) } ) }
{ data.is_contract && data.implementation_address && ( { data.is_contract && data.implementation_address && (
<DetailsInfoItem <>
title="Implementation" <DetailsInfoItem.Label
hint="Implementation address of the proxy contract" hint="Implementation address of the proxy contract"
columnGap={ 1 }
> >
Implementation
</DetailsInfoItem.Label>
<DetailsInfoItem.Value>
<AddressEntity <AddressEntity
address={{ hash: data.implementation_address, name: data.implementation_name, is_contract: true }} address={{ hash: data.implementation_address, name: data.implementation_name, is_contract: true }}
isLoading={ addressQuery.isPlaceholderData } isLoading={ addressQuery.isPlaceholderData }
noIcon noIcon
/> />
</DetailsInfoItem> </DetailsInfoItem.Value>
</>
) } ) }
<AddressBalance data={ data } isLoading={ addressQuery.isPlaceholderData }/> <AddressBalance data={ data } isLoading={ addressQuery.isPlaceholderData }/>
{ data.has_tokens && ( { data.has_tokens && (
<DetailsInfoItem <>
title="Tokens" <DetailsInfoItem.Label
hint="All tokens in the account and total value" hint="All tokens in the account and total value"
alignSelf="center"
py={ 0 }
> >
{ addressQuery.data ? <TokenSelect onClick={ handleCounterItemClick }/> : <Box py="6px">0</Box> } Tokens
</DetailsInfoItem> </DetailsInfoItem.Label>
<DetailsInfoItem.Value py={ addressQuery.data ? 0 : undefined }>
{ addressQuery.data ? <TokenSelect onClick={ handleCounterItemClick }/> : <Box>0</Box> }
</DetailsInfoItem.Value>
</>
) } ) }
{ (config.features.multichainButton.isEnabled || (data.exchange_rate && data.has_tokens)) && ( { (config.features.multichainButton.isEnabled || (data.exchange_rate && data.has_tokens)) && (
<DetailsInfoItem <>
title="Net worth" <DetailsInfoItem.Label
hint="Total net worth in USD of all tokens for the address" hint="Total net worth in USD of all tokens for the address"
alignSelf="center"
isLoading={ addressQuery.isPlaceholderData } isLoading={ addressQuery.isPlaceholderData }
> >
Net worth
</DetailsInfoItem.Label>
<DetailsInfoItem.Value alignSelf="center">
<AddressNetWorth addressData={ addressQuery.data } addressHash={ addressHash } isLoading={ addressQuery.isPlaceholderData }/> <AddressNetWorth addressData={ addressQuery.data } addressHash={ addressHash } isLoading={ addressQuery.isPlaceholderData }/>
</DetailsInfoItem> </DetailsInfoItem.Value>
</>
) )
} }
<DetailsInfoItem
title="Transactions" <DetailsInfoItem.Label
hint="Number of transactions related to this address" hint="Number of transactions related to this address"
isLoading={ addressQuery.isPlaceholderData || countersQuery.isPlaceholderData } isLoading={ addressQuery.isPlaceholderData || countersQuery.isPlaceholderData }
> >
Transactions
</DetailsInfoItem.Label>
<DetailsInfoItem.Value>
{ addressQuery.data ? ( { addressQuery.data ? (
<AddressCounterItem <AddressCounterItem
prop="transactions_count" prop="transactions_count"
...@@ -158,13 +177,17 @@ const AddressDetails = ({ addressQuery, scrollRef }: Props) => { ...@@ -158,13 +177,17 @@ const AddressDetails = ({ addressQuery, scrollRef }: Props) => {
/> />
) : ) :
0 } 0 }
</DetailsInfoItem> </DetailsInfoItem.Value>
{ data.has_token_transfers && ( { data.has_token_transfers && (
<DetailsInfoItem <>
title="Transfers" <DetailsInfoItem.Label
hint="Number of transfers to/from this address" hint="Number of transfers to/from this address"
isLoading={ addressQuery.isPlaceholderData || countersQuery.isPlaceholderData } isLoading={ addressQuery.isPlaceholderData || countersQuery.isPlaceholderData }
> >
Transfers
</DetailsInfoItem.Label>
<DetailsInfoItem.Value>
{ addressQuery.data ? ( { addressQuery.data ? (
<AddressCounterItem <AddressCounterItem
prop="token_transfers_count" prop="token_transfers_count"
...@@ -176,14 +199,19 @@ const AddressDetails = ({ addressQuery, scrollRef }: Props) => { ...@@ -176,14 +199,19 @@ const AddressDetails = ({ addressQuery, scrollRef }: Props) => {
/> />
) : ) :
0 } 0 }
</DetailsInfoItem> </DetailsInfoItem.Value>
</>
) } ) }
{ countersQuery.data?.gas_usage_count && ( { countersQuery.data?.gas_usage_count && (
<DetailsInfoItem <>
title="Gas used" <DetailsInfoItem.Label
hint="Gas used by the address" hint="Gas used by the address"
isLoading={ addressQuery.isPlaceholderData || countersQuery.isPlaceholderData } isLoading={ addressQuery.isPlaceholderData || countersQuery.isPlaceholderData }
> >
Gas used
</DetailsInfoItem.Label>
<DetailsInfoItem.Value>
{ addressQuery.data ? ( { addressQuery.data ? (
<AddressCounterItem <AddressCounterItem
prop="gas_usage_count" prop="gas_usage_count"
...@@ -195,14 +223,19 @@ const AddressDetails = ({ addressQuery, scrollRef }: Props) => { ...@@ -195,14 +223,19 @@ const AddressDetails = ({ addressQuery, scrollRef }: Props) => {
/> />
) : ) :
0 } 0 }
</DetailsInfoItem> </DetailsInfoItem.Value>
</>
) } ) }
{ data.has_validated_blocks && ( { data.has_validated_blocks && (
<DetailsInfoItem <>
title="Blocks validated" <DetailsInfoItem.Label
hint="Number of blocks validated by this validator" hint="Number of blocks validated by this validator"
isLoading={ addressQuery.isPlaceholderData || countersQuery.isPlaceholderData } isLoading={ addressQuery.isPlaceholderData || countersQuery.isPlaceholderData }
> >
Blocks validated
</DetailsInfoItem.Label>
<DetailsInfoItem.Value>
{ addressQuery.data ? ( { addressQuery.data ? (
<AddressCounterItem <AddressCounterItem
prop="validations_count" prop="validations_count"
...@@ -214,22 +247,27 @@ const AddressDetails = ({ addressQuery, scrollRef }: Props) => { ...@@ -214,22 +247,27 @@ const AddressDetails = ({ addressQuery, scrollRef }: Props) => {
/> />
) : ) :
0 } 0 }
</DetailsInfoItem> </DetailsInfoItem.Value>
</>
) } ) }
{ data.block_number_balance_updated_at && ( { data.block_number_balance_updated_at && (
<DetailsInfoItem <>
title="Last balance update" <DetailsInfoItem.Label
hint="Block number in which the address was updated" hint="Block number in which the address was updated"
alignSelf="center"
py={{ base: '2px', lg: 1 }}
isLoading={ addressQuery.isPlaceholderData } isLoading={ addressQuery.isPlaceholderData }
> >
Last balance update
</DetailsInfoItem.Label>
<DetailsInfoItem.Value>
<BlockEntity <BlockEntity
number={ data.block_number_balance_updated_at } number={ data.block_number_balance_updated_at }
isLoading={ addressQuery.isPlaceholderData } isLoading={ addressQuery.isPlaceholderData }
/> />
</DetailsInfoItem> </DetailsInfoItem.Value>
</>
) } ) }
<DetailsSponsoredItem isLoading={ addressQuery.isPlaceholderData }/> <DetailsSponsoredItem isLoading={ addressQuery.isPlaceholderData }/>
</Grid> </Grid>
</> </>
......
...@@ -10,7 +10,7 @@ import useSocketChannel from 'lib/socket/useSocketChannel'; ...@@ -10,7 +10,7 @@ import useSocketChannel from 'lib/socket/useSocketChannel';
import useSocketMessage from 'lib/socket/useSocketMessage'; import useSocketMessage from 'lib/socket/useSocketMessage';
import { currencyUnits } from 'lib/units'; import { currencyUnits } from 'lib/units';
import CurrencyValue from 'ui/shared/CurrencyValue'; import CurrencyValue from 'ui/shared/CurrencyValue';
import DetailsInfoItem from 'ui/shared/DetailsInfoItem'; import * as DetailsInfoItem from 'ui/shared/DetailsInfoItem';
import NativeTokenIcon from 'ui/shared/NativeTokenIcon'; import NativeTokenIcon from 'ui/shared/NativeTokenIcon';
interface Props { interface Props {
...@@ -66,13 +66,14 @@ const AddressBalance = ({ data, isLoading }: Props) => { ...@@ -66,13 +66,14 @@ const AddressBalance = ({ data, isLoading }: Props) => {
}); });
return ( return (
<DetailsInfoItem <>
title={ `${ currencyUnits.ether } balance` } <DetailsInfoItem.Label
hint={ `Address balance in ${ currencyUnits.ether }. Doesn't include ERC20, ERC721 and ERC1155 tokens` } hint={ `${ currencyUnits.ether } balance` }
flexWrap="nowrap"
alignSelf="center"
isLoading={ isLoading } isLoading={ isLoading }
> >
Balance
</DetailsInfoItem.Label>
<DetailsInfoItem.Value alignSelf="center" flexWrap="nowrap">
<NativeTokenIcon boxSize={ 6 } mr={ 2 } isLoading={ isLoading }/> <NativeTokenIcon boxSize={ 6 } mr={ 2 } isLoading={ isLoading }/>
<CurrencyValue <CurrencyValue
value={ data.coin_balance || '0' } value={ data.coin_balance || '0' }
...@@ -84,7 +85,8 @@ const AddressBalance = ({ data, isLoading }: Props) => { ...@@ -84,7 +85,8 @@ const AddressBalance = ({ data, isLoading }: Props) => {
flexWrap="wrap" flexWrap="wrap"
isLoading={ isLoading } isLoading={ isLoading }
/> />
</DetailsInfoItem> </DetailsInfoItem.Value>
</>
); );
}; };
......
...@@ -3,7 +3,7 @@ import React from 'react'; ...@@ -3,7 +3,7 @@ import React from 'react';
import type { Address } from 'types/api/address'; import type { Address } from 'types/api/address';
import DetailsInfoItem from 'ui/shared/DetailsInfoItem'; import * as DetailsInfoItem from 'ui/shared/DetailsInfoItem';
import TokenEntity from 'ui/shared/entities/token/TokenEntity'; import TokenEntity from 'ui/shared/entities/token/TokenEntity';
interface Props { interface Props {
...@@ -14,46 +14,58 @@ interface Props { ...@@ -14,46 +14,58 @@ interface Props {
const AddressNameInfo = ({ data, isLoading }: Props) => { const AddressNameInfo = ({ data, isLoading }: Props) => {
if (data.token) { if (data.token) {
return ( return (
<DetailsInfoItem <>
title="Token name" <DetailsInfoItem.Label
hint="Token name and symbol" hint="Token name and symbol"
isLoading={ isLoading } isLoading={ isLoading }
> >
Token name
</DetailsInfoItem.Label>
<DetailsInfoItem.Value>
<TokenEntity <TokenEntity
token={ data.token } token={ data.token }
isLoading={ isLoading } isLoading={ isLoading }
noIcon noIcon
noCopy noCopy
/> />
</DetailsInfoItem> </DetailsInfoItem.Value>
</>
); );
} }
if (data.is_contract && data.name) { if (data.is_contract && data.name) {
return ( return (
<DetailsInfoItem <>
title="Contract name" <DetailsInfoItem.Label
hint="The name found in the source code of the Contract" hint="The name found in the source code of the Contract"
isLoading={ isLoading } isLoading={ isLoading }
> >
Contract name
</DetailsInfoItem.Label>
<DetailsInfoItem.Value>
<Skeleton isLoaded={ !isLoading }> <Skeleton isLoaded={ !isLoading }>
{ data.name } { data.name }
</Skeleton> </Skeleton>
</DetailsInfoItem> </DetailsInfoItem.Value>
</>
); );
} }
if (data.name) { if (data.name) {
return ( return (
<DetailsInfoItem <>
title="Validator name" <DetailsInfoItem.Label
hint="The name of the validator" hint="The name of the validator"
isLoading={ isLoading } isLoading={ isLoading }
> >
Validator name
</DetailsInfoItem.Label>
<DetailsInfoItem.Value>
<Skeleton isLoaded={ !isLoading }> <Skeleton isLoaded={ !isLoading }>
{ data.name } { data.name }
</Skeleton> </Skeleton>
</DetailsInfoItem> </DetailsInfoItem.Value>
</>
); );
} }
......
...@@ -55,7 +55,7 @@ const TokenSelect = ({ onClick }: Props) => { ...@@ -55,7 +55,7 @@ const TokenSelect = ({ onClick }: Props) => {
} }
return ( return (
<Flex columnGap={ 3 } mt={{ base: '6px', lg: 0 }}> <Flex columnGap={ 3 } mt={{ base: 1, lg: 0 }}>
{ isMobile ? { isMobile ?
<TokenSelectMobile data={ data } isLoading={ tokensIsFetching === 1 }/> : <TokenSelectMobile data={ data } isLoading={ tokensIsFetching === 1 }/> :
<TokenSelectDesktop data={ data } isLoading={ tokensIsFetching === 1 }/> <TokenSelectDesktop data={ data } isLoading={ tokensIsFetching === 1 }/>
......
...@@ -4,7 +4,7 @@ import React from 'react'; ...@@ -4,7 +4,7 @@ import React from 'react';
import type { Blob } from 'types/api/blobs'; import type { Blob } from 'types/api/blobs';
import CopyToClipboard from 'ui/shared/CopyToClipboard'; import CopyToClipboard from 'ui/shared/CopyToClipboard';
import DetailsInfoItem from 'ui/shared/DetailsInfoItem'; import * as DetailsInfoItem from 'ui/shared/DetailsInfoItem';
import DetailsInfoItemDivider from 'ui/shared/DetailsInfoItemDivider'; import DetailsInfoItemDivider from 'ui/shared/DetailsInfoItemDivider';
import DetailsSponsoredItem from 'ui/shared/DetailsSponsoredItem'; import DetailsSponsoredItem from 'ui/shared/DetailsSponsoredItem';
import TxEntity from 'ui/shared/entities/tx/TxEntity'; import TxEntity from 'ui/shared/entities/tx/TxEntity';
...@@ -30,53 +30,73 @@ const BlobInfo = ({ data, isLoading }: Props) => { ...@@ -30,53 +30,73 @@ const BlobInfo = ({ data, isLoading }: Props) => {
</Skeleton> </Skeleton>
</GridItem> </GridItem>
) } ) }
{ data.kzg_proof && ( { data.kzg_proof && (
<DetailsInfoItem <>
title="Proof" <DetailsInfoItem.Label
hint="Zero knowledge proof. Allows for quick verification of commitment" hint="Zero knowledge proof. Allows for quick verification of commitment"
isLoading={ isLoading } isLoading={ isLoading }
> >
Proof
</DetailsInfoItem.Label>
<DetailsInfoItem.Value>
<Skeleton isLoaded={ !isLoading } overflow="hidden" whiteSpace="pre-wrap" wordBreak="break-all" lineHeight={ 6 } my="-2px"> <Skeleton isLoaded={ !isLoading } overflow="hidden" whiteSpace="pre-wrap" wordBreak="break-all" lineHeight={ 6 } my="-2px">
{ data.kzg_proof } { data.kzg_proof }
<CopyToClipboard text={ data.kzg_proof } isLoading={ isLoading }/> <CopyToClipboard text={ data.kzg_proof } isLoading={ isLoading }/>
</Skeleton> </Skeleton>
</DetailsInfoItem> </DetailsInfoItem.Value>
</>
) } ) }
{ data.kzg_commitment && ( { data.kzg_commitment && (
<DetailsInfoItem <>
title="Commitment" <DetailsInfoItem.Label
hint="Commitment to the data in the blob" hint="Commitment to the data in the blob"
isLoading={ isLoading } isLoading={ isLoading }
> >
Commitment
</DetailsInfoItem.Label>
<DetailsInfoItem.Value>
<Skeleton isLoaded={ !isLoading } overflow="hidden" whiteSpace="pre-wrap" wordBreak="break-all" lineHeight={ 6 } my="-2px"> <Skeleton isLoaded={ !isLoading } overflow="hidden" whiteSpace="pre-wrap" wordBreak="break-all" lineHeight={ 6 } my="-2px">
{ data.kzg_commitment } { data.kzg_commitment }
<CopyToClipboard text={ data.kzg_commitment } isLoading={ isLoading }/> <CopyToClipboard text={ data.kzg_commitment } isLoading={ isLoading }/>
</Skeleton> </Skeleton>
</DetailsInfoItem> </DetailsInfoItem.Value>
</>
) } ) }
{ data.blob_data && ( { data.blob_data && (
<DetailsInfoItem <>
title="Size, bytes" <DetailsInfoItem.Label
hint="Blob size in bytes" hint="Blob size in bytes"
isLoading={ isLoading } isLoading={ isLoading }
> >
Size, bytes
</DetailsInfoItem.Label>
<DetailsInfoItem.Value>
<Skeleton isLoaded={ !isLoading } overflow="hidden" whiteSpace="pre-wrap" wordBreak="break-all"> <Skeleton isLoaded={ !isLoading } overflow="hidden" whiteSpace="pre-wrap" wordBreak="break-all">
{ (data.blob_data.replace('0x', '').length / 2).toLocaleString() } { (data.blob_data.replace('0x', '').length / 2).toLocaleString() }
</Skeleton> </Skeleton>
</DetailsInfoItem> </DetailsInfoItem.Value>
</>
) } ) }
{ data.blob_data && <DetailsInfoItemDivider/> } { data.blob_data && <DetailsInfoItemDivider/> }
{ data.transaction_hashes[0] && ( { data.transaction_hashes[0] && (
<DetailsInfoItem <>
title="Transaction hash" <DetailsInfoItem.Label
hint="Hash of the transaction with this blob" hint="Hash of the transaction with this blob"
isLoading={ isLoading } isLoading={ isLoading }
> >
Transaction hash
</DetailsInfoItem.Label>
<DetailsInfoItem.Value>
<TxEntity hash={ data.transaction_hashes[0].transaction_hash } isLoading={ isLoading } noIcon noCopy={ false }/> <TxEntity hash={ data.transaction_hashes[0].transaction_hash } isLoading={ isLoading } noIcon noCopy={ false }/>
</DetailsInfoItem> </DetailsInfoItem.Value>
</>
) } ) }
<DetailsSponsoredItem isLoading={ isLoading }/> <DetailsSponsoredItem isLoading={ isLoading }/>
{ data.blob_data && ( { data.blob_data && (
......
This diff is collapsed.
...@@ -7,7 +7,7 @@ import type { Block } from 'types/api/block'; ...@@ -7,7 +7,7 @@ import type { Block } from 'types/api/block';
import { WEI, WEI_IN_GWEI, ZERO } from 'lib/consts'; import { WEI, WEI_IN_GWEI, ZERO } from 'lib/consts';
import { space } from 'lib/html-entities'; import { space } from 'lib/html-entities';
import { currencyUnits } from 'lib/units'; import { currencyUnits } from 'lib/units';
import DetailsInfoItem from 'ui/shared/DetailsInfoItem'; import * as DetailsInfoItem from 'ui/shared/DetailsInfoItem';
import DetailsInfoItemDivider from 'ui/shared/DetailsInfoItemDivider'; import DetailsInfoItemDivider from 'ui/shared/DetailsInfoItemDivider';
import IconSvg from 'ui/shared/IconSvg'; import IconSvg from 'ui/shared/IconSvg';
import Utilization from 'ui/shared/Utilization/Utilization'; import Utilization from 'ui/shared/Utilization/Utilization';
...@@ -33,30 +33,41 @@ const BlockDetailsBlobInfo = ({ data }: Props) => { ...@@ -33,30 +33,41 @@ const BlockDetailsBlobInfo = ({ data }: Props) => {
<> <>
{ data.blob_gas_price && ( { data.blob_gas_price && (
<DetailsInfoItem <>
title="Blob gas price" <DetailsInfoItem.Label
// eslint-disable-next-line max-len // eslint-disable-next-line max-len
hint="Price per unit of gas used for for blob deployment. Blob gas is independent of normal gas. Both gas prices can affect the priority of transaction execution." hint="Price per unit of gas used for for blob deployment. Blob gas is independent of normal gas. Both gas prices can affect the priority of transaction execution."
> >
Blob gas price
</DetailsInfoItem.Label>
<DetailsInfoItem.Value>
<Text>{ BigNumber(data.blob_gas_price).dividedBy(WEI).toFixed() } { currencyUnits.ether } </Text> <Text>{ BigNumber(data.blob_gas_price).dividedBy(WEI).toFixed() } { currencyUnits.ether } </Text>
<Text variant="secondary" whiteSpace="pre"> <Text variant="secondary" whiteSpace="pre">
{ space }({ BigNumber(data.blob_gas_price).dividedBy(WEI_IN_GWEI).toFixed() } { currencyUnits.gwei }) { space }({ BigNumber(data.blob_gas_price).dividedBy(WEI_IN_GWEI).toFixed() } { currencyUnits.gwei })
</Text> </Text>
</DetailsInfoItem> </DetailsInfoItem.Value>
</>
) } ) }
{ data.blob_gas_used && ( { data.blob_gas_used && (
<DetailsInfoItem <>
title="Blob gas used" <DetailsInfoItem.Label
hint="Actual amount of gas used by the blobs in this block" hint="Actual amount of gas used by the blobs in this block"
> >
Blob gas used
</DetailsInfoItem.Label>
<DetailsInfoItem.Value>
<Text>{ BigNumber(data.blob_gas_used).toFormat() }</Text> <Text>{ BigNumber(data.blob_gas_used).toFormat() }</Text>
</DetailsInfoItem> </DetailsInfoItem.Value>
</>
) } ) }
{ !burntBlobFees.isEqualTo(ZERO) && ( { !burntBlobFees.isEqualTo(ZERO) && (
<DetailsInfoItem <>
title="Blob burnt fees" <DetailsInfoItem.Label
hint={ `Amount of ${ currencyUnits.ether } used for blobs in this block` } hint={ `Amount of ${ currencyUnits.ether } used for blobs in this block` }
> >
Blob burnt fees
</DetailsInfoItem.Label>
<DetailsInfoItem.Value>
<IconSvg name="flame" boxSize={ 5 } color="gray.500" mr={ 2 }/> <IconSvg name="flame" boxSize={ 5 } color="gray.500" mr={ 2 }/>
{ burntBlobFees.dividedBy(WEI).toFixed() } { currencyUnits.ether } { burntBlobFees.dividedBy(WEI).toFixed() } { currencyUnits.ether }
{ !blobFees.isEqualTo(ZERO) && ( { !blobFees.isEqualTo(ZERO) && (
...@@ -66,18 +77,23 @@ const BlockDetailsBlobInfo = ({ data }: Props) => { ...@@ -66,18 +77,23 @@ const BlockDetailsBlobInfo = ({ data }: Props) => {
</div> </div>
</Tooltip> </Tooltip>
) } ) }
</DetailsInfoItem> </DetailsInfoItem.Value>
</>
) } ) }
{ data.excess_blob_gas && ( { data.excess_blob_gas && (
<DetailsInfoItem <>
title="Excess blob gas" <DetailsInfoItem.Label
hint="A running total of blob gas consumed in excess of the target, prior to the block." hint="A running total of blob gas consumed in excess of the target, prior to the block."
> >
Excess blob gas
</DetailsInfoItem.Label>
<DetailsInfoItem.Value>
<Text>{ BigNumber(data.excess_blob_gas).dividedBy(WEI).toFixed() } { currencyUnits.ether } </Text> <Text>{ BigNumber(data.excess_blob_gas).dividedBy(WEI).toFixed() } { currencyUnits.ether } </Text>
<Text variant="secondary" whiteSpace="pre"> <Text variant="secondary" whiteSpace="pre">
{ space }({ BigNumber(data.excess_blob_gas).dividedBy(WEI_IN_GWEI).toFixed() } { currencyUnits.gwei }) { space }({ BigNumber(data.excess_blob_gas).dividedBy(WEI_IN_GWEI).toFixed() } { currencyUnits.gwei })
</Text> </Text>
</DetailsInfoItem> </DetailsInfoItem.Value>
</>
) } ) }
<DetailsInfoItemDivider/> <DetailsInfoItemDivider/>
</> </>
......
...@@ -8,7 +8,7 @@ import { route } from 'nextjs-routes'; ...@@ -8,7 +8,7 @@ import { route } from 'nextjs-routes';
import type { ResourceError } from 'lib/api/resources'; import type { ResourceError } from 'lib/api/resources';
import dayjs from 'lib/date/dayjs'; import dayjs from 'lib/date/dayjs';
import DetailsInfoItem from 'ui/shared/DetailsInfoItem'; import * as DetailsInfoItem from 'ui/shared/DetailsInfoItem';
import AddressEntity from 'ui/shared/entities/address/AddressEntity'; import AddressEntity from 'ui/shared/entities/address/AddressEntity';
import NftEntity from 'ui/shared/entities/nft/NftEntity'; import NftEntity from 'ui/shared/entities/nft/NftEntity';
import IconSvg from 'ui/shared/IconSvg'; import IconSvg from 'ui/shared/IconSvg';
...@@ -30,25 +30,32 @@ const NameDomainDetails = ({ query }: Props) => { ...@@ -30,25 +30,32 @@ const NameDomainDetails = ({ query }: Props) => {
return ( return (
<Grid columnGap={ 8 } rowGap={ 3 } templateColumns={{ base: 'minmax(0, 1fr)', lg: 'max-content minmax(728px, auto)' }}> <Grid columnGap={ 8 } rowGap={ 3 } templateColumns={{ base: 'minmax(0, 1fr)', lg: 'max-content minmax(728px, auto)' }}>
{ query.data?.registration_date && ( { query.data?.registration_date && (
<DetailsInfoItem <>
title="Registration date" <DetailsInfoItem.Label
hint="The date the name was registered" hint="The date the name was registered"
isLoading={ isLoading } isLoading={ isLoading }
> >
Registration date
</DetailsInfoItem.Label>
<DetailsInfoItem.Value>
<IconSvg name="clock" boxSize={ 5 } color="gray.500" verticalAlign="middle" isLoading={ isLoading } mr={ 2 }/> <IconSvg name="clock" boxSize={ 5 } color="gray.500" verticalAlign="middle" isLoading={ isLoading } mr={ 2 }/>
<Skeleton isLoaded={ !isLoading } display="inline" whiteSpace="pre-wrap" lineHeight="20px"> <Skeleton isLoaded={ !isLoading } display="inline" whiteSpace="pre-wrap" lineHeight="20px">
{ dayjs(query.data.registration_date).format('llll') } { dayjs(query.data.registration_date).format('llll') }
</Skeleton> </Skeleton>
</DetailsInfoItem> </DetailsInfoItem.Value>
</>
) } ) }
{ query.data?.expiry_date && ( { query.data?.expiry_date && (
<DetailsInfoItem <>
title="Expiration date" <DetailsInfoItem.Label
// eslint-disable-next-line max-len // eslint-disable-next-line max-len
hint="The date the name expires, upon which there is a 90 day grace period for the owner to renew. After the 90 days, the name is released to the market" hint="The date the name expires, upon which there is a 90 day grace period for the owner to renew. After the 90 days, the name is released to the market"
isLoading={ isLoading } isLoading={ isLoading }
display="inline-block"
> >
Expiration date
</DetailsInfoItem.Label>
<DetailsInfoItem.Value>
<IconSvg name="clock" boxSize={ 5 } color="gray.500" verticalAlign="middle" isLoading={ isLoading } mr={ 2 } mt="-2px"/> <IconSvg name="clock" boxSize={ 5 } color="gray.500" verticalAlign="middle" isLoading={ isLoading } mr={ 2 } mt="-2px"/>
{ hasExpired && ( { hasExpired && (
<> <>
...@@ -65,13 +72,19 @@ const NameDomainDetails = ({ query }: Props) => { ...@@ -65,13 +72,19 @@ const NameDomainDetails = ({ query }: Props) => {
<Skeleton isLoaded={ !isLoading } color="text_secondary" display="inline"> <Skeleton isLoaded={ !isLoading } color="text_secondary" display="inline">
<NameDomainExpiryStatus date={ query.data?.expiry_date }/> <NameDomainExpiryStatus date={ query.data?.expiry_date }/>
</Skeleton> </Skeleton>
</DetailsInfoItem> </DetailsInfoItem.Value>
</>
) } ) }
{ query.data?.registrant && ( { query.data?.registrant && (
<DetailsInfoItem <>
title="Registrant" <DetailsInfoItem.Label
hint="The account that owns the domain name and has the rights to edit its ownership and records" hint="The account that owns the domain name and has the rights to edit its ownership and records"
isLoading={ isLoading } isLoading={ isLoading }
>
Registrant
</DetailsInfoItem.Label>
<DetailsInfoItem.Value
columnGap={ 2 } columnGap={ 2 }
flexWrap="nowrap" flexWrap="nowrap"
> >
...@@ -88,13 +101,19 @@ const NameDomainDetails = ({ query }: Props) => { ...@@ -88,13 +101,19 @@ const NameDomainDetails = ({ query }: Props) => {
<IconSvg name="search" boxSize={ 5 } isLoading={ isLoading }/> <IconSvg name="search" boxSize={ 5 } isLoading={ isLoading }/>
</LinkInternal> </LinkInternal>
</Tooltip> </Tooltip>
</DetailsInfoItem> </DetailsInfoItem.Value>
</>
) } ) }
{ query.data?.owner && ( { query.data?.owner && (
<DetailsInfoItem <>
title="Owner" <DetailsInfoItem.Label
hint="The account that owns the rights to edit the records of this domain name" hint="The account that owns the rights to edit the records of this domain name"
isLoading={ isLoading } isLoading={ isLoading }
>
Owner
</DetailsInfoItem.Label>
<DetailsInfoItem.Value
columnGap={ 2 } columnGap={ 2 }
flexWrap="nowrap" flexWrap="nowrap"
> >
...@@ -111,13 +130,19 @@ const NameDomainDetails = ({ query }: Props) => { ...@@ -111,13 +130,19 @@ const NameDomainDetails = ({ query }: Props) => {
<IconSvg name="search" boxSize={ 5 } isLoading={ isLoading }/> <IconSvg name="search" boxSize={ 5 } isLoading={ isLoading }/>
</LinkInternal> </LinkInternal>
</Tooltip> </Tooltip>
</DetailsInfoItem> </DetailsInfoItem.Value>
</>
) } ) }
{ query.data?.wrapped_owner && ( { query.data?.wrapped_owner && (
<DetailsInfoItem <>
title="Manager" <DetailsInfoItem.Label
hint="Owner of this NFT domain in NameWrapper contract" hint="Owner of this NFT domain in NameWrapper contract"
isLoading={ isLoading } isLoading={ isLoading }
>
Manager
</DetailsInfoItem.Label>
<DetailsInfoItem.Value
columnGap={ 2 } columnGap={ 2 }
flexWrap="nowrap" flexWrap="nowrap"
> >
...@@ -134,25 +159,36 @@ const NameDomainDetails = ({ query }: Props) => { ...@@ -134,25 +159,36 @@ const NameDomainDetails = ({ query }: Props) => {
<IconSvg name="search" boxSize={ 5 } isLoading={ isLoading }/> <IconSvg name="search" boxSize={ 5 } isLoading={ isLoading }/>
</LinkInternal> </LinkInternal>
</Tooltip> </Tooltip>
</DetailsInfoItem> </DetailsInfoItem.Value>
</>
) } ) }
{ query.data?.tokens.map((token) => ( { query.data?.tokens.map((token) => (
<DetailsInfoItem <React.Fragment key={ token.type }>
key={ token.type } <DetailsInfoItem.Label
title={ token.type === 'WRAPPED_DOMAIN_TOKEN' ? 'Wrapped token ID' : 'Token ID' }
hint={ `The ${ token.type === 'WRAPPED_DOMAIN_TOKEN' ? 'wrapped ' : '' }token ID of this domain name NFT` } hint={ `The ${ token.type === 'WRAPPED_DOMAIN_TOKEN' ? 'wrapped ' : '' }token ID of this domain name NFT` }
isLoading={ isLoading } isLoading={ isLoading }
>
{ token.type === 'WRAPPED_DOMAIN_TOKEN' ? 'Wrapped token ID' : 'Token ID' }
</DetailsInfoItem.Label>
<DetailsInfoItem.Value
wordBreak="break-all" wordBreak="break-all"
whiteSpace="pre-wrap" whiteSpace="pre-wrap"
> >
<NftEntity hash={ token.contract_hash } id={ token.id } isLoading={ isLoading } noIcon/> <NftEntity hash={ token.contract_hash } id={ token.id } isLoading={ isLoading } noIcon/>
</DetailsInfoItem> </DetailsInfoItem.Value>
</React.Fragment>
)) } )) }
{ otherAddresses.length > 0 && ( { otherAddresses.length > 0 && (
<DetailsInfoItem <>
title="Other addresses" <DetailsInfoItem.Label
hint="Other cryptocurrency addresses added to this domain name" hint="Other cryptocurrency addresses added to this domain name"
isLoading={ isLoading } isLoading={ isLoading }
>
Other addresses
</DetailsInfoItem.Label>
<DetailsInfoItem.Value
flexDir="column" flexDir="column"
alignItems="flex-start" alignItems="flex-start"
> >
...@@ -167,7 +203,8 @@ const NameDomainDetails = ({ query }: Props) => { ...@@ -167,7 +203,8 @@ const NameDomainDetails = ({ query }: Props) => {
/> />
</Flex> </Flex>
)) } )) }
</DetailsInfoItem> </DetailsInfoItem.Value>
</>
) } ) }
</Grid> </Grid>
); );
......
import { Text } from '@chakra-ui/react';
import React from 'react'; import React from 'react';
import ContainerWithScrollY from 'ui/shared/ContainerWithScrollY'; import ContainerWithScrollY from 'ui/shared/ContainerWithScrollY';
import DetailsInfoItem from 'ui/shared/DetailsInfoItem'; import * as DetailsInfoItem from 'ui/shared/DetailsInfoItem';
export const TX_ACTIONS_BLOCK_ID = 'tx-actions'; export const TX_ACTIONS_BLOCK_ID = 'tx-actions';
const SCROLL_GRADIENT_HEIGHT = 48; const SCROLL_GRADIENT_HEIGHT = 48;
...@@ -25,12 +26,16 @@ const DetailsActionsWrapper = ({ children, isLoading, type }: Props) => { ...@@ -25,12 +26,16 @@ const DetailsActionsWrapper = ({ children, isLoading, type }: Props) => {
}, []); }, []);
return ( return (
<DetailsInfoItem <>
title={ `${ type === 'tx' ? 'Transaction' : 'User operation' } action` } <DetailsInfoItem.Label
hint={ `Highlighted events of the ${ type === 'tx' ? 'transaction' : 'user operation' }` } hint={ `Highlighted events of the ${ type === 'tx' ? 'transaction' : 'user operation' }` }
note={ hasScroll ? 'Scroll to see more' : undefined }
position="relative"
isLoading={ isLoading } isLoading={ isLoading }
>
<span>{ `${ type === 'tx' ? 'Transaction' : 'User operation' } action` }</span>
{ hasScroll && <Text fontWeight={ 500 } variant="secondary" fontSize="xs" className="note" align="right">Scroll to see more</Text> }
</DetailsInfoItem.Label>
<DetailsInfoItem.Value
position="relative"
> >
<ContainerWithScrollY <ContainerWithScrollY
containerId={ TX_ACTIONS_BLOCK_ID } containerId={ TX_ACTIONS_BLOCK_ID }
...@@ -44,7 +49,9 @@ const DetailsActionsWrapper = ({ children, isLoading, type }: Props) => { ...@@ -44,7 +49,9 @@ const DetailsActionsWrapper = ({ children, isLoading, type }: Props) => {
> >
{ children } { children }
</ContainerWithScrollY> </ContainerWithScrollY>
</DetailsInfoItem> </DetailsInfoItem.Value>
</>
); );
}; };
......
import { GridItem, Flex, Text, Skeleton } from '@chakra-ui/react'; import { chakra, GridItem, Flex, Skeleton } from '@chakra-ui/react';
import type { HTMLChakraProps } from '@chakra-ui/system';
import React from 'react'; import React from 'react';
import Hint from 'ui/shared/Hint'; import Hint from 'ui/shared/Hint';
interface Props extends Omit<HTMLChakraProps<'div'>, 'title'> { interface LabelProps {
title: React.ReactNode;
hint?: string; hint?: string;
children: React.ReactNode; children: React.ReactNode;
note?: string;
isLoading?: boolean; isLoading?: boolean;
className?: string;
id?: string;
} }
const DetailsInfoItem = ({ title, hint, note, children, id, isLoading, ...styles }: Props) => { const Label = chakra(({ hint, children, isLoading, id, className }: LabelProps) => {
return ( return (
<> <GridItem
<GridItem py={{ base: 1, lg: 2 }} id={ id } lineHeight={ 5 } { ...styles } _notFirst={{ mt: { base: 3, lg: 0 } }}> id={ id }
className={ className }
py={ 1 }
lineHeight={{ base: 5, lg: 6 }}
_notFirst={{ mt: { base: 3, lg: 0 } }}
>
<Flex columnGap={ 2 } alignItems="flex-start"> <Flex columnGap={ 2 } alignItems="flex-start">
{ hint && <Hint label={ hint } isLoading={ isLoading }/> } { hint && <Hint label={ hint } isLoading={ isLoading } my={{ lg: '2px' }}/> }
<Skeleton isLoaded={ !isLoading }> <Skeleton isLoaded={ !isLoading } fontWeight={{ base: 700, lg: 500 }}>
<Text fontWeight={{ base: 700, lg: 500 }}> { children }
{ title }
{ note && <Text fontWeight={ 500 } variant="secondary" fontSize="xs" className="note" align="right">{ note }</Text> }
</Text>
</Skeleton> </Skeleton>
</Flex> </Flex>
</GridItem> </GridItem>
);
});
interface ValueProps {
children: React.ReactNode;
className?: string;
}
const Value = chakra(({ children, className }: ValueProps) => {
return (
<GridItem <GridItem
className={ className }
display="flex" display="flex"
alignItems="center" alignItems="center"
flexWrap="wrap" flexWrap="wrap"
rowGap={ 3 } rowGap={ 3 }
pl={{ base: 7, lg: 0 }} pl={{ base: 7, lg: 0 }}
py={{ base: 1, lg: 2 }} py={ 1 }
lineHeight={ 5 } lineHeight={{ base: 5, lg: 6 }}
whiteSpace="nowrap" whiteSpace="nowrap"
{ ...styles }
> >
{ children } { children }
</GridItem> </GridItem>
</>
); );
}; });
export default DetailsInfoItem; export {
Label,
Value,
};
...@@ -5,7 +5,7 @@ import config from 'configs/app'; ...@@ -5,7 +5,7 @@ import config from 'configs/app';
import * as cookies from 'lib/cookies'; import * as cookies from 'lib/cookies';
import useIsMobile from 'lib/hooks/useIsMobile'; import useIsMobile from 'lib/hooks/useIsMobile';
import AdBanner from 'ui/shared/ad/AdBanner'; import AdBanner from 'ui/shared/ad/AdBanner';
import DetailsInfoItem from 'ui/shared/DetailsInfoItem'; import * as DetailsInfoItem from 'ui/shared/DetailsInfoItem';
const feature = config.features.adsBanner; const feature = config.features.adsBanner;
...@@ -30,13 +30,17 @@ const DetailsSponsoredItem = ({ isLoading }: Props) => { ...@@ -30,13 +30,17 @@ const DetailsSponsoredItem = ({ isLoading }: Props) => {
} }
return ( return (
<DetailsInfoItem <>
title="Sponsored" <DetailsInfoItem.Label
hint="Sponsored banner advertisement" hint="Sponsored banner advertisement"
isLoading={ isLoading } isLoading={ isLoading }
> >
Sponsored
</DetailsInfoItem.Label>
<DetailsInfoItem.Value>
<AdBanner isLoading={ isLoading }/> <AdBanner isLoading={ isLoading }/>
</DetailsInfoItem> </DetailsInfoItem.Value>
</>
); );
}; };
......
...@@ -32,7 +32,7 @@ const PrevNext = ({ className, onClick, prevLabel, nextLabel, isPrevDisabled, is ...@@ -32,7 +32,7 @@ const PrevNext = ({ className, onClick, prevLabel, nextLabel, isPrevDisabled, is
} }
return ( return (
<Box className={ className }> <Box className={ className } display="flex">
<Tooltip label={ prevLabel }> <Tooltip label={ prevLabel }>
<IconButton <IconButton
aria-label="prev" aria-label="prev"
......
...@@ -18,7 +18,7 @@ import { TOKEN_COUNTERS } from 'stubs/token'; ...@@ -18,7 +18,7 @@ import { TOKEN_COUNTERS } from 'stubs/token';
import type { TokenTabs } from 'ui/pages/Token'; import type { TokenTabs } from 'ui/pages/Token';
import AppActionButton from 'ui/shared/AppActionButton/AppActionButton'; import AppActionButton from 'ui/shared/AppActionButton/AppActionButton';
import useAppActionData from 'ui/shared/AppActionButton/useAppActionData'; import useAppActionData from 'ui/shared/AppActionButton/useAppActionData';
import DetailsInfoItem from 'ui/shared/DetailsInfoItem'; import * as DetailsInfoItem from 'ui/shared/DetailsInfoItem';
import DetailsSponsoredItem from 'ui/shared/DetailsSponsoredItem'; import DetailsSponsoredItem from 'ui/shared/DetailsSponsoredItem';
import TruncatedValue from 'ui/shared/TruncatedValue'; import TruncatedValue from 'ui/shared/TruncatedValue';
...@@ -102,77 +102,96 @@ const TokenDetails = ({ tokenQuery }: Props) => { ...@@ -102,77 +102,96 @@ const TokenDetails = ({ tokenQuery }: Props) => {
<Grid <Grid
columnGap={ 8 } columnGap={ 8 }
rowGap={{ base: 1, lg: 3 }} rowGap={{ base: 1, lg: 3 }}
templateColumns={{ base: 'minmax(0, 1fr)', lg: 'auto minmax(0, 1fr)' }} overflow="hidden" templateColumns={{ base: 'minmax(0, 1fr)', lg: 'auto minmax(728px, auto)' }} overflow="hidden"
> >
{ exchangeRate && ( { exchangeRate && (
<DetailsInfoItem <>
title="Price" <DetailsInfoItem.Label
hint="Price per token on the exchanges" hint="Price per token on the exchanges"
alignSelf="center"
isLoading={ tokenQuery.isPlaceholderData } isLoading={ tokenQuery.isPlaceholderData }
> >
Price
</DetailsInfoItem.Label>
<DetailsInfoItem.Value>
<Skeleton isLoaded={ !tokenQuery.isPlaceholderData } display="inline-block"> <Skeleton isLoaded={ !tokenQuery.isPlaceholderData } display="inline-block">
<span>{ `$${ Number(exchangeRate).toLocaleString(undefined, { minimumSignificantDigits: 4 }) }` }</span> <span>{ `$${ Number(exchangeRate).toLocaleString(undefined, { minimumSignificantDigits: 4 }) }` }</span>
</Skeleton> </Skeleton>
</DetailsInfoItem> </DetailsInfoItem.Value>
</>
) } ) }
{ marketCap && ( { marketCap && (
<DetailsInfoItem <>
title="Fully diluted market cap" <DetailsInfoItem.Label
hint="Total supply * Price" hint="Total supply * Price"
alignSelf="center"
isLoading={ tokenQuery.isPlaceholderData } isLoading={ tokenQuery.isPlaceholderData }
> >
Fully diluted market cap
</DetailsInfoItem.Label>
<DetailsInfoItem.Value>
<Skeleton isLoaded={ !tokenQuery.isPlaceholderData } display="inline-block"> <Skeleton isLoaded={ !tokenQuery.isPlaceholderData } display="inline-block">
<span>{ `$${ BigNumber(marketCap).toFormat() }` }</span> <span>{ `$${ BigNumber(marketCap).toFormat() }` }</span>
</Skeleton> </Skeleton>
</DetailsInfoItem> </DetailsInfoItem.Value>
</>
) } ) }
<DetailsInfoItem
title="Max total supply" <DetailsInfoItem.Label
hint="The total amount of tokens issued" hint="The total amount of tokens issued"
isLoading={ tokenQuery.isPlaceholderData }
>
Max total supply
</DetailsInfoItem.Label>
<DetailsInfoItem.Value
alignSelf="center" alignSelf="center"
wordBreak="break-word" wordBreak="break-word"
whiteSpace="pre-wrap" whiteSpace="pre-wrap"
isLoading={ tokenQuery.isPlaceholderData }
> >
<Skeleton isLoaded={ !tokenQuery.isPlaceholderData } w="100%" display="flex"> <Skeleton isLoaded={ !tokenQuery.isPlaceholderData } w="100%" display="flex">
<TruncatedValue value={ totalSupplyValue || '0' } maxW="80%" flexShrink={ 0 }/> <TruncatedValue value={ totalSupplyValue || '0' } maxW="80%" flexShrink={ 0 }/>
<Box flexShrink={ 0 }> </Box> <Box flexShrink={ 0 }> </Box>
<TruncatedValue value={ symbol || '' }/> <TruncatedValue value={ symbol || '' }/>
</Skeleton> </Skeleton>
</DetailsInfoItem> </DetailsInfoItem.Value>
<DetailsInfoItem
title="Holders" <DetailsInfoItem.Label
hint="Number of accounts holding the token" hint="Number of accounts holding the token"
alignSelf="center"
isLoading={ tokenQuery.isPlaceholderData } isLoading={ tokenQuery.isPlaceholderData }
> >
Holders
</DetailsInfoItem.Label>
<DetailsInfoItem.Value>
<Skeleton isLoaded={ !tokenCountersQuery.isPlaceholderData }> <Skeleton isLoaded={ !tokenCountersQuery.isPlaceholderData }>
{ countersItem('token_holders_count') } { countersItem('token_holders_count') }
</Skeleton> </Skeleton>
</DetailsInfoItem> </DetailsInfoItem.Value>
<DetailsInfoItem
title="Transfers" <DetailsInfoItem.Label
hint="Number of transfer for the token" hint="Number of transfer for the token"
alignSelf="center"
isLoading={ tokenQuery.isPlaceholderData } isLoading={ tokenQuery.isPlaceholderData }
> >
Transfers
</DetailsInfoItem.Label>
<DetailsInfoItem.Value>
<Skeleton isLoaded={ !tokenCountersQuery.isPlaceholderData }> <Skeleton isLoaded={ !tokenCountersQuery.isPlaceholderData }>
{ countersItem('transfers_count') } { countersItem('transfers_count') }
</Skeleton> </Skeleton>
</DetailsInfoItem> </DetailsInfoItem.Value>
{ decimals && ( { decimals && (
<DetailsInfoItem <>
title="Decimals" <DetailsInfoItem.Label
hint="Number of digits that come after the decimal place when displaying token value" hint="Number of digits that come after the decimal place when displaying token value"
alignSelf="center"
isLoading={ tokenQuery.isPlaceholderData } isLoading={ tokenQuery.isPlaceholderData }
> >
Decimals
</DetailsInfoItem.Label>
<DetailsInfoItem.Value>
<Skeleton isLoaded={ !tokenQuery.isPlaceholderData } minW={ 6 }> <Skeleton isLoaded={ !tokenQuery.isPlaceholderData } minW={ 6 }>
{ decimals } { decimals }
</Skeleton> </Skeleton>
</DetailsInfoItem> </DetailsInfoItem.Value>
</>
) } ) }
{ type !== 'ERC-20' && ( { type !== 'ERC-20' && (
...@@ -186,14 +205,18 @@ const TokenDetails = ({ tokenQuery }: Props) => { ...@@ -186,14 +205,18 @@ const TokenDetails = ({ tokenQuery }: Props) => {
) } ) }
{ (type !== 'ERC-20' && config.UI.views.nft.marketplaces.length === 0 && appActionData && isActionButtonExperiment) && ( { (type !== 'ERC-20' && config.UI.views.nft.marketplaces.length === 0 && appActionData && isActionButtonExperiment) && (
<DetailsInfoItem <>
title="Dapp" <DetailsInfoItem.Label
hint="Link to the dapp" hint="Link to the dapp"
alignSelf="center" >
py={ 1 } Dapp
</DetailsInfoItem.Label>
<DetailsInfoItem.Value
py="1px"
> >
<AppActionButton data={ appActionData } height="30px" source="NFT collection"/> <AppActionButton data={ appActionData } height="30px" source="NFT collection"/>
</DetailsInfoItem> </DetailsInfoItem.Value>
</>
) } ) }
<DetailsSponsoredItem isLoading={ tokenQuery.isPlaceholderData }/> <DetailsSponsoredItem isLoading={ tokenQuery.isPlaceholderData }/>
......
...@@ -5,7 +5,7 @@ import type { AddressMetadataTagFormatted } from 'types/client/addressMetadata'; ...@@ -5,7 +5,7 @@ import type { AddressMetadataTagFormatted } from 'types/client/addressMetadata';
import config from 'configs/app'; import config from 'configs/app';
import AppActionButton from 'ui/shared/AppActionButton/AppActionButton'; import AppActionButton from 'ui/shared/AppActionButton/AppActionButton';
import DetailsInfoItem from 'ui/shared/DetailsInfoItem'; import * as DetailsInfoItem from 'ui/shared/DetailsInfoItem';
import TextSeparator from 'ui/shared/TextSeparator'; import TextSeparator from 'ui/shared/TextSeparator';
interface Props { interface Props {
...@@ -23,12 +23,15 @@ const TokenNftMarketplaces = ({ hash, id, isLoading, appActionData, source, isAc ...@@ -23,12 +23,15 @@ const TokenNftMarketplaces = ({ hash, id, isLoading, appActionData, source, isAc
} }
return ( return (
<DetailsInfoItem <>
title="Marketplaces" <DetailsInfoItem.Label
hint="Marketplaces trading this NFT" hint="Marketplaces trading this NFT"
alignSelf="center"
isLoading={ isLoading } isLoading={ isLoading }
py={ (appActionData && isActionButtonExperiment) ? 1 : { base: 1, lg: 2 } } >
Marketplaces
</DetailsInfoItem.Label>
<DetailsInfoItem.Value
py={ (appActionData && isActionButtonExperiment) ? '1px' : '6px' }
> >
<Skeleton isLoaded={ !isLoading } display="flex" columnGap={ 3 } flexWrap="wrap" alignItems="center"> <Skeleton isLoaded={ !isLoading } display="flex" columnGap={ 3 } flexWrap="wrap" alignItems="center">
{ config.UI.views.nft.marketplaces.map((item) => { { config.UI.views.nft.marketplaces.map((item) => {
...@@ -56,7 +59,8 @@ const TokenNftMarketplaces = ({ hash, id, isLoading, appActionData, source, isAc ...@@ -56,7 +59,8 @@ const TokenNftMarketplaces = ({ hash, id, isLoading, appActionData, source, isAc
</> </>
) } ) }
</Skeleton> </Skeleton>
</DetailsInfoItem> </DetailsInfoItem.Value>
</>
); );
}; };
......
...@@ -8,7 +8,7 @@ import useFeatureValue from 'lib/growthbook/useFeatureValue'; ...@@ -8,7 +8,7 @@ import useFeatureValue from 'lib/growthbook/useFeatureValue';
import AppActionButton from 'ui/shared/AppActionButton/AppActionButton'; import AppActionButton from 'ui/shared/AppActionButton/AppActionButton';
import useAppActionData from 'ui/shared/AppActionButton/useAppActionData'; import useAppActionData from 'ui/shared/AppActionButton/useAppActionData';
import CopyToClipboard from 'ui/shared/CopyToClipboard'; import CopyToClipboard from 'ui/shared/CopyToClipboard';
import DetailsInfoItem from 'ui/shared/DetailsInfoItem'; import * as DetailsInfoItem from 'ui/shared/DetailsInfoItem';
import DetailsInfoItemDivider from 'ui/shared/DetailsInfoItemDivider'; import DetailsInfoItemDivider from 'ui/shared/DetailsInfoItemDivider';
import DetailsSponsoredItem from 'ui/shared/DetailsSponsoredItem'; import DetailsSponsoredItem from 'ui/shared/DetailsSponsoredItem';
import AddressEntity from 'ui/shared/entities/address/AddressEntity'; import AddressEntity from 'ui/shared/entities/address/AddressEntity';
...@@ -53,31 +53,41 @@ const TokenInstanceDetails = ({ data, token, scrollRef, isLoading }: Props) => { ...@@ -53,31 +53,41 @@ const TokenInstanceDetails = ({ data, token, scrollRef, isLoading }: Props) => {
overflow="hidden" overflow="hidden"
> >
{ data.is_unique && data.owner && ( { data.is_unique && data.owner && (
<DetailsInfoItem <>
title="Owner" <DetailsInfoItem.Label
hint="Current owner of this token instance" hint="Current owner of this token instance"
isLoading={ isLoading } isLoading={ isLoading }
> >
Owner
</DetailsInfoItem.Label>
<DetailsInfoItem.Value>
<AddressEntity <AddressEntity
address={ data.owner } address={ data.owner }
isLoading={ isLoading } isLoading={ isLoading }
/> />
</DetailsInfoItem> </DetailsInfoItem.Value>
</>
) } ) }
<TokenInstanceCreatorAddress hash={ isLoading ? '' : token.address }/> <TokenInstanceCreatorAddress hash={ isLoading ? '' : token.address }/>
<DetailsInfoItem
title="Token ID" <DetailsInfoItem.Label
hint="This token instance unique token ID" hint="This token instance unique token ID"
isLoading={ isLoading } isLoading={ isLoading }
> >
Token ID
</DetailsInfoItem.Label>
<DetailsInfoItem.Value>
<Flex alignItems="center" overflow="hidden"> <Flex alignItems="center" overflow="hidden">
<Skeleton isLoaded={ !isLoading } overflow="hidden" display="inline-block" w="100%"> <Skeleton isLoaded={ !isLoading } overflow="hidden" display="inline-block" w="100%">
<HashStringShortenDynamic hash={ data.id }/> <HashStringShortenDynamic hash={ data.id }/>
</Skeleton> </Skeleton>
<CopyToClipboard text={ data.id } isLoading={ isLoading }/> <CopyToClipboard text={ data.id } isLoading={ isLoading }/>
</Flex> </Flex>
</DetailsInfoItem> </DetailsInfoItem.Value>
<TokenInstanceTransfersCount hash={ isLoading ? '' : token.address } id={ isLoading ? '' : data.id } onClick={ handleCounterItemClick }/> <TokenInstanceTransfersCount hash={ isLoading ? '' : token.address } id={ isLoading ? '' : data.id } onClick={ handleCounterItemClick }/>
<TokenNftMarketplaces <TokenNftMarketplaces
isLoading={ isLoading } isLoading={ isLoading }
hash={ token.address } hash={ token.address }
...@@ -86,15 +96,18 @@ const TokenInstanceDetails = ({ data, token, scrollRef, isLoading }: Props) => { ...@@ -86,15 +96,18 @@ const TokenInstanceDetails = ({ data, token, scrollRef, isLoading }: Props) => {
source="NFT item" source="NFT item"
isActionButtonExperiment={ isActionButtonExperiment } isActionButtonExperiment={ isActionButtonExperiment }
/> />
{ (config.UI.views.nft.marketplaces.length === 0 && appActionData && isActionButtonExperiment) && ( { (config.UI.views.nft.marketplaces.length === 0 && appActionData && isActionButtonExperiment) && (
<DetailsInfoItem <>
title="Dapp" <DetailsInfoItem.Label
hint="Link to the dapp" hint="Link to the dapp"
alignSelf="center"
py={ 1 }
> >
Dapp
</DetailsInfoItem.Label>
<DetailsInfoItem.Value py="1px">
<AppActionButton data={ appActionData } height="30px" source="NFT item"/> <AppActionButton data={ appActionData } height="30px" source="NFT item"/>
</DetailsInfoItem> </DetailsInfoItem.Value>
</>
) } ) }
</Grid> </Grid>
<NftMedia <NftMedia
......
...@@ -2,7 +2,7 @@ import React from 'react'; ...@@ -2,7 +2,7 @@ import React from 'react';
import useApiQuery from 'lib/api/useApiQuery'; import useApiQuery from 'lib/api/useApiQuery';
import { ADDRESS_INFO } from 'stubs/address'; import { ADDRESS_INFO } from 'stubs/address';
import DetailsInfoItem from 'ui/shared/DetailsInfoItem'; import * as DetailsInfoItem from 'ui/shared/DetailsInfoItem';
import AddressEntity from 'ui/shared/entities/address/AddressEntity'; import AddressEntity from 'ui/shared/entities/address/AddressEntity';
interface Props { interface Props {
...@@ -33,16 +33,20 @@ const TokenInstanceCreatorAddress = ({ hash }: Props) => { ...@@ -33,16 +33,20 @@ const TokenInstanceCreatorAddress = ({ hash }: Props) => {
}; };
return ( return (
<DetailsInfoItem <>
title="Creator" <DetailsInfoItem.Label
hint="Address that deployed this token contract" hint="Address that deployed this token contract"
isLoading={ addressQuery.isPlaceholderData } isLoading={ addressQuery.isPlaceholderData }
> >
Creator
</DetailsInfoItem.Label>
<DetailsInfoItem.Value>
<AddressEntity <AddressEntity
address={ creatorAddress } address={ creatorAddress }
isLoading={ addressQuery.isPlaceholderData } isLoading={ addressQuery.isPlaceholderData }
/> />
</DetailsInfoItem> </DetailsInfoItem.Value>
</>
); );
}; };
......
...@@ -5,7 +5,7 @@ import type { TokenInstance } from 'types/api/token'; ...@@ -5,7 +5,7 @@ import type { TokenInstance } from 'types/api/token';
import type { MetadataAttributes } from 'types/client/token'; import type { MetadataAttributes } from 'types/client/token';
import parseMetadata from 'lib/token/parseMetadata'; import parseMetadata from 'lib/token/parseMetadata';
import DetailsInfoItem from 'ui/shared/DetailsInfoItem'; import * as DetailsInfoItem from 'ui/shared/DetailsInfoItem';
import DetailsInfoItemDivider from 'ui/shared/DetailsInfoItemDivider'; import DetailsInfoItemDivider from 'ui/shared/DetailsInfoItemDivider';
import LinkExternal from 'ui/shared/links/LinkExternal'; import LinkExternal from 'ui/shared/links/LinkExternal';
import TruncatedValue from 'ui/shared/TruncatedValue'; import TruncatedValue from 'ui/shared/TruncatedValue';
...@@ -74,42 +74,55 @@ const TokenInstanceMetadataInfo = ({ data, isLoading }: Props) => { ...@@ -74,42 +74,55 @@ const TokenInstanceMetadataInfo = ({ data, isLoading }: Props) => {
<> <>
<DetailsInfoItemDivider/> <DetailsInfoItemDivider/>
{ metadata?.name && ( { metadata?.name && (
<DetailsInfoItem <>
title="Name" <DetailsInfoItem.Label
hint="NFT name" hint="NFT name"
isLoading={ isLoading }
>
Name
</DetailsInfoItem.Label>
<DetailsInfoItem.Value
whiteSpace="normal" whiteSpace="normal"
wordBreak="break-word" wordBreak="break-word"
isLoading={ isLoading }
> >
<Skeleton isLoaded={ !isLoading }> <Skeleton isLoaded={ !isLoading }>
{ metadata.name } { metadata.name }
</Skeleton> </Skeleton>
</DetailsInfoItem> </DetailsInfoItem.Value>
</>
) } ) }
{ metadata?.description && ( { metadata?.description && (
<DetailsInfoItem <>
title="Description" <DetailsInfoItem.Label
hint="NFT description" hint="NFT description"
isLoading={ isLoading }
>
Description
</DetailsInfoItem.Label>
<DetailsInfoItem.Value
whiteSpace="normal" whiteSpace="normal"
wordBreak="break-word" wordBreak="break-word"
isLoading={ isLoading }
> >
<Skeleton isLoaded={ !isLoading }> <Skeleton isLoaded={ !isLoading }>
{ metadata.description } { metadata.description }
</Skeleton> </Skeleton>
</DetailsInfoItem> </DetailsInfoItem.Value>
</>
) } ) }
{ metadata?.attributes && ( { metadata?.attributes && (
<DetailsInfoItem <>
title="Attributes" <DetailsInfoItem.Label
hint="NFT attributes" hint="NFT attributes"
whiteSpace="normal"
isLoading={ isLoading } isLoading={ isLoading }
> >
<Grid gap={ 2 } templateColumns="repeat(auto-fill,minmax(160px, 1fr))" w="100%"> Attributes
</DetailsInfoItem.Label>
<DetailsInfoItem.Value>
<Grid gap={ 2 } templateColumns="repeat(auto-fill,minmax(160px, 1fr))" w="100%" whiteSpace="normal">
{ metadata.attributes.map((attribute, index) => <Item key={ index } data={ attribute } isLoading={ isLoading }/>) } { metadata.attributes.map((attribute, index) => <Item key={ index } data={ attribute } isLoading={ isLoading }/>) }
</Grid> </Grid>
</DetailsInfoItem> </DetailsInfoItem.Value>
</>
) } ) }
</> </>
); );
......
...@@ -4,7 +4,7 @@ import React from 'react'; ...@@ -4,7 +4,7 @@ import React from 'react';
import { route } from 'nextjs-routes'; import { route } from 'nextjs-routes';
import useApiQuery from 'lib/api/useApiQuery'; import useApiQuery from 'lib/api/useApiQuery';
import DetailsInfoItem from 'ui/shared/DetailsInfoItem'; import * as DetailsInfoItem from 'ui/shared/DetailsInfoItem';
import LinkInternal from 'ui/shared/links/LinkInternal'; import LinkInternal from 'ui/shared/links/LinkInternal';
interface Props { interface Props {
...@@ -37,11 +37,14 @@ const TokenInstanceTransfersCount = ({ hash, id, onClick }: Props) => { ...@@ -37,11 +37,14 @@ const TokenInstanceTransfersCount = ({ hash, id, onClick }: Props) => {
undefined; undefined;
return ( return (
<DetailsInfoItem <>
title="Transfers" <DetailsInfoItem.Label
hint="Number of transfer for the token instance" hint="Number of transfer for the token instance"
isLoading={ transfersCountQuery.isPlaceholderData } isLoading={ transfersCountQuery.isPlaceholderData }
> >
Transfers
</DetailsInfoItem.Label>
<DetailsInfoItem.Value>
<Skeleton isLoaded={ !transfersCountQuery.isPlaceholderData } display="inline-block"> <Skeleton isLoaded={ !transfersCountQuery.isPlaceholderData } display="inline-block">
<LinkInternal <LinkInternal
href={ url } href={ url }
...@@ -50,7 +53,8 @@ const TokenInstanceTransfersCount = ({ hash, id, onClick }: Props) => { ...@@ -50,7 +53,8 @@ const TokenInstanceTransfersCount = ({ hash, id, onClick }: Props) => {
{ transfersCountQuery.data.transfers_count.toLocaleString() } { transfersCountQuery.data.transfers_count.toLocaleString() }
</LinkInternal> </LinkInternal>
</Skeleton> </Skeleton>
</DetailsInfoItem> </DetailsInfoItem.Value>
</>
); );
}; };
......
import { Flex, Link, useBoolean } from '@chakra-ui/react'; import { Flex, Link, useBoolean } from '@chakra-ui/react';
import React from 'react'; import React from 'react';
import DetailsInfoItem from 'ui/shared/DetailsInfoItem'; import * as DetailsInfoItem from 'ui/shared/DetailsInfoItem';
import AddressEntity from 'ui/shared/entities/address/AddressEntity'; import AddressEntity from 'ui/shared/entities/address/AddressEntity';
interface Props { interface Props {
...@@ -14,10 +14,13 @@ const TxAllowedPeekers = ({ items }: Props) => { ...@@ -14,10 +14,13 @@ const TxAllowedPeekers = ({ items }: Props) => {
const [ isExpanded, expand ] = useBoolean(false); const [ isExpanded, expand ] = useBoolean(false);
return ( return (
<DetailsInfoItem <>
title="Allowed peekers" <DetailsInfoItem.Label
hint="Smart contracts allowed to interact with confidential data" hint="Smart contracts allowed to interact with confidential data"
> >
Allowed peekers
</DetailsInfoItem.Label>
<DetailsInfoItem.Value>
<Flex flexDir="column" rowGap={ 3 } w="100%"> <Flex flexDir="column" rowGap={ 3 } w="100%">
{ items { items
.slice(0, isExpanded ? undefined : CUT_LENGTH) .slice(0, isExpanded ? undefined : CUT_LENGTH)
...@@ -34,7 +37,8 @@ const TxAllowedPeekers = ({ items }: Props) => { ...@@ -34,7 +37,8 @@ const TxAllowedPeekers = ({ items }: Props) => {
{ isExpanded ? 'Hide' : 'Show all' } { isExpanded ? 'Hide' : 'Show all' }
</Link> </Link>
) } ) }
</DetailsInfoItem> </DetailsInfoItem.Value>
</>
); );
}; };
......
...@@ -8,7 +8,7 @@ import type { ExcludeUndefined } from 'types/utils'; ...@@ -8,7 +8,7 @@ import type { ExcludeUndefined } from 'types/utils';
import { currencyUnits } from 'lib/units'; import { currencyUnits } from 'lib/units';
import Tag from 'ui/shared/chakra/Tag'; import Tag from 'ui/shared/chakra/Tag';
import CurrencyValue from 'ui/shared/CurrencyValue'; import CurrencyValue from 'ui/shared/CurrencyValue';
import DetailsInfoItem from 'ui/shared/DetailsInfoItem'; import * as DetailsInfoItem from 'ui/shared/DetailsInfoItem';
import DetailsInfoItemDivider from 'ui/shared/DetailsInfoItemDivider'; import DetailsInfoItemDivider from 'ui/shared/DetailsInfoItemDivider';
import AddressEntity from 'ui/shared/entities/address/AddressEntity'; import AddressEntity from 'ui/shared/entities/address/AddressEntity';
import TxEntity from 'ui/shared/entities/tx/TxEntity'; import TxEntity from 'ui/shared/entities/tx/TxEntity';
...@@ -24,85 +24,110 @@ interface Props { ...@@ -24,85 +24,110 @@ interface Props {
const TxDetailsWrapped = ({ data }: Props) => { const TxDetailsWrapped = ({ data }: Props) => {
return ( return (
<Grid columnGap={ 8 } rowGap={{ base: 3, lg: 3 }} templateColumns={{ base: 'minmax(0, 1fr)', lg: 'auto minmax(0, 1fr)' }}> <Grid columnGap={ 8 } rowGap={{ base: 3, lg: 3 }} templateColumns={{ base: 'minmax(0, 1fr)', lg: 'auto minmax(0, 1fr)' }}>
<DetailsInfoItem <DetailsInfoItem.Label
title="Transaction hash"
hint="Unique character string (TxID) assigned to every verified transaction" hint="Unique character string (TxID) assigned to every verified transaction"
flexWrap="nowrap"
> >
Transaction hash
</DetailsInfoItem.Label>
<DetailsInfoItem.Value flexWrap="nowrap">
<TxEntity hash={ data.hash } noIcon noLink noCopy={ false }/> <TxEntity hash={ data.hash } noIcon noLink noCopy={ false }/>
</DetailsInfoItem> </DetailsInfoItem.Value>
<DetailsInfoItem
title="Method" <DetailsInfoItem.Label
hint="Transaction method name" hint="Transaction method name"
> >
Method
</DetailsInfoItem.Label>
<DetailsInfoItem.Value>
<Tag colorScheme="gray"> <Tag colorScheme="gray">
{ data.method } { data.method }
</Tag> </Tag>
</DetailsInfoItem> </DetailsInfoItem.Value>
<DetailsInfoItemDivider/> <DetailsInfoItemDivider/>
<DetailsInfoItem <DetailsInfoItem.Label
title={ data.to?.is_contract ? 'Interacted with contract' : 'To' }
hint="Address (external or contract) receiving the transaction" hint="Address (external or contract) receiving the transaction"
flexWrap={{ base: 'wrap', lg: 'nowrap' }}
columnGap={ 3 }
> >
{ data.to?.is_contract ? 'Interacted with contract' : 'To' }
</DetailsInfoItem.Label>
<DetailsInfoItem.Value>
<Flex flexWrap="nowrap" alignItems="center" maxW="100%"> <Flex flexWrap="nowrap" alignItems="center" maxW="100%">
<AddressEntity address={ data.to }/> <AddressEntity address={ data.to }/>
</Flex> </Flex>
</DetailsInfoItem> </DetailsInfoItem.Value>
<DetailsInfoItemDivider/> <DetailsInfoItemDivider/>
<DetailsInfoItem <DetailsInfoItem.Label
title="Value"
hint="Value sent in the native token (and USD) if applicable" hint="Value sent in the native token (and USD) if applicable"
> >
Value
</DetailsInfoItem.Label>
<DetailsInfoItem.Value>
<CurrencyValue <CurrencyValue
value={ data.value } value={ data.value }
currency={ currencyUnits.ether } currency={ currencyUnits.ether }
flexWrap="wrap" flexWrap="wrap"
/> />
</DetailsInfoItem> </DetailsInfoItem.Value>
{ data.fee.value !== null && ( { data.fee.value !== null && (
<DetailsInfoItem <>
title="Transaction fee" <DetailsInfoItem.Label
hint="Total transaction fee" hint="Total transaction fee"
> >
Transaction fee
</DetailsInfoItem.Label>
<DetailsInfoItem.Value>
<CurrencyValue <CurrencyValue
value={ data.fee.value } value={ data.fee.value }
currency={ currencyUnits.ether } currency={ currencyUnits.ether }
flexWrap="wrap" flexWrap="wrap"
/> />
</DetailsInfoItem> </DetailsInfoItem.Value>
</>
) } ) }
<TxDetailsGasPrice gasPrice={ data.gas_price }/> <TxDetailsGasPrice gasPrice={ data.gas_price }/>
{ data.gas_limit && ( { data.gas_limit && (
<DetailsInfoItem <>
title="Gas limit" <DetailsInfoItem.Label
hint="Maximum amount of gas that can be used by the transaction" hint="Maximum amount of gas that can be used by the transaction"
> >
Gas limit
</DetailsInfoItem.Label>
<DetailsInfoItem.Value>
{ BigNumber(data.gas_limit).toFormat() } { BigNumber(data.gas_limit).toFormat() }
</DetailsInfoItem> </DetailsInfoItem.Value>
</>
) } ) }
<DetailsInfoItemDivider/> <DetailsInfoItemDivider/>
<TxDetailsOther type={ data.type } nonce={ data.nonce } position={ null }/> <TxDetailsOther type={ data.type } nonce={ data.nonce } position={ null }/>
<DetailsInfoItem
title="Raw input" <DetailsInfoItem.Label
hint="Binary data included with the transaction. See logs tab for additional info" hint="Binary data included with the transaction. See logs tab for additional info"
> >
Raw input
</DetailsInfoItem.Label>
<DetailsInfoItem.Value>
<RawInputData hex={ data.raw_input }/> <RawInputData hex={ data.raw_input }/>
</DetailsInfoItem> </DetailsInfoItem.Value>
{ data.decoded_input && ( { data.decoded_input && (
<DetailsInfoItem <>
title="Decoded input data" <DetailsInfoItem.Label
hint="Decoded input data" hint="Decoded input data"
> >
Decoded input data
</DetailsInfoItem.Label>
<DetailsInfoItem.Value>
<LogDecodedInputData data={ data.decoded_input }/> <LogDecodedInputData data={ data.decoded_input }/>
</DetailsInfoItem> </DetailsInfoItem.Value>
</>
) } ) }
</Grid> </Grid>
); );
......
...@@ -7,7 +7,7 @@ import config from 'configs/app'; ...@@ -7,7 +7,7 @@ import config from 'configs/app';
import { ZERO } from 'lib/consts'; import { ZERO } from 'lib/consts';
import { currencyUnits } from 'lib/units'; import { currencyUnits } from 'lib/units';
import CurrencyValue from 'ui/shared/CurrencyValue'; import CurrencyValue from 'ui/shared/CurrencyValue';
import DetailsInfoItem from 'ui/shared/DetailsInfoItem'; import * as DetailsInfoItem from 'ui/shared/DetailsInfoItem';
import IconSvg from 'ui/shared/IconSvg'; import IconSvg from 'ui/shared/IconSvg';
const rollupFeature = config.features.rollup; const rollupFeature = config.features.rollup;
...@@ -30,14 +30,17 @@ const TxDetailsBurntFees = ({ data, isLoading }: Props) => { ...@@ -30,14 +30,17 @@ const TxDetailsBurntFees = ({ data, isLoading }: Props) => {
} }
return ( return (
<DetailsInfoItem <>
title="Burnt fees" <DetailsInfoItem.Label
hint={ ` hint={ `
Amount of ${ currencyUnits.ether } burned for this transaction. Equals Block Base Fee per Gas * Gas Used Amount of ${ currencyUnits.ether } burned for this transaction. Equals Block Base Fee per Gas * Gas Used
${ data.blob_gas_price && data.blob_gas_used ? ' + Blob Gas Price * Blob Gas Used' : '' } ${ data.blob_gas_price && data.blob_gas_used ? ' + Blob Gas Price * Blob Gas Used' : '' }
` } ` }
isLoading={ isLoading } isLoading={ isLoading }
> >
Burnt fees
</DetailsInfoItem.Label>
<DetailsInfoItem.Value>
<IconSvg name="flame" boxSize={ 5 } color="gray.500" isLoading={ isLoading }/> <IconSvg name="flame" boxSize={ 5 } color="gray.500" isLoading={ isLoading }/>
<CurrencyValue <CurrencyValue
value={ value.toString() } value={ value.toString() }
...@@ -47,7 +50,8 @@ const TxDetailsBurntFees = ({ data, isLoading }: Props) => { ...@@ -47,7 +50,8 @@ const TxDetailsBurntFees = ({ data, isLoading }: Props) => {
ml={ 2 } ml={ 2 }
isLoading={ isLoading } isLoading={ isLoading }
/> />
</DetailsInfoItem> </DetailsInfoItem.Value>
</>
); );
}; };
......
...@@ -4,7 +4,7 @@ import React from 'react'; ...@@ -4,7 +4,7 @@ import React from 'react';
import config from 'configs/app'; import config from 'configs/app';
import { currencyUnits } from 'lib/units'; import { currencyUnits } from 'lib/units';
import DetailsInfoItem from 'ui/shared/DetailsInfoItem'; import * as DetailsInfoItem from 'ui/shared/DetailsInfoItem';
interface Props { interface Props {
txFee: string | null; txFee: string | null;
...@@ -18,16 +18,20 @@ const TxDetailsFeePerGas = ({ txFee, gasUsed, isLoading }: Props) => { ...@@ -18,16 +18,20 @@ const TxDetailsFeePerGas = ({ txFee, gasUsed, isLoading }: Props) => {
} }
return ( return (
<DetailsInfoItem <>
title="Fee per gas" <DetailsInfoItem.Label
hint="Fee per gas" hint="Fee per gas"
isLoading={ isLoading } isLoading={ isLoading }
> >
Fee per gas
</DetailsInfoItem.Label>
<DetailsInfoItem.Value>
<Skeleton isLoaded={ !isLoading } mr={ 1 }> <Skeleton isLoaded={ !isLoading } mr={ 1 }>
{ BigNumber(txFee).dividedBy(10 ** config.chain.currency.decimals).dividedBy(gasUsed).toFixed() } { BigNumber(txFee).dividedBy(10 ** config.chain.currency.decimals).dividedBy(gasUsed).toFixed() }
{ config.UI.views.tx.hiddenFields?.fee_currency ? '' : ` ${ currencyUnits.ether }` } { config.UI.views.tx.hiddenFields?.fee_currency ? '' : ` ${ currencyUnits.ether }` }
</Skeleton> </Skeleton>
</DetailsInfoItem> </DetailsInfoItem.Value>
</>
); );
}; };
......
...@@ -5,7 +5,7 @@ import React from 'react'; ...@@ -5,7 +5,7 @@ import React from 'react';
import config from 'configs/app'; import config from 'configs/app';
import { WEI, WEI_IN_GWEI } from 'lib/consts'; import { WEI, WEI_IN_GWEI } from 'lib/consts';
import { currencyUnits } from 'lib/units'; import { currencyUnits } from 'lib/units';
import DetailsInfoItem from 'ui/shared/DetailsInfoItem'; import * as DetailsInfoItem from 'ui/shared/DetailsInfoItem';
interface Props { interface Props {
gasPrice: string | null; gasPrice: string | null;
...@@ -18,18 +18,22 @@ const TxDetailsGasPrice = ({ gasPrice, isLoading }: Props) => { ...@@ -18,18 +18,22 @@ const TxDetailsGasPrice = ({ gasPrice, isLoading }: Props) => {
} }
return ( return (
<DetailsInfoItem <>
title="Gas price" <DetailsInfoItem.Label
hint="Price per unit of gas specified by the sender. Higher gas prices can prioritize transaction inclusion during times of high usage" hint="Price per unit of gas specified by the sender. Higher gas prices can prioritize transaction inclusion during times of high usage"
isLoading={ isLoading } isLoading={ isLoading }
> >
Gas price
</DetailsInfoItem.Label>
<DetailsInfoItem.Value>
<Skeleton isLoaded={ !isLoading } mr={ 1 }> <Skeleton isLoaded={ !isLoading } mr={ 1 }>
{ BigNumber(gasPrice).dividedBy(WEI).toFixed() } { currencyUnits.ether } { BigNumber(gasPrice).dividedBy(WEI).toFixed() } { currencyUnits.ether }
</Skeleton> </Skeleton>
<Skeleton isLoaded={ !isLoading } color="text_secondary"> <Skeleton isLoaded={ !isLoading } color="text_secondary">
<span>({ BigNumber(gasPrice).dividedBy(WEI_IN_GWEI).toFixed() } { currencyUnits.gwei })</span> <span>({ BigNumber(gasPrice).dividedBy(WEI_IN_GWEI).toFixed() } { currencyUnits.gwei })</span>
</Skeleton> </Skeleton>
</DetailsInfoItem> </DetailsInfoItem.Value>
</>
); );
}; };
......
...@@ -3,17 +3,20 @@ import React from 'react'; ...@@ -3,17 +3,20 @@ import React from 'react';
import type { Transaction } from 'types/api/transaction'; import type { Transaction } from 'types/api/transaction';
import DetailsInfoItem from 'ui/shared/DetailsInfoItem'; import * as DetailsInfoItem from 'ui/shared/DetailsInfoItem';
import TextSeparator from 'ui/shared/TextSeparator'; import TextSeparator from 'ui/shared/TextSeparator';
type Props = Pick<Transaction, 'nonce' | 'type' | 'position'> type Props = Pick<Transaction, 'nonce' | 'type' | 'position'>
const TxDetailsOther = ({ nonce, type, position }: Props) => { const TxDetailsOther = ({ nonce, type, position }: Props) => {
return ( return (
<DetailsInfoItem <>
title="Other" <DetailsInfoItem.Label
hint="Other data related to this transaction" hint="Other data related to this transaction"
> >
Other
</DetailsInfoItem.Label>
<DetailsInfoItem.Value>
{ {
[ [
typeof type === 'number' && ( typeof type === 'number' && (
...@@ -43,7 +46,8 @@ const TxDetailsOther = ({ nonce, type, position }: Props) => { ...@@ -43,7 +46,8 @@ const TxDetailsOther = ({ nonce, type, position }: Props) => {
</> </>
)) ))
} }
</DetailsInfoItem> </DetailsInfoItem.Value>
</>
); );
}; };
......
...@@ -5,7 +5,7 @@ import type { TokenTransfer } from 'types/api/tokenTransfer'; ...@@ -5,7 +5,7 @@ import type { TokenTransfer } from 'types/api/tokenTransfer';
import { route } from 'nextjs-routes'; import { route } from 'nextjs-routes';
import DetailsInfoItem from 'ui/shared/DetailsInfoItem'; import * as DetailsInfoItem from 'ui/shared/DetailsInfoItem';
import IconSvg from 'ui/shared/IconSvg'; import IconSvg from 'ui/shared/IconSvg';
import LinkInternal from 'ui/shared/links/LinkInternal'; import LinkInternal from 'ui/shared/links/LinkInternal';
...@@ -40,12 +40,13 @@ const TxDetailsTokenTransfers = ({ data, txHash, isOverflow }: Props) => { ...@@ -40,12 +40,13 @@ const TxDetailsTokenTransfers = ({ data, txHash, isOverflow }: Props) => {
} }
return ( return (
<DetailsInfoItem <React.Fragment key={ type }>
key={ type } <DetailsInfoItem.Label
title={ title }
hint={ hint } hint={ hint }
position="relative"
> >
{ title }
</DetailsInfoItem.Label>
<DetailsInfoItem.Value position="relative">
<Flex <Flex
flexDirection="column" flexDirection="column"
alignItems="flex-start" alignItems="flex-start"
...@@ -55,7 +56,8 @@ const TxDetailsTokenTransfers = ({ data, txHash, isOverflow }: Props) => { ...@@ -55,7 +56,8 @@ const TxDetailsTokenTransfers = ({ data, txHash, isOverflow }: Props) => {
> >
{ items.map((item, index) => <TxDetailsTokenTransfer key={ index } data={ item }/>) } { items.map((item, index) => <TxDetailsTokenTransfer key={ index } data={ item }/>) }
</Flex> </Flex>
</DetailsInfoItem> </DetailsInfoItem.Value>
</React.Fragment>
); );
}) } }) }
{ isOverflow && ( { isOverflow && (
......
This diff is collapsed.
...@@ -13,7 +13,7 @@ import throwOnResourceLoadError from 'lib/errors/throwOnResourceLoadError'; ...@@ -13,7 +13,7 @@ import throwOnResourceLoadError from 'lib/errors/throwOnResourceLoadError';
import isCustomAppError from 'ui/shared/AppError/isCustomAppError'; import isCustomAppError from 'ui/shared/AppError/isCustomAppError';
import CopyToClipboard from 'ui/shared/CopyToClipboard'; import CopyToClipboard from 'ui/shared/CopyToClipboard';
import DataFetchAlert from 'ui/shared/DataFetchAlert'; import DataFetchAlert from 'ui/shared/DataFetchAlert';
import DetailsInfoItem from 'ui/shared/DetailsInfoItem'; import * as DetailsInfoItem from 'ui/shared/DetailsInfoItem';
import DetailsInfoItemDivider from 'ui/shared/DetailsInfoItemDivider'; import DetailsInfoItemDivider from 'ui/shared/DetailsInfoItemDivider';
import DetailsTimestamp from 'ui/shared/DetailsTimestamp'; import DetailsTimestamp from 'ui/shared/DetailsTimestamp';
import TxEntityL1 from 'ui/shared/entities/tx/TxEntityL1'; import TxEntityL1 from 'ui/shared/entities/tx/TxEntityL1';
...@@ -61,10 +61,12 @@ const ZkEvmL2TxnBatchDetails = ({ query }: Props) => { ...@@ -61,10 +61,12 @@ const ZkEvmL2TxnBatchDetails = ({ query }: Props) => {
templateColumns={{ base: 'minmax(0, 1fr)', lg: 'minmax(min-content, 200px) minmax(0, 1fr)' }} templateColumns={{ base: 'minmax(0, 1fr)', lg: 'minmax(min-content, 200px) minmax(0, 1fr)' }}
overflow="hidden" overflow="hidden"
> >
<DetailsInfoItem <DetailsInfoItem.Label
title="Tx batch number"
isLoading={ isPlaceholderData } isLoading={ isPlaceholderData }
> >
Tx batch number
</DetailsInfoItem.Label>
<DetailsInfoItem.Value>
<Skeleton isLoaded={ !isPlaceholderData }> <Skeleton isLoaded={ !isPlaceholderData }>
{ data.number } { data.number }
</Skeleton> </Skeleton>
...@@ -76,23 +78,32 @@ const ZkEvmL2TxnBatchDetails = ({ query }: Props) => { ...@@ -76,23 +78,32 @@ const ZkEvmL2TxnBatchDetails = ({ query }: Props) => {
isPrevDisabled={ data.number === 0 } isPrevDisabled={ data.number === 0 }
isLoading={ isPlaceholderData } isLoading={ isPlaceholderData }
/> />
</DetailsInfoItem> </DetailsInfoItem.Value>
<DetailsInfoItem
title="Status" <DetailsInfoItem.Label
isLoading={ isPlaceholderData } isLoading={ isPlaceholderData }
> >
Status
</DetailsInfoItem.Label>
<DetailsInfoItem.Value>
<VerificationSteps steps={ ZKEVM_L2_TX_BATCH_STATUSES } currentStep={ data.status } isLoading={ isPlaceholderData }/> <VerificationSteps steps={ ZKEVM_L2_TX_BATCH_STATUSES } currentStep={ data.status } isLoading={ isPlaceholderData }/>
</DetailsInfoItem> </DetailsInfoItem.Value>
<DetailsInfoItem
title="Timestamp" <DetailsInfoItem.Label
isLoading={ isPlaceholderData } isLoading={ isPlaceholderData }
> >
Timestamp
</DetailsInfoItem.Label>
<DetailsInfoItem.Value>
{ data.timestamp ? <DetailsTimestamp timestamp={ data.timestamp } isLoading={ isPlaceholderData }/> : 'Undefined' } { data.timestamp ? <DetailsTimestamp timestamp={ data.timestamp } isLoading={ isPlaceholderData }/> : 'Undefined' }
</DetailsInfoItem> </DetailsInfoItem.Value>
<DetailsInfoItem
title="Verify tx hash" <DetailsInfoItem.Label
isLoading={ isPlaceholderData } isLoading={ isPlaceholderData }
> >
Verify tx hash
</DetailsInfoItem.Label>
<DetailsInfoItem.Value>
{ data.verify_tx_hash ? ( { data.verify_tx_hash ? (
<TxEntityL1 <TxEntityL1
isLoading={ isPlaceholderData } isLoading={ isPlaceholderData }
...@@ -100,44 +111,57 @@ const ZkEvmL2TxnBatchDetails = ({ query }: Props) => { ...@@ -100,44 +111,57 @@ const ZkEvmL2TxnBatchDetails = ({ query }: Props) => {
maxW="100%" maxW="100%"
/> />
) : <Text>Pending</Text> } ) : <Text>Pending</Text> }
</DetailsInfoItem> </DetailsInfoItem.Value>
<DetailsInfoItem
title="Transactions" <DetailsInfoItem.Label
isLoading={ isPlaceholderData } isLoading={ isPlaceholderData }
> >
Transactions
</DetailsInfoItem.Label>
<DetailsInfoItem.Value>
<Skeleton isLoaded={ !isPlaceholderData }> <Skeleton isLoaded={ !isPlaceholderData }>
<LinkInternal href={ route({ pathname: '/batches/[number]', query: { number: data.number.toString(), tab: 'txs' } }) }> <LinkInternal href={ route({ pathname: '/batches/[number]', query: { number: data.number.toString(), tab: 'txs' } }) }>
{ data.transactions.length } transaction{ data.transactions.length === 1 ? '' : 's' } { data.transactions.length } transaction{ data.transactions.length === 1 ? '' : 's' }
</LinkInternal> </LinkInternal>
</Skeleton> </Skeleton>
</DetailsInfoItem> </DetailsInfoItem.Value>
<DetailsInfoItemDivider/> <DetailsInfoItemDivider/>
<DetailsInfoItem <DetailsInfoItem.Label
title="Global exit root"
isLoading={ isPlaceholderData } isLoading={ isPlaceholderData }
>
Global exit root
</DetailsInfoItem.Label>
<DetailsInfoItem.Value
flexWrap="nowrap" flexWrap="nowrap"
> >
<Skeleton isLoaded={ !isPlaceholderData } overflow="hidden"> <Skeleton isLoaded={ !isPlaceholderData } overflow="hidden">
<HashStringShortenDynamic hash={ data.global_exit_root }/> <HashStringShortenDynamic hash={ data.global_exit_root }/>
</Skeleton> </Skeleton>
<CopyToClipboard text={ data.global_exit_root } isLoading={ isPlaceholderData }/> <CopyToClipboard text={ data.global_exit_root } isLoading={ isPlaceholderData }/>
</DetailsInfoItem> </DetailsInfoItem.Value>
<DetailsInfoItem
title="Acc input hash" <DetailsInfoItem.Label
isLoading={ isPlaceholderData } isLoading={ isPlaceholderData }
>
Acc input hash
</DetailsInfoItem.Label>
<DetailsInfoItem.Value
flexWrap="nowrap" flexWrap="nowrap"
> >
<Skeleton isLoaded={ !isPlaceholderData } overflow="hidden"> <Skeleton isLoaded={ !isPlaceholderData } overflow="hidden">
<HashStringShortenDynamic hash={ data.acc_input_hash }/> <HashStringShortenDynamic hash={ data.acc_input_hash }/>
</Skeleton> </Skeleton>
<CopyToClipboard text={ data.acc_input_hash } isLoading={ isPlaceholderData }/> <CopyToClipboard text={ data.acc_input_hash } isLoading={ isPlaceholderData }/>
</DetailsInfoItem> </DetailsInfoItem.Value>
<DetailsInfoItem
title="Sequence tx hash" <DetailsInfoItem.Label
isLoading={ isPlaceholderData } isLoading={ isPlaceholderData }
> >
Sequence tx hash
</DetailsInfoItem.Label>
<DetailsInfoItem.Value>
{ data.sequence_tx_hash ? ( { data.sequence_tx_hash ? (
<TxEntityL1 <TxEntityL1
isLoading={ isPlaceholderData } isLoading={ isPlaceholderData }
...@@ -145,17 +169,21 @@ const ZkEvmL2TxnBatchDetails = ({ query }: Props) => { ...@@ -145,17 +169,21 @@ const ZkEvmL2TxnBatchDetails = ({ query }: Props) => {
maxW="100%" maxW="100%"
/> />
) : <Text>Pending</Text> } ) : <Text>Pending</Text> }
</DetailsInfoItem> </DetailsInfoItem.Value>
<DetailsInfoItem
title="State root" <DetailsInfoItem.Label
isLoading={ isPlaceholderData } isLoading={ isPlaceholderData }
>
State root
</DetailsInfoItem.Label>
<DetailsInfoItem.Value
flexWrap="nowrap" flexWrap="nowrap"
> >
<Skeleton isLoaded={ !isPlaceholderData } overflow="hidden"> <Skeleton isLoaded={ !isPlaceholderData } overflow="hidden">
<HashStringShortenDynamic hash={ data.state_root }/> <HashStringShortenDynamic hash={ data.state_root }/>
</Skeleton> </Skeleton>
<CopyToClipboard text={ data.state_root } isLoading={ isPlaceholderData }/> <CopyToClipboard text={ data.state_root } isLoading={ isPlaceholderData }/>
</DetailsInfoItem> </DetailsInfoItem.Value>
</Grid> </Grid>
); );
}; };
......
...@@ -16,7 +16,7 @@ import { currencyUnits } from 'lib/units'; ...@@ -16,7 +16,7 @@ import { currencyUnits } from 'lib/units';
import isCustomAppError from 'ui/shared/AppError/isCustomAppError'; import isCustomAppError from 'ui/shared/AppError/isCustomAppError';
import CopyToClipboard from 'ui/shared/CopyToClipboard'; import CopyToClipboard from 'ui/shared/CopyToClipboard';
import DataFetchAlert from 'ui/shared/DataFetchAlert'; import DataFetchAlert from 'ui/shared/DataFetchAlert';
import DetailsInfoItem from 'ui/shared/DetailsInfoItem'; import * as DetailsInfoItem from 'ui/shared/DetailsInfoItem';
import DetailsInfoItemDivider from 'ui/shared/DetailsInfoItemDivider'; import DetailsInfoItemDivider from 'ui/shared/DetailsInfoItemDivider';
import DetailsTimestamp from 'ui/shared/DetailsTimestamp'; import DetailsTimestamp from 'ui/shared/DetailsTimestamp';
import LinkInternal from 'ui/shared/links/LinkInternal'; import LinkInternal from 'ui/shared/links/LinkInternal';
...@@ -76,11 +76,13 @@ const ZkSyncL2TxnBatchDetails = ({ query }: Props) => { ...@@ -76,11 +76,13 @@ const ZkSyncL2TxnBatchDetails = ({ query }: Props) => {
templateColumns={{ base: 'minmax(0, 1fr)', lg: 'minmax(min-content, 200px) minmax(0, 1fr)' }} templateColumns={{ base: 'minmax(0, 1fr)', lg: 'minmax(min-content, 200px) minmax(0, 1fr)' }}
overflow="hidden" overflow="hidden"
> >
<DetailsInfoItem <DetailsInfoItem.Label
title="Tx batch number"
hint="Batch number indicates the length of batches produced by grouping L2 blocks to be proven on Ethereum." hint="Batch number indicates the length of batches produced by grouping L2 blocks to be proven on Ethereum."
isLoading={ isPlaceholderData } isLoading={ isPlaceholderData }
> >
Tx batch number
</DetailsInfoItem.Label>
<DetailsInfoItem.Value>
<Skeleton isLoaded={ !isPlaceholderData }> <Skeleton isLoaded={ !isPlaceholderData }>
{ data.number } { data.number }
</Skeleton> </Skeleton>
...@@ -92,35 +94,41 @@ const ZkSyncL2TxnBatchDetails = ({ query }: Props) => { ...@@ -92,35 +94,41 @@ const ZkSyncL2TxnBatchDetails = ({ query }: Props) => {
isPrevDisabled={ data.number === 0 } isPrevDisabled={ data.number === 0 }
isLoading={ isPlaceholderData } isLoading={ isPlaceholderData }
/> />
</DetailsInfoItem> </DetailsInfoItem.Value>
<DetailsInfoItem <DetailsInfoItem.Label
title="Status"
hint="Status is the short interpretation of the batch lifecycle" hint="Status is the short interpretation of the batch lifecycle"
isLoading={ isPlaceholderData } isLoading={ isPlaceholderData }
> >
Status
</DetailsInfoItem.Label>
<DetailsInfoItem.Value>
<VerificationSteps steps={ ZKSYNC_L2_TX_BATCH_STATUSES.slice(1) } currentStep={ data.status } isLoading={ isPlaceholderData }/> <VerificationSteps steps={ ZKSYNC_L2_TX_BATCH_STATUSES.slice(1) } currentStep={ data.status } isLoading={ isPlaceholderData }/>
</DetailsInfoItem> </DetailsInfoItem.Value>
<DetailsInfoItem <DetailsInfoItem.Label
title="Timestamp"
hint="Date and time at which batch is produced" hint="Date and time at which batch is produced"
isLoading={ isPlaceholderData } isLoading={ isPlaceholderData }
> >
Timestamp
</DetailsInfoItem.Label>
<DetailsInfoItem.Value>
{ data.timestamp ? <DetailsTimestamp timestamp={ data.timestamp } isLoading={ isPlaceholderData }/> : 'Undefined' } { data.timestamp ? <DetailsTimestamp timestamp={ data.timestamp } isLoading={ isPlaceholderData }/> : 'Undefined' }
</DetailsInfoItem> </DetailsInfoItem.Value>
<DetailsInfoItem <DetailsInfoItem.Label
title="Transactions"
hint="Number of transactions inside the batch." hint="Number of transactions inside the batch."
isLoading={ isPlaceholderData } isLoading={ isPlaceholderData }
> >
Transactions
</DetailsInfoItem.Label>
<DetailsInfoItem.Value>
<Skeleton isLoaded={ !isPlaceholderData }> <Skeleton isLoaded={ !isPlaceholderData }>
<LinkInternal href={ route({ pathname: '/batches/[number]', query: { number: data.number.toString(), tab: 'txs' } }) }> <LinkInternal href={ route({ pathname: '/batches/[number]', query: { number: data.number.toString(), tab: 'txs' } }) }>
{ txNum } transaction{ txNum === 1 ? '' : 's' } { txNum } transaction{ txNum === 1 ? '' : 's' }
</LinkInternal> </LinkInternal>
</Skeleton> </Skeleton>
</DetailsInfoItem> </DetailsInfoItem.Value>
<DetailsInfoItemDivider/> <DetailsInfoItemDivider/>
...@@ -146,31 +154,38 @@ const ZkSyncL2TxnBatchDetails = ({ query }: Props) => { ...@@ -146,31 +154,38 @@ const ZkSyncL2TxnBatchDetails = ({ query }: Props) => {
<> <>
<GridItem colSpan={{ base: undefined, lg: 2 }} mt={{ base: 1, lg: 4 }}/> <GridItem colSpan={{ base: undefined, lg: 2 }} mt={{ base: 1, lg: 4 }}/>
<DetailsInfoItem <DetailsInfoItem.Label
title="Root hash"
hint="L1 batch root is a hash that summarizes batch data and submitted to the L1" hint="L1 batch root is a hash that summarizes batch data and submitted to the L1"
>
Root hash
</DetailsInfoItem.Label>
<DetailsInfoItem.Value
flexWrap="nowrap" flexWrap="nowrap"
alignSelf="flex-start" alignSelf="flex-start"
> >
<TruncatedValue value={ data.root_hash }/> <TruncatedValue value={ data.root_hash }/>
<CopyToClipboard text={ data.root_hash }/> <CopyToClipboard text={ data.root_hash }/>
</DetailsInfoItem> </DetailsInfoItem.Value>
<DetailsInfoItem <DetailsInfoItem.Label
title="L1 gas price"
hint="Gas price for the batch settlement transaction on L1" hint="Gas price for the batch settlement transaction on L1"
> >
L1 gas price
</DetailsInfoItem.Label>
<DetailsInfoItem.Value>
<Text mr={ 1 }>{ BigNumber(data.l1_gas_price).dividedBy(WEI).toFixed() } { currencyUnits.ether }</Text> <Text mr={ 1 }>{ BigNumber(data.l1_gas_price).dividedBy(WEI).toFixed() } { currencyUnits.ether }</Text>
<Text variant="secondary">({ BigNumber(data.l1_gas_price).dividedBy(WEI_IN_GWEI).toFixed() } { currencyUnits.gwei })</Text> <Text variant="secondary">({ BigNumber(data.l1_gas_price).dividedBy(WEI_IN_GWEI).toFixed() } { currencyUnits.gwei })</Text>
</DetailsInfoItem> </DetailsInfoItem.Value>
<DetailsInfoItem <DetailsInfoItem.Label
title="L2 fair gas price"
hint={ 'The gas price below which the "baseFee" of the batch should not fall' } hint={ 'The gas price below which the "baseFee" of the batch should not fall' }
> >
L2 fair gas price
</DetailsInfoItem.Label>
<DetailsInfoItem.Value>
<Text mr={ 1 }>{ BigNumber(data.l2_fair_gas_price).dividedBy(WEI).toFixed() } { currencyUnits.ether }</Text> <Text mr={ 1 }>{ BigNumber(data.l2_fair_gas_price).dividedBy(WEI).toFixed() } { currencyUnits.ether }</Text>
<Text variant="secondary">({ BigNumber(data.l2_fair_gas_price).dividedBy(WEI_IN_GWEI).toFixed() } { currencyUnits.gwei })</Text> <Text variant="secondary">({ BigNumber(data.l2_fair_gas_price).dividedBy(WEI_IN_GWEI).toFixed() } { currencyUnits.gwei })</Text>
</DetailsInfoItem> </DetailsInfoItem.Value>
</> </>
) } ) }
</Grid> </Grid>
......
...@@ -3,7 +3,7 @@ import React from 'react'; ...@@ -3,7 +3,7 @@ import React from 'react';
import type { ZkSyncBatch } from 'types/api/zkSyncL2'; import type { ZkSyncBatch } from 'types/api/zkSyncL2';
import DetailsInfoItem from 'ui/shared/DetailsInfoItem'; import * as DetailsInfoItem from 'ui/shared/DetailsInfoItem';
import DetailsTimestamp from 'ui/shared/DetailsTimestamp'; import DetailsTimestamp from 'ui/shared/DetailsTimestamp';
import TxEntityL1 from 'ui/shared/entities/tx/TxEntityL1'; import TxEntityL1 from 'ui/shared/entities/tx/TxEntityL1';
...@@ -23,10 +23,13 @@ interface Props { ...@@ -23,10 +23,13 @@ interface Props {
const ZkSyncL2TxnBatchHashesInfo = ({ isLoading, data }: Props) => { const ZkSyncL2TxnBatchHashesInfo = ({ isLoading, data }: Props) => {
return ( return (
<> <>
<DetailsInfoItem <DetailsInfoItem.Label
title="Commit tx hash"
hint="Hash of L1 tx on which the batch was committed" hint="Hash of L1 tx on which the batch was committed"
isLoading={ isLoading } isLoading={ isLoading }
>
Commit tx hash
</DetailsInfoItem.Label>
<DetailsInfoItem.Value
flexDir="column" flexDir="column"
alignItems="flex-start" alignItems="flex-start"
> >
...@@ -45,12 +48,15 @@ const ZkSyncL2TxnBatchHashesInfo = ({ isLoading, data }: Props) => { ...@@ -45,12 +48,15 @@ const ZkSyncL2TxnBatchHashesInfo = ({ isLoading, data }: Props) => {
) } ) }
</> </>
) : <Skeleton isLoaded={ !isLoading }>Pending</Skeleton> } ) : <Skeleton isLoaded={ !isLoading }>Pending</Skeleton> }
</DetailsInfoItem> </DetailsInfoItem.Value>
<DetailsInfoItem <DetailsInfoItem.Label
title="Prove tx hash"
hint="Hash of L1 tx on which the batch was proven" hint="Hash of L1 tx on which the batch was proven"
isLoading={ isLoading } isLoading={ isLoading }
>
Prove tx hash
</DetailsInfoItem.Label>
<DetailsInfoItem.Value
flexDir="column" flexDir="column"
alignItems="flex-start" alignItems="flex-start"
> >
...@@ -69,12 +75,15 @@ const ZkSyncL2TxnBatchHashesInfo = ({ isLoading, data }: Props) => { ...@@ -69,12 +75,15 @@ const ZkSyncL2TxnBatchHashesInfo = ({ isLoading, data }: Props) => {
) } ) }
</> </>
) : <Skeleton isLoaded={ !isLoading }>Pending</Skeleton> } ) : <Skeleton isLoaded={ !isLoading }>Pending</Skeleton> }
</DetailsInfoItem> </DetailsInfoItem.Value>
<DetailsInfoItem <DetailsInfoItem.Label
title="Execute tx hash"
hint="Hash of L1 tx on which the batch was executed and finalized" hint="Hash of L1 tx on which the batch was executed and finalized"
isLoading={ isLoading } isLoading={ isLoading }
>
Execute tx hash
</DetailsInfoItem.Label>
<DetailsInfoItem.Value
flexDir="column" flexDir="column"
alignItems="flex-start" alignItems="flex-start"
> >
...@@ -93,7 +102,7 @@ const ZkSyncL2TxnBatchHashesInfo = ({ isLoading, data }: Props) => { ...@@ -93,7 +102,7 @@ const ZkSyncL2TxnBatchHashesInfo = ({ isLoading, data }: Props) => {
) } ) }
</> </>
) : <Skeleton isLoaded={ !isLoading }>Pending</Skeleton> } ) : <Skeleton isLoaded={ !isLoading }>Pending</Skeleton> }
</DetailsInfoItem> </DetailsInfoItem.Value>
</> </>
); );
}; };
......
...@@ -2,7 +2,7 @@ import React from 'react'; ...@@ -2,7 +2,7 @@ import React from 'react';
import type { UserOp } from 'types/api/userOps'; import type { UserOp } from 'types/api/userOps';
import DetailsInfoItem from 'ui/shared/DetailsInfoItem'; import * as DetailsInfoItem from 'ui/shared/DetailsInfoItem';
import RawInputData from 'ui/shared/RawInputData'; import RawInputData from 'ui/shared/RawInputData';
import UserOpCallDataSwitch from './UserOpCallDataSwitch'; import UserOpCallDataSwitch from './UserOpCallDataSwitch';
...@@ -33,12 +33,16 @@ const UserOpDecodedCallData = ({ data }: Props) => { ...@@ -33,12 +33,16 @@ const UserOpDecodedCallData = ({ data }: Props) => {
) : null; ) : null;
return ( return (
<DetailsInfoItem <>
title="Call data" <DetailsInfoItem.Label
hint="Data that’s passed to the sender for execution" hint="Data that’s passed to the sender for execution"
> >
Call data
</DetailsInfoItem.Label>
<DetailsInfoItem.Value>
<RawInputData hex={ callData } rightSlot={ toggler }/> <RawInputData hex={ callData } rightSlot={ toggler }/>
</DetailsInfoItem> </DetailsInfoItem.Value>
</>
); );
}; };
......
...@@ -2,7 +2,7 @@ import React from 'react'; ...@@ -2,7 +2,7 @@ import React from 'react';
import type { UserOp } from 'types/api/userOps'; import type { UserOp } from 'types/api/userOps';
import DetailsInfoItem from 'ui/shared/DetailsInfoItem'; import * as DetailsInfoItem from 'ui/shared/DetailsInfoItem';
import LogDecodedInputData from 'ui/shared/logs/LogDecodedInputData'; import LogDecodedInputData from 'ui/shared/logs/LogDecodedInputData';
import UserOpCallDataSwitch from './UserOpCallDataSwitch'; import UserOpCallDataSwitch from './UserOpCallDataSwitch';
...@@ -33,14 +33,19 @@ const UserOpDecodedCallData = ({ data }: Props) => { ...@@ -33,14 +33,19 @@ const UserOpDecodedCallData = ({ data }: Props) => {
) : null; ) : null;
return ( return (
<DetailsInfoItem <>
title="Decoded call data" <DetailsInfoItem.Label
hint="Decoded call data" hint="Decoded call data"
>
Decoded call data
</DetailsInfoItem.Label>
<DetailsInfoItem.Value
flexDir={{ base: 'column', lg: 'row' }} flexDir={{ base: 'column', lg: 'row' }}
alignItems={{ base: 'flex-start', lg: 'center' }} alignItems={{ base: 'flex-start', lg: 'center' }}
> >
<LogDecodedInputData data={ callData } rightSlot={ toggler }/> <LogDecodedInputData data={ callData } rightSlot={ toggler }/>
</DetailsInfoItem> </DetailsInfoItem.Value>
</>
); );
}; };
......
This diff is collapsed.
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