Commit 473d2b27 authored by tom's avatar tom

basic pagination for blocks

parent d6fd6c2c
......@@ -4,23 +4,32 @@ import { useRouter } from 'next/router';
import React, { useCallback } from 'react';
import { animateScroll } from 'react-scroll';
import type { TransactionsResponse } from 'types/api/transaction';
import type { BlockFilters } from 'types/api/block';
import type { PaginationParams } from 'types/api/pagination';
import type { TTxsFilters } from 'types/api/txsFilters';
import type { QueryKeys } from 'types/client/queries';
import useFetch from 'lib/hooks/useFetch';
const PAGINATION_FIELDS = [ 'block_number', 'index', 'items_count' ];
const PAGINATION_FIELDS: Array<keyof PaginationParams> = [ 'block_number', 'index', 'items_count' ];
export default function useQueryWithPages(apiPath: string, queryName: QueryKeys, filters?: TTxsFilters) {
interface ResponseWithPagination {
next_page_params: PaginationParams | null;
}
export default function useQueryWithPages<Response extends ResponseWithPagination>(
apiPath: string,
queryName: QueryKeys,
filters?: TTxsFilters | BlockFilters,
) {
const queryClient = useQueryClient();
const router = useRouter();
const [ page, setPage ] = React.useState(1);
const currPageParams = pick(router.query, PAGINATION_FIELDS);
const [ pageParams, setPageParams ] = React.useState<Array<Partial<TransactionsResponse['next_page_params']>>>([ {} ]);
const [ pageParams, setPageParams ] = React.useState<Array<Partial<PaginationParams>>>([ {} ]);
const fetch = useFetch();
const { data, isLoading, isError } = useQuery<unknown, unknown, TransactionsResponse>(
const queryResult = useQuery<unknown, unknown, Response>(
[ queryName, { page, filters } ],
async() => {
const params: Array<string> = [];
......@@ -37,6 +46,7 @@ export default function useQueryWithPages(apiPath: string, queryName: QueryKeys,
},
{ staleTime: Infinity },
);
const { data } = queryResult;
const onNextPageClick = useCallback(() => {
if (!data?.next_page_params) {
......@@ -88,6 +98,7 @@ export default function useQueryWithPages(apiPath: string, queryName: QueryKeys,
}, [ router, queryClient ]);
const hasPaginationParams = Object.keys(currPageParams).length > 0;
const nextPageParams = data?.next_page_params;
const pagination = {
page,
......@@ -95,7 +106,8 @@ export default function useQueryWithPages(apiPath: string, queryName: QueryKeys,
onPrevPageClick,
hasPaginationParams,
resetPage,
hasNextPage: nextPageParams ? Object.keys(nextPageParams).length > 0 : false,
};
return { data, isError, isLoading, pagination };
return { ...queryResult, pagination };
}
import type { NextApiRequest } from 'next';
import getSearchParams from 'lib/api/getSearchParams';
import handler from 'lib/api/handler';
const getUrl = (req: NextApiRequest) => {
return `/v2/blocks${ req.query.type ? `?type=${ req.query.type }` : '' }`;
const searchParamsStr = getSearchParams(req);
return `/v2/blocks${ searchParamsStr ? '?' + searchParamsStr : '' }`;
};
const requestHandler = handler(getUrl, [ 'GET' ]);
......
import type { AddressParam } from 'types/api/addressParams';
import type { PaginationParams } from 'types/api/pagination';
import type { Reward } from 'types/api/reward';
import type { Transaction } from 'types/api/transaction';
......@@ -33,22 +34,19 @@ export interface Block {
export interface BlocksResponse {
items: Array<Block>;
next_page_params: {
block_number: number;
items_count: number;
} | null;
next_page_params: PaginationParams | null;
}
export interface BlockTransactionsResponse {
items: Array<Transaction>;
next_page_params: {
block_number: number;
index: number;
items_count: number;
} | null;
next_page_params: PaginationParams | null;
}
export interface NewBlockSocketResponse {
average_block_time: string;
block: Block;
}
export interface BlockFilters {
type?: BlockType;
}
import type { AddressParam } from './addressParams';
import type { PaginationParams } from './pagination';
export type TxInternalsType = 'call' | 'delegatecall' | 'staticcall' | 'create' | 'create2' | 'selfdestruct' | 'reward'
......@@ -19,10 +20,7 @@ export interface InternalTransaction {
export interface InternalTransactionsResponse {
items: Array<InternalTransaction>;
next_page_params: {
block_number: number;
index: number;
items_count: number;
next_page_params: PaginationParams & {
transaction_hash: string;
transaction_index: number;
};
......
export interface PaginationParams {
block_number: number;
index?: number;
items_count: number;
}
import type { AddressParam } from './addressParams';
import type { DecodedInput } from './decodedInput';
import type { Fee } from './fee';
import type { PaginationParams } from './pagination';
import type { TokenTransfer } from './tokenTransfer';
export type TransactionRevertReason = {
......@@ -45,11 +46,7 @@ export interface Transaction {
export interface TransactionsResponse {
items: Array<Transaction>;
next_page_params: {
block_number: number;
index: number;
items_count: number;
} | null;
next_page_params: PaginationParams | null;
}
export type TransactionType = 'token_transfer' | 'contract_creation' | 'contract_call' | 'token_creation' | 'coin_transfer'
export enum QueryKeys {
addressTags = 'address-tags',
apiKeys = 'api-keys',
block = 'block',
blocks = 'blocks',
customAbis = 'custom-abis',
profile = 'profile',
publicTags = 'public-tags',
......
......@@ -7,4 +7,6 @@ export enum QueryKeys {
txLog = 'tx-log',
txRawTrace = 'tx-raw-trace',
blockTxs = 'block-transactions',
block = 'block',
blocks = 'blocks',
}
......@@ -7,7 +7,7 @@ import React from 'react';
import { scroller, Element } from 'react-scroll';
import type { Block } from 'types/api/block';
import { QueryKeys } from 'types/client/accountQueries';
import { QueryKeys } from 'types/client/queries';
import appConfig from 'configs/app/config';
import clockIcon from 'icons/clock.svg';
......
import { Text, Show, Alert, Skeleton } from '@chakra-ui/react';
import { useQuery, useQueryClient } from '@tanstack/react-query';
import { useQueryClient } from '@tanstack/react-query';
import React from 'react';
import type { SocketMessage } from 'lib/socket/types';
import type { BlockType, BlocksResponse } from 'types/api/block';
import { QueryKeys } from 'types/client/accountQueries';
import { QueryKeys } from 'types/client/queries';
import useFetch from 'lib/hooks/useFetch';
import useQueryWithPages from 'lib/hooks/useQueryWithPages';
import useSocketChannel from 'lib/socket/useSocketChannel';
import useSocketMessage from 'lib/socket/useSocketMessage';
import BlocksList from 'ui/blocks/BlocksList';
......@@ -22,17 +22,13 @@ interface Props {
}
const BlocksContent = ({ type }: Props) => {
const fetch = useFetch();
const queryClient = useQueryClient();
const [ socketAlert, setSocketAlert ] = React.useState('');
const { data, isLoading, isError } = useQuery<unknown, unknown, BlocksResponse>(
[ QueryKeys.blocks, type ],
async() => await fetch(`/node-api/blocks${ type ? `?type=${ type }` : '' }`),
);
const { data, isLoading, isError, pagination } = useQueryWithPages<BlocksResponse>('/node-api/blocks', QueryKeys.blocks, { type });
const handleNewBlockMessage: SocketMessage.NewBlock['handler'] = React.useCallback((payload) => {
queryClient.setQueryData([ QueryKeys.blocks, type ], (prevData: BlocksResponse | undefined) => {
queryClient.setQueryData([ QueryKeys.blocks, { page: pagination.page, filters: { type } } ], (prevData: BlocksResponse | undefined) => {
const shouldAddToList = !type || type === payload.block.type;
if (!prevData) {
......@@ -43,7 +39,7 @@ const BlocksContent = ({ type }: Props) => {
}
return shouldAddToList ? { ...prevData, items: [ payload.block, ...prevData.items ] } : prevData;
});
}, [ queryClient, type ]);
}, [ pagination.page, queryClient, type ]);
const handleSocketClose = React.useCallback(() => {
setSocketAlert('Connection is lost. Please click here to load new blocks.');
......@@ -57,7 +53,7 @@ const BlocksContent = ({ type }: Props) => {
topic: 'blocks:new_block',
onSocketClose: handleSocketClose,
onSocketError: handleSocketError,
isDisabled: isLoading || isError,
isDisabled: isLoading || isError || pagination.page !== 1,
});
useSocketMessage({
channel,
......@@ -91,8 +87,7 @@ const BlocksContent = ({ type }: Props) => {
<>
<Text as="span">Total of { data.items[0].height.toLocaleString() } blocks</Text>
<ActionBar>
{ /* eslint-disable-next-line react/jsx-no-bind */ }
<Pagination ml="auto" page={ 1 } onNextPageClick={ () => {} } onPrevPageClick={ () => {} } resetPage={ () => {} } hasNextPage/>
<Pagination ml="auto" { ...pagination }/>
</ActionBar>
{ socketAlert && <Alert status="warning" mt={ 8 } as="a" href={ window.document.location.href }>{ socketAlert }</Alert> }
<Show below="lg" key="content-mobile"><BlocksList data={ data.items }/></Show>
......
import { Alert, Box, Show } from '@chakra-ui/react';
import React, { useState, useCallback } from 'react';
import type { TransactionsResponse } from 'types/api/transaction';
import type { TTxsFilters } from 'types/api/txsFilters';
import type { QueryKeys } from 'types/client/queries';
import type { Sort } from 'types/client/txs-sort';
import * as cookies from 'lib/cookies';
import useQueryWithPages from 'lib/hooks/useQueryWithPages';
import DataFetchAlert from 'ui/shared/DataFetchAlert';
import TxsHeader from './TxsHeader';
import TxsSkeletonDesktop from './TxsSkeletonDesktop';
import TxsSkeletonMobile from './TxsSkeletonMobile';
import TxsWithSort from './TxsWithSort';
import useQueryWithPages from './useQueryWithPages';
type Props = {
queryName: QueryKeys;
......@@ -61,7 +62,7 @@ const TxsContent = ({
isLoading,
isError,
pagination,
} = useQueryWithPages(apiPath, queryName, stateFilter && { filter: stateFilter });
} = useQueryWithPages<TransactionsResponse>(apiPath, queryName, stateFilter && { filter: stateFilter });
// } = useQueryWithPages({ ...filters, filter: stateFilter, apiPath });
if (isError) {
......@@ -85,15 +86,10 @@ const TxsContent = ({
content = <TxsWithSort txs={ txs } sorting={ sorting } sort={ sort }/>;
}
const paginationProps = {
...pagination,
hasNextPage: data?.next_page_params !== undefined && data?.next_page_params !== null && Object.keys(data?.next_page_params).length > 0,
};
return (
<>
{ showDescription && <Box mb={ 12 }>Only the first 10,000 elements are displayed</Box> }
<TxsHeader sorting={ sorting } setSorting={ setSorting } paginationProps={ paginationProps }/>
<TxsHeader sorting={ sorting } setSorting={ setSorting } paginationProps={ pagination }/>
{ content }
</>
);
......
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