Commit 9f9707ca authored by isstuev's avatar isstuev

address txs api sorting

parent 3a2be4be
...@@ -58,7 +58,13 @@ import type { ...@@ -58,7 +58,13 @@ import type {
} from 'types/api/token'; } from 'types/api/token';
import type { TokensResponse, TokensFilters, TokensSorting, TokenInstanceTransferResponse, TokensBridgedFilters } from 'types/api/tokens'; import type { TokensResponse, TokensFilters, TokensSorting, TokenInstanceTransferResponse, TokensBridgedFilters } from 'types/api/tokens';
import type { TokenTransferResponse, TokenTransferFilters } from 'types/api/tokenTransfer'; import type { TokenTransferResponse, TokenTransferFilters } from 'types/api/tokenTransfer';
import type { TransactionsResponseValidated, TransactionsResponsePending, Transaction, TransactionsResponseWatchlist } from 'types/api/transaction'; import type {
TransactionsResponseValidated,
TransactionsResponsePending,
Transaction,
TransactionsResponseWatchlist,
TransactionsSorting,
} from 'types/api/transaction';
import type { TTxsFilters } from 'types/api/txsFilters'; import type { TTxsFilters } from 'types/api/txsFilters';
import type { TxStateChanges } from 'types/api/txStateChanges'; import type { TxStateChanges } from 'types/api/txStateChanges';
import type { VerifiedContractsSorting } from 'types/api/verifiedContracts'; import type { VerifiedContractsSorting } from 'types/api/verifiedContracts';
...@@ -727,5 +733,6 @@ export type PaginationSorting<Q extends PaginatedResources> = ...@@ -727,5 +733,6 @@ export type PaginationSorting<Q extends PaginatedResources> =
Q extends 'tokens' ? TokensSorting : Q extends 'tokens' ? TokensSorting :
Q extends 'tokens_bridged' ? TokensSorting : Q extends 'tokens_bridged' ? TokensSorting :
Q extends 'verified_contracts' ? VerifiedContractsSorting : Q extends 'verified_contracts' ? VerifiedContractsSorting :
Q extends 'address_txs' ? TransactionsSorting :
never; never;
/* eslint-enable @typescript-eslint/indent */ /* eslint-enable @typescript-eslint/indent */
import type { Transaction } from 'types/api/transaction';
import type { Sort } from 'types/client/txs-sort';
import compareBns from 'lib/bigint/compareBns';
const sortTxs = (sorting?: Sort) => (tx1: Transaction, tx2: Transaction) => {
switch (sorting) {
case 'val-desc':
return compareBns(tx1.value, tx2.value);
case 'val-asc':
return compareBns(tx2.value, tx1.value);
case 'fee-desc':
return compareBns(tx1.fee.value || 0, tx2.fee.value || 0);
case 'fee-asc':
return compareBns(tx2.fee.value || 0, tx1.fee.value || 0);
default:
return 0;
}
};
export default sortTxs;
...@@ -117,3 +117,12 @@ export type TransactionType = 'rootstock_remasc' | ...@@ -117,3 +117,12 @@ export type TransactionType = 'rootstock_remasc' |
'coin_transfer' 'coin_transfer'
export type TxsResponse = TransactionsResponseValidated | TransactionsResponsePending | BlockTransactionsResponse; export type TxsResponse = TransactionsResponseValidated | TransactionsResponsePending | BlockTransactionsResponse;
export interface TransactionsSorting {
sort: 'value' | 'fee';
order: 'asc' | 'desc';
}
export type TransactionsSortingField = TransactionsSorting['sort'];
export type TransactionsSortingValue = `${ TransactionsSortingField }-${ TransactionsSorting['order'] }`;
export type Sort = 'val-desc' | 'val-asc' | 'fee-desc' | 'fee-asc' | '';
...@@ -5,7 +5,7 @@ import React from 'react'; ...@@ -5,7 +5,7 @@ import React from 'react';
import type { SocketMessage } from 'lib/socket/types'; import type { SocketMessage } from 'lib/socket/types';
import type { AddressFromToFilter, AddressTransactionsResponse } from 'types/api/address'; import type { AddressFromToFilter, AddressTransactionsResponse } from 'types/api/address';
import { AddressFromToFilterValues } from 'types/api/address'; import { AddressFromToFilterValues } from 'types/api/address';
import type { Transaction } from 'types/api/transaction'; import type { Transaction, TransactionsSortingField, TransactionsSortingValue, TransactionsSorting } from 'types/api/transaction';
import { getResourceKey } from 'lib/api/useApiQuery'; import { getResourceKey } from 'lib/api/useApiQuery';
import getFilterValueFromQuery from 'lib/getFilterValueFromQuery'; import getFilterValueFromQuery from 'lib/getFilterValueFromQuery';
...@@ -18,7 +18,10 @@ import { generateListStub } from 'stubs/utils'; ...@@ -18,7 +18,10 @@ import { generateListStub } from 'stubs/utils';
import ActionBar from 'ui/shared/ActionBar'; import ActionBar from 'ui/shared/ActionBar';
import Pagination from 'ui/shared/pagination/Pagination'; import Pagination from 'ui/shared/pagination/Pagination';
import useQueryWithPages from 'ui/shared/pagination/useQueryWithPages'; import useQueryWithPages from 'ui/shared/pagination/useQueryWithPages';
import TxsContent from 'ui/txs/TxsContent'; import getSortParamsFromValue from 'ui/shared/sort/getSortParamsFromValue';
import getSortValueFromQuery from 'ui/shared/sort/getSortValueFromQuery';
import TxsWithAPISorting from 'ui/txs/TxsWithAPISorting';
import { SORT_OPTIONS } from 'ui/txs/useTxsSort';
import AddressCsvExportLink from './AddressCsvExportLink'; import AddressCsvExportLink from './AddressCsvExportLink';
import AddressTxsFilter from './AddressTxsFilter'; import AddressTxsFilter from './AddressTxsFilter';
...@@ -53,6 +56,7 @@ const AddressTxs = ({ scrollRef, overloadCount = OVERLOAD_COUNT }: Props) => { ...@@ -53,6 +56,7 @@ const AddressTxs = ({ scrollRef, overloadCount = OVERLOAD_COUNT }: Props) => {
const [ socketAlert, setSocketAlert ] = React.useState(''); const [ socketAlert, setSocketAlert ] = React.useState('');
const [ newItemsCount, setNewItemsCount ] = React.useState(0); const [ newItemsCount, setNewItemsCount ] = React.useState(0);
const [ sort, setSort ] = React.useState<TransactionsSortingValue | undefined>(getSortValueFromQuery<TransactionsSortingValue>(router.query, SORT_OPTIONS));
const isMobile = useIsMobile(); const isMobile = useIsMobile();
const currentAddress = getQueryParamString(router.query.hash); const currentAddress = getQueryParamString(router.query.hash);
...@@ -63,6 +67,7 @@ const AddressTxs = ({ scrollRef, overloadCount = OVERLOAD_COUNT }: Props) => { ...@@ -63,6 +67,7 @@ const AddressTxs = ({ scrollRef, overloadCount = OVERLOAD_COUNT }: Props) => {
resourceName: 'address_txs', resourceName: 'address_txs',
pathParams: { hash: currentAddress }, pathParams: { hash: currentAddress },
filters: { filter: filterValue }, filters: { filter: filterValue },
sorting: getSortParamsFromValue<TransactionsSortingValue, TransactionsSortingField, TransactionsSorting['order']>(sort),
scrollRef, scrollRef,
options: { options: {
placeholderData: generateListStub<'address_txs'>(TX, 50, { next_page_params: { placeholderData: generateListStub<'address_txs'>(TX, 50, { next_page_params: {
...@@ -177,7 +182,7 @@ const AddressTxs = ({ scrollRef, overloadCount = OVERLOAD_COUNT }: Props) => { ...@@ -177,7 +182,7 @@ const AddressTxs = ({ scrollRef, overloadCount = OVERLOAD_COUNT }: Props) => {
<Pagination { ...addressTxsQuery.pagination } ml={ 8 }/> <Pagination { ...addressTxsQuery.pagination } ml={ 8 }/>
</ActionBar> </ActionBar>
) } ) }
<TxsContent <TxsWithAPISorting
filter={ filter } filter={ filter }
filterValue={ filterValue } filterValue={ filterValue }
query={ addressTxsQuery } query={ addressTxsQuery }
...@@ -187,6 +192,8 @@ const AddressTxs = ({ scrollRef, overloadCount = OVERLOAD_COUNT }: Props) => { ...@@ -187,6 +192,8 @@ const AddressTxs = ({ scrollRef, overloadCount = OVERLOAD_COUNT }: Props) => {
socketInfoAlert={ socketAlert } socketInfoAlert={ socketAlert }
socketInfoNum={ newItemsCount } socketInfoNum={ newItemsCount }
top={ 80 } top={ 80 }
sorting={ sort }
setSort={ setSort }
/> />
</> </>
); );
......
...@@ -24,7 +24,7 @@ import Pagination from 'ui/shared/pagination/Pagination'; ...@@ -24,7 +24,7 @@ import Pagination from 'ui/shared/pagination/Pagination';
import useQueryWithPages from 'ui/shared/pagination/useQueryWithPages'; import useQueryWithPages from 'ui/shared/pagination/useQueryWithPages';
import RoutedTabs from 'ui/shared/Tabs/RoutedTabs'; import RoutedTabs from 'ui/shared/Tabs/RoutedTabs';
import TabsSkeleton from 'ui/shared/Tabs/TabsSkeleton'; import TabsSkeleton from 'ui/shared/Tabs/TabsSkeleton';
import TxsContent from 'ui/txs/TxsContent'; import TxsWithFrontendSorting from 'ui/txs/TxsWithFrontendSorting';
const TAB_LIST_PROPS = { const TAB_LIST_PROPS = {
marginBottom: 0, marginBottom: 0,
...@@ -82,7 +82,7 @@ const BlockPageContent = () => { ...@@ -82,7 +82,7 @@ const BlockPageContent = () => {
const tabs: Array<RoutedTab> = React.useMemo(() => ([ const tabs: Array<RoutedTab> = React.useMemo(() => ([
{ id: 'index', title: 'Details', component: <BlockDetails query={ blockQuery }/> }, { id: 'index', title: 'Details', component: <BlockDetails query={ blockQuery }/> },
{ id: 'txs', title: 'Transactions', component: <TxsContent query={ blockTxsQuery } showBlockInfo={ false } showSocketInfo={ false }/> }, { id: 'txs', title: 'Transactions', component: <TxsWithFrontendSorting query={ blockTxsQuery } showBlockInfo={ false } showSocketInfo={ false }/> },
config.features.beaconChain.isEnabled && Boolean(blockQuery.data?.withdrawals_count) ? config.features.beaconChain.isEnabled && Boolean(blockQuery.data?.withdrawals_count) ?
{ id: 'withdrawals', title: 'Withdrawals', component: <BlockWithdrawals blockWithdrawalsQuery={ blockWithdrawalsQuery }/> } : { id: 'withdrawals', title: 'Withdrawals', component: <BlockWithdrawals blockWithdrawalsQuery={ blockWithdrawalsQuery }/> } :
null, null,
......
...@@ -7,7 +7,7 @@ import { generateListStub } from 'stubs/utils'; ...@@ -7,7 +7,7 @@ import { generateListStub } from 'stubs/utils';
import AddressEntity from 'ui/shared/entities/address/AddressEntity'; import AddressEntity from 'ui/shared/entities/address/AddressEntity';
import PageTitle from 'ui/shared/Page/PageTitle'; import PageTitle from 'ui/shared/Page/PageTitle';
import useQueryWithPages from 'ui/shared/pagination/useQueryWithPages'; import useQueryWithPages from 'ui/shared/pagination/useQueryWithPages';
import TxsContent from 'ui/txs/TxsContent'; import TxsWithFrontendSorting from 'ui/txs/TxsWithFrontendSorting';
const KettleTxs = () => { const KettleTxs = () => {
const router = useRouter(); const router = useRouter();
...@@ -31,7 +31,7 @@ const KettleTxs = () => { ...@@ -31,7 +31,7 @@ const KettleTxs = () => {
<> <>
<PageTitle title="Computor transactions" withTextAd/> <PageTitle title="Computor transactions" withTextAd/>
<AddressEntity address={{ hash }} mb={ 6 }/> <AddressEntity address={{ hash }} mb={ 6 }/>
<TxsContent <TxsWithFrontendSorting
query={ query } query={ query }
showSocketInfo={ false } showSocketInfo={ false }
/> />
......
...@@ -13,8 +13,8 @@ import PageTitle from 'ui/shared/Page/PageTitle'; ...@@ -13,8 +13,8 @@ import PageTitle from 'ui/shared/Page/PageTitle';
import Pagination from 'ui/shared/pagination/Pagination'; import Pagination from 'ui/shared/pagination/Pagination';
import useQueryWithPages from 'ui/shared/pagination/useQueryWithPages'; import useQueryWithPages from 'ui/shared/pagination/useQueryWithPages';
import RoutedTabs from 'ui/shared/Tabs/RoutedTabs'; import RoutedTabs from 'ui/shared/Tabs/RoutedTabs';
import TxsContent from 'ui/txs/TxsContent';
import TxsWatchlist from 'ui/txs/TxsWatchlist'; import TxsWatchlist from 'ui/txs/TxsWatchlist';
import TxsWithFrontendSorting from 'ui/txs/TxsWithFrontendSorting';
const TAB_LIST_PROPS = { const TAB_LIST_PROPS = {
marginBottom: 0, marginBottom: 0,
...@@ -60,12 +60,13 @@ const Transactions = () => { ...@@ -60,12 +60,13 @@ const Transactions = () => {
{ {
id: 'validated', id: 'validated',
title: verifiedTitle, title: verifiedTitle,
component: <TxsContent query={ txsQuery } showSocketInfo={ txsQuery.pagination.page === 1 } socketInfoNum={ num } socketInfoAlert={ socketAlert }/> }, component:
<TxsWithFrontendSorting query={ txsQuery } showSocketInfo={ txsQuery.pagination.page === 1 } socketInfoNum={ num } socketInfoAlert={ socketAlert }/> },
{ {
id: 'pending', id: 'pending',
title: 'Pending', title: 'Pending',
component: ( component: (
<TxsContent <TxsWithFrontendSorting
query={ txsQuery } query={ txsQuery }
showBlockInfo={ false } showBlockInfo={ false }
showSocketInfo={ txsQuery.pagination.page === 1 } showSocketInfo={ txsQuery.pagination.page === 1 }
......
...@@ -14,7 +14,7 @@ import PageTitle from 'ui/shared/Page/PageTitle'; ...@@ -14,7 +14,7 @@ import PageTitle from 'ui/shared/Page/PageTitle';
import useQueryWithPages from 'ui/shared/pagination/useQueryWithPages'; import useQueryWithPages from 'ui/shared/pagination/useQueryWithPages';
import RoutedTabs from 'ui/shared/Tabs/RoutedTabs'; import RoutedTabs from 'ui/shared/Tabs/RoutedTabs';
import TabsSkeleton from 'ui/shared/Tabs/TabsSkeleton'; import TabsSkeleton from 'ui/shared/Tabs/TabsSkeleton';
import TxsContent from 'ui/txs/TxsContent'; import TxsWithFrontendSorting from 'ui/txs/TxsWithFrontendSorting';
import ZkEvmL2TxnBatchDetails from 'ui/zkEvmL2TxnBatches/ZkEvmL2TxnBatchDetails'; import ZkEvmL2TxnBatchDetails from 'ui/zkEvmL2TxnBatches/ZkEvmL2TxnBatchDetails';
const ZkEvmL2TxnBatch = () => { const ZkEvmL2TxnBatch = () => {
...@@ -51,7 +51,7 @@ const ZkEvmL2TxnBatch = () => { ...@@ -51,7 +51,7 @@ const ZkEvmL2TxnBatch = () => {
const tabs: Array<RoutedTab> = React.useMemo(() => ([ const tabs: Array<RoutedTab> = React.useMemo(() => ([
{ id: 'index', title: 'Details', component: <ZkEvmL2TxnBatchDetails query={ batchQuery }/> }, { id: 'index', title: 'Details', component: <ZkEvmL2TxnBatchDetails query={ batchQuery }/> },
{ id: 'txs', title: 'Transactions', component: <TxsContent query={ batchTxsQuery } showSocketInfo={ false }/> }, { id: 'txs', title: 'Transactions', component: <TxsWithFrontendSorting query={ batchTxsQuery } showSocketInfo={ false }/> },
].filter(Boolean)), [ batchQuery, batchTxsQuery ]); ].filter(Boolean)), [ batchQuery, batchTxsQuery ]);
const backLink = React.useMemo(() => { const backLink = React.useMemo(() => {
......
...@@ -2,17 +2,23 @@ import { Box, Show, Hide } from '@chakra-ui/react'; ...@@ -2,17 +2,23 @@ import { Box, Show, Hide } from '@chakra-ui/react';
import React from 'react'; import React from 'react';
import type { AddressFromToFilter } from 'types/api/address'; import type { AddressFromToFilter } from 'types/api/address';
import type { Transaction, TransactionsSortingField, TransactionsSortingValue } 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 DataListDisplay from 'ui/shared/DataListDisplay'; import DataListDisplay from 'ui/shared/DataListDisplay';
import type { QueryWithPagesResult } from 'ui/shared/pagination/useQueryWithPages'; import type { QueryWithPagesResult } from 'ui/shared/pagination/useQueryWithPages';
import * as SocketNewItemsNotice from 'ui/shared/SocketNewItemsNotice'; import * as SocketNewItemsNotice from 'ui/shared/SocketNewItemsNotice';
import getNextSortValue from 'ui/shared/sort/getNextSortValue';
import TxsHeaderMobile from './TxsHeaderMobile'; import TxsHeaderMobile from './TxsHeaderMobile';
import TxsListItem from './TxsListItem'; import TxsListItem from './TxsListItem';
import TxsTable from './TxsTable'; import TxsTable from './TxsTable';
import useTxsSort from './useTxsSort';
const SORT_SEQUENCE: Record<TransactionsSortingField, Array<TransactionsSortingValue | undefined>> = {
value: [ 'value-desc', 'value-asc', undefined ],
fee: [ 'fee-desc', 'fee-asc', undefined ],
};
type Props = { type Props = {
// eslint-disable-next-line max-len // eslint-disable-next-line max-len
...@@ -26,12 +32,17 @@ type Props = { ...@@ -26,12 +32,17 @@ type Props = {
filterValue?: AddressFromToFilter; filterValue?: AddressFromToFilter;
enableTimeIncrement?: boolean; enableTimeIncrement?: boolean;
top?: number; top?: number;
items?: Array<Transaction>;
isPlaceholderData: boolean;
isError: boolean;
setSorting: (value: TransactionsSortingValue | undefined) => void;
sort: TransactionsSortingValue | undefined;
} }
const TxsContent = ({ const TxsContent = ({
query,
filter, filter,
filterValue, filterValue,
query,
showBlockInfo = true, showBlockInfo = true,
showSocketInfo = true, showSocketInfo = true,
socketInfoAlert, socketInfoAlert,
...@@ -39,11 +50,20 @@ const TxsContent = ({ ...@@ -39,11 +50,20 @@ const TxsContent = ({
currentAddress, currentAddress,
enableTimeIncrement, enableTimeIncrement,
top, top,
items,
isPlaceholderData,
isError,
setSorting,
sort,
}: Props) => { }: Props) => {
const { data, isPlaceholderData, isError, setSortByField, setSortByValue, sorting } = useTxsSort(query);
const isMobile = useIsMobile(); const isMobile = useIsMobile();
const content = data?.items ? ( const onSortToggle = React.useCallback((field: TransactionsSortingField) => () => {
const value = getNextSortValue<TransactionsSortingField, TransactionsSortingValue>(SORT_SEQUENCE, field)(sort);
setSorting(value);
}, [ sort, setSorting ]);
const content = items ? (
<> <>
<Show below="lg" ssr={ false }> <Show below="lg" ssr={ false }>
<Box> <Box>
...@@ -55,7 +75,7 @@ const TxsContent = ({ ...@@ -55,7 +75,7 @@ const TxsContent = ({
isLoading={ isPlaceholderData } isLoading={ isPlaceholderData }
/> />
) } ) }
{ data.items.map((tx, index) => ( { items.map((tx, index) => (
<TxsListItem <TxsListItem
key={ tx.hash + (isPlaceholderData ? index : '') } key={ tx.hash + (isPlaceholderData ? index : '') }
tx={ tx } tx={ tx }
...@@ -69,9 +89,9 @@ const TxsContent = ({ ...@@ -69,9 +89,9 @@ const TxsContent = ({
</Show> </Show>
<Hide below="lg" ssr={ false }> <Hide below="lg" ssr={ false }>
<TxsTable <TxsTable
txs={ data.items } txs={ items }
sort={ setSortByField } sort={ onSortToggle }
sorting={ sorting } sorting={ sort }
showBlockInfo={ showBlockInfo } showBlockInfo={ showBlockInfo }
showSocketInfo={ showSocketInfo } showSocketInfo={ showSocketInfo }
socketInfoAlert={ socketInfoAlert } socketInfoAlert={ socketInfoAlert }
...@@ -88,8 +108,8 @@ const TxsContent = ({ ...@@ -88,8 +108,8 @@ const TxsContent = ({
const actionBar = isMobile ? ( const actionBar = isMobile ? (
<TxsHeaderMobile <TxsHeaderMobile
mt={ -6 } mt={ -6 }
sorting={ sorting } sorting={ sort }
setSorting={ setSortByValue } setSorting={ setSorting }
paginationProps={ query.pagination } paginationProps={ query.pagination }
showPagination={ query.pagination.isVisible } showPagination={ query.pagination.isVisible }
filterComponent={ filter } filterComponent={ filter }
...@@ -107,7 +127,7 @@ const TxsContent = ({ ...@@ -107,7 +127,7 @@ const TxsContent = ({
return ( return (
<DataListDisplay <DataListDisplay
isError={ isError } isError={ isError }
items={ data?.items } items={ items }
emptyText="There are no transactions." emptyText="There are no transactions."
content={ content } content={ content }
actionBar={ actionBar } actionBar={ actionBar }
......
import { HStack, chakra } from '@chakra-ui/react'; import { HStack, chakra } from '@chakra-ui/react';
import React from 'react'; import React from 'react';
import type { Sort as TSort } from 'types/client/txs-sort'; import type { TransactionsSortingValue } from 'types/api/transaction';
import type { PaginationParams } from 'ui/shared/pagination/types'; import type { PaginationParams } from 'ui/shared/pagination/types';
// import FilterInput from 'ui/shared/filters/FilterInput'; // import FilterInput from 'ui/shared/filters/FilterInput';
import ActionBar from 'ui/shared/ActionBar'; import ActionBar from 'ui/shared/ActionBar';
import Pagination from 'ui/shared/pagination/Pagination'; import Pagination from 'ui/shared/pagination/Pagination';
import type { Option } from 'ui/shared/sort/Sort';
import Sort from 'ui/shared/sort/Sort'; import Sort from 'ui/shared/sort/Sort';
// import TxsFilters from './TxsFilters'; import { SORT_OPTIONS } from './useTxsSort';
const SORT_OPTIONS: Array<Option<TSort>> = [ // import TxsFilters from './TxsFilters';
{ title: 'Default', id: undefined },
{ title: 'Value ascending', id: 'val-asc' },
{ title: 'Value descending', id: 'val-desc' },
{ title: 'Fee ascending', id: 'fee-asc' },
{ title: 'Fee descending', id: 'fee-desc' },
];
type Props = { type Props = {
sorting: TSort; sorting: TransactionsSortingValue | undefined;
setSorting: (val: TSort | undefined) => void; setSorting: (val: TransactionsSortingValue | undefined) => void;
paginationProps: PaginationParams; paginationProps: PaginationParams;
className?: string; className?: string;
showPagination?: boolean; showPagination?: boolean;
......
...@@ -2,8 +2,7 @@ import { Link, Table, Tbody, Tr, Th, Icon, Show, Hide } from '@chakra-ui/react'; ...@@ -2,8 +2,7 @@ import { Link, Table, Tbody, Tr, Th, Icon, Show, Hide } from '@chakra-ui/react';
import { AnimatePresence } from 'framer-motion'; import { AnimatePresence } from 'framer-motion';
import React from 'react'; import React from 'react';
import type { Transaction } from 'types/api/transaction'; import type { Transaction, TransactionsSortingField, TransactionsSortingValue } from 'types/api/transaction';
import type { Sort } from 'types/client/txs-sort';
import config from 'configs/app'; import config from 'configs/app';
import rightArrowIcon from 'icons/arrows/east.svg'; import rightArrowIcon from 'icons/arrows/east.svg';
...@@ -14,8 +13,8 @@ import TxsTableItem from './TxsTableItem'; ...@@ -14,8 +13,8 @@ import TxsTableItem from './TxsTableItem';
type Props = { type Props = {
txs: Array<Transaction>; txs: Array<Transaction>;
sort: (field: 'val' | 'fee') => () => void; sort: (field: TransactionsSortingField) => () => void;
sorting?: Sort; sorting?: TransactionsSortingValue;
top: number; top: number;
showBlockInfo: boolean; showBlockInfo: boolean;
showSocketInfo: boolean; showSocketInfo: boolean;
...@@ -58,9 +57,9 @@ const TxsTable = ({ ...@@ -58,9 +57,9 @@ const TxsTable = ({
</Th> </Th>
{ !config.UI.views.tx.hiddenFields?.value && ( { !config.UI.views.tx.hiddenFields?.value && (
<Th width="20%" isNumeric> <Th width="20%" isNumeric>
<Link onClick={ sort('val') } display="flex" justifyContent="end"> <Link onClick={ sort('value') } display="flex" justifyContent="end">
{ sorting === 'val-asc' && <Icon boxSize={ 5 } as={ rightArrowIcon } transform="rotate(-90deg)"/> } { sorting === 'value-asc' && <Icon boxSize={ 5 } as={ rightArrowIcon } transform="rotate(-90deg)"/> }
{ sorting === 'val-desc' && <Icon boxSize={ 5 } as={ rightArrowIcon } transform="rotate(90deg)"/> } { sorting === 'value-desc' && <Icon boxSize={ 5 } as={ rightArrowIcon } transform="rotate(90deg)"/> }
{ `Value ${ config.chain.currency.symbol }` } { `Value ${ config.chain.currency.symbol }` }
</Link> </Link>
</Th> </Th>
......
...@@ -2,7 +2,7 @@ import React from 'react'; ...@@ -2,7 +2,7 @@ import React from 'react';
import useRedirectForInvalidAuthToken from 'lib/hooks/useRedirectForInvalidAuthToken'; import useRedirectForInvalidAuthToken from 'lib/hooks/useRedirectForInvalidAuthToken';
import type { QueryWithPagesResult } from 'ui/shared/pagination/useQueryWithPages'; import type { QueryWithPagesResult } from 'ui/shared/pagination/useQueryWithPages';
import TxsContent from 'ui/txs/TxsContent'; import TxsWithFrontendSorting from 'ui/txs/TxsWithFrontendSorting';
type Props = { type Props = {
query: QueryWithPagesResult<'txs_watchlist'>; query: QueryWithPagesResult<'txs_watchlist'>;
...@@ -10,7 +10,7 @@ type Props = { ...@@ -10,7 +10,7 @@ type Props = {
const TxsWatchlist = ({ query }: Props) => { const TxsWatchlist = ({ query }: Props) => {
useRedirectForInvalidAuthToken(); useRedirectForInvalidAuthToken();
return <TxsContent query={ query } showSocketInfo={ false }/>; return <TxsWithFrontendSorting query={ query } showSocketInfo={ false }/>;
}; };
export default TxsWatchlist; export default TxsWatchlist;
import React from 'react';
import type { AddressFromToFilter } from 'types/api/address';
import type { TransactionsSortingValue } from 'types/api/transaction';
import type { QueryWithPagesResult } from 'ui/shared/pagination/useQueryWithPages';
import getSortParamsFromValue from 'ui/shared/sort/getSortParamsFromValue';
import TxsContent from './TxsContent';
type Props = {
// eslint-disable-next-line max-len
query: QueryWithPagesResult<'address_txs'>;
showBlockInfo?: boolean;
showSocketInfo?: boolean;
socketInfoAlert?: string;
socketInfoNum?: number;
currentAddress?: string;
filter?: React.ReactNode;
filterValue?: AddressFromToFilter;
enableTimeIncrement?: boolean;
top?: number;
sorting: TransactionsSortingValue | undefined;
setSort: (value?: TransactionsSortingValue) => void;
}
const TxsWithAPISorting = ({
filter,
filterValue,
query,
showBlockInfo = true,
showSocketInfo = true,
socketInfoAlert,
socketInfoNum,
currentAddress,
enableTimeIncrement,
top,
sorting,
setSort,
}: Props) => {
const handleSortChange = React.useCallback((value?: TransactionsSortingValue) => {
setSort(value);
query.onSortingChange(getSortParamsFromValue(value));
}, [ setSort, query ]);
return (
<TxsContent
filter={ filter }
filterValue={ filterValue }
showBlockInfo={ showBlockInfo }
showSocketInfo={ showSocketInfo }
socketInfoAlert={ socketInfoAlert }
socketInfoNum={ socketInfoNum }
currentAddress={ currentAddress }
enableTimeIncrement={ enableTimeIncrement }
top={ top }
items={ query.data?.items }
isPlaceholderData={ query.isPlaceholderData }
isError={ query.isError }
setSorting={ handleSortChange }
sort={ sorting }
query={ query }
/>
);
};
export default TxsWithAPISorting;
import React from 'react';
import type { AddressFromToFilter } from 'types/api/address';
import type { QueryWithPagesResult } from 'ui/shared/pagination/useQueryWithPages';
import TxsContent from './TxsContent';
import useTxsSort from './useTxsSort';
type Props = {
// eslint-disable-next-line max-len
query: QueryWithPagesResult<'txs_validated' | 'txs_pending'> | QueryWithPagesResult<'txs_watchlist'> | QueryWithPagesResult<'block_txs'> | QueryWithPagesResult<'zkevm_l2_txn_batch_txs'>;
showBlockInfo?: boolean;
showSocketInfo?: boolean;
socketInfoAlert?: string;
socketInfoNum?: number;
currentAddress?: string;
filter?: React.ReactNode;
filterValue?: AddressFromToFilter;
enableTimeIncrement?: boolean;
top?: number;
}
const TxsWithFrontendSorting = ({
filter,
filterValue,
query,
showBlockInfo = true,
showSocketInfo = true,
socketInfoAlert,
socketInfoNum,
currentAddress,
enableTimeIncrement,
top,
}: Props) => {
const { data, isPlaceholderData, isError, setSortByValue, sorting } = useTxsSort(query);
return (
<TxsContent
filter={ filter }
filterValue={ filterValue }
showBlockInfo={ showBlockInfo }
showSocketInfo={ showSocketInfo }
socketInfoAlert={ socketInfoAlert }
socketInfoNum={ socketInfoNum }
currentAddress={ currentAddress }
enableTimeIncrement={ enableTimeIncrement }
top={ top }
items={ data?.items }
isPlaceholderData={ isPlaceholderData }
isError={ isError }
setSorting={ setSortByValue }
sort={ sorting }
query={ query }
/>
);
};
export default TxsWithFrontendSorting;
import type { UseQueryResult } from '@tanstack/react-query'; import type { UseQueryResult } from '@tanstack/react-query';
import React from 'react'; import React from 'react';
import type { TxsResponse } from 'types/api/transaction'; import type { Transaction, TransactionsSortingValue, TxsResponse } from 'types/api/transaction';
import type { Sort } from 'types/client/txs-sort';
import type { ResourceError } from 'lib/api/resources'; import type { ResourceError } from 'lib/api/resources';
import compareBns from 'lib/bigint/compareBns';
import * as cookies from 'lib/cookies'; import * as cookies from 'lib/cookies';
import sortTxs from 'lib/tx/sortTxs'; import type { Option } from 'ui/shared/sort/Sort';
export const SORT_OPTIONS: Array<Option<TransactionsSortingValue>> = [
{ title: 'Default', id: undefined },
{ title: 'Value ascending', id: 'value-asc' },
{ title: 'Value descending', id: 'value-desc' },
{ title: 'Fee ascending', id: 'fee-asc' },
{ title: 'Fee descending', id: 'fee-desc' },
];
type SortingValue = TransactionsSortingValue | undefined;
type HookResult = UseQueryResult<TxsResponse, ResourceError<unknown>> & { type HookResult = UseQueryResult<TxsResponse, ResourceError<unknown>> & {
sorting: Sort; sorting: SortingValue;
setSortByField: (field: 'val' | 'fee') => () => void; setSortByValue: (value: SortingValue) => void;
setSortByValue: (value: Sort | undefined) => void;
} }
const sortTxs = (sorting: SortingValue) => (tx1: Transaction, tx2: Transaction) => {
switch (sorting) {
case 'value-desc':
return compareBns(tx1.value, tx2.value);
case 'value-asc':
return compareBns(tx2.value, tx1.value);
case 'fee-desc':
return compareBns(tx1.fee.value || 0, tx2.fee.value || 0);
case 'fee-asc':
return compareBns(tx2.fee.value || 0, tx1.fee.value || 0);
default:
return 0;
}
};
export default function useTxsSort( export default function useTxsSort(
queryResult: UseQueryResult<TxsResponse, ResourceError<unknown>>, queryResult: UseQueryResult<TxsResponse, ResourceError<unknown>>,
): HookResult { ): HookResult {
const [ sorting, setSorting ] = React.useState<Sort>(cookies.get(cookies.NAMES.TXS_SORT) as Sort); const [ sorting, setSorting ] = React.useState<SortingValue>(cookies.get(cookies.NAMES.TXS_SORT) as SortingValue);
const setSortByField = React.useCallback((field: 'val' | 'fee') => () => {
if (queryResult.isPlaceholderData) {
return;
}
setSorting((prevVal) => {
let newVal: Sort = '';
if (field === 'val') {
if (prevVal === 'val-asc') {
newVal = '';
} else if (prevVal === 'val-desc') {
newVal = 'val-asc';
} else {
newVal = 'val-desc';
}
}
if (field === 'fee') {
if (prevVal === 'fee-asc') {
newVal = '';
} else if (prevVal === 'fee-desc') {
newVal = 'fee-asc';
} else {
newVal = 'fee-desc';
}
}
cookies.set(cookies.NAMES.TXS_SORT, newVal);
return newVal;
});
}, [ queryResult.isPlaceholderData ]);
const setSortByValue = React.useCallback((value: Sort | undefined) => { const setSortByValue = React.useCallback((value: SortingValue) => {
setSorting((prevVal: Sort) => { setSorting((prevVal: SortingValue) => {
let newVal: Sort = ''; let newVal: SortingValue = undefined;
if (value !== prevVal) { if (value !== prevVal) {
newVal = value as Sort; newVal = value as SortingValue;
} }
cookies.set(cookies.NAMES.TXS_SORT, newVal); cookies.set(cookies.NAMES.TXS_SORT, newVal ? newVal : '');
return newVal; return newVal;
}); });
}, []); }, []);
return React.useMemo(() => { return React.useMemo(() => {
if (queryResult.isError || queryResult.isPending) { if (queryResult.isError || queryResult.isPending) {
return { ...queryResult, setSortByField, setSortByValue, sorting }; return { ...queryResult, setSortByValue, sorting };
} }
return { return {
...queryResult, ...queryResult,
data: { ...queryResult.data, items: queryResult.data.items.slice().sort(sortTxs(sorting)) }, data: { ...queryResult.data, items: queryResult.data.items.slice().sort(sortTxs(sorting)) },
setSortByField,
setSortByValue, setSortByValue,
sorting, sorting,
}; };
}, [ queryResult, setSortByField, setSortByValue, sorting ]); }, [ queryResult, setSortByValue, sorting ]);
} }
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