import { chakra, Flex } from '@chakra-ui/react'; import { capitalize } from 'es-toolkit'; import { useRouter } from 'next/router'; import React from 'react'; import type { TabItemRegular } from 'toolkit/components/AdaptiveTabs/types'; import type { PaginationParams } from 'ui/shared/pagination/types'; import { routeParams } from 'nextjs/routes'; import config from 'configs/app'; import { useMultichainContext } from 'lib/contexts/multichain'; import throwOnAbsentParamError from 'lib/errors/throwOnAbsentParamError'; import throwOnResourceLoadError from 'lib/errors/throwOnResourceLoadError'; import useIsMobile from 'lib/hooks/useIsMobile'; import getNetworkValidatorTitle from 'lib/networks/getNetworkValidatorTitle'; import getQueryParamString from 'lib/router/getQueryParamString'; import { Skeleton } from 'toolkit/chakra/skeleton'; import RoutedTabs from 'toolkit/components/RoutedTabs/RoutedTabs'; import BlockCeloEpochTag from 'ui/block/BlockCeloEpochTag'; import BlockDeposits from 'ui/block/BlockDeposits'; import BlockDetails from 'ui/block/BlockDetails'; import BlockInternalTxs from 'ui/block/BlockInternalTxs'; import BlockWithdrawals from 'ui/block/BlockWithdrawals'; import useBlockBlobTxsQuery from 'ui/block/useBlockBlobTxsQuery'; import useBlockDepositsQuery from 'ui/block/useBlockDepositsQuery'; import useBlockInternalTxsQuery from 'ui/block/useBlockInternalTxsQuery'; import useBlockQuery from 'ui/block/useBlockQuery'; import useBlockTxsQuery from 'ui/block/useBlockTxsQuery'; import useBlockWithdrawalsQuery from 'ui/block/useBlockWithdrawalsQuery'; import TextAd from 'ui/shared/ad/TextAd'; import ServiceDegradationWarning from 'ui/shared/alerts/ServiceDegradationWarning'; import BlockPendingUpdateAlert from 'ui/shared/block/BlockPendingUpdateAlert'; import AddressEntity from 'ui/shared/entities/address/AddressEntity'; import * as BlockEntity from 'ui/shared/entities/block/BlockEntity'; import NetworkExplorers from 'ui/shared/NetworkExplorers'; import PageTitle from 'ui/shared/Page/PageTitle'; import Pagination from 'ui/shared/pagination/Pagination'; import TxsWithFrontendSorting from 'ui/txs/TxsWithFrontendSorting'; const TAB_LIST_PROPS = { marginBottom: 0, pt: 6, pb: 6, marginTop: -5, }; const TABS_HEIGHT = 88; const beaconChainFeature = config.features.beaconChain; const BlockPageContent = () => { const router = useRouter(); const isMobile = useIsMobile(); const heightOrHash = getQueryParamString(router.query.height_or_hash); const tab = getQueryParamString(router.query.tab); const multichainContext = useMultichainContext(); const blockQuery = useBlockQuery({ heightOrHash }); const blockTxsQuery = useBlockTxsQuery({ heightOrHash, blockQuery, tab }); const blockWithdrawalsQuery = useBlockWithdrawalsQuery({ heightOrHash, blockQuery, tab }); const blockDepositsQuery = useBlockDepositsQuery({ heightOrHash, blockQuery, tab }); const blockBlobTxsQuery = useBlockBlobTxsQuery({ heightOrHash, blockQuery, tab }); const blockInternalTxsQuery = useBlockInternalTxsQuery({ heightOrHash, blockQuery, tab }); const hasPagination = !isMobile && ( (tab === 'txs' && blockTxsQuery.pagination.isVisible) || (tab === 'withdrawals' && blockWithdrawalsQuery.pagination.isVisible) || (tab === 'deposits' && blockDepositsQuery.pagination.isVisible) || (tab === 'internal_txs' && blockInternalTxsQuery.pagination.isVisible) ); const tabs: Array = React.useMemo(() => ([ { id: 'index', title: 'Details', component: ( <> { blockQuery.isDegradedData && } { blockQuery.data?.is_pending_update && } ), }, { id: 'txs', title: 'Transactions', component: ( <> { blockTxsQuery.isDegradedData && } ), }, { id: 'internal_txs', title: 'Internal txns', component: ( <> { blockTxsQuery.isDegradedData && } ), }, config.features.dataAvailability.isEnabled && blockQuery.data?.blob_transactions_count ? { id: 'blob_txs', title: 'Blob txns', component: ( ), } : null, beaconChainFeature.isEnabled && !beaconChainFeature.withdrawalsOnly && Boolean(blockQuery.data?.beacon_deposits_count) ? { id: 'deposits', title: 'Deposits', component: ( <> { blockDepositsQuery.isDegradedData && } ), } : null, config.features.beaconChain.isEnabled && Boolean(blockQuery.data?.withdrawals_count) ? { id: 'withdrawals', title: 'Withdrawals', component: ( <> { blockWithdrawalsQuery.isDegradedData && } ), } : null, ].filter(Boolean)), [ blockBlobTxsQuery, blockDepositsQuery, blockInternalTxsQuery, blockQuery, blockTxsQuery, blockWithdrawalsQuery, hasPagination ]); let pagination; if (tab === 'txs') { pagination = blockTxsQuery.pagination; } else if (tab === 'withdrawals') { pagination = blockWithdrawalsQuery.pagination; } else if (tab === 'deposits') { pagination = blockDepositsQuery.pagination; } else if (tab === 'internal_txs') { pagination = blockInternalTxsQuery.pagination; } throwOnAbsentParamError(heightOrHash); if (blockQuery.isError) { if (!blockQuery.isDegradedData && blockQuery.error.status === 404 && !heightOrHash.startsWith('0x') && blockQuery.isFutureBlock) { const url = routeParams({ pathname: '/block/countdown/[height]', query: { height: heightOrHash } }, multichainContext); router.push(url, undefined, { shallow: true }); return null; } else { throwOnResourceLoadError(blockQuery); } } const title = (() => { switch (blockQuery.data?.type) { case 'reorg': return `Reorged block #${ blockQuery.data?.height }`; case 'uncle': return `Uncle block #${ blockQuery.data?.height }`; default: return `Block #${ blockQuery.data?.height }`; } })(); const beforeTitleElement = multichainContext?.chain ? ( ) : null; const titleSecondRow = ( <> { !config.UI.views.block.hiddenFields?.miner && blockQuery.data?.miner && ( { capitalize(getNetworkValidatorTitle()) } ) } ); return ( <> } secondRow={ titleSecondRow } isLoading={ blockQuery.isPlaceholderData } /> : null } stickyEnabled={ hasPagination } /> ); }; export default BlockPageContent;