mirror of
https://github.com/luxfi/explore.git
synced 2026-07-27 05:54:15 +00:00
- Rename all @blockscout/* npm packages to @luxfi/* aliases (150+ files) - Override blue accent colors to gray for monochrome theme - Fix dropdown/menu/popover fonts to use Geist Sans - Change Latest Blocks to horizontal scrolling layout - Show dashes instead of zeros for validator stats on error - Fix GHA deploy step to use correct deployment name
138 lines
4.6 KiB
TypeScript
138 lines
4.6 KiB
TypeScript
import { chakra, Box, Flex, HStack, Text } from '@chakra-ui/react';
|
|
import { useQueryClient } from '@tanstack/react-query';
|
|
import { upperFirst } from 'es-toolkit';
|
|
import React from 'react';
|
|
|
|
import type { SocketMessage } from 'lib/socket/types';
|
|
import type { Block } from 'types/api/block';
|
|
|
|
import { route } from 'nextjs-routes';
|
|
|
|
import config from 'configs/app';
|
|
import useApiQuery, { getResourceKey } from 'lib/api/useApiQuery';
|
|
import useInitialList from 'lib/hooks/useInitialList';
|
|
import useIsMobile from 'lib/hooks/useIsMobile';
|
|
import getNetworkUtilizationParams from 'lib/networks/getNetworkUtilizationParams';
|
|
import useSocketChannel from 'lib/socket/useSocketChannel';
|
|
import useSocketMessage from 'lib/socket/useSocketMessage';
|
|
import { BLOCK } from 'stubs/block';
|
|
import { HOMEPAGE_STATS } from 'stubs/stats';
|
|
import { Heading } from 'toolkit/chakra/heading';
|
|
import { Link } from 'toolkit/chakra/link';
|
|
import { Skeleton } from 'toolkit/chakra/skeleton';
|
|
import { Tooltip } from 'toolkit/chakra/tooltip';
|
|
import { nbsp } from 'toolkit/utils/htmlEntities';
|
|
|
|
import LatestBlocksItem from './LatestBlocksItem';
|
|
|
|
const LatestBlocks = () => {
|
|
const isMobile = useIsMobile();
|
|
// const blocksMaxCount = isMobile ? 2 : 3;
|
|
let blocksMaxCount: number;
|
|
if (config.features.rollup.isEnabled || config.UI.views.block.hiddenFields?.total_reward) {
|
|
blocksMaxCount = isMobile ? 4 : 5;
|
|
} else {
|
|
blocksMaxCount = isMobile ? 2 : 3;
|
|
}
|
|
const { data, isPlaceholderData, isError } = useApiQuery('general:homepage_blocks', {
|
|
queryOptions: {
|
|
placeholderData: Array(blocksMaxCount).fill(BLOCK),
|
|
},
|
|
});
|
|
const initialList = useInitialList({
|
|
data: data ?? [],
|
|
idFn: (block) => block.height,
|
|
enabled: !isPlaceholderData,
|
|
});
|
|
|
|
const queryClient = useQueryClient();
|
|
const statsQueryResult = useApiQuery('general:stats', {
|
|
queryOptions: {
|
|
refetchOnMount: false,
|
|
placeholderData: HOMEPAGE_STATS,
|
|
},
|
|
});
|
|
|
|
const handleNewBlockMessage: SocketMessage.NewBlock['handler'] = React.useCallback((payload) => {
|
|
queryClient.setQueryData(getResourceKey('general:homepage_blocks'), (prevData: Array<Block> | undefined) => {
|
|
|
|
const newData = prevData ? [ ...prevData ] : [];
|
|
|
|
if (newData.some((block => block.height === payload.block.height))) {
|
|
return newData;
|
|
}
|
|
|
|
return [ payload.block, ...newData ].sort((b1, b2) => b2.height - b1.height).slice(0, blocksMaxCount);
|
|
});
|
|
}, [ queryClient, blocksMaxCount ]);
|
|
|
|
const channel = useSocketChannel({
|
|
topic: 'blocks:new_block',
|
|
isDisabled: isPlaceholderData || isError,
|
|
});
|
|
useSocketMessage({
|
|
channel,
|
|
event: 'new_block',
|
|
handler: handleNewBlockMessage,
|
|
});
|
|
|
|
let content;
|
|
|
|
if (isError) {
|
|
content = <Text>No data. Please reload the page.</Text>;
|
|
}
|
|
|
|
if (data) {
|
|
const dataToShow = data.slice(0, blocksMaxCount);
|
|
|
|
content = (
|
|
<>
|
|
<HStack gap={ 3 } mb={ 3 } overflowX="auto" overflowY="hidden" alignItems="stretch" pb={ 1 }>
|
|
{ dataToShow.map(((block, index) => (
|
|
<LatestBlocksItem
|
|
key={ block.height + (isPlaceholderData ? String(index) : '') }
|
|
block={ block }
|
|
isLoading={ isPlaceholderData }
|
|
animation={ initialList.getAnimationProp(block) }
|
|
/>
|
|
))) }
|
|
</HStack>
|
|
<Flex justifyContent="center">
|
|
<Link textStyle="sm" href={ route({ pathname: '/blocks' }) }>View all blocks</Link>
|
|
</Flex>
|
|
</>
|
|
);
|
|
}
|
|
|
|
const networkUtilization = getNetworkUtilizationParams(statsQueryResult.data?.network_utilization_percentage ?? 0);
|
|
|
|
return (
|
|
<Box width="100%">
|
|
<Heading level="3">Latest blocks</Heading>
|
|
{ statsQueryResult.data?.network_utilization_percentage !== undefined && (
|
|
<Skeleton loading={ statsQueryResult.isPlaceholderData } mt={ 2 } display="inline-block" textStyle="sm">
|
|
<Text as="span">
|
|
Network utilization:{ nbsp }
|
|
</Text>
|
|
<Tooltip content={ `${ upperFirst(networkUtilization.load) } load` }>
|
|
<Text as="span" color={ networkUtilization.color } fontWeight={ 700 }>
|
|
{ statsQueryResult.data?.network_utilization_percentage.toFixed(2) }%
|
|
</Text>
|
|
</Tooltip>
|
|
</Skeleton>
|
|
) }
|
|
{ statsQueryResult.data?.celo && (
|
|
<Box whiteSpace="pre-wrap" textStyle="sm" mt={ 2 }>
|
|
<span>Current epoch: </span>
|
|
<chakra.span fontWeight={ 700 }>#{ statsQueryResult.data.celo.epoch_number }</chakra.span>
|
|
</Box>
|
|
) }
|
|
<Box mt={ 3 }>
|
|
{ content }
|
|
</Box>
|
|
</Box>
|
|
);
|
|
};
|
|
|
|
export default LatestBlocks;
|