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

trim block height if it is too long (#1033)

Fixes #1023
parent 940af88e
import { Skeleton } from '@chakra-ui/react'; import { Skeleton, chakra } from '@chakra-ui/react';
import type { TypographyProps } from '@chakra-ui/react';
import React from 'react'; import React from 'react';
import useTimeAgoIncrement from 'lib/hooks/useTimeAgoIncrement'; import useTimeAgoIncrement from 'lib/hooks/useTimeAgoIncrement';
...@@ -8,17 +7,17 @@ interface Props { ...@@ -8,17 +7,17 @@ interface Props {
ts: string; ts: string;
isEnabled?: boolean; isEnabled?: boolean;
isLoading?: boolean; isLoading?: boolean;
fontSize?: TypographyProps['fontSize']; className?: string;
} }
const BlockTimestamp = ({ ts, isEnabled, isLoading, fontSize }: Props) => { const BlockTimestamp = ({ ts, isEnabled, isLoading, className }: Props) => {
const timeAgo = useTimeAgoIncrement(ts, isEnabled); const timeAgo = useTimeAgoIncrement(ts, isEnabled);
return ( return (
<Skeleton isLoaded={ !isLoading } color="text_secondary" fontWeight={ 400 } fontSize={ fontSize } display="inline-block"> <Skeleton isLoaded={ !isLoading } color="text_secondary" fontWeight={ 400 } className={ className } display="inline-block">
<span>{ timeAgo }</span> <span>{ timeAgo }</span>
</Skeleton> </Skeleton>
); );
}; };
export default React.memo(BlockTimestamp); export default React.memo(chakra(BlockTimestamp));
...@@ -38,6 +38,30 @@ test('default view +@mobile +@dark-mode', async({ mount, page }) => { ...@@ -38,6 +38,30 @@ test('default view +@mobile +@dark-mode', async({ mount, page }) => {
await expect(component).toHaveScreenshot(); await expect(component).toHaveScreenshot();
}); });
test('with long block height', async({ mount, page }) => {
await page.route(STATS_API_URL, (route) => route.fulfill({
status: 200,
body: JSON.stringify(statsMock.base),
}));
await page.route(BLOCKS_API_URL, (route) => route.fulfill({
status: 200,
body: JSON.stringify([
{
...blockMock.base,
height: 123456789012345,
},
]),
}));
const component = await mount(
<TestApp>
<LatestBlocks/>
</TestApp>,
);
await expect(component).toHaveScreenshot();
});
test.describe('socket', () => { test.describe('socket', () => {
test.describe.configure({ mode: 'serial' }); test.describe.configure({ mode: 'serial' });
......
...@@ -2,11 +2,9 @@ import { ...@@ -2,11 +2,9 @@ import {
Box, Box,
Flex, Flex,
Grid, Grid,
HStack,
Skeleton, Skeleton,
} from '@chakra-ui/react'; } from '@chakra-ui/react';
import { motion } from 'framer-motion'; import { motion } from 'framer-motion';
import { route } from 'nextjs-routes';
import React from 'react'; import React from 'react';
import type { Block } from 'types/api/block'; import type { Block } from 'types/api/block';
...@@ -17,7 +15,6 @@ import getBlockTotalReward from 'lib/block/getBlockTotalReward'; ...@@ -17,7 +15,6 @@ import getBlockTotalReward from 'lib/block/getBlockTotalReward';
import BlockTimestamp from 'ui/blocks/BlockTimestamp'; import BlockTimestamp from 'ui/blocks/BlockTimestamp';
import AddressLink from 'ui/shared/address/AddressLink'; import AddressLink from 'ui/shared/address/AddressLink';
import Icon from 'ui/shared/chakra/Icon'; import Icon from 'ui/shared/chakra/Icon';
import LinkInternal from 'ui/shared/LinkInternal';
type Props = { type Props = {
block: Block; block: Block;
...@@ -40,22 +37,29 @@ const LatestBlocksItem = ({ block, h, isLoading }: Props) => { ...@@ -40,22 +37,29 @@ const LatestBlocksItem = ({ block, h, isLoading }: Props) => {
p={ 6 } p={ 6 }
h={ `${ h }px` } h={ `${ h }px` }
minWidth={{ base: '100%', lg: '280px' }} minWidth={{ base: '100%', lg: '280px' }}
w="100%"
> >
<Flex justifyContent="space-between" alignItems="center" mb={ 3 }> <Flex alignItems="center" overflow="hidden" w="100%" mb={ 3 }>
<HStack spacing={ 2 }> <Icon as={ blockIcon } boxSize="30px" color="link" isLoading={ isLoading } borderRadius="base"/>
<Icon as={ blockIcon } boxSize="30px" color="link" isLoading={ isLoading } borderRadius="base"/> <AddressLink
<LinkInternal isLoading={ isLoading }
href={ route({ pathname: '/block/[height_or_hash]', query: { height_or_hash: String(block.height) } }) } type="block"
fontSize="xl" hash={ String(block.height) }
fontWeight="500" blockHeight={ String(block.height) }
isLoading={ isLoading } fontSize="xl"
> fontWeight="500"
<Skeleton isLoaded={ !isLoading }> ml={ 2 }
{ block.height } mr="auto"
</Skeleton> tailLength={ 2 }
</LinkInternal> />
</HStack> <BlockTimestamp
<BlockTimestamp ts={ block.timestamp } isEnabled={ !isLoading } isLoading={ isLoading } fontSize="sm"/> ts={ block.timestamp }
isEnabled={ !isLoading }
isLoading={ isLoading }
fontSize="sm"
flexShrink={ 0 }
ml={ 2 }
/>
</Flex> </Flex>
<Grid gridGap={ 2 } templateColumns="auto minmax(0, 1fr)" fontSize="sm"> <Grid gridGap={ 2 } templateColumns="auto minmax(0, 1fr)" fontSize="sm">
<Skeleton isLoaded={ !isLoading }>Txn</Skeleton> <Skeleton isLoaded={ !isLoading }>Txn</Skeleton>
......
...@@ -23,9 +23,10 @@ interface Props { ...@@ -23,9 +23,10 @@ interface Props {
hash: string; hash: string;
fontWeight?: string | number; fontWeight?: string | number;
isTooltipDisabled?: boolean; isTooltipDisabled?: boolean;
tailLength?: number;
} }
const HashStringShortenDynamic = ({ hash, fontWeight = '400', isTooltipDisabled }: Props) => { const HashStringShortenDynamic = ({ hash, fontWeight = '400', isTooltipDisabled, tailLength = TAIL_LENGTH }: Props) => {
const elementRef = useRef<HTMLSpanElement>(null); const elementRef = useRef<HTMLSpanElement>(null);
const [ displayedString, setDisplayedString ] = React.useState(hash); const [ displayedString, setDisplayedString ] = React.useState(hash);
...@@ -48,9 +49,9 @@ const HashStringShortenDynamic = ({ hash, fontWeight = '400', isTooltipDisabled ...@@ -48,9 +49,9 @@ const HashStringShortenDynamic = ({ hash, fontWeight = '400', isTooltipDisabled
const parentWidth = getWidth(parent); const parentWidth = getWidth(parent);
if (getWidth(shadowEl) > parentWidth) { if (getWidth(shadowEl) > parentWidth) {
const tail = hash.slice(-TAIL_LENGTH); const tail = hash.slice(-tailLength);
let leftI = HEAD_MIN_LENGTH; let leftI = HEAD_MIN_LENGTH;
let rightI = hash.length - TAIL_LENGTH; let rightI = hash.length - tailLength;
while (rightI - leftI > 1) { while (rightI - leftI > 1) {
const medI = ((rightI - leftI) % 2) ? leftI + (rightI - leftI + 1) / 2 : leftI + (rightI - leftI) / 2; const medI = ((rightI - leftI) % 2) ? leftI + (rightI - leftI + 1) / 2 : leftI + (rightI - leftI) / 2;
...@@ -68,7 +69,7 @@ const HashStringShortenDynamic = ({ hash, fontWeight = '400', isTooltipDisabled ...@@ -68,7 +69,7 @@ const HashStringShortenDynamic = ({ hash, fontWeight = '400', isTooltipDisabled
} }
parent.removeChild(shadowEl); parent.removeChild(shadowEl);
}, [ hash ]); }, [ hash, tailLength ]);
// we want to do recalculation when isFontFaceLoaded flag is changed // we want to do recalculation when isFontFaceLoaded flag is changed
// but we don't want to create more resize event listeners // but we don't want to create more resize event listeners
......
...@@ -20,6 +20,7 @@ type CommonProps = { ...@@ -20,6 +20,7 @@ type CommonProps = {
isLoading?: boolean; isLoading?: boolean;
onClick?: (e: React.MouseEvent<HTMLAnchorElement>) => void; onClick?: (e: React.MouseEvent<HTMLAnchorElement>) => void;
query?: Record<string, string>; query?: Record<string, string>;
tailLength?: number;
} }
type AddressTokenTxProps = { type AddressTokenTxProps = {
...@@ -78,7 +79,7 @@ const AddressLink = (props: Props) => { ...@@ -78,7 +79,7 @@ const AddressLink = (props: Props) => {
case 'constant': case 'constant':
return <HashStringShorten hash={ hash } isTooltipDisabled={ isMobile }/>; return <HashStringShorten hash={ hash } isTooltipDisabled={ isMobile }/>;
case 'dynamic': case 'dynamic':
return <HashStringShortenDynamic hash={ hash } fontWeight={ fontWeight } isTooltipDisabled={ isMobile }/>; return <HashStringShortenDynamic hash={ hash } fontWeight={ fontWeight } isTooltipDisabled={ isMobile } tailLength={ props.tailLength }/>;
case 'none': case 'none':
return <span>{ hash }</span>; return <span>{ hash }</span>;
} }
......
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