Commit ae98d50c authored by isstuev's avatar isstuev

txs watchlist

parent cc425ddb
...@@ -39,7 +39,7 @@ import type { ...@@ -39,7 +39,7 @@ import type {
} from 'types/api/token'; } from 'types/api/token';
import type { TokensResponse, TokensFilters, TokenInstanceTransferResponse } from 'types/api/tokens'; import type { TokensResponse, TokensFilters, TokenInstanceTransferResponse } 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 } from 'types/api/transaction'; import type { TransactionsResponseValidated, TransactionsResponsePending, Transaction, TransactionsResponseWatchlist } 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 { VisualizedContract } from 'types/api/visualization'; import type { VisualizedContract } from 'types/api/visualization';
...@@ -145,6 +145,11 @@ export const RESOURCES = { ...@@ -145,6 +145,11 @@ export const RESOURCES = {
paginationFields: [ 'filter' as const, 'hash' as const, 'inserted_at' as const ], paginationFields: [ 'filter' as const, 'hash' as const, 'inserted_at' as const ],
filterFields: [ 'filter' as const, 'type' as const, 'method' as const ], filterFields: [ 'filter' as const, 'type' as const, 'method' as const ],
}, },
txs_watchlist: {
path: '/api/v2/transactions/watchlist',
paginationFields: [ 'filter' as const, 'hash' as const, 'inserted_at' as const ],
filterFields: [ ],
},
tx: { tx: {
path: '/api/v2/transactions/:hash', path: '/api/v2/transactions/:hash',
pathParams: [ 'hash' as const ], pathParams: [ 'hash' as const ],
...@@ -490,7 +495,7 @@ export interface ResourceError<T = unknown> { ...@@ -490,7 +495,7 @@ export interface ResourceError<T = unknown> {
export type ResourceErrorAccount<T> = ResourceError<{ errors: T }> export type ResourceErrorAccount<T> = ResourceError<{ errors: T }>
export type PaginatedResources = 'blocks' | 'block_txs' | export type PaginatedResources = 'blocks' | 'block_txs' |
'txs_validated' | 'txs_pending' | 'txs_validated' | 'txs_pending' | 'txs_watchlist' |
'tx_internal_txs' | 'tx_logs' | 'tx_token_transfers' | 'tx_internal_txs' | 'tx_logs' | 'tx_token_transfers' |
'addresses' | 'addresses' |
'address_txs' | 'address_internal_txs' | 'address_token_transfers' | 'address_blocks_validated' | 'address_coin_balance' | 'address_txs' | 'address_internal_txs' | 'address_token_transfers' | 'address_blocks_validated' | 'address_coin_balance' |
...@@ -529,6 +534,7 @@ Q extends 'block_txs' ? BlockTransactionsResponse : ...@@ -529,6 +534,7 @@ Q extends 'block_txs' ? BlockTransactionsResponse :
Q extends 'block_withdrawals' ? BlockWithdrawalsResponse : Q extends 'block_withdrawals' ? BlockWithdrawalsResponse :
Q extends 'txs_validated' ? TransactionsResponseValidated : Q extends 'txs_validated' ? TransactionsResponseValidated :
Q extends 'txs_pending' ? TransactionsResponsePending : Q extends 'txs_pending' ? TransactionsResponsePending :
Q extends 'txs_watchlist' ? TransactionsResponseWatchlist :
Q extends 'tx' ? Transaction : Q extends 'tx' ? Transaction :
Q extends 'tx_internal_txs' ? InternalTransactionsResponse : Q extends 'tx_internal_txs' ? InternalTransactionsResponse :
Q extends 'tx_logs' ? LogsResponseTx : Q extends 'tx_logs' ? LogsResponseTx :
......
import appConfig from 'configs/app/config';
import { useAppContext } from 'lib/appContext';
import * as cookies from 'lib/cookies';
export default function useHasAccount() {
const appProps = useAppContext();
const cookiesString = appProps.cookies;
const hasAuth = Boolean(cookies.get(cookies.NAMES.API_TOKEN, cookiesString));
return hasAuth && appConfig.isAccountSupported;
}
...@@ -17,7 +17,9 @@ export function middleware(req: NextRequest) { ...@@ -17,7 +17,9 @@ export function middleware(req: NextRequest) {
} }
// we don't have any info from router here, so just do straight forward sub-string search (sorry) // we don't have any info from router here, so just do straight forward sub-string search (sorry)
const isAccountRoute = req.nextUrl.pathname.includes('/account/'); const isAccountRoute =
req.nextUrl.pathname.includes('/account/') ||
(req.nextUrl.pathname === '/txs' && req.nextUrl.searchParams.get('tab') === 'watchlist');
const isProfileRoute = req.nextUrl.pathname.includes('/auth/profile'); const isProfileRoute = req.nextUrl.pathname.includes('/auth/profile');
const apiToken = req.cookies.get(NAMES.API_TOKEN); const apiToken = req.cookies.get(NAMES.API_TOKEN);
......
...@@ -70,6 +70,15 @@ export interface TransactionsResponsePending { ...@@ -70,6 +70,15 @@ export interface TransactionsResponsePending {
} | null; } | null;
} }
export interface TransactionsResponseWatchlist {
items: Array<Transaction>;
next_page_params: {
inserted_at: string;
hash: string;
filter: 'pending';
} | null;
}
export type TransactionType = 'token_transfer' | 'contract_creation' | 'contract_call' | 'token_creation' | 'coin_transfer' export type TransactionType = 'token_transfer' | 'contract_creation' | 'contract_call' | 'token_creation' | 'coin_transfer'
export type TxsResponse = TransactionsResponseValidated | TransactionsResponsePending | BlockTransactionsResponse; export type TxsResponse = TransactionsResponseValidated | TransactionsResponsePending | BlockTransactionsResponse;
...@@ -5,6 +5,7 @@ import React from 'react'; ...@@ -5,6 +5,7 @@ import React from 'react';
import type { RoutedTab } from 'ui/shared/RoutedTabs/types'; import type { RoutedTab } from 'ui/shared/RoutedTabs/types';
import appConfig from 'configs/app/config'; import appConfig from 'configs/app/config';
import useHasAccount from 'lib/hooks/useHasAccount';
import useIsMobile from 'lib/hooks/useIsMobile'; import useIsMobile from 'lib/hooks/useIsMobile';
import useNewTxsSocket from 'lib/hooks/useNewTxsSocket'; import useNewTxsSocket from 'lib/hooks/useNewTxsSocket';
import useQueryWithPages from 'lib/hooks/useQueryWithPages'; import useQueryWithPages from 'lib/hooks/useQueryWithPages';
...@@ -13,6 +14,7 @@ import PageTitle from 'ui/shared/Page/PageTitle'; ...@@ -13,6 +14,7 @@ import PageTitle from 'ui/shared/Page/PageTitle';
import RoutedTabs from 'ui/shared/RoutedTabs/RoutedTabs'; import RoutedTabs from 'ui/shared/RoutedTabs/RoutedTabs';
import TxsContent from 'ui/txs/TxsContent'; import TxsContent from 'ui/txs/TxsContent';
import TxsTabSlot from 'ui/txs/TxsTabSlot'; import TxsTabSlot from 'ui/txs/TxsTabSlot';
import TxsWatchlist from 'ui/txs/TxsWatchlist';
const TAB_LIST_PROPS = { const TAB_LIST_PROPS = {
marginBottom: 0, marginBottom: 0,
...@@ -24,27 +26,49 @@ const Transactions = () => { ...@@ -24,27 +26,49 @@ const Transactions = () => {
const verifiedTitle = appConfig.network.verificationType === 'validation' ? 'Validated' : 'Mined'; const verifiedTitle = appConfig.network.verificationType === 'validation' ? 'Validated' : 'Mined';
const router = useRouter(); const router = useRouter();
const isMobile = useIsMobile(); const isMobile = useIsMobile();
const filter = router.query.tab === 'pending' ? 'pending' : 'validated';
const txsQuery = useQueryWithPages({ const txsQuery = useQueryWithPages({
resourceName: filter === 'validated' ? 'txs_validated' : 'txs_pending', resourceName: router.query.tab === 'pending' ? 'txs_pending' : 'txs_validated',
filters: { filter }, filters: { filter: router.query.tab === 'pending' ? 'pending' : 'validated' },
options: {
enabled: !router.query.tab || router.query.tab === 'validated' || router.query.tab === 'pending',
},
});
const txsWatchlistQuery = useQueryWithPages({
resourceName: 'txs_watchlist',
options: {
enabled: router.query.tab === 'watchlist',
},
}); });
const { num, socketAlert } = useNewTxsSocket(); const { num, socketAlert } = useNewTxsSocket();
const isFirstPage = txsQuery.pagination.page === 1; const hasAccount = useHasAccount();
const tabs: Array<RoutedTab> = [ const tabs: Array<RoutedTab> = [
{ {
id: 'validated', id: 'validated',
title: verifiedTitle, title: verifiedTitle,
component: <TxsContent query={ txsQuery } showSocketInfo={ isFirstPage } socketInfoNum={ num } socketInfoAlert={ socketAlert }/> }, component: <TxsContent query={ txsQuery } showSocketInfo={ txsQuery.pagination.page === 1 } socketInfoNum={ num } socketInfoAlert={ socketAlert }/> },
{ {
id: 'pending', id: 'pending',
title: 'Pending', title: 'Pending',
component: <TxsContent query={ txsQuery } showBlockInfo={ false } showSocketInfo={ isFirstPage } socketInfoNum={ num } socketInfoAlert={ socketAlert }/>, component: (
<TxsContent
query={ txsQuery }
showBlockInfo={ false }
showSocketInfo={ txsQuery.pagination.page === 1 }
socketInfoNum={ num }
socketInfoAlert={ socketAlert }
/>
),
}, },
]; hasAccount ? {
id: 'watchlist',
title: 'Watchlist',
component: <TxsWatchlist query={ txsWatchlistQuery }/>,
} : undefined,
].filter(Boolean);
return ( return (
<Page> <Page>
......
...@@ -6,6 +6,7 @@ import chevronIcon from 'icons/arrows/east-mini.svg'; ...@@ -6,6 +6,7 @@ import chevronIcon from 'icons/arrows/east-mini.svg';
import testnetIcon from 'icons/testnet.svg'; import testnetIcon from 'icons/testnet.svg';
import { useAppContext } from 'lib/appContext'; import { useAppContext } from 'lib/appContext';
import * as cookies from 'lib/cookies'; import * as cookies from 'lib/cookies';
import useHasAccount from 'lib/hooks/useHasAccount';
import useNavItems, { isGroupItem } from 'lib/hooks/useNavItems'; import useNavItems, { isGroupItem } from 'lib/hooks/useNavItems';
import getDefaultTransitionProps from 'theme/utils/getDefaultTransitionProps'; import getDefaultTransitionProps from 'theme/utils/getDefaultTransitionProps';
import NetworkLogo from 'ui/snippets/networkMenu/NetworkLogo'; import NetworkLogo from 'ui/snippets/networkMenu/NetworkLogo';
...@@ -28,11 +29,10 @@ const NavigationDesktop = () => { ...@@ -28,11 +29,10 @@ const NavigationDesktop = () => {
isNavBarCollapsed = false; isNavBarCollapsed = false;
} }
const hasAuth = Boolean(cookies.get(cookies.NAMES.API_TOKEN, cookiesString));
const { mainNavItems, accountNavItems } = useNavItems(); const { mainNavItems, accountNavItems } = useNavItems();
const hasAccount = hasAuth && appConfig.isAccountSupported; const hasAccount = useHasAccount();
const [ isCollapsed, setCollapsedState ] = React.useState<boolean | undefined>(isNavBarCollapsed); const [ isCollapsed, setCollapsedState ] = React.useState<boolean | undefined>(isNavBarCollapsed);
const handleTogglerClick = React.useCallback(() => { const handleTogglerClick = React.useCallback(() => {
......
...@@ -2,9 +2,8 @@ import { Box, Flex, Text, Icon, VStack, useColorModeValue } from '@chakra-ui/rea ...@@ -2,9 +2,8 @@ import { Box, Flex, Text, Icon, VStack, useColorModeValue } from '@chakra-ui/rea
import { animate, motion, useMotionValue } from 'framer-motion'; import { animate, motion, useMotionValue } from 'framer-motion';
import React, { useCallback } from 'react'; import React, { useCallback } from 'react';
import appConfig from 'configs/app/config';
import chevronIcon from 'icons/arrows/east-mini.svg'; import chevronIcon from 'icons/arrows/east-mini.svg';
import * as cookies from 'lib/cookies'; import useHasAccount from 'lib/hooks/useHasAccount';
import useNavItems, { isGroupItem } from 'lib/hooks/useNavItems'; import useNavItems, { isGroupItem } from 'lib/hooks/useNavItems';
import NavFooter from 'ui/snippets/navigation/NavFooter'; import NavFooter from 'ui/snippets/navigation/NavFooter';
import NavLink from 'ui/snippets/navigation/NavLink'; import NavLink from 'ui/snippets/navigation/NavLink';
...@@ -30,8 +29,7 @@ const NavigationMobile = () => { ...@@ -30,8 +29,7 @@ const NavigationMobile = () => {
animate(subX, 250, { ease: 'easeInOut', onComplete: () => setOpenedGroupIndex(-1) }); animate(subX, 250, { ease: 'easeInOut', onComplete: () => setOpenedGroupIndex(-1) });
}, [ mainX, subX ]); }, [ mainX, subX ]);
const isAuth = Boolean(cookies.get(cookies.NAMES.API_TOKEN)); const hasAccount = useHasAccount();
const hasAccount = appConfig.isAccountSupported && isAuth;
const iconColor = useColorModeValue('blue.600', 'blue.300'); const iconColor = useColorModeValue('blue.600', 'blue.300');
......
import type { UseQueryResult } from '@tanstack/react-query';
import React from 'react';
import type { TxsResponse } from 'types/api/transaction';
import useRedirectForInvalidAuthToken from 'lib/hooks/useRedirectForInvalidAuthToken';
import type { Props as PaginationProps } from 'ui/shared/Pagination';
import TxsContent from 'ui/txs/TxsContent';
type QueryResult = UseQueryResult<TxsResponse> & {
pagination: PaginationProps;
isPaginationVisible: boolean;
};
type Props = {
query: QueryResult;
}
const TxsWatchlist = ({ query }: Props) => {
useRedirectForInvalidAuthToken();
return <TxsContent query={ query } showSocketInfo={ false }/>;
};
export default TxsWatchlist;
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