Commit 2e4117d6 authored by tom's avatar tom

refactor sockets for transactions

parent 5e920bb5
...@@ -85,36 +85,6 @@ test.describe('socket', () => { ...@@ -85,36 +85,6 @@ test.describe('socket', () => {
// test cases which use socket cannot run in parallel since the socket server always run on the same port // test cases which use socket cannot run in parallel since the socket server always run on the same port
test.describe.configure({ mode: 'serial' }); test.describe.configure({ mode: 'serial' });
test('without overload', async({ render, mockApiResponse, page, createSocket }) => {
await mockApiResponse(
'address_txs',
{ items: [ txMock.base ], next_page_params: DEFAULT_PAGINATION },
{ pathParams: { hash: CURRENT_ADDRESS } },
);
await render(
<Box pt={{ base: '134px', lg: 6 }}>
<AddressTxs/>
</Box>,
{ hooksConfig },
{ withSocket: true },
);
const socket = await createSocket();
const channel = await socketServer.joinChannel(socket, `addresses:${ CURRENT_ADDRESS.toLowerCase() }`);
const itemsCount = await page.locator('tbody tr').count();
expect(itemsCount).toBe(2);
socketServer.sendMessage(socket, channel, 'transaction', { transactions: [ txMock.base2, txMock.base4 ] });
const thirdRow = page.locator('tbody tr:nth-child(3)');
await thirdRow.waitFor();
const itemsCountNew = await page.locator('tbody tr').count();
expect(itemsCountNew).toBe(4);
});
test('with update', async({ render, mockApiResponse, page, createSocket }) => { test('with update', async({ render, mockApiResponse, page, createSocket }) => {
await mockApiResponse( await mockApiResponse(
'address_txs', 'address_txs',
...@@ -136,13 +106,13 @@ test.describe('socket', () => { ...@@ -136,13 +106,13 @@ test.describe('socket', () => {
const itemsCount = await page.locator('tbody tr').count(); const itemsCount = await page.locator('tbody tr').count();
expect(itemsCount).toBe(2); expect(itemsCount).toBe(2);
socketServer.sendMessage(socket, channel, 'transaction', { transactions: [ txMock.base, txMock.base2 ] }); socketServer.sendMessage(socket, channel, 'transaction', { transactions: [ txMock.base ] });
const thirdRow = page.locator('tbody tr:nth-child(3)'); const secondRow = page.locator('tbody tr:nth-child(2)');
await thirdRow.waitFor(); await secondRow.waitFor();
const itemsCountNew = await page.locator('tbody tr').count(); const itemsCountNew = await page.locator('tbody tr').count();
expect(itemsCountNew).toBe(3); expect(itemsCountNew).toBe(2);
}); });
test('with overload', async({ render, mockApiResponse, page, createSocket }) => { test('with overload', async({ render, mockApiResponse, page, createSocket }) => {
...@@ -154,7 +124,7 @@ test.describe('socket', () => { ...@@ -154,7 +124,7 @@ test.describe('socket', () => {
await render( await render(
<Box pt={{ base: '134px', lg: 6 }}> <Box pt={{ base: '134px', lg: 6 }}>
<AddressTxs overloadCount={ 2 }/> <AddressTxs/>
</Box>, </Box>,
{ hooksConfig }, { hooksConfig },
{ withSocket: true }, { withSocket: true },
...@@ -205,10 +175,10 @@ test.describe('socket', () => { ...@@ -205,10 +175,10 @@ test.describe('socket', () => {
const itemsCount = await page.locator('tbody tr').count(); const itemsCount = await page.locator('tbody tr').count();
expect(itemsCount).toBe(2); expect(itemsCount).toBe(2);
socketServer.sendMessage(socket, channel, 'transaction', { transactions: [ txMock.base2, txMock.base4 ] }); socketServer.sendMessage(socket, channel, 'transaction', { transactions: [ txMock.base2 ] });
const thirdRow = page.locator('tbody tr:nth-child(3)'); const secondRow = page.locator('tbody tr:nth-child(2)');
await thirdRow.waitFor(); await secondRow.waitFor();
const itemsCountNew = await page.locator('tbody tr').count(); const itemsCountNew = await page.locator('tbody tr').count();
expect(itemsCountNew).toBe(3); expect(itemsCountNew).toBe(3);
...@@ -229,7 +199,7 @@ test.describe('socket', () => { ...@@ -229,7 +199,7 @@ test.describe('socket', () => {
await render( await render(
<Box pt={{ base: '134px', lg: 6 }}> <Box pt={{ base: '134px', lg: 6 }}>
<AddressTxs overloadCount={ 2 }/> <AddressTxs/>
</Box>, </Box>,
{ hooksConfig: hooksConfigWithFilter }, { hooksConfig: hooksConfigWithFilter },
{ withSocket: true }, { withSocket: true },
......
import { useQueryClient } from '@tanstack/react-query';
import { useRouter } from 'next/router'; import { useRouter } from 'next/router';
import React from 'react'; import React from 'react';
import type { SocketMessage } from 'lib/socket/types'; import type { AddressFromToFilter } 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, TransactionsSortingField, TransactionsSortingValue, TransactionsSorting } from 'types/api/transaction'; import type { TransactionsSortingField, TransactionsSortingValue, TransactionsSorting } from 'types/api/transaction';
import { getResourceKey } from 'lib/api/useApiQuery';
import getFilterValueFromQuery from 'lib/getFilterValueFromQuery'; import getFilterValueFromQuery from 'lib/getFilterValueFromQuery';
import useIsMobile from 'lib/hooks/useIsMobile'; import useIsMobile from 'lib/hooks/useIsMobile';
import useIsMounted from 'lib/hooks/useIsMounted'; import useIsMounted from 'lib/hooks/useIsMounted';
import getQueryParamString from 'lib/router/getQueryParamString'; import getQueryParamString from 'lib/router/getQueryParamString';
import useSocketChannel from 'lib/socket/useSocketChannel';
import useSocketMessage from 'lib/socket/useSocketMessage';
import { TX } from 'stubs/tx'; import { TX } from 'stubs/tx';
import { generateListStub } from 'stubs/utils'; import { generateListStub } from 'stubs/utils';
import ActionBar, { ACTION_BAR_HEIGHT_DESKTOP } from 'ui/shared/ActionBar'; import ActionBar, { ACTION_BAR_HEIGHT_DESKTOP } from 'ui/shared/ActionBar';
...@@ -21,45 +16,23 @@ import Pagination from 'ui/shared/pagination/Pagination'; ...@@ -21,45 +16,23 @@ import Pagination from 'ui/shared/pagination/Pagination';
import useQueryWithPages from 'ui/shared/pagination/useQueryWithPages'; import useQueryWithPages from 'ui/shared/pagination/useQueryWithPages';
import getSortParamsFromValue from 'ui/shared/sort/getSortParamsFromValue'; import getSortParamsFromValue from 'ui/shared/sort/getSortParamsFromValue';
import getSortValueFromQuery from 'ui/shared/sort/getSortValueFromQuery'; import getSortValueFromQuery from 'ui/shared/sort/getSortValueFromQuery';
import { sortTxsFromSocket } from 'ui/txs/sortTxs';
import TxsWithAPISorting from 'ui/txs/TxsWithAPISorting'; import TxsWithAPISorting from 'ui/txs/TxsWithAPISorting';
import { SORT_OPTIONS } from 'ui/txs/useTxsSort'; import { SORT_OPTIONS } from 'ui/txs/useTxsSort';
import AddressCsvExportLink from './AddressCsvExportLink'; import AddressCsvExportLink from './AddressCsvExportLink';
import AddressTxsFilter from './AddressTxsFilter'; import AddressTxsFilter from './AddressTxsFilter';
const OVERLOAD_COUNT = 75;
const getFilterValue = (getFilterValueFromQuery<AddressFromToFilter>).bind(null, AddressFromToFilterValues); const getFilterValue = (getFilterValueFromQuery<AddressFromToFilter>).bind(null, AddressFromToFilterValues);
const matchFilter = (filterValue: AddressFromToFilter, transaction: Transaction, address?: string) => {
if (!filterValue) {
return true;
}
if (filterValue === 'from') {
return transaction.from.hash === address;
}
if (filterValue === 'to') {
return transaction.to?.hash === address;
}
};
type Props = { type Props = {
shouldRender?: boolean; shouldRender?: boolean;
isQueryEnabled?: boolean; isQueryEnabled?: boolean;
// for tests only
overloadCount?: number;
}; };
const AddressTxs = ({ overloadCount = OVERLOAD_COUNT, shouldRender = true, isQueryEnabled = true }: Props) => { const AddressTxs = ({ shouldRender = true, isQueryEnabled = true }: Props) => {
const router = useRouter(); const router = useRouter();
const queryClient = useQueryClient();
const isMounted = useIsMounted(); const isMounted = useIsMounted();
const [ socketAlert, setSocketAlert ] = React.useState('');
const [ newItemsCount, setNewItemsCount ] = React.useState(0);
const [ sort, setSort ] = React.useState<TransactionsSortingValue>(getSortValueFromQuery<TransactionsSortingValue>(router.query, SORT_OPTIONS) || 'default'); const [ sort, setSort ] = React.useState<TransactionsSortingValue>(getSortValueFromQuery<TransactionsSortingValue>(router.query, SORT_OPTIONS) || 'default');
const isMobile = useIsMobile(); const isMobile = useIsMobile();
...@@ -90,76 +63,6 @@ const AddressTxs = ({ overloadCount = OVERLOAD_COUNT, shouldRender = true, isQue ...@@ -90,76 +63,6 @@ const AddressTxs = ({ overloadCount = OVERLOAD_COUNT, shouldRender = true, isQue
addressTxsQuery.onFilterChange({ filter: newVal }); addressTxsQuery.onFilterChange({ filter: newVal });
}, [ addressTxsQuery ]); }, [ addressTxsQuery ]);
const handleNewSocketMessage: SocketMessage.AddressTxs['handler'] = React.useCallback((payload) => {
setSocketAlert('');
queryClient.setQueryData(
getResourceKey('address_txs', { pathParams: { hash: currentAddress }, queryParams: { filter: filterValue } }),
(prevData: AddressTransactionsResponse | undefined) => {
if (!prevData) {
return;
}
const newItems: Array<Transaction> = [];
let newCount = 0;
payload.transactions.forEach(tx => {
const currIndex = prevData.items.findIndex((item) => item.hash === tx.hash);
if (currIndex > -1) {
prevData.items[currIndex] = tx;
} else {
if (matchFilter(filterValue, tx, currentAddress)) {
if (newItems.length + prevData.items.length >= overloadCount) {
newCount++;
} else {
newItems.push(tx);
}
}
}
});
if (newCount > 0) {
setNewItemsCount(prev => prev + newCount);
}
return {
...prevData,
items: [
...newItems,
...prevData.items,
].sort(sortTxsFromSocket(sort)),
};
});
}, [ currentAddress, filterValue, overloadCount, queryClient, sort ]);
const handleSocketClose = React.useCallback(() => {
setSocketAlert('Connection is lost. Please refresh the page to load new transactions.');
}, []);
const handleSocketError = React.useCallback(() => {
setSocketAlert('An error has occurred while fetching new transactions. Please refresh the page.');
}, []);
const channel = useSocketChannel({
topic: `addresses:${ currentAddress?.toLowerCase() }`,
onSocketClose: handleSocketClose,
onSocketError: handleSocketError,
isDisabled: addressTxsQuery.pagination.page !== 1 || addressTxsQuery.isPlaceholderData,
});
useSocketMessage({
channel,
event: 'transaction',
handler: handleNewSocketMessage,
});
useSocketMessage({
channel,
event: 'pending_transaction',
handler: handleNewSocketMessage,
});
if (!isMounted || !shouldRender) { if (!isMounted || !shouldRender) {
return null; return null;
} }
...@@ -197,9 +100,7 @@ const AddressTxs = ({ overloadCount = OVERLOAD_COUNT, shouldRender = true, isQue ...@@ -197,9 +100,7 @@ const AddressTxs = ({ overloadCount = OVERLOAD_COUNT, shouldRender = true, isQue
query={ addressTxsQuery } query={ addressTxsQuery }
currentAddress={ typeof currentAddress === 'string' ? currentAddress : undefined } currentAddress={ typeof currentAddress === 'string' ? currentAddress : undefined }
enableTimeIncrement enableTimeIncrement
showSocketInfo={ addressTxsQuery.pagination.page === 1 } socketType="address_txs"
socketInfoAlert={ socketAlert }
socketInfoNum={ newItemsCount }
top={ ACTION_BAR_HEIGHT_DESKTOP } top={ ACTION_BAR_HEIGHT_DESKTOP }
sorting={ sort } sorting={ sort }
setSort={ setSort } setSort={ setSort }
......
...@@ -6,10 +6,10 @@ import { route } from 'nextjs-routes'; ...@@ -6,10 +6,10 @@ import { route } from 'nextjs-routes';
import useApiQuery from 'lib/api/useApiQuery'; import useApiQuery from 'lib/api/useApiQuery';
import { AddressHighlightProvider } from 'lib/contexts/addressHighlight'; import { AddressHighlightProvider } from 'lib/contexts/addressHighlight';
import useIsMobile from 'lib/hooks/useIsMobile'; import useIsMobile from 'lib/hooks/useIsMobile';
import useNewTxsSocket from 'lib/hooks/useNewTxsSocket';
import { TX } from 'stubs/tx'; import { TX } from 'stubs/tx';
import { Link } from 'toolkit/chakra/link'; import { Link } from 'toolkit/chakra/link';
import SocketNewItemsNotice from 'ui/shared/SocketNewItemsNotice'; import SocketNewItemsNotice from 'ui/shared/SocketNewItemsNotice';
import useNewTxsSocket from 'ui/txs/socket/useTxsSocketTypeAll';
import LatestTxsItem from './LatestTxsItem'; import LatestTxsItem from './LatestTxsItem';
import LatestTxsItemMobile from './LatestTxsItemMobile'; import LatestTxsItemMobile from './LatestTxsItemMobile';
...@@ -23,7 +23,7 @@ const LatestTransactions = () => { ...@@ -23,7 +23,7 @@ const LatestTransactions = () => {
}, },
}); });
const { num, socketAlert } = useNewTxsSocket(); const { num, alertText } = useNewTxsSocket({ type: 'txs_home', isLoading: isPlaceholderData });
if (isError) { if (isError) {
return <Text mt={ 4 }>No data. Please reload the page.</Text>; return <Text mt={ 4 }>No data. Please reload the page.</Text>;
...@@ -33,7 +33,7 @@ const LatestTransactions = () => { ...@@ -33,7 +33,7 @@ const LatestTransactions = () => {
const txsUrl = route({ pathname: '/txs' }); const txsUrl = route({ pathname: '/txs' });
return ( return (
<> <>
<SocketNewItemsNotice borderBottomRadius={ 0 } url={ txsUrl } num={ num } alert={ socketAlert } isLoading={ isPlaceholderData }/> <SocketNewItemsNotice borderBottomRadius={ 0 } url={ txsUrl } num={ num } alert={ alertText } isLoading={ isPlaceholderData }/>
<Box mb={ 3 } display={{ base: 'block', lg: 'none' }}> <Box mb={ 3 } display={{ base: 'block', lg: 'none' }}>
{ data.slice(0, txsCount).map(((tx, index) => ( { data.slice(0, txsCount).map(((tx, index) => (
<LatestTxsItemMobile <LatestTxsItemMobile
......
...@@ -85,7 +85,7 @@ const ArbitrumL2TxnBatch = () => { ...@@ -85,7 +85,7 @@ const ArbitrumL2TxnBatch = () => {
{ {
id: 'txs', id: 'txs',
title: 'Transactions', title: 'Transactions',
component: <TxsWithFrontendSorting query={ batchTxsQuery } showSocketInfo={ false } top={ hasPagination ? TABS_HEIGHT : 0 }/>, component: <TxsWithFrontendSorting query={ batchTxsQuery } top={ hasPagination ? TABS_HEIGHT : 0 }/>,
}, },
{ {
id: 'blocks', id: 'blocks',
......
...@@ -73,7 +73,7 @@ const BlockPageContent = () => { ...@@ -73,7 +73,7 @@ const BlockPageContent = () => {
component: ( component: (
<> <>
{ blockTxsQuery.isDegradedData && <ServiceDegradationWarning isLoading={ blockTxsQuery.isPlaceholderData } mb={ 6 }/> } { blockTxsQuery.isDegradedData && <ServiceDegradationWarning isLoading={ blockTxsQuery.isPlaceholderData } mb={ 6 }/> }
<TxsWithFrontendSorting query={ blockTxsQuery } showBlockInfo={ false } showSocketInfo={ false } top={ hasPagination ? TABS_HEIGHT : 0 }/> <TxsWithFrontendSorting query={ blockTxsQuery } showBlockInfo={ false } top={ hasPagination ? TABS_HEIGHT : 0 }/>
</> </>
), ),
}, },
...@@ -82,7 +82,7 @@ const BlockPageContent = () => { ...@@ -82,7 +82,7 @@ const BlockPageContent = () => {
id: 'blob_txs', id: 'blob_txs',
title: 'Blob txns', title: 'Blob txns',
component: ( component: (
<TxsWithFrontendSorting query={ blockBlobTxsQuery } showBlockInfo={ false } showSocketInfo={ false }/> <TxsWithFrontendSorting query={ blockBlobTxsQuery } showBlockInfo={ false }/>
), ),
} : null, } : null,
config.features.beaconChain.isEnabled && Boolean(blockQuery.data?.withdrawals_count) ? config.features.beaconChain.isEnabled && Boolean(blockQuery.data?.withdrawals_count) ?
......
...@@ -31,10 +31,7 @@ const KettleTxs = () => { ...@@ -31,10 +31,7 @@ const KettleTxs = () => {
<> <>
<PageTitle title="Computor transactions" withTextAd/> <PageTitle title="Computor transactions" withTextAd/>
<AddressEntity address={{ hash }} mb={ 6 }/> <AddressEntity address={{ hash }} mb={ 6 }/>
<TxsWithFrontendSorting <TxsWithFrontendSorting query={ query }/>
query={ query }
showSocketInfo={ false }
/>
</> </>
); );
}; };
......
...@@ -83,7 +83,7 @@ const OptimisticL2TxnBatch = () => { ...@@ -83,7 +83,7 @@ const OptimisticL2TxnBatch = () => {
{ {
id: 'txs', id: 'txs',
title: 'Transactions', title: 'Transactions',
component: <TxsWithFrontendSorting query={ batchTxsQuery } showSocketInfo={ false } top={ hasPagination ? TABS_HEIGHT : 0 }/>, component: <TxsWithFrontendSorting query={ batchTxsQuery } top={ hasPagination ? TABS_HEIGHT : 0 }/>,
}, },
{ {
id: 'blocks', id: 'blocks',
......
...@@ -90,7 +90,7 @@ const ScrollL2TxnBatch = () => { ...@@ -90,7 +90,7 @@ const ScrollL2TxnBatch = () => {
{ {
id: 'txs', id: 'txs',
title: 'Transactions', title: 'Transactions',
component: <TxsWithFrontendSorting query={ batchTxsQuery } showSocketInfo={ false } top={ hasPagination ? TABS_HEIGHT : 0 }/>, component: <TxsWithFrontendSorting query={ batchTxsQuery } top={ hasPagination ? TABS_HEIGHT : 0 }/>,
}, },
{ {
id: 'blocks', id: 'blocks',
......
...@@ -9,7 +9,6 @@ import { route } from 'nextjs-routes'; ...@@ -9,7 +9,6 @@ import { route } from 'nextjs-routes';
import config from 'configs/app'; import config from 'configs/app';
import useIsMobile from 'lib/hooks/useIsMobile'; import useIsMobile from 'lib/hooks/useIsMobile';
import useNewTxsSocket from 'lib/hooks/useNewTxsSocket';
import getNetworkValidationActionText from 'lib/networks/getNetworkValidationActionText'; import getNetworkValidationActionText from 'lib/networks/getNetworkValidationActionText';
import getQueryParamString from 'lib/router/getQueryParamString'; import getQueryParamString from 'lib/router/getQueryParamString';
import { TX } from 'stubs/tx'; import { TX } from 'stubs/tx';
...@@ -91,8 +90,6 @@ const Transactions = () => { ...@@ -91,8 +90,6 @@ const Transactions = () => {
}, },
}); });
const { num, socketAlert } = useNewTxsSocket();
const isAuth = useIsAuth(); const isAuth = useIsAuth();
const tabs: Array<TabItemRegular> = [ const tabs: Array<TabItemRegular> = [
...@@ -102,9 +99,7 @@ const Transactions = () => { ...@@ -102,9 +99,7 @@ const Transactions = () => {
component: component:
<TxsWithFrontendSorting <TxsWithFrontendSorting
query={ txsValidatedQuery } query={ txsValidatedQuery }
showSocketInfo={ txsValidatedQuery.pagination.page === 1 } socketType="txs_validated"
socketInfoNum={ num }
socketInfoAlert={ socketAlert }
top={ TABS_HEIGHT } top={ TABS_HEIGHT }
/> }, /> },
{ {
...@@ -114,9 +109,7 @@ const Transactions = () => { ...@@ -114,9 +109,7 @@ const Transactions = () => {
<TxsWithFrontendSorting <TxsWithFrontendSorting
query={ txsPendingQuery } query={ txsPendingQuery }
showBlockInfo={ false } showBlockInfo={ false }
showSocketInfo={ txsPendingQuery.pagination.page === 1 } socketType="txs_pending"
socketInfoNum={ num }
socketInfoAlert={ socketAlert }
top={ TABS_HEIGHT } top={ TABS_HEIGHT }
/> />
), ),
...@@ -127,9 +120,6 @@ const Transactions = () => { ...@@ -127,9 +120,6 @@ const Transactions = () => {
component: ( component: (
<TxsWithFrontendSorting <TxsWithFrontendSorting
query={ txsWithBlobsQuery } query={ txsWithBlobsQuery }
showSocketInfo={ txsWithBlobsQuery.pagination.page === 1 }
socketInfoNum={ num }
socketInfoAlert={ socketAlert }
top={ TABS_HEIGHT } top={ TABS_HEIGHT }
/> />
), ),
......
...@@ -47,7 +47,7 @@ const ZkEvmL2TxnBatch = () => { ...@@ -47,7 +47,7 @@ const ZkEvmL2TxnBatch = () => {
const tabs: Array<TabItemRegular> = React.useMemo(() => ([ const tabs: Array<TabItemRegular> = React.useMemo(() => ([
{ id: 'index', title: 'Details', component: <ZkEvmL2TxnBatchDetails query={ batchQuery }/> }, { id: 'index', title: 'Details', component: <ZkEvmL2TxnBatchDetails query={ batchQuery }/> },
{ id: 'txs', title: 'Transactions', component: <TxsWithFrontendSorting query={ batchTxsQuery } showSocketInfo={ false }/> }, { id: 'txs', title: 'Transactions', component: <TxsWithFrontendSorting query={ batchTxsQuery }/> },
].filter(Boolean)), [ batchQuery, batchTxsQuery ]); ].filter(Boolean)), [ batchQuery, batchTxsQuery ]);
const backLink = React.useMemo(() => { const backLink = React.useMemo(() => {
......
...@@ -67,7 +67,7 @@ const ZkSyncL2TxnBatch = () => { ...@@ -67,7 +67,7 @@ const ZkSyncL2TxnBatch = () => {
{ {
id: 'txs', id: 'txs',
title: 'Transactions', title: 'Transactions',
component: <TxsWithFrontendSorting query={ batchTxsQuery } showSocketInfo={ false } top={ hasPagination ? TABS_HEIGHT : 0 }/>, component: <TxsWithFrontendSorting query={ batchTxsQuery } top={ hasPagination ? TABS_HEIGHT : 0 }/>,
}, },
].filter(Boolean)), [ batchQuery, batchTxsQuery, hasPagination ]); ].filter(Boolean)), [ batchQuery, batchTxsQuery, hasPagination ]);
......
import { Box } from '@chakra-ui/react'; import { Box } from '@chakra-ui/react';
import React from 'react'; import React from 'react';
import type { TxsSocketType } from './socket/types';
import type { AddressFromToFilter } from 'types/api/address'; import type { AddressFromToFilter } from 'types/api/address';
import type { Transaction, TransactionsSortingField, TransactionsSortingValue } from 'types/api/transaction'; import type { Transaction, TransactionsSortingField, TransactionsSortingValue } from 'types/api/transaction';
...@@ -26,9 +27,7 @@ type Props = { ...@@ -26,9 +27,7 @@ type Props = {
// eslint-disable-next-line max-len // eslint-disable-next-line max-len
query: QueryWithPagesResult<'txs_validated' | 'txs_pending'> | QueryWithPagesResult<'txs_watchlist'> | QueryWithPagesResult<'block_txs'> | QueryWithPagesResult<'zkevm_l2_txn_batch_txs'>; query: QueryWithPagesResult<'txs_validated' | 'txs_pending'> | QueryWithPagesResult<'txs_watchlist'> | QueryWithPagesResult<'block_txs'> | QueryWithPagesResult<'zkevm_l2_txn_batch_txs'>;
showBlockInfo?: boolean; showBlockInfo?: boolean;
showSocketInfo?: boolean; socketType?: TxsSocketType;
socketInfoAlert?: string;
socketInfoNum?: number;
currentAddress?: string; currentAddress?: string;
filter?: React.ReactNode; filter?: React.ReactNode;
filterValue?: AddressFromToFilter; filterValue?: AddressFromToFilter;
...@@ -46,9 +45,7 @@ const TxsContent = ({ ...@@ -46,9 +45,7 @@ const TxsContent = ({
filter, filter,
filterValue, filterValue,
showBlockInfo = true, showBlockInfo = true,
showSocketInfo = true, socketType,
socketInfoAlert,
socketInfoNum,
currentAddress, currentAddress,
enableTimeIncrement, enableTimeIncrement,
top, top,
...@@ -72,9 +69,7 @@ const TxsContent = ({ ...@@ -72,9 +69,7 @@ const TxsContent = ({
<Box hideFrom="lg"> <Box hideFrom="lg">
<TxsList <TxsList
showBlockInfo={ showBlockInfo } showBlockInfo={ showBlockInfo }
showSocketInfo={ showSocketInfo } socketType={ socketType }
socketInfoAlert={ socketInfoAlert }
socketInfoNum={ socketInfoNum }
isLoading={ isPlaceholderData } isLoading={ isPlaceholderData }
enableTimeIncrement={ enableTimeIncrement } enableTimeIncrement={ enableTimeIncrement }
currentAddress={ currentAddress } currentAddress={ currentAddress }
...@@ -87,9 +82,7 @@ const TxsContent = ({ ...@@ -87,9 +82,7 @@ const TxsContent = ({
sort={ sort } sort={ sort }
onSortToggle={ onSortToggle } onSortToggle={ onSortToggle }
showBlockInfo={ showBlockInfo } showBlockInfo={ showBlockInfo }
showSocketInfo={ showSocketInfo } socketType={ socketType }
socketInfoAlert={ socketInfoAlert }
socketInfoNum={ socketInfoNum }
top={ top || (query.pagination.isVisible ? ACTION_BAR_HEIGHT_DESKTOP : 0) } top={ top || (query.pagination.isVisible ? ACTION_BAR_HEIGHT_DESKTOP : 0) }
currentAddress={ currentAddress } currentAddress={ currentAddress }
enableTimeIncrement={ enableTimeIncrement } enableTimeIncrement={ enableTimeIncrement }
......
import { Box } from '@chakra-ui/react'; import { Box } from '@chakra-ui/react';
import React from 'react'; import React from 'react';
import type { TxsSocketType } from './socket/types';
import type { Transaction } from 'types/api/transaction'; import type { Transaction } from 'types/api/transaction';
import useInitialList from 'lib/hooks/useInitialList'; import useInitialList from 'lib/hooks/useInitialList';
import useLazyRenderedList from 'lib/hooks/useLazyRenderedList'; import useLazyRenderedList from 'lib/hooks/useLazyRenderedList';
import * as SocketNewItemsNotice from 'ui/shared/SocketNewItemsNotice';
import TxsSocketNotice from './socket/TxsSocketNotice';
import TxsListItem from './TxsListItem'; import TxsListItem from './TxsListItem';
interface Props { interface Props {
showBlockInfo: boolean; showBlockInfo: boolean;
showSocketInfo?: boolean; socketType?: TxsSocketType;
socketInfoAlert?: string;
socketInfoNum?: number;
enableTimeIncrement?: boolean; enableTimeIncrement?: boolean;
currentAddress?: string; currentAddress?: string;
isLoading: boolean; isLoading: boolean;
...@@ -30,14 +29,7 @@ const TxsList = (props: Props) => { ...@@ -30,14 +29,7 @@ const TxsList = (props: Props) => {
return ( return (
<Box> <Box>
{ props.showSocketInfo && ( { props.socketType && <TxsSocketNotice type={ props.socketType } place="list" isLoading={ props.isLoading }/> }
<SocketNewItemsNotice.Mobile
url={ window.location.href }
num={ props.socketInfoNum }
alert={ props.socketInfoAlert }
isLoading={ props.isLoading }
/>
) }
{ props.items.slice(0, renderedItemsNum).map((tx, index) => ( { props.items.slice(0, renderedItemsNum).map((tx, index) => (
<TxsListItem <TxsListItem
key={ tx.hash + (props.isLoading ? index : '') } key={ tx.hash + (props.isLoading ? index : '') }
......
...@@ -15,7 +15,6 @@ test('base view +@dark-mode', async({ render }) => { ...@@ -15,7 +15,6 @@ test('base view +@dark-mode', async({ render }) => {
onSortToggle={ () => {} } onSortToggle={ () => {} }
top={ 0 } top={ 0 }
showBlockInfo showBlockInfo
showSocketInfo={ false }
/>, />,
); );
...@@ -36,7 +35,6 @@ test.describe('screen xl', () => { ...@@ -36,7 +35,6 @@ test.describe('screen xl', () => {
onSortToggle={ () => {} } onSortToggle={ () => {} }
top={ 0 } top={ 0 }
showBlockInfo showBlockInfo
showSocketInfo={ false }
/>, />,
); );
......
import React from 'react'; import React from 'react';
import type { TxsSocketType } from './socket/types';
import type { Transaction, TransactionsSortingField, TransactionsSortingValue } from 'types/api/transaction'; import type { Transaction, TransactionsSortingField, TransactionsSortingValue } from 'types/api/transaction';
import config from 'configs/app'; import config from 'configs/app';
...@@ -8,8 +9,8 @@ import useInitialList from 'lib/hooks/useInitialList'; ...@@ -8,8 +9,8 @@ import useInitialList from 'lib/hooks/useInitialList';
import useLazyRenderedList from 'lib/hooks/useLazyRenderedList'; import useLazyRenderedList from 'lib/hooks/useLazyRenderedList';
import { currencyUnits } from 'lib/units'; import { currencyUnits } from 'lib/units';
import { TableBody, TableColumnHeader, TableColumnHeaderSortable, TableHeaderSticky, TableRoot, TableRow } from 'toolkit/chakra/table'; import { TableBody, TableColumnHeader, TableColumnHeaderSortable, TableHeaderSticky, TableRoot, TableRow } from 'toolkit/chakra/table';
import * as SocketNewItemsNotice from 'ui/shared/SocketNewItemsNotice';
import TxsSocketNotice from './socket/TxsSocketNotice';
import TxsTableItem from './TxsTableItem'; import TxsTableItem from './TxsTableItem';
type Props = { type Props = {
...@@ -18,9 +19,7 @@ type Props = { ...@@ -18,9 +19,7 @@ type Props = {
onSortToggle: (field: TransactionsSortingField) => void; onSortToggle: (field: TransactionsSortingField) => void;
top: number; top: number;
showBlockInfo: boolean; showBlockInfo: boolean;
showSocketInfo: boolean; socketType?: TxsSocketType;
socketInfoAlert?: string;
socketInfoNum?: number;
currentAddress?: string; currentAddress?: string;
enableTimeIncrement?: boolean; enableTimeIncrement?: boolean;
isLoading?: boolean; isLoading?: boolean;
...@@ -32,9 +31,7 @@ const TxsTable = ({ ...@@ -32,9 +31,7 @@ const TxsTable = ({
onSortToggle, onSortToggle,
top, top,
showBlockInfo, showBlockInfo,
showSocketInfo, socketType,
socketInfoAlert,
socketInfoNum,
currentAddress, currentAddress,
enableTimeIncrement, enableTimeIncrement,
isLoading, isLoading,
...@@ -96,14 +93,7 @@ const TxsTable = ({ ...@@ -96,14 +93,7 @@ const TxsTable = ({
</TableRow> </TableRow>
</TableHeaderSticky> </TableHeaderSticky>
<TableBody> <TableBody>
{ showSocketInfo && ( { socketType && <TxsSocketNotice type={ socketType } place="table" isLoading={ isLoading }/> }
<SocketNewItemsNotice.Desktop
url={ window.location.href }
alert={ socketInfoAlert }
num={ socketInfoNum }
isLoading={ isLoading }
/>
) }
{ txs.slice(0, renderedItemsNum).map((item, index) => ( { txs.slice(0, renderedItemsNum).map((item, index) => (
<TxsTableItem <TxsTableItem
key={ item.hash + (isLoading ? index : '') } key={ item.hash + (isLoading ? index : '') }
......
...@@ -10,7 +10,7 @@ type Props = { ...@@ -10,7 +10,7 @@ type Props = {
const TxsWatchlist = ({ query }: Props) => { const TxsWatchlist = ({ query }: Props) => {
useRedirectForInvalidAuthToken(); useRedirectForInvalidAuthToken();
return <TxsWithFrontendSorting query={ query } showSocketInfo={ false } top={ 88 }/>; return <TxsWithFrontendSorting query={ query } top={ 88 }/>;
}; };
export default TxsWatchlist; export default TxsWatchlist;
import React from 'react'; import React from 'react';
import type { TxsSocketType } from './socket/types';
import type { AddressFromToFilter } from 'types/api/address'; import type { AddressFromToFilter } from 'types/api/address';
import type { TransactionsSortingValue } from 'types/api/transaction'; import type { TransactionsSortingValue } from 'types/api/transaction';
...@@ -12,9 +13,7 @@ type Props = { ...@@ -12,9 +13,7 @@ type Props = {
query: QueryWithPagesResult<'address_txs'>; query: QueryWithPagesResult<'address_txs'>;
showBlockInfo?: boolean; showBlockInfo?: boolean;
showSocketInfo?: boolean; socketType?: TxsSocketType;
socketInfoAlert?: string;
socketInfoNum?: number;
currentAddress?: string; currentAddress?: string;
filter?: React.ReactNode; filter?: React.ReactNode;
filterValue?: AddressFromToFilter; filterValue?: AddressFromToFilter;
...@@ -29,9 +28,7 @@ const TxsWithAPISorting = ({ ...@@ -29,9 +28,7 @@ const TxsWithAPISorting = ({
filterValue, filterValue,
query, query,
showBlockInfo = true, showBlockInfo = true,
showSocketInfo = true, socketType,
socketInfoAlert,
socketInfoNum,
currentAddress, currentAddress,
enableTimeIncrement, enableTimeIncrement,
top, top,
...@@ -49,9 +46,7 @@ const TxsWithAPISorting = ({ ...@@ -49,9 +46,7 @@ const TxsWithAPISorting = ({
filter={ filter } filter={ filter }
filterValue={ filterValue } filterValue={ filterValue }
showBlockInfo={ showBlockInfo } showBlockInfo={ showBlockInfo }
showSocketInfo={ showSocketInfo } socketType={ socketType }
socketInfoAlert={ socketInfoAlert }
socketInfoNum={ socketInfoNum }
currentAddress={ currentAddress } currentAddress={ currentAddress }
enableTimeIncrement={ enableTimeIncrement } enableTimeIncrement={ enableTimeIncrement }
top={ top } top={ top }
......
import React from 'react'; import React from 'react';
import type { TxsSocketType } from './socket/types';
import type { AddressFromToFilter } from 'types/api/address'; import type { AddressFromToFilter } from 'types/api/address';
import type { QueryWithPagesResult } from 'ui/shared/pagination/useQueryWithPages'; import type { QueryWithPagesResult } from 'ui/shared/pagination/useQueryWithPages';
...@@ -11,9 +12,7 @@ type Props = { ...@@ -11,9 +12,7 @@ type Props = {
// eslint-disable-next-line max-len // eslint-disable-next-line max-len
query: QueryWithPagesResult<'txs_validated' | 'txs_pending'> | QueryWithPagesResult<'txs_watchlist'> | QueryWithPagesResult<'block_txs'> | QueryWithPagesResult<'zkevm_l2_txn_batch_txs'>; query: QueryWithPagesResult<'txs_validated' | 'txs_pending'> | QueryWithPagesResult<'txs_watchlist'> | QueryWithPagesResult<'block_txs'> | QueryWithPagesResult<'zkevm_l2_txn_batch_txs'>;
showBlockInfo?: boolean; showBlockInfo?: boolean;
showSocketInfo?: boolean; socketType?: TxsSocketType;
socketInfoAlert?: string;
socketInfoNum?: number;
currentAddress?: string; currentAddress?: string;
filter?: React.ReactNode; filter?: React.ReactNode;
filterValue?: AddressFromToFilter; filterValue?: AddressFromToFilter;
...@@ -26,9 +25,7 @@ const TxsWithFrontendSorting = ({ ...@@ -26,9 +25,7 @@ const TxsWithFrontendSorting = ({
filterValue, filterValue,
query, query,
showBlockInfo = true, showBlockInfo = true,
showSocketInfo = true, socketType,
socketInfoAlert,
socketInfoNum,
currentAddress, currentAddress,
enableTimeIncrement, enableTimeIncrement,
top, top,
...@@ -40,9 +37,7 @@ const TxsWithFrontendSorting = ({ ...@@ -40,9 +37,7 @@ const TxsWithFrontendSorting = ({
filter={ filter } filter={ filter }
filterValue={ filterValue } filterValue={ filterValue }
showBlockInfo={ showBlockInfo } showBlockInfo={ showBlockInfo }
showSocketInfo={ showSocketInfo } socketType={ socketType }
socketInfoAlert={ socketInfoAlert }
socketInfoNum={ socketInfoNum }
currentAddress={ currentAddress } currentAddress={ currentAddress }
enableTimeIncrement={ enableTimeIncrement } enableTimeIncrement={ enableTimeIncrement }
top={ top } top={ top }
......
import React from 'react';
import type { TxsSocketNoticePlace, TxsSocketType } from './types';
import useIsMobile from 'lib/hooks/useIsMobile';
import TxsSocketNoticeTypeAddress from './TxsSocketNoticeTypeAddress';
import TxsSocketNoticeTypeAll from './TxsSocketNoticeTypeAll';
interface Props {
type: TxsSocketType;
place: TxsSocketNoticePlace;
isLoading?: boolean;
}
const TxsSocketNotice = ({ type, place, isLoading }: Props) => {
const isMobile = useIsMobile();
if ((isMobile && place === 'table') || (!isMobile && place === 'list')) {
return null;
}
switch (type) {
case 'txs_home':
case 'txs_validated':
case 'txs_pending': {
return <TxsSocketNoticeTypeAll type={ type } place={ place } isLoading={ isLoading }/>;
}
case 'address_txs': {
return <TxsSocketNoticeTypeAddress place={ place } isLoading={ isLoading }/>;
}
default:
return null;
}
};
export default React.memo(TxsSocketNotice);
import React from 'react';
import type { TxsSocketNoticePlace } from './types';
import * as SocketNewItemsNotice from 'ui/shared/SocketNewItemsNotice';
import useTxsSocketTypeAddress from './useTxsSocketTypeAddress';
interface Props {
place: TxsSocketNoticePlace;
isLoading?: boolean;
}
const TxsSocketNoticeTypeAddress = ({ place, isLoading }: Props) => {
const { num, alertText } = useTxsSocketTypeAddress({ isLoading });
if (num === undefined) {
return null;
}
if (place === 'table') {
return (
<SocketNewItemsNotice.Desktop
url={ window.location.href }
alert={ alertText }
num={ num }
isLoading={ isLoading }
/>
);
}
if (place === 'list') {
return (
<SocketNewItemsNotice.Mobile
url={ window.location.href }
num={ num }
alert={ alertText }
isLoading={ isLoading }
/>
);
}
};
export default React.memo(TxsSocketNoticeTypeAddress);
import React from 'react';
import type { TxsSocketNoticePlace, TxsSocketType } from './types';
import * as SocketNewItemsNotice from 'ui/shared/SocketNewItemsNotice';
import useNewTxsSocketTypeAll from './useTxsSocketTypeAll';
interface Props {
type: TxsSocketType;
place: TxsSocketNoticePlace;
isLoading?: boolean;
}
const TxsSocketNoticeTypeAll = ({ type, place, isLoading }: Props) => {
const { num, alertText } = useNewTxsSocketTypeAll({ type, isLoading });
if (num === undefined) {
return null;
}
if (place === 'table') {
return (
<SocketNewItemsNotice.Desktop
url={ window.location.href }
alert={ alertText }
num={ num }
isLoading={ isLoading }
/>
);
}
if (place === 'list') {
return (
<SocketNewItemsNotice.Mobile
url={ window.location.href }
num={ num }
alert={ alertText }
isLoading={ isLoading }
/>
);
}
};
export default React.memo(TxsSocketNoticeTypeAll);
export type TxsSocketType = 'txs_validated' | 'txs_pending' | 'txs_home' | 'address_txs';
export type TxsSocketNoticePlace = 'list' | 'table';
import { useQueryClient } from '@tanstack/react-query';
import { useRouter } from 'next/router';
import React from 'react';
import type { SocketMessage } from 'lib/socket/types';
import type { AddressFromToFilter, AddressTransactionsResponse } from 'types/api/address';
import type { Transaction, TransactionsSortingValue } from 'types/api/transaction';
import config from 'configs/app';
import { getResourceKey } from 'lib/api/useApiQuery';
import getQueryParamString from 'lib/router/getQueryParamString';
import useSocketChannel from 'lib/socket/useSocketChannel';
import useSocketMessage from 'lib/socket/useSocketMessage';
import getSortValueFromQuery from 'ui/shared/sort/getSortValueFromQuery';
import { sortTxsFromSocket } from '../sortTxs';
import { SORT_OPTIONS } from '../useTxsSort';
const matchFilter = (filterValue: AddressFromToFilter, transaction: Transaction, address?: string) => {
if (!filterValue) {
return true;
}
if (filterValue === 'from') {
return transaction.from.hash === address;
}
if (filterValue === 'to') {
return transaction.to?.hash === address;
}
};
const OVERLOAD_COUNT = config.app.isPw ? 2 : 75;
interface Params {
isLoading?: boolean;
}
export default function useTxsSocketTypeAddress({ isLoading }: Params) {
const [ alertText, setAlertText ] = React.useState('');
const [ num, setNum ] = React.useState(0);
const router = useRouter();
const queryClient = useQueryClient();
const currentAddress = getQueryParamString(router.query.hash);
const filterValue = getQueryParamString(router.query.filter);
const page = getQueryParamString(router.query.page);
const sort = getSortValueFromQuery<TransactionsSortingValue>(router.query, SORT_OPTIONS) || 'default';
const handleNewSocketMessage: SocketMessage.AddressTxs['handler'] = React.useCallback((payload) => {
setAlertText('');
queryClient.setQueryData(
getResourceKey('address_txs', { pathParams: { hash: currentAddress }, queryParams: filterValue ? { filter: filterValue } : undefined }),
(prevData: AddressTransactionsResponse | undefined) => {
if (!prevData) {
return;
}
const newItems: Array<Transaction> = [];
let newCount = 0;
payload.transactions.forEach(tx => {
const currIndex = prevData.items.findIndex((item) => item.hash === tx.hash);
if (currIndex > -1) {
prevData.items[currIndex] = tx;
} else {
const isMatch = matchFilter(filterValue as AddressFromToFilter, tx, currentAddress);
if (isMatch) {
if (newItems.length + prevData.items.length >= OVERLOAD_COUNT) {
newCount++;
} else {
newItems.push(tx);
}
}
}
});
if (newCount > 0) {
setNum(prev => prev + newCount);
}
return {
...prevData,
items: [
...newItems,
...prevData.items,
].sort(sortTxsFromSocket(sort)),
};
});
}, [ currentAddress, filterValue, queryClient, sort ]);
const handleSocketClose = React.useCallback(() => {
setAlertText('Connection is lost. Please refresh the page to load new transactions.');
}, []);
const handleSocketError = React.useCallback(() => {
setAlertText('An error has occurred while fetching new transactions. Please refresh the page.');
}, []);
const isDisabled = Boolean((page && page !== '1') || isLoading);
const channel = useSocketChannel({
topic: `addresses:${ currentAddress?.toLowerCase() }`,
onSocketClose: handleSocketClose,
onSocketError: handleSocketError,
isDisabled,
});
useSocketMessage({
channel,
event: 'transaction',
handler: handleNewSocketMessage,
});
useSocketMessage({
channel,
event: 'pending_transaction',
handler: handleNewSocketMessage,
});
if (isDisabled) {
return { };
}
return { num, alertText };
}
import type { NextRouter } from 'next/router';
import { useRouter } from 'next/router'; import { useRouter } from 'next/router';
import React from 'react'; import React from 'react';
import type { TxsSocketType } from './types';
import useGradualIncrement from 'lib/hooks/useGradualIncrement'; import useGradualIncrement from 'lib/hooks/useGradualIncrement';
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';
function getSocketParams(router: NextRouter) { function getSocketParams(type: TxsSocketType, page: string) {
if (
router.pathname === '/txs' &&
(router.query.tab === 'validated' || router.query.tab === undefined) &&
!router.query.block_number &&
!router.query.page
) {
return { topic: 'transactions:new_transaction' as const, event: 'transaction' as const };
}
if (router.pathname === '/') {
return { topic: 'transactions:new_transaction' as const, event: 'transaction' as const };
}
if ( switch (type) {
router.pathname === '/txs' && case 'txs_home': {
router.query.tab === 'pending' && return { topic: 'transactions:new_transaction' as const, event: 'transaction' as const };
!router.query.block_number && }
!router.query.page case 'txs_validated': {
) { return !page || page === '1' ? { topic: 'transactions:new_transaction' as const, event: 'transaction' as const } : {};
return { topic: 'transactions:new_pending_transaction' as const, event: 'pending_transaction' as const }; }
case 'txs_pending': {
return !page || page === '1' ? { topic: 'transactions:new_pending_transaction' as const, event: 'pending_transaction' as const } : {};
}
default:
return {};
} }
return {};
} }
function assertIsNewTxResponse(response: unknown): response is { transaction: number } { function assertIsNewTxResponse(response: unknown): response is { transaction: number } {
...@@ -40,12 +32,19 @@ function assertIsNewPendingTxResponse(response: unknown): response is { pending_ ...@@ -40,12 +32,19 @@ function assertIsNewPendingTxResponse(response: unknown): response is { pending_
return typeof response === 'object' && response !== null && 'pending_transaction' in response; return typeof response === 'object' && response !== null && 'pending_transaction' in response;
} }
export default function useNewTxsSocket() { interface Params {
type: TxsSocketType;
isLoading?: boolean;
}
export default function useNewTxsSocketTypeAll({ type, isLoading }: Params) {
const router = useRouter(); const router = useRouter();
const page = getQueryParamString(router.query.page);
const [ num, setNum ] = useGradualIncrement(0); const [ num, setNum ] = useGradualIncrement(0);
const [ socketAlert, setSocketAlert ] = React.useState(''); const [ alertText, setAlertText ] = React.useState('');
const { topic, event } = getSocketParams(router); const { topic, event } = getSocketParams(type, page);
const handleNewTxMessage = React.useCallback((response: { transaction: number } | { pending_transaction: number } | unknown) => { const handleNewTxMessage = React.useCallback((response: { transaction: number } | { pending_transaction: number } | unknown) => {
if (assertIsNewTxResponse(response)) { if (assertIsNewTxResponse(response)) {
...@@ -57,18 +56,18 @@ export default function useNewTxsSocket() { ...@@ -57,18 +56,18 @@ export default function useNewTxsSocket() {
}, [ setNum ]); }, [ setNum ]);
const handleSocketClose = React.useCallback(() => { const handleSocketClose = React.useCallback(() => {
setSocketAlert('Connection is lost. Please reload the page.'); setAlertText('Connection is lost. Please reload the page.');
}, []); }, []);
const handleSocketError = React.useCallback(() => { const handleSocketError = React.useCallback(() => {
setSocketAlert('An error has occurred while fetching new transactions. Please reload the page.'); setAlertText('An error has occurred while fetching new transactions. Please reload the page.');
}, []); }, []);
const channel = useSocketChannel({ const channel = useSocketChannel({
topic, topic,
onSocketClose: handleSocketClose, onSocketClose: handleSocketClose,
onSocketError: handleSocketError, onSocketError: handleSocketError,
isDisabled: !topic, isDisabled: !topic || Boolean(isLoading),
}); });
useSocketMessage({ useSocketMessage({
...@@ -78,8 +77,8 @@ export default function useNewTxsSocket() { ...@@ -78,8 +77,8 @@ export default function useNewTxsSocket() {
}); });
if (!topic && !event) { if (!topic && !event) {
return {}; return { };
} }
return { num, socketAlert }; return { num, alertText };
} }
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