Commit 2822ced9 authored by tom goriunov's avatar tom goriunov Committed by GitHub

Merge pull request #641 from blockscout/address-fixed-tags

ad fixes and tags for address / token
parents aae435fe b9231907
......@@ -11,6 +11,7 @@ import * as countersMock from 'mocks/address/counters';
import * as tokensMock from 'mocks/address/tokens';
import TestApp from 'playwright/TestApp';
import buildApiUrl from 'playwright/utils/buildApiUrl';
import insertAdPlaceholder from 'playwright/utils/insertAdPlaceholder';
import AddressDetails from './AddressDetails';
import MockAddressPage from './testUtils/MockAddressPage';
......@@ -44,6 +45,8 @@ test('contract +@mobile', async({ mount, page }) => {
{ hooksConfig },
);
await insertAdPlaceholder(page);
await expect(component).toHaveScreenshot();
});
......@@ -82,6 +85,8 @@ test('token', async({ mount, page }) => {
{ hooksConfig },
);
await insertAdPlaceholder(page);
await expect(component).toHaveScreenshot();
});
......@@ -102,5 +107,7 @@ test('validator +@mobile', async({ mount, page }) => {
{ hooksConfig },
);
await insertAdPlaceholder(page);
await expect(component).toHaveScreenshot();
});
......@@ -16,6 +16,7 @@ import AddressLink from 'ui/shared/address/AddressLink';
import AddressHeadingInfo from 'ui/shared/AddressHeadingInfo';
import DataFetchAlert from 'ui/shared/DataFetchAlert';
import DetailsInfoItem from 'ui/shared/DetailsInfoItem';
import DetailsSponsoredItem from 'ui/shared/DetailsSponsoredItem';
import HashStringShortenDynamic from 'ui/shared/HashStringShortenDynamic';
import LinkExternal from 'ui/shared/LinkExternal';
import LinkInternal from 'ui/shared/LinkInternal';
......@@ -193,6 +194,7 @@ const AddressDetails = ({ addressQuery, scrollRef }: Props) => {
</LinkInternal>
</DetailsInfoItem>
) }
<DetailsSponsoredItem/>
</Grid>
</Box>
);
......
......@@ -118,7 +118,7 @@ const BlockDetails = () => {
hint="The number of transactions in the block"
>
<LinkInternal href={ route({ pathname: '/block/[height]', query: { height, tab: 'txs' } }) }>
{ data.tx_count } transactions
{ data.tx_count } transaction{ data.tx_count === 1 ? '' : 's' }
</LinkInternal>
</DetailsInfoItem>
<DetailsInfoItem
......@@ -274,18 +274,18 @@ const BlockDetails = () => {
<DetailsInfoItem
title="Difficulty"
hint={ `Block difficulty for ${ validatorTitle }, used to calibrate block generation time` }
whiteSpace="normal"
wordBreak="break-all"
>
{ BigNumber(data.difficulty).toFormat() }
<Box whiteSpace="nowrap" overflow="hidden">
<HashStringShortenDynamic hash={ BigNumber(data.difficulty).toFormat() }/>
</Box>
</DetailsInfoItem>
<DetailsInfoItem
title="Total difficulty"
hint="Total difficulty of the chain until this block"
whiteSpace="normal"
wordBreak="break-all"
>
{ BigNumber(data.total_difficulty).toFormat() }
<Box whiteSpace="nowrap" overflow="hidden">
<HashStringShortenDynamic hash={ BigNumber(data.total_difficulty).toFormat() }/>
</Box>
</DetailsInfoItem>
{ sectionGap }
......
......@@ -20,7 +20,6 @@ import AddressLogs from 'ui/address/AddressLogs';
import AddressTokens from 'ui/address/AddressTokens';
import AddressTokenTransfers from 'ui/address/AddressTokenTransfers';
import AddressTxs from 'ui/address/AddressTxs';
import AdBanner from 'ui/shared/ad/AdBanner';
import TextAd from 'ui/shared/ad/TextAd';
import Page from 'ui/shared/Page/Page';
import PageTitle from 'ui/shared/Page/PageTitle';
......@@ -51,10 +50,15 @@ const AddressPageContent = () => {
});
const tags = [
addressQuery.data?.is_contract ? { label: 'contract', display_name: 'Contract' } : { label: 'eoa', display_name: 'EOA' },
addressQuery.data?.implementation_address ? { label: 'proxy', display_name: 'Proxy' } : undefined,
addressQuery.data?.token ? { label: 'token', display_name: 'Token' } : undefined,
...(addressQuery.data?.private_tags || []),
...(addressQuery.data?.public_tags || []),
...(addressQuery.data?.watchlist_names || []),
].map((tag) => <Tag key={ tag.label }>{ tag.display_name }</Tag>);
]
.filter(notEmpty)
.map((tag) => <Tag key={ tag.label }>{ tag.display_name }</Tag>);
const contractTabs = useContractTabs(addressQuery.data);
......@@ -97,7 +101,7 @@ const AddressPageContent = () => {
return (
<Page>
<TextAd mb={ 6 }/>
{ addressQuery.isLoading ? <Skeleton h={{ base: 12, lg: 6 }} mb={ 6 } w="100%" maxW="680px"/> : <TextAd mb={ 6 }/> }
{ addressQuery.isLoading ? (
<Skeleton h={ 10 } w="260px" mb={ 6 }/>
) : (
......@@ -109,7 +113,6 @@ const AddressPageContent = () => {
/>
) }
<AddressDetails addressQuery={ addressQuery } scrollRef={ tabsScrollRef }/>
<AdBanner mt={{ base: 6, lg: 8 }} justifyContent="center"/>
{ /* should stay before tabs to scroll up whith pagination */ }
<Box ref={ tabsScrollRef }></Box>
{ addressQuery.isLoading ? <SkeletonTabs/> : content }
......
import { Skeleton, Box, Flex, SkeletonCircle, Icon } from '@chakra-ui/react';
import { Skeleton, Box, Flex, SkeletonCircle, Icon, Tag } from '@chakra-ui/react';
import { useRouter } from 'next/router';
import React, { useEffect } from 'react';
......@@ -13,7 +13,6 @@ import useQueryWithPages from 'lib/hooks/useQueryWithPages';
import notEmpty from 'lib/notEmpty';
import trimTokenSymbol from 'lib/token/trimTokenSymbol';
import AddressContract from 'ui/address/AddressContract';
import AdBanner from 'ui/shared/ad/AdBanner';
import TextAd from 'ui/shared/ad/TextAd';
import Page from 'ui/shared/Page/Page';
import PageTitle from 'ui/shared/Page/PageTitle';
......@@ -144,10 +143,13 @@ const TokenPageContent = () => {
return (
<Page>
{ tokenQuery.isLoading ? (
<Flex alignItems="center" mb={ 6 }>
<SkeletonCircle w={ 6 } h={ 6 } mr={ 3 }/>
<Skeleton w="500px" h={ 10 }/>
</Flex>
<>
<Skeleton h={{ base: 12, lg: 6 }} mb={ 6 } w="100%" maxW="680px"/>
<Flex alignItems="center" mb={ 6 }>
<SkeletonCircle w={ 6 } h={ 6 } mr={ 3 }/>
<Skeleton w="500px" h={ 10 }/>
</Flex>
</>
) : (
<>
<TextAd mb={ 6 }/>
......@@ -158,12 +160,12 @@ const TokenPageContent = () => {
additionalsLeft={ (
<TokenLogo hash={ tokenQuery.data?.address } name={ tokenQuery.data?.name } boxSize={ 6 }/>
) }
additionalsRight={ <Tag>{ tokenQuery.data?.type }</Tag> }
/>
</>
) }
<TokenContractInfo tokenQuery={ tokenQuery }/>
<TokenDetails tokenQuery={ tokenQuery }/>
<AdBanner mt={{ base: 6, lg: 8 }} justifyContent="center"/>
{ /* should stay before tabs to scroll up whith pagination */ }
<Box ref={ scrollRef }></Box>
......
import { GridItem } from '@chakra-ui/react';
import React from 'react';
import useIsMobile from 'lib/hooks/useIsMobile';
import AdBanner from 'ui/shared/ad/AdBanner';
import DetailsInfoItem from 'ui/shared/DetailsInfoItem';
const DetailsSponsoredItem = () => {
const isMobile = useIsMobile();
if (isMobile) {
return (
<GridItem mt={ 5 }>
<AdBanner justifyContent="center"/>
</GridItem>
);
}
return (
<DetailsInfoItem
title="Sponsored"
hint="Sponsored banner advertisement"
>
<AdBanner/>
</DetailsInfoItem>
);
};
export default React.memo(DetailsSponsoredItem);
......@@ -26,6 +26,8 @@ type AdData = {
const CoinzillaTextAd = ({ className }: {className?: string}) => {
const [ adData, setAdData ] = React.useState<AdData | null>(null);
const [ isLoading, setIsLoading ] = React.useState(true);
useEffect(() => {
fetch('https://request-global.czilladx.com/serve/native.php?z=19260bf627546ab7242')
.then(res => res.status === 200 ? res.json() : null)
......@@ -34,9 +36,16 @@ const CoinzillaTextAd = ({ className }: {className?: string}) => {
if (data?.ad?.impressionUrl) {
fetch(data.ad.impressionUrl);
}
})
.finally(() => {
setIsLoading(false);
});
}, []);
if (isLoading) {
return <Box className={ className } h={{ base: 12, lg: 6 }}/>;
}
if (!adData) {
return null;
}
......@@ -52,7 +61,7 @@ const CoinzillaTextAd = ({ className }: {className?: string}) => {
mr={ 3 }
display={{ base: 'none', lg: 'inline' }}
>
ADs:
Ads:
</Text>
{ urlObject.hostname === 'nifty.ink' ?
<Text as="span" mr={ 1 }>🎨</Text> :
......
......@@ -45,6 +45,7 @@ const NavLinkGroupDesktop = ({ text, subItems, icon, isCollapsed, isActive }: Pr
display="grid"
gridColumnGap={ 3 }
gridTemplateColumns="auto, 30px"
overflow="hidden"
>
<Flex justifyContent="space-between" width="100%" alignItems="center" pr={ 1 }>
<HStack spacing={ 3 } overflow="hidden">
......
......@@ -52,7 +52,7 @@ const NavigationDesktop = () => {
display={{ base: 'none', lg: 'flex' }}
position="relative"
flexDirection="column"
alignItems="flex-start"
alignItems="stretch"
borderRight="1px solid"
borderColor="divider"
px={{ lg: isExpanded ? 6 : 4, xl: isCollapsed ? 4 : 6 }}
......
import { Grid, Link, Skeleton } from '@chakra-ui/react';
import { Box, Flex, Grid, Link, Skeleton } from '@chakra-ui/react';
import type { UseQueryResult } from '@tanstack/react-query';
import { useRouter } from 'next/router';
import React, { useCallback } from 'react';
......@@ -10,6 +10,8 @@ import useApiQuery from 'lib/api/useApiQuery';
import getCurrencyValue from 'lib/getCurrencyValue';
import type { TokenTabs } from 'ui/pages/Token';
import DetailsInfoItem from 'ui/shared/DetailsInfoItem';
import DetailsSponsoredItem from 'ui/shared/DetailsSponsoredItem';
import HashStringShortenDynamic from 'ui/shared/HashStringShortenDynamic';
import DetailsSkeletonRow from 'ui/shared/skeletons/DetailsSkeletonRow';
interface Props {
......@@ -108,7 +110,12 @@ const TokenDetails = ({ tokenQuery }: Props) => {
wordBreak="break-word"
whiteSpace="pre-wrap"
>
{ `${ totalValue?.valueStr || 0 } ${ symbol || '' }` }
<Flex w="100%">
<Box whiteSpace="nowrap" overflow="hidden">
<HashStringShortenDynamic hash={ totalValue?.valueStr || '0' }/>
</Box>
<Box flexShrink={ 0 }> { symbol || '' }</Box>
</Flex>
</DetailsInfoItem>
<DetailsInfoItem
title="Holders"
......@@ -135,6 +142,7 @@ const TokenDetails = ({ tokenQuery }: Props) => {
{ decimals }
</DetailsInfoItem>
) }
<DetailsSponsoredItem/>
</Grid>
);
};
......
......@@ -8,7 +8,6 @@ import useApiQuery from 'lib/api/useApiQuery';
import { useAppContext } from 'lib/appContext';
import useIsMobile from 'lib/hooks/useIsMobile';
import useQueryWithPages from 'lib/hooks/useQueryWithPages';
import AdBanner from 'ui/shared/ad/AdBanner';
import TextAd from 'ui/shared/ad/TextAd';
import AddressHeadingInfo from 'ui/shared/AddressHeadingInfo';
import PageTitle from 'ui/shared/Page/PageTitle';
......@@ -89,8 +88,6 @@ const TokenInstanceContent = () => {
<TokenInstanceDetails data={ tokenInstanceQuery.data } scrollRef={ scrollRef }/>
<AdBanner mt={{ base: 6, lg: 8 }} justifyContent="center"/>
{ /* should stay before tabs to scroll up with pagination */ }
<Box ref={ scrollRef }></Box>
......
......@@ -5,6 +5,7 @@ import * as addressMock from 'mocks/address/address';
import * as tokenInstanceMock from 'mocks/tokens/tokenInstance';
import TestApp from 'playwright/TestApp';
import buildApiUrl from 'playwright/utils/buildApiUrl';
import insertAdPlaceholder from 'playwright/utils/insertAdPlaceholder';
import TokenInstanceDetails from './TokenInstanceDetails';
......@@ -30,5 +31,7 @@ test('base view +@dark-mode', async({ mount, page }) => {
</TestApp>,
);
await insertAdPlaceholder(page);
await expect(component).toHaveScreenshot();
});
......@@ -8,6 +8,7 @@ import AddressIcon from 'ui/shared/address/AddressIcon';
import AddressLink from 'ui/shared/address/AddressLink';
import CopyToClipboard from 'ui/shared/CopyToClipboard';
import DetailsInfoItem from 'ui/shared/DetailsInfoItem';
import DetailsSponsoredItem from 'ui/shared/DetailsSponsoredItem';
import HashStringShortenDynamic from 'ui/shared/HashStringShortenDynamic';
import NftMedia from 'ui/shared/nft/NftMedia';
import TokenSnippet from 'ui/shared/TokenSnippet/TokenSnippet';
......@@ -65,6 +66,7 @@ const TokenInstanceDetails = ({ data, scrollRef }: Props) => {
</Flex>
</DetailsInfoItem>
<TokenInstanceTransfersCount hash={ data.token.address } id={ data.id } onClick={ handleCounterItemClick }/>
<DetailsSponsoredItem/>
</Grid>
<NftMedia
imageUrl={ data.image_url }
......
......@@ -7,6 +7,7 @@ import SkeletonTabs from 'ui/shared/skeletons/SkeletonTabs';
const TokenInstanceSkeleton = () => {
return (
<Box>
<Skeleton h={{ base: 12, lg: 6 }} mb={ 6 } w="100%" maxW="680px"/>
<Skeleton h={ 10 } maxW="400px" w="100%" mb={ 6 }/>
<Flex align="center">
<SkeletonCircle boxSize={ 6 } flexShrink={ 0 }/>
......
......@@ -12,6 +12,7 @@ import {
chakra,
} from '@chakra-ui/react';
import BigNumber from 'bignumber.js';
import { route } from 'nextjs-routes';
import React from 'react';
import { scroller, Element } from 'react-scroll';
......@@ -22,9 +23,7 @@ import errorIcon from 'icons/status/error.svg';
import successIcon from 'icons/status/success.svg';
import { WEI, WEI_IN_GWEI } from 'lib/consts';
import dayjs from 'lib/date/dayjs';
import useIsMobile from 'lib/hooks/useIsMobile';
import getConfirmationDuration from 'lib/tx/getConfirmationDuration';
import AdBanner from 'ui/shared/ad/AdBanner';
import Address from 'ui/shared/address/Address';
import AddressIcon from 'ui/shared/address/AddressIcon';
import AddressLink from 'ui/shared/address/AddressLink';
......@@ -32,8 +31,10 @@ import CopyToClipboard from 'ui/shared/CopyToClipboard';
import CurrencyValue from 'ui/shared/CurrencyValue';
import DataFetchAlert from 'ui/shared/DataFetchAlert';
import DetailsInfoItem from 'ui/shared/DetailsInfoItem';
import DetailsSponsoredItem from 'ui/shared/DetailsSponsoredItem';
import HashStringShortenDynamic from 'ui/shared/HashStringShortenDynamic';
// import PrevNext from 'ui/shared/PrevNext';
import LinkInternal from 'ui/shared/LinkInternal';
import LogDecodedInputData from 'ui/shared/logs/LogDecodedInputData';
import RawInputData from 'ui/shared/RawInputData';
import TextSeparator from 'ui/shared/TextSeparator';
......@@ -49,8 +50,6 @@ import useFetchTxInfo from 'ui/tx/useFetchTxInfo';
const TxDetails = () => {
const { data, isLoading, isError, socketStatus, error } = useFetchTxInfo();
const isMobile = useIsMobile();
const [ isExpanded, setIsExpanded ] = React.useState(false);
const handleCutClick = React.useCallback(() => {
......@@ -155,7 +154,9 @@ const TxDetails = () => {
title="Block"
hint="Block number containing the transaction"
>
<Text>{ data.block === null ? 'Pending' : data.block }</Text>
{ data.block === null ?
<Text>Pending</Text> :
<LinkInternal href={ route({ pathname: '/block/[height]', query: { height: String(data.block) } }) }>{ data.block }</LinkInternal> }
{ Boolean(data.confirmations) && (
<>
<TextSeparator color="gray.500"/>
......@@ -177,22 +178,7 @@ const TxDetails = () => {
<Text variant="secondary">{ getConfirmationDuration(data.confirmation_duration) }</Text>
</DetailsInfoItem>
) }
{ isMobile ?
(
<GridItem
colSpan={{ base: undefined, lg: 2 }}
>
<AdBanner justifyContent="center"/>
</GridItem>
) :
(
<DetailsInfoItem
title="Sponsored"
hint="Sponsored banner advertisement"
>
<AdBanner/>
</DetailsInfoItem>
) }
<DetailsSponsoredItem/>
{ divider }
......
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