Commit a3417b52 authored by Igor Stuev's avatar Igor Stuev Committed by GitHub

Merge pull request #690 from blockscout/display

display list component
parents d5eb9cd0 e3de71bc
import { Box, Hide, Show, Table, Tbody, Th, Tr } from '@chakra-ui/react'; import { Hide, Show, Table, Tbody, Th, Tr } from '@chakra-ui/react';
import { useQueryClient } from '@tanstack/react-query'; import { useQueryClient } from '@tanstack/react-query';
import { useRouter } from 'next/router'; import { useRouter } from 'next/router';
import React from 'react'; import React from 'react';
...@@ -12,10 +12,8 @@ import useQueryWithPages from 'lib/hooks/useQueryWithPages'; ...@@ -12,10 +12,8 @@ import useQueryWithPages from 'lib/hooks/useQueryWithPages';
import useSocketChannel from 'lib/socket/useSocketChannel'; import useSocketChannel from 'lib/socket/useSocketChannel';
import useSocketMessage from 'lib/socket/useSocketMessage'; import useSocketMessage from 'lib/socket/useSocketMessage';
import ActionBar from 'ui/shared/ActionBar'; import ActionBar from 'ui/shared/ActionBar';
import DataFetchAlert from 'ui/shared/DataFetchAlert'; import DataListDisplay from 'ui/shared/DataListDisplay';
import Pagination from 'ui/shared/Pagination'; import Pagination from 'ui/shared/Pagination';
import SkeletonList from 'ui/shared/skeletons/SkeletonList';
import SkeletonTable from 'ui/shared/skeletons/SkeletonTable';
import SocketAlert from 'ui/shared/SocketAlert'; import SocketAlert from 'ui/shared/SocketAlert';
import { default as Thead } from 'ui/shared/TheadSticky'; import { default as Thead } from 'ui/shared/TheadSticky';
...@@ -71,30 +69,9 @@ const AddressBlocksValidated = ({ scrollRef }: Props) => { ...@@ -71,30 +69,9 @@ const AddressBlocksValidated = ({ scrollRef }: Props) => {
handler: handleNewSocketMessage, handler: handleNewSocketMessage,
}); });
const content = (() => { const content = query.data?.items ? (
if (query.isLoading) {
return (
<>
<Hide below="lg" ssr={ false }>
<SkeletonTable columns={ [ '17%', '17%', '16%', '25%', '25%' ] } isLong/>
</Hide>
<Show below="lg" ssr={ false }>
<SkeletonList/>
</Show>
</>
);
}
if (query.isError) {
return <DataFetchAlert/>;
}
if (query.data.items.length === 0) {
return 'There is no validated blocks for this address';
}
return (
<> <>
{ socketAlert && <SocketAlert mb={ 6 }/> }
<Hide below="lg" ssr={ false }> <Hide below="lg" ssr={ false }>
<Table variant="simple" size="sm"> <Table variant="simple" size="sm">
<Thead top={ query.isPaginationVisible ? 80 : 0 }> <Thead top={ query.isPaginationVisible ? 80 : 0 }>
...@@ -119,19 +96,24 @@ const AddressBlocksValidated = ({ scrollRef }: Props) => { ...@@ -119,19 +96,24 @@ const AddressBlocksValidated = ({ scrollRef }: Props) => {
)) } )) }
</Show> </Show>
</> </>
); ) : null;
})();
return ( const actionBar = query.isPaginationVisible ? (
<Box>
{ query.isPaginationVisible && (
<ActionBar mt={ -6 } showShadow={ query.isLoading }> <ActionBar mt={ -6 } showShadow={ query.isLoading }>
<Pagination ml="auto" { ...query.pagination }/> <Pagination ml="auto" { ...query.pagination }/>
</ActionBar> </ActionBar>
) } ) : null;
{ socketAlert && <SocketAlert mb={ 6 }/> }
{ content } return (
</Box> <DataListDisplay
isError={ query.isError }
isLoading={ query.isLoading }
items={ query.data?.items }
skeletonProps={{ isLongSkeleton: true, skeletonDesktopColumns: [ '17%', '17%', '16%', '25%', '25%' ] }}
emptyText="There are no validated blocks for this address."
content={ content }
actionBar={ actionBar }
/>
); );
}; };
......
import { Text, Show, Hide } from '@chakra-ui/react'; import { Show, Hide } from '@chakra-ui/react';
import { useRouter } from 'next/router'; import { useRouter } from 'next/router';
import React from 'react'; import React from 'react';
...@@ -10,12 +10,9 @@ import useQueryWithPages from 'lib/hooks/useQueryWithPages'; ...@@ -10,12 +10,9 @@ import useQueryWithPages from 'lib/hooks/useQueryWithPages';
import { apos } from 'lib/html-entities'; import { apos } from 'lib/html-entities';
import getQueryParamString from 'lib/router/getQueryParamString'; import getQueryParamString from 'lib/router/getQueryParamString';
import AddressIntTxsTable from 'ui/address/internals/AddressIntTxsTable'; import AddressIntTxsTable from 'ui/address/internals/AddressIntTxsTable';
import EmptySearchResult from 'ui/apps/EmptySearchResult';
import ActionBar from 'ui/shared/ActionBar'; import ActionBar from 'ui/shared/ActionBar';
import DataFetchAlert from 'ui/shared/DataFetchAlert'; import DataListDisplay from 'ui/shared/DataListDisplay';
import Pagination from 'ui/shared/Pagination'; import Pagination from 'ui/shared/Pagination';
import SkeletonList from 'ui/shared/skeletons/SkeletonList';
import SkeletonTable from 'ui/shared/skeletons/SkeletonTable';
import AddressCsvExportLink from './AddressCsvExportLink'; import AddressCsvExportLink from './AddressCsvExportLink';
import AddressTxsFilter from './AddressTxsFilter'; import AddressTxsFilter from './AddressTxsFilter';
...@@ -43,33 +40,7 @@ const AddressInternalTxs = ({ scrollRef }: {scrollRef?: React.RefObject<HTMLDivE ...@@ -43,33 +40,7 @@ const AddressInternalTxs = ({ scrollRef }: {scrollRef?: React.RefObject<HTMLDivE
onFilterChange({ filter: newVal }); onFilterChange({ filter: newVal });
}, [ onFilterChange ]); }, [ onFilterChange ]);
const content = (() => { const content = data?.items ? (
if (isError) {
return <DataFetchAlert/>;
}
if (isLoading) {
return (
<>
<Show below="lg" ssr={ false }>
<SkeletonList/>
</Show>
<Hide below="lg" ssr={ false }>
<SkeletonTable columns={ [ '15%', '15%', '10%', '20%', '20%', '20%' ] } isLong/>
</Hide>
</>
);
}
if (data.items.length === 0 && !filterValue) {
return <Text as="span">There are no internal transactions for this address.</Text>;
}
if (data.items.length === 0) {
return <EmptySearchResult text={ `Couldn${ apos }t find any transaction that matches your query.` }/>;
}
return (
<> <>
<Show below="lg" ssr={ false }> <Show below="lg" ssr={ false }>
<AddressIntTxsList data={ data.items } currentAddress={ hash }/> <AddressIntTxsList data={ data.items } currentAddress={ hash }/>
...@@ -78,11 +49,9 @@ const AddressInternalTxs = ({ scrollRef }: {scrollRef?: React.RefObject<HTMLDivE ...@@ -78,11 +49,9 @@ const AddressInternalTxs = ({ scrollRef }: {scrollRef?: React.RefObject<HTMLDivE
<AddressIntTxsTable data={ data.items } currentAddress={ hash }/> <AddressIntTxsTable data={ data.items } currentAddress={ hash }/>
</Hide> </Hide>
</> </>
); ) : null ;
})();
return ( const actionBar = (
<>
<ActionBar mt={ -6 } justifyContent="left" showShadow={ isLoading }> <ActionBar mt={ -6 } justifyContent="left" showShadow={ isLoading }>
<AddressTxsFilter <AddressTxsFilter
defaultFilter={ filterValue } defaultFilter={ filterValue }
...@@ -92,8 +61,19 @@ const AddressInternalTxs = ({ scrollRef }: {scrollRef?: React.RefObject<HTMLDivE ...@@ -92,8 +61,19 @@ const AddressInternalTxs = ({ scrollRef }: {scrollRef?: React.RefObject<HTMLDivE
<AddressCsvExportLink address={ hash } type="internal-transactions" ml={{ base: 2, lg: 'auto' }}/> <AddressCsvExportLink address={ hash } type="internal-transactions" ml={{ base: 2, lg: 'auto' }}/>
{ isPaginationVisible && <Pagination ml={{ base: 'auto', lg: 8 }} { ...pagination }/> } { isPaginationVisible && <Pagination ml={{ base: 'auto', lg: 8 }} { ...pagination }/> }
</ActionBar> </ActionBar>
{ content } );
</>
return (
<DataListDisplay
isError={ isError }
isLoading={ isLoading }
items={ data?.items }
skeletonProps={{ isLongSkeleton: true, skeletonDesktopColumns: [ '15%', '15%', '10%', '20%', '20%', '20%' ] }}
filterProps={{ emptyFilteredText: `Couldn${ apos }t find any transaction that matches your query.`, hasActiveFilters: Boolean(filterValue) }}
emptyText="There are no internal transactions for this address."
content={ content }
actionBar={ actionBar }
/>
); );
}; };
......
import { Box } from '@chakra-ui/react';
import { useRouter } from 'next/router'; import { useRouter } from 'next/router';
import React from 'react'; import React from 'react';
import useQueryWithPages from 'lib/hooks/useQueryWithPages'; import useQueryWithPages from 'lib/hooks/useQueryWithPages';
import getQueryParamString from 'lib/router/getQueryParamString'; import getQueryParamString from 'lib/router/getQueryParamString';
import ActionBar from 'ui/shared/ActionBar'; import ActionBar from 'ui/shared/ActionBar';
import DataFetchAlert from 'ui/shared/DataFetchAlert'; import DataListDisplay from 'ui/shared/DataListDisplay';
import LogItem from 'ui/shared/logs/LogItem'; import LogItem from 'ui/shared/logs/LogItem';
import LogSkeleton from 'ui/shared/logs/LogSkeleton'; import LogSkeleton from 'ui/shared/logs/LogSkeleton';
import Pagination from 'ui/shared/Pagination'; import Pagination from 'ui/shared/Pagination';
...@@ -20,35 +19,26 @@ const AddressLogs = ({ scrollRef }: {scrollRef?: React.RefObject<HTMLDivElement> ...@@ -20,35 +19,26 @@ const AddressLogs = ({ scrollRef }: {scrollRef?: React.RefObject<HTMLDivElement>
scrollRef, scrollRef,
}); });
if (isError) { const actionBar = isPaginationVisible ? (
return <DataFetchAlert/>;
}
const bar = isPaginationVisible ? (
<ActionBar mt={ -6 } showShadow> <ActionBar mt={ -6 } showShadow>
<Pagination ml="auto" { ...pagination }/> <Pagination ml="auto" { ...pagination }/>
</ActionBar> </ActionBar>
) : null; ) : null;
if (isLoading) { const content = data?.items ? data.items.map((item, index) => <LogItem key={ index } { ...item } type="address"/>) : null;
return (
<Box>
{ bar }
<LogSkeleton/>
<LogSkeleton/>
</Box>
);
}
if (data.items.length === 0) { const skeleton = <><LogSkeleton/><LogSkeleton/></>;
return <span>There are no logs for this address.</span>;
}
return ( return (
<> <DataListDisplay
{ bar } isError={ isError }
{ data.items.map((item, index) => <LogItem key={ index } { ...item } type="address"/>) } isLoading={ isLoading }
</> items={ data?.items }
emptyText="There are no logs for this address."
content={ content }
actionBar={ actionBar }
skeletonProps={{ customSkeleton: skeleton }}
/>
); );
}; };
......
...@@ -20,13 +20,10 @@ import getQueryParamString from 'lib/router/getQueryParamString'; ...@@ -20,13 +20,10 @@ import getQueryParamString from 'lib/router/getQueryParamString';
import useSocketChannel from 'lib/socket/useSocketChannel'; import useSocketChannel from 'lib/socket/useSocketChannel';
import useSocketMessage from 'lib/socket/useSocketMessage'; import useSocketMessage from 'lib/socket/useSocketMessage';
import TOKEN_TYPE from 'lib/token/tokenTypes'; import TOKEN_TYPE from 'lib/token/tokenTypes';
import EmptySearchResult from 'ui/apps/EmptySearchResult';
import ActionBar from 'ui/shared/ActionBar'; import ActionBar from 'ui/shared/ActionBar';
import DataFetchAlert from 'ui/shared/DataFetchAlert'; import DataListDisplay from 'ui/shared/DataListDisplay';
import HashStringShorten from 'ui/shared/HashStringShorten'; import HashStringShorten from 'ui/shared/HashStringShorten';
import Pagination from 'ui/shared/Pagination'; import Pagination from 'ui/shared/Pagination';
import SkeletonList from 'ui/shared/skeletons/SkeletonList';
import SkeletonTable from 'ui/shared/skeletons/SkeletonTable';
import SocketNewItemsNotice from 'ui/shared/SocketNewItemsNotice'; import SocketNewItemsNotice from 'ui/shared/SocketNewItemsNotice';
import TokenLogo from 'ui/shared/TokenLogo'; import TokenLogo from 'ui/shared/TokenLogo';
import { flattenTotal } from 'ui/shared/TokenTransfer/helpers'; import { flattenTotal } from 'ui/shared/TokenTransfer/helpers';
...@@ -164,34 +161,8 @@ const AddressTokenTransfers = ({ scrollRef }: {scrollRef?: React.RefObject<HTMLD ...@@ -164,34 +161,8 @@ const AddressTokenTransfers = ({ scrollRef }: {scrollRef?: React.RefObject<HTMLD
const numActiveFilters = (filters.type?.length || 0) + (filters.filter ? 1 : 0); const numActiveFilters = (filters.type?.length || 0) + (filters.filter ? 1 : 0);
const isActionBarHidden = !tokenFilter && !numActiveFilters && !data?.items.length && !currentAddress; const isActionBarHidden = !tokenFilter && !numActiveFilters && !data?.items.length && !currentAddress;
const content = (() => { const items = data?.items?.reduce(flattenTotal, []);
if (isLoading) { const content = items ? (
return (
<>
<Hide below="lg" ssr={ false }>
<SkeletonTable columns={ [ '44px', '185px', '160px', '25%', '25%', '25%', '25%' ] } isLong/>
</Hide>
<Show below="lg" ssr={ false }>
<SkeletonList/>
</Show>
</>
);
}
if (isError) {
return <DataFetchAlert/>;
}
if (!data.items?.length && !numActiveFilters) {
return <Text as="span">There are no token transfers</Text>;
}
if (!data.items?.length) {
return <EmptySearchResult text={ `Couldn${ apos }t find any token transfer that matches your query.` }/>;
}
const items = data.items.reduce(flattenTotal, []);
return (
<> <>
<Hide below="lg" ssr={ false }> <Hide below="lg" ssr={ false }>
<TokenTransferTable <TokenTransferTable
...@@ -223,8 +194,7 @@ const AddressTokenTransfers = ({ scrollRef }: {scrollRef?: React.RefObject<HTMLD ...@@ -223,8 +194,7 @@ const AddressTokenTransfers = ({ scrollRef }: {scrollRef?: React.RefObject<HTMLD
/> />
</Show> </Show>
</> </>
); ) : null;
})();
const tokenFilterComponent = tokenFilter && ( const tokenFilterComponent = tokenFilter && (
<Flex alignItems="center" flexWrap="wrap" mb={{ base: isActionBarHidden ? 3 : 6, lg: 0 }} mr={ 4 }> <Flex alignItems="center" flexWrap="wrap" mb={{ base: isActionBarHidden ? 3 : 6, lg: 0 }} mr={ 4 }>
...@@ -249,7 +219,7 @@ const AddressTokenTransfers = ({ scrollRef }: {scrollRef?: React.RefObject<HTMLD ...@@ -249,7 +219,7 @@ const AddressTokenTransfers = ({ scrollRef }: {scrollRef?: React.RefObject<HTMLD
</Flex> </Flex>
); );
return ( const actionBar = (
<> <>
{ isMobile && tokenFilterComponent } { isMobile && tokenFilterComponent }
{ !isActionBarHidden && ( { !isActionBarHidden && (
...@@ -269,9 +239,27 @@ const AddressTokenTransfers = ({ scrollRef }: {scrollRef?: React.RefObject<HTMLD ...@@ -269,9 +239,27 @@ const AddressTokenTransfers = ({ scrollRef }: {scrollRef?: React.RefObject<HTMLD
{ isPaginationVisible && <Pagination ml={{ base: 'auto', lg: 8 }} { ...pagination }/> } { isPaginationVisible && <Pagination ml={{ base: 'auto', lg: 8 }} { ...pagination }/> }
</ActionBar> </ActionBar>
) } ) }
{ content }
</> </>
); );
return (
<DataListDisplay
isError={ isError }
isLoading={ isLoading }
items={ data?.items }
skeletonProps={{
isLongSkeleton: true,
skeletonDesktopColumns: [ '44px', '185px', '160px', '25%', '25%', '25%', '25%' ],
}}
emptyText="There are no token transfers."
filterProps={{
emptyFilteredText: `Couldn${ apos }t find any token transfer that matches your query.`,
hasActiveFilters: Boolean(numActiveFilters),
}}
content={ content }
actionBar={ actionBar }
/>
);
}; };
export default AddressTokenTransfers; export default AddressTokenTransfers;
import { Box, Hide, Show, Table, Tbody, Th, Tr } from '@chakra-ui/react'; import { Hide, Show, Table, Tbody, Th, Tr } from '@chakra-ui/react';
import type { UseQueryResult } from '@tanstack/react-query'; import type { UseQueryResult } from '@tanstack/react-query';
import React from 'react'; import React from 'react';
...@@ -6,11 +6,9 @@ import type { AddressCoinBalanceHistoryResponse } from 'types/api/address'; ...@@ -6,11 +6,9 @@ import type { AddressCoinBalanceHistoryResponse } from 'types/api/address';
import appConfig from 'configs/app/config'; import appConfig from 'configs/app/config';
import ActionBar from 'ui/shared/ActionBar'; import ActionBar from 'ui/shared/ActionBar';
import DataFetchAlert from 'ui/shared/DataFetchAlert'; import DataListDisplay from 'ui/shared/DataListDisplay';
import type { Props as PaginationProps } from 'ui/shared/Pagination'; import type { Props as PaginationProps } from 'ui/shared/Pagination';
import Pagination from 'ui/shared/Pagination'; import Pagination from 'ui/shared/Pagination';
import SkeletonList from 'ui/shared/skeletons/SkeletonList';
import SkeletonTable from 'ui/shared/skeletons/SkeletonTable';
import { default as Thead } from 'ui/shared/TheadSticky'; import { default as Thead } from 'ui/shared/TheadSticky';
import AddressCoinBalanceListItem from './AddressCoinBalanceListItem'; import AddressCoinBalanceListItem from './AddressCoinBalanceListItem';
...@@ -25,29 +23,7 @@ interface Props { ...@@ -25,29 +23,7 @@ interface Props {
const AddressCoinBalanceHistory = ({ query }: Props) => { const AddressCoinBalanceHistory = ({ query }: Props) => {
const content = (() => { const content = query.data?.items ? (
if (query.isLoading) {
return (
<>
<Hide below="lg" ssr={ false }>
<SkeletonTable columns={ [ '25%', '25%', '25%', '25%', '120px' ] }/>
</Hide>
<Show below="lg" ssr={ false }>
<SkeletonList/>
</Show>
</>
);
}
if (query.isError) {
return <DataFetchAlert/>;
}
if (query.data.items.length === 0 && !query.isPaginationVisible) {
return <span>There is no coin balance history for this address</span>;
}
return (
<> <>
<Hide below="lg" ssr={ false }> <Hide below="lg" ssr={ false }>
<Table variant="simple" size="sm"> <Table variant="simple" size="sm">
...@@ -73,18 +49,25 @@ const AddressCoinBalanceHistory = ({ query }: Props) => { ...@@ -73,18 +49,25 @@ const AddressCoinBalanceHistory = ({ query }: Props) => {
)) } )) }
</Show> </Show>
</> </>
); ) : null;
})();
return ( const actionBar = query.isPaginationVisible ? (
<Box mt={ 8 }>
{ query.isPaginationVisible && (
<ActionBar mt={ -6 }> <ActionBar mt={ -6 }>
<Pagination ml="auto" { ...query.pagination }/> <Pagination ml="auto" { ...query.pagination }/>
</ActionBar> </ActionBar>
) } ) : null;
{ content }
</Box> return (
<DataListDisplay
mt={ 8 }
isError={ query.isError }
isLoading={ query.isLoading }
items={ query.data?.items }
skeletonProps={{ skeletonDesktopColumns: [ '25%', '25%', '25%', '25%', '120px' ] }}
emptyText="There is no coin balance history for this address."
content={ content }
actionBar={ actionBar }
/>
); );
}; };
......
import { Grid, Skeleton, Text } from '@chakra-ui/react'; import { Grid, Skeleton } from '@chakra-ui/react';
import type { UseQueryResult } from '@tanstack/react-query'; import type { UseQueryResult } from '@tanstack/react-query';
import React from 'react'; import React from 'react';
...@@ -6,7 +6,7 @@ import type { AddressTokensResponse } from 'types/api/address'; ...@@ -6,7 +6,7 @@ import type { AddressTokensResponse } from 'types/api/address';
import useIsMobile from 'lib/hooks/useIsMobile'; import useIsMobile from 'lib/hooks/useIsMobile';
import ActionBar from 'ui/shared/ActionBar'; import ActionBar from 'ui/shared/ActionBar';
import DataFetchAlert from 'ui/shared/DataFetchAlert'; import DataListDisplay from 'ui/shared/DataListDisplay';
import type { Props as PaginationProps } from 'ui/shared/Pagination'; import type { Props as PaginationProps } from 'ui/shared/Pagination';
import Pagination from 'ui/shared/Pagination'; import Pagination from 'ui/shared/Pagination';
...@@ -24,20 +24,13 @@ const TokensWithIds = ({ tokensQuery }: Props) => { ...@@ -24,20 +24,13 @@ const TokensWithIds = ({ tokensQuery }: Props) => {
const { isError, isLoading, data, pagination, isPaginationVisible } = tokensQuery; const { isError, isLoading, data, pagination, isPaginationVisible } = tokensQuery;
if (isError) { const actionBar = isMobile && isPaginationVisible && (
return <DataFetchAlert/>;
}
const bar = isMobile && isPaginationVisible && (
<ActionBar mt={ -6 }> <ActionBar mt={ -6 }>
<Pagination ml="auto" { ...pagination }/> <Pagination ml="auto" { ...pagination }/>
</ActionBar> </ActionBar>
); );
if (isLoading) { const skeleton = (
return (
<>
{ bar }
<Grid <Grid
w="100%" w="100%"
columnGap={{ base: 3, lg: 6 }} columnGap={{ base: 3, lg: 6 }}
...@@ -50,17 +43,9 @@ const TokensWithIds = ({ tokensQuery }: Props) => { ...@@ -50,17 +43,9 @@ const TokensWithIds = ({ tokensQuery }: Props) => {
<Skeleton w={{ base: '100%', lg: '210px' }} h="272px"/> <Skeleton w={{ base: '100%', lg: '210px' }} h="272px"/>
<Skeleton w={{ base: '100%', lg: '210px' }} h="272px"/> <Skeleton w={{ base: '100%', lg: '210px' }} h="272px"/>
</Grid> </Grid>
</>
); );
}
if (!data.items.length) {
return <Text as="span">There are no tokens of selected type.</Text>;
}
return ( const content = data?.items ? (
<>
{ bar }
<Grid <Grid
w="100%" w="100%"
columnGap={{ base: 3, lg: 6 }} columnGap={{ base: 3, lg: 6 }}
...@@ -69,7 +54,18 @@ const TokensWithIds = ({ tokensQuery }: Props) => { ...@@ -69,7 +54,18 @@ const TokensWithIds = ({ tokensQuery }: Props) => {
> >
{ data.items.map(item => <NFTItem key={ item.token.address } { ...item }/>) } { data.items.map(item => <NFTItem key={ item.token.address } { ...item }/>) }
</Grid> </Grid>
</> ) : null;
return (
<DataListDisplay
isError={ isError }
isLoading={ isLoading }
items={ data?.items }
emptyText="There are no tokens of selected type."
content={ content }
actionBar={ actionBar }
skeletonProps={{ customSkeleton: skeleton }}
/>
); );
}; };
......
import { Text, Show, Hide } from '@chakra-ui/react'; import { Show, Hide } from '@chakra-ui/react';
import type { UseQueryResult } from '@tanstack/react-query'; import type { UseQueryResult } from '@tanstack/react-query';
import React from 'react'; import React from 'react';
...@@ -6,11 +6,9 @@ import type { AddressTokensResponse } from 'types/api/address'; ...@@ -6,11 +6,9 @@ import type { AddressTokensResponse } from 'types/api/address';
import useIsMobile from 'lib/hooks/useIsMobile'; import useIsMobile from 'lib/hooks/useIsMobile';
import ActionBar from 'ui/shared/ActionBar'; import ActionBar from 'ui/shared/ActionBar';
import DataFetchAlert from 'ui/shared/DataFetchAlert'; import DataListDisplay from 'ui/shared/DataListDisplay';
import Pagination from 'ui/shared/Pagination'; import Pagination from 'ui/shared/Pagination';
import type { Props as PaginationProps } from 'ui/shared/Pagination'; import type { Props as PaginationProps } from 'ui/shared/Pagination';
import SkeletonList from 'ui/shared/skeletons/SkeletonList';
import SkeletonTable from 'ui/shared/skeletons/SkeletonTable';
import TokensListItem from './TokensListItem'; import TokensListItem from './TokensListItem';
import TokensTable from './TokensTable'; import TokensTable from './TokensTable';
...@@ -27,36 +25,31 @@ const TokensWithoutIds = ({ tokensQuery }: Props) => { ...@@ -27,36 +25,31 @@ const TokensWithoutIds = ({ tokensQuery }: Props) => {
const { isError, isLoading, data, pagination, isPaginationVisible } = tokensQuery; const { isError, isLoading, data, pagination, isPaginationVisible } = tokensQuery;
if (isError) { const actionBar = isMobile && isPaginationVisible && (
return <DataFetchAlert/>;
}
const bar = isMobile && isPaginationVisible && (
<ActionBar mt={ -6 }> <ActionBar mt={ -6 }>
<Pagination ml="auto" { ...pagination }/> <Pagination ml="auto" { ...pagination }/>
</ActionBar> </ActionBar>
); );
if (isLoading) { const content = data?.items ? (
return (
<> <>
{ bar } <Hide below="lg" ssr={ false }><TokensTable data={ data.items } top={ isPaginationVisible ? 72 : 0 }/></Hide>
<Hide below="lg" ssr={ false }><SkeletonTable columns={ [ '30%', '30%', '10%', '20%', '10%' ] }/></Hide> <Show below="lg" ssr={ false }>{ data.items.map(item => <TokensListItem key={ item.token.address } { ...item }/>) }</Show></>
<Show below="lg" ssr={ false }><SkeletonList/></Show> ) : null;
</>
);
}
if (data.items.length === 0) {
return <Text as="span">There are no tokens of selected type.</Text>;
}
return ( return (
<> <DataListDisplay
{ bar } isError={ isError }
<Hide below="lg" ssr={ false }><TokensTable data={ data.items } top={ isPaginationVisible ? 72 : 0 }/></Hide> isLoading={ isLoading }
<Show below="lg" ssr={ false }>{ data.items.map(item => <TokensListItem key={ item.token.address } { ...item }/>) }</Show> items={ data?.items }
</> skeletonProps={{
isLongSkeleton: true,
skeletonDesktopColumns: [ '30%', '30%', '10%', '20%', '10%' ],
}}
emptyText="There are no tokens of selected type."
content={ content }
actionBar={ actionBar }
/>
); );
}; };
......
import { Text, Show, Hide, Alert } from '@chakra-ui/react'; import { Show, Hide, Alert } from '@chakra-ui/react';
import type { UseQueryResult } from '@tanstack/react-query'; import type { UseQueryResult } from '@tanstack/react-query';
import { useQueryClient } from '@tanstack/react-query'; import { useQueryClient } from '@tanstack/react-query';
import React from 'react'; import React from 'react';
...@@ -13,11 +13,9 @@ import useSocketMessage from 'lib/socket/useSocketMessage'; ...@@ -13,11 +13,9 @@ import useSocketMessage from 'lib/socket/useSocketMessage';
import BlocksList from 'ui/blocks/BlocksList'; import BlocksList from 'ui/blocks/BlocksList';
import BlocksTable from 'ui/blocks/BlocksTable'; import BlocksTable from 'ui/blocks/BlocksTable';
import ActionBar from 'ui/shared/ActionBar'; import ActionBar from 'ui/shared/ActionBar';
import DataFetchAlert from 'ui/shared/DataFetchAlert'; import DataListDisplay from 'ui/shared/DataListDisplay';
import Pagination from 'ui/shared/Pagination'; import Pagination from 'ui/shared/Pagination';
import type { Props as PaginationProps } from 'ui/shared/Pagination'; import type { Props as PaginationProps } from 'ui/shared/Pagination';
import SkeletonList from 'ui/shared/skeletons/SkeletonList';
import SkeletonTable from 'ui/shared/skeletons/SkeletonTable';
type QueryResult = UseQueryResult<BlocksResponse> & { type QueryResult = UseQueryResult<BlocksResponse> & {
pagination: PaginationProps; pagination: PaginationProps;
...@@ -76,29 +74,7 @@ const BlocksContent = ({ type, query }: Props) => { ...@@ -76,29 +74,7 @@ const BlocksContent = ({ type, query }: Props) => {
handler: handleNewBlockMessage, handler: handleNewBlockMessage,
}); });
const content = (() => { const content = query.data?.items ? (
if (query.isLoading) {
return (
<>
<Show below="lg" key="skeleton-mobile" ssr={ false }>
<SkeletonList/>
</Show>
<Hide below="lg" key="skeleton-desktop" ssr={ false }>
<SkeletonTable columns={ [ '125px', '120px', '21%', '64px', '35%', '22%', '22%' ] }/>
</Hide>
</>
);
}
if (query.isError) {
return <DataFetchAlert/>;
}
if (query.data.items.length === 0) {
return <Text as="span">There are no blocks.</Text>;
}
return (
<> <>
{ socketAlert && <Alert status="warning" mb={ 6 } as="a" href={ window.document.location.href }>{ socketAlert }</Alert> } { socketAlert && <Alert status="warning" mb={ 6 } as="a" href={ window.document.location.href }>{ socketAlert }</Alert> }
<Show below="lg" key="content-mobile" ssr={ false }> <Show below="lg" key="content-mobile" ssr={ false }>
...@@ -108,19 +84,24 @@ const BlocksContent = ({ type, query }: Props) => { ...@@ -108,19 +84,24 @@ const BlocksContent = ({ type, query }: Props) => {
<BlocksTable data={ query.data.items } top={ query.isPaginationVisible ? 80 : 0 } page={ query.pagination.page }/> <BlocksTable data={ query.data.items } top={ query.isPaginationVisible ? 80 : 0 } page={ query.pagination.page }/>
</Hide> </Hide>
</> </>
); ) : null;
})();
return ( const actionBar = isMobile && query.isPaginationVisible ? (
<>
{ isMobile && query.isPaginationVisible && (
<ActionBar mt={ -6 }> <ActionBar mt={ -6 }>
<Pagination ml="auto" { ...query.pagination }/> <Pagination ml="auto" { ...query.pagination }/>
</ActionBar> </ActionBar>
) } ) : null;
{ content }
</> return (
<DataListDisplay
isError={ query.isError }
isLoading={ query.isLoading }
items={ query.data?.items }
skeletonProps={{ skeletonDesktopColumns: [ '125px', '120px', '21%', '64px', '35%', '22%', '22%' ] }}
emptyText="There are no blocks."
content={ content }
actionBar={ actionBar }
/>
); );
}; };
......
...@@ -5,12 +5,10 @@ import useQueryWithPages from 'lib/hooks/useQueryWithPages'; ...@@ -5,12 +5,10 @@ import useQueryWithPages from 'lib/hooks/useQueryWithPages';
import AddressesListItem from 'ui/addresses/AddressesListItem'; import AddressesListItem from 'ui/addresses/AddressesListItem';
import AddressesTable from 'ui/addresses/AddressesTable'; import AddressesTable from 'ui/addresses/AddressesTable';
import ActionBar from 'ui/shared/ActionBar'; import ActionBar from 'ui/shared/ActionBar';
import DataFetchAlert from 'ui/shared/DataFetchAlert'; import DataListDisplay from 'ui/shared/DataListDisplay';
import Page from 'ui/shared/Page/Page'; import Page from 'ui/shared/Page/Page';
import PageTitle from 'ui/shared/Page/PageTitle'; import PageTitle from 'ui/shared/Page/PageTitle';
import Pagination from 'ui/shared/Pagination'; import Pagination from 'ui/shared/Pagination';
import SkeletonList from 'ui/shared/skeletons/SkeletonList';
import SkeletonTable from 'ui/shared/skeletons/SkeletonTable';
const PAGE_SIZE = 50; const PAGE_SIZE = 50;
...@@ -19,32 +17,15 @@ const Accounts = () => { ...@@ -19,32 +17,15 @@ const Accounts = () => {
resourceName: 'addresses', resourceName: 'addresses',
}); });
const content = (() => { const actionBar = isPaginationVisible && (
if (isError) {
return <DataFetchAlert/>;
}
const bar = isPaginationVisible && (
<ActionBar mt={ -6 }> <ActionBar mt={ -6 }>
<Pagination ml="auto" { ...pagination }/> <Pagination ml="auto" { ...pagination }/>
</ActionBar> </ActionBar>
); );
if (isLoading) {
return (
<>
{ bar }
<SkeletonList display={{ base: 'block', lg: 'none' }}/>
<SkeletonTable display={{ base: 'none', lg: 'block' }} columns={ [ '64px', '30%', '20%', '20%', '15%', '15%' ] }/>
</>
);
}
const pageStartIndex = (pagination.page - 1) * PAGE_SIZE + 1; const pageStartIndex = (pagination.page - 1) * PAGE_SIZE + 1;
const content = data?.items ? (
return (
<> <>
{ bar }
<Hide below="lg" ssr={ false }> <Hide below="lg" ssr={ false }>
<AddressesTable <AddressesTable
top={ isPaginationVisible ? 80 : 0 } top={ isPaginationVisible ? 80 : 0 }
...@@ -66,13 +47,20 @@ const Accounts = () => { ...@@ -66,13 +47,20 @@ const Accounts = () => {
}) } }) }
</Show> </Show>
</> </>
); ) : null;
})();
return ( return (
<Page> <Page>
<PageTitle text="Top accounts" withTextAd/> <PageTitle text="Top accounts" withTextAd/>
{ content } <DataListDisplay
isError={ isError }
isLoading={ isLoading }
items={ data?.items }
skeletonProps={{ skeletonDesktopColumns: [ '64px', '30%', '20%', '20%', '15%', '15%' ] }}
emptyText="There are no accounts."
content={ content }
actionBar={ actionBar }
/>
</Page> </Page>
); );
}; };
......
...@@ -21,8 +21,7 @@ const hooksConfig = { ...@@ -21,8 +21,7 @@ const hooksConfig = {
}; };
// FIXME: idk why mobile test doesn't work (it's ok locally) // FIXME: idk why mobile test doesn't work (it's ok locally)
// test('base view +@mobile +@dark-mode', async({ mount, page }) => { test('base view +@mobile +@dark-mode', async({ mount, page }) => {
test('base view +@dark-mode', async({ mount, page }) => {
await page.route('https://request-global.czilladx.com/serve/native.php?z=19260bf627546ab7242', (route) => route.fulfill({ await page.route('https://request-global.czilladx.com/serve/native.php?z=19260bf627546ab7242', (route) => route.fulfill({
status: 200, status: 200,
body: '', body: '',
......
import { Box, Flex, Hide, Show, Text } from '@chakra-ui/react'; import { Box, Flex, Hide, Show } from '@chakra-ui/react';
import { useRouter } from 'next/router'; import { useRouter } from 'next/router';
import React from 'react'; import React from 'react';
...@@ -8,14 +8,11 @@ import useDebounce from 'lib/hooks/useDebounce'; ...@@ -8,14 +8,11 @@ import useDebounce from 'lib/hooks/useDebounce';
import useQueryWithPages from 'lib/hooks/useQueryWithPages'; import useQueryWithPages from 'lib/hooks/useQueryWithPages';
import { apos } from 'lib/html-entities'; import { apos } from 'lib/html-entities';
import getQueryParamString from 'lib/router/getQueryParamString'; import getQueryParamString from 'lib/router/getQueryParamString';
import EmptySearchResult from 'ui/apps/EmptySearchResult';
import ActionBar from 'ui/shared/ActionBar'; import ActionBar from 'ui/shared/ActionBar';
import DataFetchAlert from 'ui/shared/DataFetchAlert'; import DataListDisplay from 'ui/shared/DataListDisplay';
import FilterInput from 'ui/shared/filters/FilterInput'; import FilterInput from 'ui/shared/filters/FilterInput';
import PageTitle from 'ui/shared/Page/PageTitle'; import PageTitle from 'ui/shared/Page/PageTitle';
import Pagination from 'ui/shared/Pagination'; import Pagination from 'ui/shared/Pagination';
import SkeletonList from 'ui/shared/skeletons/SkeletonList';
import SkeletonTable from 'ui/shared/skeletons/SkeletonTable';
import Sort from 'ui/shared/sort/Sort'; import Sort from 'ui/shared/sort/Sort';
import type { SortField, Sort as TSort } from 'ui/verifiedContracts/utils'; import type { SortField, Sort as TSort } from 'ui/verifiedContracts/utils';
import { SORT_OPTIONS, sortFn, getNextSortValue } from 'ui/verifiedContracts/utils'; import { SORT_OPTIONS, sortFn, getNextSortValue } from 'ui/verifiedContracts/utils';
...@@ -82,7 +79,7 @@ const VerifiedContracts = () => { ...@@ -82,7 +79,7 @@ const VerifiedContracts = () => {
/> />
); );
const bar = ( const actionBar = (
<> <>
<Show below="lg" ssr={ false }> <Show below="lg" ssr={ false }>
<Flex columnGap={ 3 } mb={ 6 }> <Flex columnGap={ 3 } mb={ 6 }>
...@@ -103,35 +100,9 @@ const VerifiedContracts = () => { ...@@ -103,35 +100,9 @@ const VerifiedContracts = () => {
</> </>
); );
const content = (() => { const sortedData = data?.items.slice().sort(sortFn(sort));
if (isError) {
return <DataFetchAlert/>;
}
if (isLoading) { const content = sortedData ? (
return (
<>
<Show below="lg" ssr={ false }>
<SkeletonList/>
</Show>
<Hide below="lg" ssr={ false }>
<SkeletonTable columns={ [ '50%', '130px', '130px', '50%', '80px', '110px' ] }/>
</Hide>
</>
);
}
if (data.items.length === 0 && !searchTerm && !type) {
return <Text as="span">There are no verified contracts</Text>;
}
if (data.items.length === 0) {
return <EmptySearchResult text={ `Couldn${ apos }t find any contract that matches your query.` }/>;
}
const sortedData = data.items.slice().sort(sortFn(sort));
return (
<> <>
<Show below="lg" ssr={ false }> <Show below="lg" ssr={ false }>
<VerifiedContractsList data={ sortedData }/> <VerifiedContractsList data={ sortedData }/>
...@@ -140,14 +111,24 @@ const VerifiedContracts = () => { ...@@ -140,14 +111,24 @@ const VerifiedContracts = () => {
<VerifiedContractsTable data={ sortedData } sort={ sort } onSortToggle={ handleSortToggle }/> <VerifiedContractsTable data={ sortedData } sort={ sort } onSortToggle={ handleSortToggle }/>
</Hide> </Hide>
</> </>
); ) : null;
})();
return ( return (
<Box> <Box>
<PageTitle text="Verified contracts" withTextAd/> <PageTitle text="Verified contracts" withTextAd/>
{ bar } <DataListDisplay
{ content } isError={ isError }
isLoading={ isLoading }
items={ data?.items }
skeletonProps={{ skeletonDesktopColumns: [ '50%', '130px', '130px', '50%', '80px', '110px' ] }}
emptyText="There are no verified contracts."
filterProps={{
emptyFilteredText: `Couldn${ apos }t find any contract that matches your query.`,
hasActiveFilters: Boolean(searchTerm || type),
}}
content={ content }
actionBar={ actionBar }
/>
</Box> </Box>
); );
}; };
......
import { Box, Text, chakra } from '@chakra-ui/react';
import React from 'react';
import EmptySearchResult from 'ui/apps/EmptySearchResult';
import DataFetchAlert from './DataFetchAlert';
import SkeletonList from './skeletons/SkeletonList';
import SkeletonTable from './skeletons/SkeletonTable';
type SkeletonProps =
{ customSkeleton: React.ReactNode } |
{
skeletonDesktopColumns: Array<string>;
isLongSkeleton?: boolean;
}
type FilterProps = {
hasActiveFilters: boolean;
emptyFilteredText: string;
};
type Props = {
isError: boolean;
isLoading: boolean;
// eslint-disable-next-line @typescript-eslint/no-explicit-any
items?: Array<any>;
emptyText: string;
actionBar?: React.ReactNode;
content: React.ReactNode;
className?: string;
skeletonProps: SkeletonProps;
filterProps?: FilterProps;
}
const DataListDisplay = (props: Props) => {
if (props.isError) {
return <DataFetchAlert/>;
}
if (props.isLoading) {
return (
<>
{ props.actionBar }
{ 'customSkeleton' in props.skeletonProps && props.skeletonProps.customSkeleton }
{ 'skeletonDesktopColumns' in props.skeletonProps && (
<>
<SkeletonList display={{ base: 'block', lg: 'none' }}/>
<SkeletonTable
display={{ base: 'none', lg: 'block' }}
columns={ props.skeletonProps.skeletonDesktopColumns || [] }
isLong={ props.skeletonProps.isLongSkeleton }
/>
</>
) }
</>
);
}
if (props.filterProps?.hasActiveFilters && !props.items?.length) {
return (
<>
{ props.actionBar }
<EmptySearchResult text={ props.filterProps.emptyFilteredText }/>
</>
);
}
if (!props.items?.length) {
return <Text as="span">{ props.emptyText }</Text>;
}
return (
<Box className={ props.className }>
{ props.actionBar }
{ props.content }
</Box>
);
};
export default chakra(DataListDisplay);
import { Text } from '@chakra-ui/react';
import type { UseQueryResult } from '@tanstack/react-query'; import type { UseQueryResult } from '@tanstack/react-query';
import React from 'react'; import React from 'react';
...@@ -7,10 +6,9 @@ import type { TokenHolders, TokenInfo } from 'types/api/token'; ...@@ -7,10 +6,9 @@ import type { TokenHolders, TokenInfo } from 'types/api/token';
import useIsMobile from 'lib/hooks/useIsMobile'; import useIsMobile from 'lib/hooks/useIsMobile';
import ActionBar from 'ui/shared/ActionBar'; import ActionBar from 'ui/shared/ActionBar';
import DataFetchAlert from 'ui/shared/DataFetchAlert'; import DataFetchAlert from 'ui/shared/DataFetchAlert';
import DataListDisplay from 'ui/shared/DataListDisplay';
import Pagination from 'ui/shared/Pagination'; import Pagination from 'ui/shared/Pagination';
import type { Props as PaginationProps } from 'ui/shared/Pagination'; import type { Props as PaginationProps } from 'ui/shared/Pagination';
import SkeletonList from 'ui/shared/skeletons/SkeletonList';
import SkeletonTable from 'ui/shared/skeletons/SkeletonTable';
import TokenHoldersList from './TokenHoldersList'; import TokenHoldersList from './TokenHoldersList';
import TokenHoldersTable from './TokenHoldersTable'; import TokenHoldersTable from './TokenHoldersTable';
...@@ -30,36 +28,31 @@ const TokenHoldersContent = ({ holdersQuery, tokenQuery }: Props) => { ...@@ -30,36 +28,31 @@ const TokenHoldersContent = ({ holdersQuery, tokenQuery }: Props) => {
return <DataFetchAlert/>; return <DataFetchAlert/>;
} }
const bar = isMobile && holdersQuery.isPaginationVisible && ( const actionBar = isMobile && holdersQuery.isPaginationVisible && (
<ActionBar mt={ -6 }> <ActionBar mt={ -6 }>
<Pagination ml="auto" { ...holdersQuery.pagination }/> <Pagination ml="auto" { ...holdersQuery.pagination }/>
</ActionBar> </ActionBar>
); );
if (holdersQuery.isLoading || tokenQuery.isLoading) { const items = holdersQuery.data?.items;
return (
<>
{ bar }
{ isMobile && <SkeletonList/> }
{ !isMobile && (
<SkeletonTable columns={ [ '100%', '300px', '175px' ] } isLong/>
) }
</>
);
}
const items = holdersQuery.data.items;
if (!items?.length) { const content = items && tokenQuery.data ? (
return <Text as="span">There are no holders for this token.</Text>;
}
return (
<> <>
{ bar }
{ !isMobile && <TokenHoldersTable data={ items } token={ tokenQuery.data } top={ holdersQuery.isPaginationVisible ? 80 : 0 }/> } { !isMobile && <TokenHoldersTable data={ items } token={ tokenQuery.data } top={ holdersQuery.isPaginationVisible ? 80 : 0 }/> }
{ isMobile && <TokenHoldersList data={ items } token={ tokenQuery.data }/> } { isMobile && <TokenHoldersList data={ items } token={ tokenQuery.data }/> }
</> </>
) : null;
return (
<DataListDisplay
isError={ holdersQuery.isError || tokenQuery.isError }
isLoading={ holdersQuery.isLoading || tokenQuery.isLoading }
items={ holdersQuery.data?.items }
skeletonProps={{ skeletonDesktopColumns: [ '100%', '300px', '175px' ] }}
emptyText="There are no holders for this token."
content={ content }
actionBar={ actionBar }
/>
); );
}; };
......
import { Grid, Text, Skeleton } from '@chakra-ui/react'; import { Grid, Skeleton } from '@chakra-ui/react';
import type { UseQueryResult } from '@tanstack/react-query'; import type { UseQueryResult } from '@tanstack/react-query';
import React from 'react'; import React from 'react';
...@@ -6,7 +6,7 @@ import type { TokenInventoryResponse } from 'types/api/token'; ...@@ -6,7 +6,7 @@ import type { TokenInventoryResponse } from 'types/api/token';
import useIsMobile from 'lib/hooks/useIsMobile'; import useIsMobile from 'lib/hooks/useIsMobile';
import ActionBar from 'ui/shared/ActionBar'; import ActionBar from 'ui/shared/ActionBar';
import DataFetchAlert from 'ui/shared/DataFetchAlert'; import DataListDisplay from 'ui/shared/DataListDisplay';
import type { Props as PaginationProps } from 'ui/shared/Pagination'; import type { Props as PaginationProps } from 'ui/shared/Pagination';
import Pagination from 'ui/shared/Pagination'; import Pagination from 'ui/shared/Pagination';
...@@ -21,20 +21,14 @@ type Props = { ...@@ -21,20 +21,14 @@ type Props = {
const TokenInventory = ({ inventoryQuery }: Props) => { const TokenInventory = ({ inventoryQuery }: Props) => {
const isMobile = useIsMobile(); const isMobile = useIsMobile();
if (inventoryQuery.isError) {
return <DataFetchAlert/>;
}
const bar = isMobile && inventoryQuery.isPaginationVisible && ( const actionBar = isMobile && inventoryQuery.isPaginationVisible && (
<ActionBar mt={ -6 }> <ActionBar mt={ -6 }>
<Pagination ml="auto" { ...inventoryQuery.pagination }/> <Pagination ml="auto" { ...inventoryQuery.pagination }/>
</ActionBar> </ActionBar>
); );
if (inventoryQuery.isLoading) { const skeleton = (
return (
<>
{ bar }
<Grid <Grid
w="100%" w="100%"
columnGap={{ base: 3, lg: 6 }} columnGap={{ base: 3, lg: 6 }}
...@@ -47,19 +41,11 @@ const TokenInventory = ({ inventoryQuery }: Props) => { ...@@ -47,19 +41,11 @@ const TokenInventory = ({ inventoryQuery }: Props) => {
<Skeleton w={{ base: '100%', lg: '210px' }} h="272px"/> <Skeleton w={{ base: '100%', lg: '210px' }} h="272px"/>
<Skeleton w={{ base: '100%', lg: '210px' }} h="272px"/> <Skeleton w={{ base: '100%', lg: '210px' }} h="272px"/>
</Grid> </Grid>
</>
); );
}
const items = inventoryQuery.data.items;
if (!items?.length) { const items = inventoryQuery.data?.items;
return <Text as="span">There are no tokens.</Text>;
}
return ( const content = items ? (
<>
{ bar }
<Grid <Grid
w="100%" w="100%"
columnGap={{ base: 3, lg: 6 }} columnGap={{ base: 3, lg: 6 }}
...@@ -67,7 +53,19 @@ const TokenInventory = ({ inventoryQuery }: Props) => { ...@@ -67,7 +53,19 @@ const TokenInventory = ({ inventoryQuery }: Props) => {
gridTemplateColumns={{ base: 'repeat(2, calc((100% - 12px)/2))', lg: 'repeat(auto-fill, minmax(210px, 1fr))' }} gridTemplateColumns={{ base: 'repeat(2, calc((100% - 12px)/2))', lg: 'repeat(auto-fill, minmax(210px, 1fr))' }}
> >
{ items.map((item) => <TokenInventoryItem key={ item.token.address + '_' + item.id } item={ item }/>) } { items.map((item) => <TokenInventoryItem key={ item.token.address + '_' + item.id } item={ item }/>) }
</Grid></> </Grid>
) : null;
return (
<DataListDisplay
isError={ inventoryQuery.isError }
isLoading={ inventoryQuery.isLoading }
items={ items }
emptyText="There are no tokens."
content={ content }
actionBar={ actionBar }
skeletonProps={{ customSkeleton: skeleton }}
/>
); );
}; };
......
import { Hide, Show, Text } from '@chakra-ui/react'; import { Hide, Show } from '@chakra-ui/react';
import type { UseQueryResult } from '@tanstack/react-query'; import type { UseQueryResult } from '@tanstack/react-query';
import { useRouter } from 'next/router'; import { useRouter } from 'next/router';
import React from 'react'; import React from 'react';
...@@ -11,11 +11,9 @@ import useIsMobile from 'lib/hooks/useIsMobile'; ...@@ -11,11 +11,9 @@ import useIsMobile from 'lib/hooks/useIsMobile';
import useSocketChannel from 'lib/socket/useSocketChannel'; import useSocketChannel from 'lib/socket/useSocketChannel';
import useSocketMessage from 'lib/socket/useSocketMessage'; import useSocketMessage from 'lib/socket/useSocketMessage';
import ActionBar from 'ui/shared/ActionBar'; import ActionBar from 'ui/shared/ActionBar';
import DataFetchAlert from 'ui/shared/DataFetchAlert'; import DataListDisplay from 'ui/shared/DataListDisplay';
import Pagination from 'ui/shared/Pagination'; import Pagination from 'ui/shared/Pagination';
import type { Props as PaginationProps } from 'ui/shared/Pagination'; import type { Props as PaginationProps } from 'ui/shared/Pagination';
import SkeletonList from 'ui/shared/skeletons/SkeletonList';
import SkeletonTable from 'ui/shared/skeletons/SkeletonTable';
import SocketNewItemsNotice from 'ui/shared/SocketNewItemsNotice'; import SocketNewItemsNotice from 'ui/shared/SocketNewItemsNotice';
import { flattenTotal } from 'ui/shared/TokenTransfer/helpers'; import { flattenTotal } from 'ui/shared/TokenTransfer/helpers';
import TokenTransferList from 'ui/token/TokenTransfer/TokenTransferList'; import TokenTransferList from 'ui/token/TokenTransfer/TokenTransferList';
...@@ -61,30 +59,10 @@ const TokenTransfer = ({ transfersQuery, tokenId }: Props) => { ...@@ -61,30 +59,10 @@ const TokenTransfer = ({ transfersQuery, tokenId }: Props) => {
handler: handleNewTransfersMessage, handler: handleNewTransfersMessage,
}); });
const content = (() => { const items = data?.items?.reduce(flattenTotal, []);
if (isLoading) {
return (
<>
<Hide below="lg" ssr={ false }>
<SkeletonTable columns={ [ '45%', '15%', '36px', '15%', '25%' ] } isLong/>
</Hide>
<Show below="lg" ssr={ false }>
<SkeletonList/>
</Show>
</>
);
}
if (isError) {
return <DataFetchAlert/>;
}
if (!data.items?.length) { const content = items ? (
return <Text as="span">There are no token transfers</Text>;
}
const items = data.items.reduce(flattenTotal, []);
return (
<> <>
<Hide below="lg" ssr={ false }> <Hide below="lg" ssr={ false }>
<TokenTransferTable <TokenTransferTable
...@@ -109,18 +87,27 @@ const TokenTransfer = ({ transfersQuery, tokenId }: Props) => { ...@@ -109,18 +87,27 @@ const TokenTransfer = ({ transfersQuery, tokenId }: Props) => {
<TokenTransferList data={ items } tokenId={ tokenId }/> <TokenTransferList data={ items } tokenId={ tokenId }/>
</Show> </Show>
</> </>
); ) : null;
})();
return ( const actionBar = isMobile && isPaginationVisible ? (
<>
{ isMobile && isPaginationVisible && (
<ActionBar mt={ -6 }> <ActionBar mt={ -6 }>
<Pagination ml="auto" { ...pagination }/> <Pagination ml="auto" { ...pagination }/>
</ActionBar> </ActionBar>
) } ) : null;
{ content }
</> return (
<DataListDisplay
isError={ isError }
isLoading={ isLoading }
items={ data?.items }
skeletonProps={{
isLongSkeleton: true,
skeletonDesktopColumns: [ '45%', '15%', '36px', '15%', '25%' ],
}}
emptyText="There are no token transfers."
content={ content }
actionBar={ actionBar }
/>
); );
}; };
......
import { Hide, HStack, Show, Text } from '@chakra-ui/react'; import { Hide, HStack, Show } from '@chakra-ui/react';
import { useRouter } from 'next/router'; import { useRouter } from 'next/router';
import React, { useCallback } from 'react'; import React, { useCallback } from 'react';
...@@ -9,15 +9,13 @@ import useDebounce from 'lib/hooks/useDebounce'; ...@@ -9,15 +9,13 @@ import useDebounce from 'lib/hooks/useDebounce';
import useQueryWithPages from 'lib/hooks/useQueryWithPages'; import useQueryWithPages from 'lib/hooks/useQueryWithPages';
import { apos } from 'lib/html-entities'; import { apos } from 'lib/html-entities';
import TOKEN_TYPE from 'lib/token/tokenTypes'; import TOKEN_TYPE from 'lib/token/tokenTypes';
import EmptySearchResult from 'ui/apps/EmptySearchResult';
import ActionBar from 'ui/shared/ActionBar'; import ActionBar from 'ui/shared/ActionBar';
import DataFetchAlert from 'ui/shared/DataFetchAlert'; import DataFetchAlert from 'ui/shared/DataFetchAlert';
import DataListDisplay from 'ui/shared/DataListDisplay';
import FilterInput from 'ui/shared/filters/FilterInput'; import FilterInput from 'ui/shared/filters/FilterInput';
import PopoverFilter from 'ui/shared/filters/PopoverFilter'; import PopoverFilter from 'ui/shared/filters/PopoverFilter';
import TokenTypeFilter from 'ui/shared/filters/TokenTypeFilter'; import TokenTypeFilter from 'ui/shared/filters/TokenTypeFilter';
import Pagination from 'ui/shared/Pagination'; import Pagination from 'ui/shared/Pagination';
import SkeletonList from 'ui/shared/skeletons/SkeletonList';
import SkeletonTable from 'ui/shared/skeletons/SkeletonTable';
import TokensListItem from './TokensListItem'; import TokensListItem from './TokensListItem';
import TokensTable from './TokensTable'; import TokensTable from './TokensTable';
...@@ -67,7 +65,7 @@ const Tokens = () => { ...@@ -67,7 +65,7 @@ const Tokens = () => {
/> />
); );
const bar = ( const actionBar = (
<> <>
<HStack spacing={ 3 } mb={ 6 } display={{ base: 'flex', lg: 'none' }}> <HStack spacing={ 3 } mb={ 6 } display={{ base: 'flex', lg: 'none' }}>
{ typeFilter } { typeFilter }
...@@ -83,36 +81,28 @@ const Tokens = () => { ...@@ -83,36 +81,28 @@ const Tokens = () => {
</> </>
); );
if (isLoading) { const content = data?.items ? (
return (
<>
{ bar }
<SkeletonList display={{ base: 'block', lg: 'none' }}/>
<SkeletonTable display={{ base: 'none', lg: 'block' }} columns={ [ '25px', '33%', '33%', '33%', '110px' ] }/>
</>
);
}
if (!data.items.length) {
if (debouncedFilter || type) {
return (
<>
{ bar }
<EmptySearchResult text={ `Couldn${ apos }t find token that matches your filter query.` }/>;
</>
);
}
return <Text as="span">There are no tokens</Text>;
}
return (
<> <>
{ bar }
<Show below="lg" ssr={ false }> <Show below="lg" ssr={ false }>
{ data.items.map((item, index) => <TokensListItem key={ item.address } token={ item } index={ index } page={ pagination.page }/>) } { data.items.map((item, index) => <TokensListItem key={ item.address } token={ item } index={ index } page={ pagination.page }/>) }
</Show> </Show>
<Hide below="lg" ssr={ false }><TokensTable items={ data.items } page={ pagination.page }/></Hide> <Hide below="lg" ssr={ false }><TokensTable items={ data.items } page={ pagination.page }/></Hide></>
</> ) : null;
return (
<DataListDisplay
isError={ isError }
isLoading={ isLoading }
items={ data?.items }
skeletonProps={{ skeletonDesktopColumns: [ '25px', '33%', '33%', '33%', '110px' ] }}
emptyText="There are no tokens."
filterProps={{
emptyFilteredText: `Couldn${ apos }t find token that matches your filter query.`,
hasActiveFilters: Boolean(debouncedFilter || type),
}}
content={ content }
actionBar={ actionBar }
/>
); );
}; };
......
import { Box, Text, Show, Hide } from '@chakra-ui/react'; import { Show, Hide } from '@chakra-ui/react';
import React from 'react'; import React from 'react';
import type { InternalTransaction } from 'types/api/internalTransaction'; import type { InternalTransaction } from 'types/api/internalTransaction';
import { SECOND } from 'lib/consts'; import { SECOND } from 'lib/consts';
import useIsMobile from 'lib/hooks/useIsMobile';
import useQueryWithPages from 'lib/hooks/useQueryWithPages'; import useQueryWithPages from 'lib/hooks/useQueryWithPages';
import { apos } from 'lib/html-entities'; // import { apos } from 'lib/html-entities';
import EmptySearchResult from 'ui/apps/EmptySearchResult';
import ActionBar from 'ui/shared/ActionBar'; import ActionBar from 'ui/shared/ActionBar';
import DataFetchAlert from 'ui/shared/DataFetchAlert'; import DataListDisplay from 'ui/shared/DataListDisplay';
// import FilterInput from 'ui/shared/filters/FilterInput'; // import FilterInput from 'ui/shared/filters/FilterInput';
// import TxInternalsFilter from 'ui/tx/internals/TxInternalsFilter'; // import TxInternalsFilter from 'ui/tx/internals/TxInternalsFilter';
import Pagination from 'ui/shared/Pagination'; import Pagination from 'ui/shared/Pagination';
import SkeletonList from 'ui/shared/skeletons/SkeletonList';
import SkeletonTable from 'ui/shared/skeletons/SkeletonTable';
import TxInternalsList from 'ui/tx/internals/TxInternalsList'; import TxInternalsList from 'ui/tx/internals/TxInternalsList';
import TxInternalsTable from 'ui/tx/internals/TxInternalsTable'; import TxInternalsTable from 'ui/tx/internals/TxInternalsTable';
import type { Sort, SortField } from 'ui/tx/internals/utils'; import type { Sort, SortField } from 'ui/tx/internals/utils';
...@@ -82,8 +78,6 @@ const TxInternals = () => { ...@@ -82,8 +78,6 @@ const TxInternals = () => {
}, },
}); });
const isMobile = useIsMobile();
// const handleFilterChange = React.useCallback((nextValue: Array<TxInternalsType>) => { // const handleFilterChange = React.useCallback((nextValue: Array<TxInternalsType>) => {
// setFilters(nextValue); // setFilters(nextValue);
// }, []); // }, []);
...@@ -98,52 +92,43 @@ const TxInternals = () => { ...@@ -98,52 +92,43 @@ const TxInternals = () => {
return txInfo.socketStatus ? <TxSocketAlert status={ txInfo.socketStatus }/> : <TxPendingAlert/>; return txInfo.socketStatus ? <TxSocketAlert status={ txInfo.socketStatus }/> : <TxPendingAlert/>;
} }
if (isLoading || txInfo.isLoading) { const filteredData = data?.items
return (
<>
<Show below="lg" ssr={ false }><SkeletonList/></Show>
<Hide below="lg" ssr={ false }><SkeletonTable columns={ [ '28%', '20%', '24px', '20%', '16%', '16%' ] }/></Hide>
</>
);
}
if (isError || txInfo.isError) {
return <DataFetchAlert/>;
}
if (data.items.length === 0) {
return <Text as="span">There are no internal transactions for this transaction.</Text>;
}
const content = (() => {
const filteredData = data.items
.slice() .slice()
// .filter(({ type }) => filters.length > 0 ? filters.includes(type) : true) // .filter(({ type }) => filters.length > 0 ? filters.includes(type) : true)
// .filter(searchFn(searchTerm)) // .filter(searchFn(searchTerm))
.sort(sortFn(sort)); .sort(sortFn(sort));
if (filteredData.length === 0) { const content = filteredData ? (
return <EmptySearchResult text={ `Couldn${ apos }t find any transaction that matches your query.` }/>; <>
} <Show below="lg" ssr={ false }><TxInternalsList data={ filteredData }/></Show>
<Hide below="lg" ssr={ false }>
return isMobile ? <TxInternalsTable data={ filteredData } sort={ sort } onSortToggle={ handleSortToggle } top={ isPaginationVisible ? 80 : 0 }/>
<TxInternalsList data={ filteredData }/> : </Hide>
<TxInternalsTable data={ filteredData } sort={ sort } onSortToggle={ handleSortToggle } top={ isPaginationVisible ? 80 : 0 }/>; </>
})(); ) : null;
return ( const actionBar = isPaginationVisible ? (
<Box>
{ isPaginationVisible && (
<ActionBar mt={ -6 }> <ActionBar mt={ -6 }>
{ /* <TxInternalsFilter onFilterChange={ handleFilterChange } defaultFilters={ filters } appliedFiltersNum={ filters.length }/> */ }
{ /* <FilterInput onChange={ setSearchTerm } maxW="360px" ml={ 3 } size="xs" placeholder="Search by addresses, hash, method..."/> */ }
<Pagination ml="auto" { ...pagination }/> <Pagination ml="auto" { ...pagination }/>
</ActionBar> </ActionBar>
) } ) : null;
{ /* <Flex mb={ 6 }>
<TxInternalsFilter onFilterChange={ handleFilterChange } defaultFilters={ filters } appliedFiltersNum={ filters.length }/> return (
<FilterInput onChange={ setSearchTerm } maxW="360px" ml={ 3 } size="xs" placeholder="Search by addresses, hash, method..."/> <DataListDisplay
</Flex> */ } isError={ isError || txInfo.isError }
{ content } isLoading={ isLoading || txInfo.isLoading }
</Box> items={ data?.items }
skeletonProps={{ skeletonDesktopColumns: [ '28%', '20%', '24px', '20%', '16%', '16%' ] }}
emptyText="There are no internal transactions for this transaction."
// filterProps={{
// emptyFilteredText: `Couldn${ apos }t find any transaction that matches your query.`.
// hasActiveFilters: Boolean(filters.length || searchTerm),
// }}
content={ content }
actionBar={ actionBar }
/>
); );
}; };
......
import { Hide, Show, Text } from '@chakra-ui/react'; import { Hide, Show } from '@chakra-ui/react';
import { useRouter } from 'next/router'; import { useRouter } from 'next/router';
import React from 'react'; import React from 'react';
...@@ -9,12 +9,10 @@ import getFilterValuesFromQuery from 'lib/getFilterValuesFromQuery'; ...@@ -9,12 +9,10 @@ import getFilterValuesFromQuery from 'lib/getFilterValuesFromQuery';
import useQueryWithPages from 'lib/hooks/useQueryWithPages'; import useQueryWithPages from 'lib/hooks/useQueryWithPages';
import { apos } from 'lib/html-entities'; import { apos } from 'lib/html-entities';
import TOKEN_TYPE from 'lib/token/tokenTypes'; import TOKEN_TYPE from 'lib/token/tokenTypes';
import EmptySearchResult from 'ui/apps/EmptySearchResult';
import ActionBar from 'ui/shared/ActionBar'; import ActionBar from 'ui/shared/ActionBar';
import DataFetchAlert from 'ui/shared/DataFetchAlert'; import DataFetchAlert from 'ui/shared/DataFetchAlert';
import DataListDisplay from 'ui/shared/DataListDisplay';
import Pagination from 'ui/shared/Pagination'; import Pagination from 'ui/shared/Pagination';
import SkeletonList from 'ui/shared/skeletons/SkeletonList';
import SkeletonTable from 'ui/shared/skeletons/SkeletonTable';
import { flattenTotal } from 'ui/shared/TokenTransfer/helpers'; import { flattenTotal } from 'ui/shared/TokenTransfer/helpers';
import TokenTransferFilter from 'ui/shared/TokenTransfer/TokenTransferFilter'; import TokenTransferFilter from 'ui/shared/TokenTransfer/TokenTransferFilter';
import TokenTransferList from 'ui/shared/TokenTransfer/TokenTransferList'; import TokenTransferList from 'ui/shared/TokenTransfer/TokenTransferList';
...@@ -57,31 +55,9 @@ const TxTokenTransfer = () => { ...@@ -57,31 +55,9 @@ const TxTokenTransfer = () => {
const numActiveFilters = typeFilter.length; const numActiveFilters = typeFilter.length;
const isActionBarHidden = !numActiveFilters && !tokenTransferQuery.data?.items.length; const isActionBarHidden = !numActiveFilters && !tokenTransferQuery.data?.items.length;
const content = (() => { const items = tokenTransferQuery.data?.items?.reduce(flattenTotal, []);
if (txsInfo.isLoading || tokenTransferQuery.isLoading) {
return (
<>
<Hide below="lg" ssr={ false }>
<SkeletonTable columns={ [ '185px', '25%', '25%', '25%', '25%' ] }
/>
</Hide>
<Show below="lg" ssr={ false }>
<SkeletonList/>
</Show>
</>
);
}
if (!tokenTransferQuery.data.items?.length && !numActiveFilters) {
return <Text as="span">There are no token transfers</Text>;
}
if (!tokenTransferQuery.data.items?.length) {
return <EmptySearchResult text={ `Couldn${ apos }t find any token transfer that matches your query.` }/>;
}
const items = tokenTransferQuery.data.items.reduce(flattenTotal, []); const content = items ? (
return (
<> <>
<Hide below="lg" ssr={ false }> <Hide below="lg" ssr={ false }>
<TokenTransferTable data={ items } top={ isActionBarHidden ? 0 : 80 }/> <TokenTransferTable data={ items } top={ isActionBarHidden ? 0 : 80 }/>
...@@ -90,12 +66,9 @@ const TxTokenTransfer = () => { ...@@ -90,12 +66,9 @@ const TxTokenTransfer = () => {
<TokenTransferList data={ items }/> <TokenTransferList data={ items }/>
</Show> </Show>
</> </>
); ) : null;
})();
return ( const actionBar = !isActionBarHidden ? (
<>
{ !isActionBarHidden && (
<ActionBar mt={ -6 }> <ActionBar mt={ -6 }>
<TokenTransferFilter <TokenTransferFilter
defaultTypeFilters={ typeFilter } defaultTypeFilters={ typeFilter }
...@@ -104,9 +77,25 @@ const TxTokenTransfer = () => { ...@@ -104,9 +77,25 @@ const TxTokenTransfer = () => {
/> />
{ tokenTransferQuery.isPaginationVisible && <Pagination ml="auto" { ...tokenTransferQuery.pagination }/> } { tokenTransferQuery.isPaginationVisible && <Pagination ml="auto" { ...tokenTransferQuery.pagination }/> }
</ActionBar> </ActionBar>
) } ) : null;
{ content }
</> return (
<DataListDisplay
isError={ txsInfo.isError || tokenTransferQuery.isError }
isLoading={ txsInfo.isLoading || tokenTransferQuery.isLoading }
items={ tokenTransferQuery.data?.items }
skeletonProps={{
isLongSkeleton: true,
skeletonDesktopColumns: [ '185px', '25%', '25%', '25%', '25%' ],
}}
emptyText="There are no token transfers."
filterProps={{
emptyFilteredText: `Couldn${ apos }t find any token transfer that matches your query.`,
hasActiveFilters: Boolean(numActiveFilters),
}}
content={ content }
actionBar={ actionBar }
/>
); );
}; };
......
import { Text, Box, Show, Hide } from '@chakra-ui/react'; import { Box, Show, Hide } from '@chakra-ui/react';
import type { UseQueryResult } from '@tanstack/react-query'; import type { UseQueryResult } from '@tanstack/react-query';
import React from 'react'; import React from 'react';
...@@ -6,10 +6,8 @@ import type { TxsResponse } from 'types/api/transaction'; ...@@ -6,10 +6,8 @@ import type { TxsResponse } from 'types/api/transaction';
import useIsMobile from 'lib/hooks/useIsMobile'; import useIsMobile from 'lib/hooks/useIsMobile';
import AddressCsvExportLink from 'ui/address/AddressCsvExportLink'; import AddressCsvExportLink from 'ui/address/AddressCsvExportLink';
import DataFetchAlert from 'ui/shared/DataFetchAlert'; import DataListDisplay from 'ui/shared/DataListDisplay';
import type { Props as PaginationProps } from 'ui/shared/Pagination'; import type { Props as PaginationProps } from 'ui/shared/Pagination';
import SkeletonList from 'ui/shared/skeletons/SkeletonList';
import SkeletonTable from 'ui/shared/skeletons/SkeletonTable';
import SocketNewItemsNotice from 'ui/shared/SocketNewItemsNotice'; import SocketNewItemsNotice from 'ui/shared/SocketNewItemsNotice';
import TxsHeaderMobile from './TxsHeaderMobile'; import TxsHeaderMobile from './TxsHeaderMobile';
...@@ -50,35 +48,7 @@ const TxsContent = ({ ...@@ -50,35 +48,7 @@ const TxsContent = ({
const { data, isLoading, isError, setSortByField, setSortByValue, sorting } = useTxsSort(query); const { data, isLoading, isError, setSortByField, setSortByValue, sorting } = useTxsSort(query);
const isMobile = useIsMobile(); const isMobile = useIsMobile();
const content = (() => { const content = data?.items ? (
if (isError) {
return <DataFetchAlert/>;
}
if (isLoading) {
return (
<>
<Show below="lg" ssr={ false }><SkeletonList/></Show>
<Hide below="lg" ssr={ false }>
<SkeletonTable
columns={ showBlockInfo ?
[ '32px', '22%', '160px', '20%', '18%', '292px', '20%', '20%' ] :
[ '32px', '22%', '160px', '20%', '292px', '20%', '20%' ]
}
isLong={ hasLongSkeleton }
/>
</Hide>
</>
);
}
const txs = data.items;
if (!txs.length) {
return <Text as="span">There are no transactions.</Text>;
}
return (
<> <>
<Show below="lg" ssr={ false }> <Show below="lg" ssr={ false }>
<Box> <Box>
...@@ -92,7 +62,7 @@ const TxsContent = ({ ...@@ -92,7 +62,7 @@ const TxsContent = ({
{ ({ content }) => <Box>{ content }</Box> } { ({ content }) => <Box>{ content }</Box> }
</SocketNewItemsNotice> </SocketNewItemsNotice>
) } ) }
{ txs.map(tx => ( { data.items.map(tx => (
<TxsListItem <TxsListItem
tx={ tx } tx={ tx }
key={ tx.hash } key={ tx.hash }
...@@ -105,7 +75,7 @@ const TxsContent = ({ ...@@ -105,7 +75,7 @@ const TxsContent = ({
</Show> </Show>
<Hide below="lg" ssr={ false }> <Hide below="lg" ssr={ false }>
<TxsTable <TxsTable
txs={ txs } txs={ data.items }
sort={ setSortByField } sort={ setSortByField }
sorting={ sorting } sorting={ sorting }
showBlockInfo={ showBlockInfo } showBlockInfo={ showBlockInfo }
...@@ -118,12 +88,9 @@ const TxsContent = ({ ...@@ -118,12 +88,9 @@ const TxsContent = ({
/> />
</Hide> </Hide>
</> </>
); ) : null;
})();
return ( const actionBar = isMobile ? (
<>
{ isMobile && (
<TxsHeaderMobile <TxsHeaderMobile
mt={ -6 } mt={ -6 }
sorting={ sorting } sorting={ sorting }
...@@ -133,9 +100,23 @@ const TxsContent = ({ ...@@ -133,9 +100,23 @@ const TxsContent = ({
filterComponent={ filter } filterComponent={ filter }
linkSlot={ currentAddress ? <AddressCsvExportLink address={ currentAddress } type="transactions" ml={ 2 }/> : null } linkSlot={ currentAddress ? <AddressCsvExportLink address={ currentAddress } type="transactions" ml={ 2 }/> : null }
/> />
) } ) : null;
{ content }
</> return (
<DataListDisplay
isError={ isError }
isLoading={ isLoading }
items={ data?.items }
skeletonProps={{
isLongSkeleton: hasLongSkeleton,
skeletonDesktopColumns: showBlockInfo ?
[ '32px', '22%', '160px', '20%', '18%', '292px', '20%', '20%' ] :
[ '32px', '22%', '160px', '20%', '292px', '20%', '20%' ],
}}
emptyText="There are no transactions."
content={ content }
actionBar={ actionBar }
/>
); );
}; };
......
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