Commit c203ef12 authored by tom's avatar tom

rewrite pagination types

parent ae01b122
......@@ -6,35 +6,30 @@ import React, { useCallback } from 'react';
import { animateScroll } from 'react-scroll';
import type { BlockFilters } from 'types/api/block';
import type { PaginationParams } from 'types/api/pagination';
import { PAGINATION_FIELDS } from 'types/api/pagination';
import type { PaginationParams, PaginatedResponse, PaginatedQueryKeys } 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: Array<keyof PaginationParams> = [ 'block_number', 'index', 'items_count' ];
interface ResponseWithPagination {
next_page_params: PaginationParams | null;
}
interface Params<Response> {
interface Params<QueryName extends PaginatedQueryKeys> {
apiPath: string;
queryName: QueryKeys;
queryName: QueryName;
queryIds?: Array<string>;
filters?: TTxsFilters | BlockFilters;
options?: Omit<UseQueryOptions<unknown, unknown, Response>, 'queryKey' | 'queryFn'>;
options?: Omit<UseQueryOptions<unknown, unknown, PaginatedResponse<QueryName>>, 'queryKey' | 'queryFn'>;
}
export default function useQueryWithPages<Response extends ResponseWithPagination>({ queryName, filters, options, apiPath, queryIds }: Params<Response>) {
export default function useQueryWithPages<QueryName extends PaginatedQueryKeys>({ queryName, filters, options, apiPath, queryIds }: Params<QueryName>) {
const paginationFields = PAGINATION_FIELDS[queryName];
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<PaginationParams>>>([ {} ]);
const currPageParams = pick(router.query, paginationFields);
const [ pageParams, setPageParams ] = React.useState<Array<PaginationParams<QueryName>>>([ ]);
const fetch = useFetch();
const queryResult = useQuery<unknown, unknown, Response>(
const queryResult = useQuery<unknown, unknown, PaginatedResponse<QueryName>>(
[ queryName, ...(queryIds || []), { page, filters } ],
async() => {
const params: Array<string> = [];
......@@ -58,9 +53,7 @@ export default function useQueryWithPages<Response extends ResponseWithPaginatio
// we hide next page button if no next_page_params
return;
}
// api adds filters into next-page-params now
// later filters will be removed from response
const nextPageParams = pick(data.next_page_params, PAGINATION_FIELDS);
const nextPageParams = data.next_page_params;
if (page >= pageParams.length && data?.next_page_params) {
setPageParams(prev => [ ...prev, nextPageParams ]);
}
......@@ -71,18 +64,18 @@ export default function useQueryWithPages<Response extends ResponseWithPaginatio
animateScroll.scrollToTop({ duration: 0 });
setPage(prev => prev + 1);
});
}, [ data, page, pageParams, router ]);
}, [ data?.next_page_params, page, pageParams.length, router ]);
const onPrevPageClick = useCallback(() => {
// returning to the first page
// we dont have pagination params for the first page
let nextPageQuery: typeof router.query;
if (page === 2) {
nextPageQuery = omit(router.query, PAGINATION_FIELDS);
nextPageQuery = omit(router.query, paginationFields);
} else {
const nextPageParams = { ...pageParams[page - 2] };
nextPageQuery = { ...router.query };
Object.entries(nextPageParams).forEach(([ key, val ]) => nextPageQuery[key] = val.toString());
nextPageParams && Object.entries(nextPageParams).forEach(([ key, val ]) => nextPageQuery[key] = val.toString());
}
router.query = nextPageQuery;
router.push({ pathname: router.pathname, query: nextPageQuery }, undefined, { shallow: true })
......@@ -91,16 +84,16 @@ export default function useQueryWithPages<Response extends ResponseWithPaginatio
setPage(prev => prev - 1);
page === 2 && queryClient.clear();
});
}, [ router, page, pageParams, queryClient ]);
}, [ router, page, paginationFields, pageParams, queryClient ]);
const resetPage = useCallback(() => {
queryClient.clear();
router.push({ pathname: router.pathname, query: omit(router.query, PAGINATION_FIELDS) }, undefined, { shallow: true }).then(() => {
router.push({ pathname: router.pathname, query: omit(router.query, paginationFields) }, undefined, { shallow: true }).then(() => {
animateScroll.scrollToTop({ duration: 0 });
setPage(1);
setPageParams([ {} ]);
setPageParams([ ]);
});
}, [ router, queryClient ]);
}, [ queryClient, router, paginationFields ]);
const hasPaginationParams = Object.keys(currPageParams).length > 0;
const nextPageParams = data?.next_page_params;
......
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';
......@@ -34,12 +33,18 @@ export interface Block {
export interface BlocksResponse {
items: Array<Block>;
next_page_params: PaginationParams | null;
next_page_params: {
block_number: number;
items_count: number;
} | null;
}
export interface BlockTransactionsResponse {
items: Array<Transaction>;
next_page_params: PaginationParams | null;
next_page_params: {
block_number: number;
items_count: number;
} | null;
}
export interface NewBlockSocketResponse {
......
import type { AddressParam } from './addressParams';
import type { PaginationParams } from './pagination';
export type TxInternalsType = 'call' | 'delegatecall' | 'staticcall' | 'create' | 'create2' | 'selfdestruct' | 'reward'
......@@ -20,7 +19,10 @@ export interface InternalTransaction {
export interface InternalTransactionsResponse {
items: Array<InternalTransaction>;
next_page_params: PaginationParams & {
next_page_params: {
block_number: number;
index: number;
items_count: number;
transaction_hash: string;
transaction_index: number;
};
......
export interface PaginationParams {
block_number: number;
index?: number;
items_count: number;
import type { BlocksResponse, BlockTransactionsResponse } from 'types/api/block';
import type { InternalTransactionsResponse } from 'types/api/internalTransaction';
import type { TokenTransferResponse } from 'types/api/tokenTransfer';
import type { TransactionsResponseValidated, TransactionsResponsePending } from 'types/api/transaction';
import { QueryKeys } from 'types/client/queries';
import type { KeysOfObjectOrNull } from 'types/utils/KeysOfObjectOrNull';
export type PaginatedQueryKeys =
QueryKeys.blocks |
QueryKeys.blockTxs |
QueryKeys.txsValidate |
QueryKeys.txsPending |
QueryKeys.txInternals |
QueryKeys.txTokenTransfers;
export type PaginatedResponse<Q extends PaginatedQueryKeys> =
Q extends QueryKeys.blocks ? BlocksResponse :
Q extends QueryKeys.blockTxs ? BlockTransactionsResponse :
Q extends QueryKeys.txsValidate ? TransactionsResponseValidated :
Q extends QueryKeys.txsPending ? TransactionsResponsePending :
Q extends QueryKeys.txInternals ? InternalTransactionsResponse :
Q extends QueryKeys.txTokenTransfers ? TokenTransferResponse :
never
export type PaginationParams<Q extends PaginatedQueryKeys> = PaginatedResponse<Q>['next_page_params'];
type PaginationFields = {
[K in PaginatedQueryKeys]: Array<KeysOfObjectOrNull<PaginatedResponse<K>['next_page_params']>>
}
export const PAGINATION_FIELDS: PaginationFields = {
[QueryKeys.blocks]: [ 'block_number', 'items_count' ],
[QueryKeys.blockTxs]: [ 'block_number', 'items_count' ],
[QueryKeys.txsValidate]: [ 'block_number', 'items_count', 'filter', 'index' ],
[QueryKeys.txsPending]: [ 'filter', 'hash', 'inserted_at' ],
[QueryKeys.txInternals]: [ 'block_number', 'items_count', 'transaction_hash', 'index', 'transaction_index' ],
[QueryKeys.txTokenTransfers]: [ 'block_number', 'items_count', 'transaction_hash', 'index' ],
};
import type { AddressParam } from './addressParams';
import type { PaginationParams } from './pagination';
import type { TokenInfoGeneric } from './tokenInfo';
export type Erc20TotalPayload = {
......@@ -41,5 +40,10 @@ interface TokenTransferBase {
export interface TokenTransferResponse {
items: Array<TokenTransfer>;
next_page_params: PaginationParams | null;
next_page_params: {
block_number: number;
index: number;
items_count: number;
transaction_hash: string;
} | null;
}
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 = {
......@@ -44,9 +43,25 @@ export interface Transaction {
tx_tag: string | null;
}
export interface TransactionsResponse {
export type TransactionsResponse = TransactionsResponseValidated | TransactionsResponsePending;
export interface TransactionsResponseValidated {
items: Array<Transaction>;
next_page_params: PaginationParams | null;
next_page_params: {
block_number: number;
index: number;
items_count: number;
filter: 'validated';
} | null;
}
export interface TransactionsResponsePending {
items: Array<Transaction>;
next_page_params: {
inserted_at: string;
hash: string;
filter: 'pending';
} | null;
}
export type TransactionType = 'token_transfer' | 'contract_creation' | 'contract_call' | 'token_creation' | 'coin_transfer'
export enum QueryKeys {
csrf = 'csrf',
profile = 'profile',
transactions = 'transactions',
txsValidate = 'txs-validated',
txsPending = 'txs-pending',
tx = 'tx',
txInternals = 'tx-internals',
txLog = 'tx-log',
......
export type KeysOfObjectOrNull<T> = T extends null ? never : keyof T;
......@@ -25,7 +25,7 @@ const BlocksContent = ({ type }: Props) => {
const queryClient = useQueryClient();
const [ socketAlert, setSocketAlert ] = React.useState('');
const { data, isLoading, isError, pagination } = useQueryWithPages<BlocksResponse>({
const { data, isLoading, isError, pagination } = useQueryWithPages({
apiPath: '/node-api/blocks',
queryName: QueryKeys.blocks,
filters: { type },
......
import { Hide, Show, Text, Flex, Skeleton } from '@chakra-ui/react';
import React from 'react';
import type { TokenTransferResponse } from 'types/api/tokenTransfer';
import type { QueryKeys } from 'types/client/queries';
import useQueryWithPages from 'lib/hooks/useQueryWithPages';
......@@ -19,7 +18,7 @@ interface Props {
isLoading?: boolean;
isDisabled?: boolean;
path: string;
queryName: QueryKeys;
queryName: QueryKeys.txTokenTransfers;
queryIds?: Array<string>;
baseAddress?: string;
showTxInfo?: boolean;
......@@ -27,7 +26,7 @@ interface Props {
}
const TokenTransfer = ({ isLoading: isLoadingProp, isDisabled, queryName, queryIds, path, baseAddress, showTxInfo = true, txHash }: Props) => {
const { isError, isLoading, data, pagination } = useQueryWithPages<TokenTransferResponse>({
const { isError, isLoading, data, pagination } = useQueryWithPages({
apiPath: path,
queryName,
queryIds,
......
import { Text, Box, Show, Hide } 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';
......@@ -16,7 +15,7 @@ import TxsSkeletonMobile from './TxsSkeletonMobile';
import TxsWithSort from './TxsWithSort';
type Props = {
queryName: QueryKeys;
queryName: QueryKeys.txsPending | QueryKeys.txsValidate | QueryKeys.blockTxs;
showDescription?: boolean;
stateFilter?: TTxsFilters['filter'];
apiPath: string;
......@@ -62,7 +61,7 @@ const TxsContent = ({
isLoading,
isError,
pagination,
} = useQueryWithPages<TransactionsResponse>({
} = useQueryWithPages({
apiPath,
queryName,
filters: stateFilter ? { filter: stateFilter } : undefined,
......
......@@ -9,11 +9,21 @@ type Props = {
}
const TxsTab = ({ tab }: Props) => {
if (tab === 'validated') {
return (
<TxsContent
queryName={ QueryKeys.transactions }
showDescription={ tab === 'validated' }
stateFilter={ tab }
queryName={ QueryKeys.txsValidate }
showDescription
stateFilter="validated"
apiPath="/api/transactions"
/>
);
}
return (
<TxsContent
queryName={ QueryKeys.txsPending }
stateFilter="pending"
apiPath="/api/transactions"
/>
);
......
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