Commit 79fa44f9 authored by tom's avatar tom

other paginated resources

parent 3d60e745
......@@ -6,7 +6,7 @@ import type { ApiResource } from './resources';
export default function buildUrl(
resource: ApiResource,
pathParams?: Record<string, string>,
pathParams?: Record<string, string | undefined>,
queryParams?: Record<string, string | number | undefined>,
) {
// FIXME
......
......@@ -55,6 +55,58 @@ export const RESOURCES = {
paginationFields: [ 'block_number' as const, 'items_count' as const, 'index' as const ],
filterFields: [],
},
txs_validated: {
path: '/api/v2/transactions',
paginationFields: [ 'block_number' as const, 'items_count' as const, 'filter' as const, 'index' as const ],
filterFields: [ 'filter' as const, 'type' as const, 'method' as const ],
},
txs_pending: {
path: '/api/v2/transactions',
paginationFields: [ 'filter' as const, 'hash' as const, 'inserted_at' as const ],
filterFields: [ 'filter' as const, 'type' as const, 'method' as const ],
},
tx_internal_txs: {
path: '/api/v2/transactions/:id/internal-transactions',
paginationFields: [ 'block_number' as const, 'items_count' as const, 'transaction_hash' as const, 'index' as const, 'transaction_index' as const ],
filterFields: [ ],
},
tx_logs: {
path: '/api/v2/transactions/:id/logs',
paginationFields: [ 'items_count' as const, 'transaction_hash' as const, 'index' as const ],
filterFields: [ ],
},
tx_token_transfers: {
path: '/api/v2/transactions/:id/token-transfers',
paginationFields: [ 'block_number' as const, 'items_count' as const, 'transaction_hash' as const, 'index' as const ],
filterFields: [ 'type' as const ],
},
// ADDRESS
address_txs: {
path: '/api/v2/addresses/:id/transactions',
paginationFields: [ 'block_number' as const, 'items_count' as const, 'index' as const ],
filterFields: [ 'filter' as const ],
},
address_internal_txs: {
path: '/api/v2/addresses/:id/internal-transactions',
paginationFields: [ 'block_number' as const, 'items_count' as const, 'index' as const, 'transaction_index' as const ],
filterFields: [ 'filter' as const ],
},
address_token_transfers: {
path: '/api/v2/addresses/:id/token-transfers',
paginationFields: [ 'block_number' as const, 'items_count' as const, 'index' as const, 'transaction_index' as const ],
filterFields: [ 'filter' as const, 'type' as const ],
},
address_blocks_validated: {
path: '/api/v2/addresses/:id/blocks-validated',
paginationFields: [ 'items_count' as const, 'block_number' as const ],
filterFields: [ ],
},
address_coin_balance: {
path: '/api/v2/addresses/:id/coin-balance-history',
paginationFields: [ 'items_count' as const, 'block_number' as const ],
filterFields: [ ],
},
// DEPRECATED
old_api: {
......
......@@ -9,7 +9,7 @@ import { RESOURCES } from './resources';
import type { ResourceError, ApiResource } from './resources';
export interface Params {
pathParams?: Record<string, string>;
pathParams?: Record<string, string | undefined>;
queryParams?: Record<string, string | number | undefined>;
fetchParams?: Pick<FetchParams, 'body' | 'method'>;
}
......
......@@ -2,10 +2,21 @@ import type { UseQueryOptions } from '@tanstack/react-query';
import { useQuery } from '@tanstack/react-query';
import type { UserInfo, CustomAbis, PublicTags, AddressTags, TransactionTags, ApiKeys, WatchlistAddress } from 'types/api/account';
import type {
AddressTransactionsResponse,
AddressTokenTransferResponse,
AddressCoinBalanceHistoryResponse,
AddressBlocksValidatedResponse,
AddressInternalTxsResponse,
} from 'types/api/address';
import type { BlocksResponse, BlockTransactionsResponse } from 'types/api/block';
import type { InternalTransactionsResponse } from 'types/api/internalTransaction';
import type { LogsResponse } from 'types/api/log';
import type { Stats, Charts } from 'types/api/stats';
import type { TokenTransferResponse } from 'types/api/tokenTransfer';
import type { TransactionsResponseValidated, TransactionsResponsePending } from 'types/api/transaction';
import type { RESOURCES, ResourceError, ResourceName } from './resources';
import type { ResourceError, ResourceName } from './resources';
import type { Params as ApiFetchParams } from './useApiFetch';
import useApiFetch from './useApiFetch';
......@@ -34,7 +45,7 @@ export default function useApiQuery<R extends ResourceName>(
}, queryOptions);
}
export type ResourcePayload<Q extends keyof typeof RESOURCES> =
export type ResourcePayload<Q extends ResourceName> =
Q extends 'user_info' ? UserInfo :
Q extends 'custom_abi' ? CustomAbis :
Q extends 'public_tags' ? PublicTags :
......@@ -46,4 +57,14 @@ export type ResourcePayload<Q extends keyof typeof RESOURCES> =
Q extends 'stats_charts' ? Charts :
Q extends 'blocks' ? BlocksResponse :
Q extends 'block_txs' ? BlockTransactionsResponse :
never;
Q extends 'txs_validated' ? TransactionsResponseValidated :
Q extends 'txs_pending' ? TransactionsResponsePending :
Q extends 'tx_internal_txs' ? InternalTransactionsResponse :
Q extends 'tx_logs' ? LogsResponse :
Q extends 'tx_token_transfers' ? TokenTransferResponse :
Q extends 'address_txs' ? AddressTransactionsResponse :
Q extends 'address_internal_txs' ? AddressInternalTxsResponse :
Q extends 'address_token_transfers' ? AddressTokenTransferResponse :
Q extends 'address_blocks_validated' ? AddressBlocksValidatedResponse :
Q extends 'address_coin_balance' ? AddressCoinBalanceHistoryResponse :
never;
......@@ -15,7 +15,7 @@ import useApiQuery from 'lib/api/useApiQuery';
interface Params<Resource extends PaginatedResources> {
resourceName: Resource;
options?: UseApiQueryParams<Resource>['queryOptions'];
pathParams?: Record<string, string>;
pathParams?: UseApiQueryParams<Resource>['pathParams'];
filters?: PaginationFiltersX<Resource>;
scroll?: { elem: string; offset: number };
}
......@@ -69,7 +69,7 @@ export default function useQueryWithPages<Resource extends PaginatedResources>({
setPageParams((prev) => ({
...prev,
[page + 1]: mapValues(nextPageParams, (value) => value?.toString()) as NextPageParams,
[page + 1]: mapValues(nextPageParams, (value) => String(value)) as NextPageParams,
}));
setPage(prev => prev + 1);
......
import type {
AddressTransactionsResponse,
AddressTokenTransferResponse,
AddressTxsFilters,
AddressTokenTransferFilters,
AddressCoinBalanceHistoryResponse,
AddressBlocksValidatedResponse,
AddressInternalTxsResponse,
} from 'types/api/address';
import type { BlocksResponse, BlockTransactionsResponse, BlockFilters } from 'types/api/block';
import type { InternalTransactionsResponse } from 'types/api/internalTransaction';
import type { LogsResponse } from 'types/api/log';
import type { TokenTransferResponse, TokenTransferFilters } from 'types/api/tokenTransfer';
import type { TransactionsResponseValidated, TransactionsResponsePending } from 'types/api/transaction';
import type { BlockFilters } from 'types/api/block';
import type { TokenTransferFilters } from 'types/api/tokenTransfer';
import type { TTxsFilters } from 'types/api/txsFilters';
import { QueryKeys } from 'types/client/queries';
import type { KeysOfObjectOrNull } from 'types/utils/KeysOfObjectOrNull';
export type PaginatedQueryKeys =
QueryKeys.addressTxs |
QueryKeys.addressTokenTransfers |
QueryKeys.addressInternalTxs |
QueryKeys.blocks |
QueryKeys.blocksReorgs |
QueryKeys.blocksUncles |
QueryKeys.blockTxs |
QueryKeys.txsValidate |
QueryKeys.txsPending |
QueryKeys.txInternals |
QueryKeys.txLogs |
QueryKeys.txTokenTransfers |
QueryKeys.addressCoinBalanceHistory |
QueryKeys.addressBlocksValidated;
import type { ResourcePayload } from 'lib/api/useApiQuery';
export type PaginatedResources = 'blocks' | 'block_txs';
export type PaginatedResources = 'blocks' | 'block_txs' |
'txs_validated' | 'txs_pending' |
'tx_internal_txs' | 'tx_logs' | 'tx_token_transfers' |
'address_txs' | 'address_internal_txs' | 'address_token_transfers' | 'address_blocks_validated' | 'address_coin_balance';
export type PaginatedResponseX<Q extends PaginatedResources> =
Q extends 'blocks' ? BlocksResponse :
Q extends 'block_txs' ? BlockTransactionsResponse :
never;
export type PaginatedResponseX<Q extends PaginatedResources> = ResourcePayload<Q>;
export type PaginationFiltersX<Q extends PaginatedResources> =
Q extends 'blocks' ? BlockFilters :
never;
export type PaginatedResponse<Q extends PaginatedQueryKeys> =
Q extends QueryKeys.addressInternalTxs ? AddressInternalTxsResponse :
Q extends QueryKeys.addressTxs ? AddressTransactionsResponse :
Q extends QueryKeys.addressTokenTransfers ? AddressTokenTransferResponse :
Q extends (QueryKeys.blocks | QueryKeys.blocksReorgs | QueryKeys.blocksUncles) ? BlocksResponse :
Q extends QueryKeys.blockTxs ? BlockTransactionsResponse :
Q extends QueryKeys.txsValidate ? TransactionsResponseValidated :
Q extends QueryKeys.txsPending ? TransactionsResponsePending :
Q extends QueryKeys.txInternals ? InternalTransactionsResponse :
Q extends QueryKeys.txLogs ? LogsResponse :
Q extends QueryKeys.txTokenTransfers ? TokenTransferResponse :
Q extends QueryKeys.addressCoinBalanceHistory ? AddressCoinBalanceHistoryResponse :
Q extends QueryKeys.addressBlocksValidated ? AddressBlocksValidatedResponse :
never
export type PaginationFilters<Q extends PaginatedQueryKeys> =
Q extends (QueryKeys.addressTxs | QueryKeys.addressInternalTxs) ? AddressTxsFilters :
Q extends QueryKeys.addressTokenTransfers ? AddressTokenTransferFilters :
Q extends QueryKeys.blocks ? BlockFilters :
Q extends QueryKeys.txsValidate ? TTxsFilters :
Q extends QueryKeys.txsPending ? TTxsFilters :
Q extends QueryKeys.txTokenTransfers ? TokenTransferFilters :
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.addressTxs]: [ 'block_number', 'items_count', 'index' ],
[QueryKeys.addressInternalTxs]: [ 'block_number', 'items_count', 'index', 'transaction_index' ],
[QueryKeys.addressTokenTransfers]: [ 'block_number', 'items_count', 'index', 'transaction_hash' ],
[QueryKeys.blocks]: [ 'block_number', 'items_count' ],
[QueryKeys.blocksReorgs]: [ 'block_number', 'items_count' ],
[QueryKeys.blocksUncles]: [ 'block_number', 'items_count' ],
[QueryKeys.blockTxs]: [ 'block_number', 'items_count', 'index' ],
[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' ],
[QueryKeys.txLogs]: [ 'items_count', 'transaction_hash', 'index' ],
[QueryKeys.addressCoinBalanceHistory]: [ 'items_count', 'block_number' ],
[QueryKeys.addressBlocksValidated]: [ 'items_count', 'block_number' ],
};
type PaginationFiltersFields = {
[K in PaginatedQueryKeys]: Array<KeysOfObjectOrNull<PaginationFilters<K>>>
}
export const PAGINATION_FILTERS_FIELDS: PaginationFiltersFields = {
[QueryKeys.addressTxs]: [ 'filter' ],
[QueryKeys.addressInternalTxs]: [ 'filter' ],
[QueryKeys.addressTokenTransfers]: [ 'filter', 'type' ],
[QueryKeys.addressCoinBalanceHistory]: [],
[QueryKeys.addressBlocksValidated]: [],
[QueryKeys.blocks]: [ 'type' ],
[QueryKeys.txsValidate]: [ 'filter', 'type', 'method' ],
[QueryKeys.txsPending]: [ 'filter', 'type', 'method' ],
[QueryKeys.txTokenTransfers]: [ 'type' ],
[QueryKeys.blocksReorgs]: [],
[QueryKeys.blocksUncles]: [],
[QueryKeys.blockTxs]: [],
[QueryKeys.txInternals]: [],
[QueryKeys.txLogs]: [],
};
Q extends 'txs_validated' | 'txs_pending' ? TTxsFilters :
Q extends 'tx_token_transfers' ? TokenTransferFilters :
Q extends 'address_txs' | 'address_internal_txs' ? AddressTxsFilters :
Q extends 'address_token_transfers' ? AddressTokenTransferFilters :
never;
// todo_tom DELETE
export enum QueryKeys {
csrf = 'csrf',
profile = 'profile',
txsValidate = 'txs-validated',
txsPending = 'txs-pending',
homeStats='homeStats',
indexingStatus='indexingStatus',
stats='stats',
charts='stats',
tx = 'tx',
txInternals = 'tx-internals',
txLogs = 'tx-logs',
txRawTrace = 'tx-raw-trace',
txTokenTransfers = 'tx-token-transfers',
blockTxs = 'block-transactions',
block = 'block',
blocks = 'blocks',
blocksReorgs = 'blocks-reorgs',
blocksUncles = 'blocks-uncles',
chartsTxs = 'charts-txs',
chartsMarket = 'charts-market',
indexBlocks='indexBlocks',
......@@ -25,10 +15,5 @@ export enum QueryKeys {
address='address',
addressCounters='address-counters',
addressTokenBalances='address-token-balances',
addressCoinBalanceHistory='address-coin-balance-history',
addressCoinBalanceHistoryByDay='address-coin-balance-history-by-day',
addressTxs='addressTxs',
addressTokenTransfers='addressTokenTransfers',
addressBlocksValidated='address-blocks-validated',
addressInternalTxs='address-internal-txs',
}
......@@ -5,9 +5,9 @@ import React from 'react';
import type { SocketMessage } from 'lib/socket/types';
import type { Address, AddressBlocksValidatedResponse } from 'types/api/address';
import { QueryKeys } from 'types/client/queries';
import appConfig from 'configs/app/config';
import { getResourceKey } from 'lib/api/useApiQuery';
import useQueryWithPages from 'lib/hooks/useQueryWithPages';
import useSocketChannel from 'lib/socket/useSocketChannel';
import useSocketMessage from 'lib/socket/useSocketMessage';
......@@ -31,8 +31,8 @@ const AddressBlocksValidated = ({ addressQuery }: Props) => {
const queryClient = useQueryClient();
const query = useQueryWithPages({
apiPath: `/node-api/addresses/${ addressQuery.data?.hash }/blocks-validated`,
queryName: QueryKeys.addressBlocksValidated,
resourceName: 'address_blocks_validated',
pathParams: { id: addressQuery.data?.hash },
options: {
enabled: Boolean(addressQuery.data),
},
......@@ -46,7 +46,7 @@ const AddressBlocksValidated = ({ addressQuery }: Props) => {
setSocketAlert(false);
queryClient.setQueryData(
[ QueryKeys.addressBlocksValidated, { page: query.pagination.page } ],
getResourceKey('address_blocks_validated', { pathParams: { id: addressQuery.data?.hash } }),
(prevData: AddressBlocksValidatedResponse | undefined) => {
if (!prevData) {
return;
......@@ -57,7 +57,7 @@ const AddressBlocksValidated = ({ addressQuery }: Props) => {
items: [ payload.block, ...prevData.items ],
};
});
}, [ query.pagination.page, queryClient ]);
}, [ addressQuery.data?.hash, queryClient ]);
const channel = useSocketChannel({
topic: `blocks:${ addressQuery.data?.hash.toLowerCase() }`,
......
......@@ -4,8 +4,8 @@ import React from 'react';
import type { SocketMessage } from 'lib/socket/types';
import type { Address, AddressCoinBalanceHistoryResponse } from 'types/api/address';
import { QueryKeys } from 'types/client/queries';
import { getResourceKey } from 'lib/api/useApiQuery';
import useQueryWithPages from 'lib/hooks/useQueryWithPages';
import useSocketChannel from 'lib/socket/useSocketChannel';
import useSocketMessage from 'lib/socket/useSocketMessage';
......@@ -23,8 +23,8 @@ const AddressCoinBalance = ({ addressQuery }: Props) => {
const queryClient = useQueryClient();
const coinBalanceQuery = useQueryWithPages({
apiPath: `/node-api/addresses/${ addressQuery.data?.hash }/coin-balance-history`,
queryName: QueryKeys.addressCoinBalanceHistory,
resourceName: 'address_coin_balance',
pathParams: { id: addressQuery.data?.hash },
options: {
enabled: Boolean(addressQuery.data),
},
......@@ -38,7 +38,7 @@ const AddressCoinBalance = ({ addressQuery }: Props) => {
setSocketAlert(false);
queryClient.setQueryData(
[ QueryKeys.addressCoinBalanceHistory, { page: coinBalanceQuery.pagination.page } ],
getResourceKey('address_coin_balance', { pathParams: { id: addressQuery.data?.hash } }),
(prevData: AddressCoinBalanceHistoryResponse | undefined) => {
if (!prevData) {
return;
......@@ -52,7 +52,7 @@ const AddressCoinBalance = ({ addressQuery }: Props) => {
],
};
});
}, [ coinBalanceQuery.pagination.page, queryClient ]);
}, [ addressQuery.data?.hash, queryClient ]);
const channel = useSocketChannel({
topic: `addresses:${ addressQuery.data?.hash.toLowerCase() }`,
......
......@@ -6,7 +6,6 @@ import { Element } from 'react-scroll';
import type { AddressFromToFilter } from 'types/api/address';
import { AddressFromToFilterValues } from 'types/api/address';
import { QueryKeys } from 'types/client/queries';
import getFilterValueFromQuery from 'lib/getFilterValueFromQuery';
import useQueryWithPages from 'lib/hooks/useQueryWithPages';
......@@ -36,9 +35,8 @@ const AddressInternalTxs = () => {
const queryIdStr = queryIdArray[0];
const { data, isLoading, isError, pagination, onFilterChange, isPaginationVisible } = useQueryWithPages({
apiPath: `/node-api/addresses/${ queryId }/internal-transactions`,
queryName: QueryKeys.addressInternalTxs,
queryIds: queryIdArray,
resourceName: 'address_internal_txs',
pathParams: { id: queryIdStr },
filters: { filter: filterValue },
scroll: { elem: SCROLL_ELEM, offset: SCROLL_OFFSET },
});
......
import castArray from 'lodash/castArray';
import { useRouter } from 'next/router';
import React from 'react';
import { QueryKeys } from 'types/client/queries';
import TokenTransfer from 'ui/shared/TokenTransfer/TokenTransfer';
const AddressTokenTransfers = () => {
......@@ -12,9 +9,8 @@ const AddressTokenTransfers = () => {
const hash = router.query.id;
return (
<TokenTransfer
path={ `/node-api/addresses/${ hash }/token-transfers` }
queryName={ QueryKeys.addressTokenTransfers }
queryIds={ castArray(router.query.id) }
resourceName="address_token_transfers"
pathParams={{ id: hash?.toString() }}
baseAddress={ typeof hash === 'string' ? hash : undefined }
enableTimeIncrement
/>
......
......@@ -5,7 +5,6 @@ import { Element } from 'react-scroll';
import type { AddressFromToFilter } from 'types/api/address';
import { AddressFromToFilterValues } from 'types/api/address';
import { QueryKeys } from 'types/client/queries';
import getFilterValueFromQuery from 'lib/getFilterValueFromQuery';
import useIsMobile from 'lib/hooks/useIsMobile';
......@@ -29,9 +28,8 @@ const AddressTxs = () => {
const [ filterValue, setFilterValue ] = React.useState<AddressFromToFilter>(getFilterValue(router.query.filter));
const addressTxsQuery = useQueryWithPages({
apiPath: `/node-api/addresses/${ router.query.id }/transactions`,
queryName: QueryKeys.addressTxs,
queryIds: castArray(router.query.id),
resourceName: 'address_txs',
pathParams: { id: castArray(router.query.id)[0] },
filters: { filter: filterValue },
scroll: { elem: SCROLL_ELEM, offset: SCROLL_OFFSET },
});
......
......@@ -5,8 +5,8 @@ import React from 'react';
import type { SocketMessage } from 'lib/socket/types';
import type { BlockType, BlocksResponse } from 'types/api/block';
import { QueryKeys } from 'types/client/queries';
import { getResourceKey } from 'lib/api/useApiQuery';
import useIsMobile from 'lib/hooks/useIsMobile';
import useSocketChannel from 'lib/socket/useSocketChannel';
import useSocketMessage from 'lib/socket/useSocketMessage';
......@@ -35,18 +35,9 @@ const BlocksContent = ({ type, query }: Props) => {
const [ socketAlert, setSocketAlert ] = React.useState('');
const handleNewBlockMessage: SocketMessage.NewBlock['handler'] = React.useCallback((payload) => {
const queryKey = (() => {
switch (type) {
case 'uncle':
return QueryKeys.blocksUncles;
case 'reorg':
return QueryKeys.blocksReorgs;
default:
return QueryKeys.blocks;
}
})();
const queryKey = getResourceKey('blocks', { queryParams: { type } });
queryClient.setQueryData([ queryKey, { page: query.pagination.page, filters: { type } } ], (prevData: BlocksResponse | undefined) => {
queryClient.setQueryData(queryKey, (prevData: BlocksResponse | undefined) => {
const shouldAddToList = !type || type === payload.block.type;
if (!prevData) {
......@@ -57,7 +48,7 @@ const BlocksContent = ({ type, query }: Props) => {
}
return shouldAddToList ? { ...prevData, items: [ payload.block, ...prevData.items ] } : prevData;
});
}, [ query.pagination.page, queryClient, type ]);
}, [ queryClient, type ]);
const handleSocketClose = React.useCallback(() => {
setSocketAlert('Connection is lost. Please click here to load new blocks.');
......
......@@ -30,6 +30,7 @@ const BlockPageContent = () => {
const blockTxsQuery = useQueryWithPages({
resourceName: 'block_txs',
pathParams: { id: router.query.id?.toString() },
options: {
enabled: Boolean(router.query.id && router.query.tab === 'txs'),
},
......
......@@ -2,7 +2,6 @@ import { Box } from '@chakra-ui/react';
import { useRouter } from 'next/router';
import React from 'react';
import { QueryKeys } from 'types/client/queries';
import type { RoutedTab } from 'ui/shared/RoutedTabs/types';
import appConfig from 'configs/app/config';
......@@ -26,8 +25,7 @@ const Transactions = () => {
const isMobile = useIsMobile();
const filter = router.query.tab === 'pending' ? 'pending' : 'validated';
const txsQuery = useQueryWithPages({
apiPath: '/node-api/transactions',
queryName: filter === 'validated' ? QueryKeys.txsValidate : QueryKeys.txsPending,
resourceName: filter === 'validated' ? 'txs_validated' : 'txs_pending',
filters: { filter },
});
......
......@@ -2,8 +2,6 @@ import { Box } from '@chakra-ui/react';
import { test, expect } from '@playwright/experimental-ct-react';
import React from 'react';
import { QueryKeys } from 'types/client/queries';
import * as tokenTransferMock from 'mocks/tokens/tokenTransfer';
import TestApp from 'playwright/TestApp';
......@@ -21,8 +19,8 @@ test('without tx info +@mobile', async({ mount, page }) => {
<TestApp>
<Box h={{ base: '134px', lg: 6 }}/>
<TokenTransfer
path={ API_URL }
queryName={ QueryKeys.txTokenTransfers }
resourceName="tx_token_transfers"
pathParams={{ id: '1' }}
showTxInfo={ false }
/>
</TestApp>,
......@@ -43,8 +41,8 @@ test('with tx info +@mobile', async({ mount, page }) => {
<TestApp>
<Box h={{ base: '134px', lg: 6 }}/>
<TokenTransfer
path={ API_URL }
queryName={ QueryKeys.txTokenTransfers }
resourceName="tx_token_transfers"
pathParams={{ id: '1' }}
showTxInfo={ true }
/>
</TestApp>,
......
......@@ -5,10 +5,11 @@ import { Element } from 'react-scroll';
import type { AddressTokenTransferFilters, AddressFromToFilter } from 'types/api/address';
import { AddressFromToFilterValues } from 'types/api/address';
import type { PaginationFiltersX } from 'types/api/pagination';
import type { TokenType } from 'types/api/tokenInfo';
import type { TokenTransferFilters } from 'types/api/tokenTransfer';
import type { QueryKeys } from 'types/client/queries';
import type { Params as UseApiQueryParams } from 'lib/api/useApiQuery';
import getFilterValueFromQuery from 'lib/getFilterValueFromQuery';
import getFilterValuesFromQuery from 'lib/getFilterValuesFromQuery';
import useQueryWithPages from 'lib/hooks/useQueryWithPages';
......@@ -34,50 +35,45 @@ const SCROLL_OFFSET = -100;
const getTokenFilterValue = (getFilterValuesFromQuery<TokenType>).bind(null, TOKEN_TYPES);
const getAddressFilterValue = (getFilterValueFromQuery<AddressFromToFilter>).bind(null, AddressFromToFilterValues);
interface Props {
interface Props<Resource extends 'tx_token_transfers' | 'address_token_transfers'> {
isLoading?: boolean;
isDisabled?: boolean;
path: string;
queryName: QueryKeys.txTokenTransfers | QueryKeys.addressTokenTransfers;
queryIds?: Array<string>;
resourceName: Resource;
baseAddress?: string;
showTxInfo?: boolean;
txHash?: string;
enableTimeIncrement?: boolean;
pathParams?: UseApiQueryParams<Resource>['pathParams'];
}
const TokenTransfer = ({
const TokenTransfer = <Resource extends 'tx_token_transfers' | 'address_token_transfers'>({
isLoading: isLoadingProp,
isDisabled,
queryName,
queryIds,
path,
resourceName,
baseAddress,
showTxInfo = true,
enableTimeIncrement,
}: Props) => {
}: Props<Resource>) => {
const router = useRouter();
const [ filters, setFilters ] = React.useState<AddressTokenTransferFilters & TokenTransferFilters>(
{ type: getTokenFilterValue(router.query.type), filter: getAddressFilterValue(router.query.filter) },
);
const { isError, isLoading, data, pagination, onFilterChange, isPaginationVisible } = useQueryWithPages({
apiPath: path,
queryName,
queryIds,
resourceName,
options: { enabled: !isDisabled },
filters: filters,
filters: filters as PaginationFiltersX<Resource>,
scroll: { elem: SCROLL_ELEM, offset: SCROLL_OFFSET },
});
const handleTypeFilterChange = React.useCallback((nextValue: Array<TokenType>) => {
onFilterChange({ ...filters, type: nextValue });
onFilterChange({ ...filters, type: nextValue } as PaginationFiltersX<Resource>);
setFilters((prevState) => ({ ...prevState, type: nextValue }));
}, [ filters, onFilterChange ]);
const handleAddressFilterChange = React.useCallback((nextValue: string) => {
const filterVal = getAddressFilterValue(nextValue);
onFilterChange({ ...filters, filter: filterVal });
onFilterChange({ ...filters, filter: filterVal } as PaginationFiltersX<Resource>);
setFilters((prevState) => ({ ...prevState, filter: filterVal }));
}, [ filters, onFilterChange ]);
......
......@@ -2,7 +2,6 @@ import { Box, Text, Show, Hide } from '@chakra-ui/react';
import React from 'react';
import type { InternalTransaction } from 'types/api/internalTransaction';
import { QueryKeys } from 'types/client/queries';
import { SECOND } from 'lib/consts';
import useIsMobile from 'lib/hooks/useIsMobile';
......@@ -76,9 +75,8 @@ const TxInternals = () => {
const [ sort, setSort ] = React.useState<Sort>();
const txInfo = useFetchTxInfo({ updateDelay: 5 * SECOND });
const { data, isLoading, isError, pagination, isPaginationVisible } = useQueryWithPages({
apiPath: `/node-api/transactions/${ txInfo.data?.hash }/internal-transactions`,
queryName: QueryKeys.txInternals,
queryIds: txInfo.data?.hash ? [ txInfo.data.hash ] : undefined,
resourceName: 'tx_internal_txs',
pathParams: { id: txInfo.data?.hash },
options: {
enabled: Boolean(txInfo.data?.hash) && Boolean(txInfo.data?.status),
},
......
import { Box, Text } from '@chakra-ui/react';
import React from 'react';
import { QueryKeys } from 'types/client/queries';
import { SECOND } from 'lib/consts';
import useQueryWithPages from 'lib/hooks/useQueryWithPages';
import ActionBar from 'ui/shared/ActionBar';
......@@ -17,9 +15,8 @@ import useFetchTxInfo from 'ui/tx/useFetchTxInfo';
const TxLogs = () => {
const txInfo = useFetchTxInfo({ updateDelay: 5 * SECOND });
const { data, isLoading, isError, pagination, isPaginationVisible } = useQueryWithPages({
apiPath: `/node-api/transactions/${ txInfo.data?.hash }/logs`,
queryName: QueryKeys.txLogs,
queryIds: txInfo.data?.hash ? [ txInfo.data.hash ] : undefined,
resourceName: 'tx_logs',
pathParams: { id: txInfo.data?.hash },
options: {
enabled: Boolean(txInfo.data?.hash) && Boolean(txInfo.data?.status),
},
......
import React from 'react';
import { QueryKeys } from 'types/client/queries';
import { SECOND } from 'lib/consts';
import DataFetchAlert from 'ui/shared/DataFetchAlert';
import TokenTransfer from 'ui/shared/TokenTransfer/TokenTransfer';
......@@ -20,15 +18,12 @@ const TxTokenTransfer = () => {
return <DataFetchAlert/>;
}
const path = `/node-api/transactions/${ data?.hash }/token-transfers`;
return (
<TokenTransfer
isLoading={ isLoading }
isDisabled={ !data?.status || !data?.hash }
path={ path }
queryName={ QueryKeys.txTokenTransfers }
queryIds={ data?.hash ? [ data.hash ] : undefined }
resourceName="tx_token_transfers"
pathParams={{ id: data?.hash.toString() }}
showTxInfo={ false }
txHash={ data?.hash || '' }
/>
......
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