Commit a8c723ca authored by Igor Stuev's avatar Igor Stuev Committed by GitHub

watchlist and private tags pagination (#1333)

Co-authored-by: default avatarisstuev <natix.naf@gmail.com>
parent 15cfad34
...@@ -3,13 +3,13 @@ import type { ...@@ -3,13 +3,13 @@ import type {
UserInfo, UserInfo,
CustomAbis, CustomAbis,
PublicTags, PublicTags,
AddressTags,
TransactionTags,
ApiKeys, ApiKeys,
WatchlistAddress,
VerifiedAddressResponse, VerifiedAddressResponse,
TokenInfoApplicationConfig, TokenInfoApplicationConfig,
TokenInfoApplications, TokenInfoApplications,
WatchlistResponse,
TransactionTagsResponse,
AddressTagsResponse,
} from 'types/api/account'; } from 'types/api/account';
import type { import type {
Address, Address,
...@@ -90,20 +90,23 @@ export const RESOURCES = { ...@@ -90,20 +90,23 @@ export const RESOURCES = {
pathParams: [ 'id' as const ], pathParams: [ 'id' as const ],
}, },
watchlist: { watchlist: {
path: '/api/account/v1/user/watchlist/:id?', path: '/api/account/v2/user/watchlist/:id?',
pathParams: [ 'id' as const ], pathParams: [ 'id' as const ],
filterFields: [ ],
}, },
public_tags: { public_tags: {
path: '/api/account/v1/user/public_tags/:id?', path: '/api/account/v1/user/public_tags/:id?',
pathParams: [ 'id' as const ], pathParams: [ 'id' as const ],
}, },
private_tags_address: { private_tags_address: {
path: '/api/account/v1/user/tags/address/:id?', path: '/api/account/v2/user/tags/address/:id?',
pathParams: [ 'id' as const ], pathParams: [ 'id' as const ],
filterFields: [ ],
}, },
private_tags_tx: { private_tags_tx: {
path: '/api/account/v1/user/tags/transaction/:id?', path: '/api/account/v2/user/tags/transaction/:id?',
pathParams: [ 'id' as const ], pathParams: [ 'id' as const ],
filterFields: [ ],
}, },
api_keys: { api_keys: {
path: '/api/account/v1/user/api_keys/:id?', path: '/api/account/v1/user/api_keys/:id?',
...@@ -579,7 +582,8 @@ export type PaginatedResources = 'blocks' | 'block_txs' | ...@@ -579,7 +582,8 @@ export type PaginatedResources = 'blocks' | 'block_txs' |
'verified_contracts' | 'verified_contracts' |
'l2_output_roots' | 'l2_withdrawals' | 'l2_txn_batches' | 'l2_deposits' | 'l2_output_roots' | 'l2_withdrawals' | 'l2_txn_batches' | 'l2_deposits' |
'zkevm_l2_txn_batches' | 'zkevm_l2_txn_batch_txs' | 'zkevm_l2_txn_batches' | 'zkevm_l2_txn_batch_txs' |
'withdrawals' | 'address_withdrawals' | 'block_withdrawals'; 'withdrawals' | 'address_withdrawals' | 'block_withdrawals' |
'watchlist' | 'private_tags_address' | 'private_tags_tx';
export type PaginatedResponse<Q extends PaginatedResources> = ResourcePayload<Q>; export type PaginatedResponse<Q extends PaginatedResources> = ResourcePayload<Q>;
...@@ -588,10 +592,10 @@ export type ResourcePayload<Q extends ResourceName> = ...@@ -588,10 +592,10 @@ export type ResourcePayload<Q extends ResourceName> =
Q extends 'user_info' ? UserInfo : Q extends 'user_info' ? UserInfo :
Q extends 'custom_abi' ? CustomAbis : Q extends 'custom_abi' ? CustomAbis :
Q extends 'public_tags' ? PublicTags : Q extends 'public_tags' ? PublicTags :
Q extends 'private_tags_address' ? AddressTags : Q extends 'private_tags_address' ? AddressTagsResponse :
Q extends 'private_tags_tx' ? TransactionTags : Q extends 'private_tags_tx' ? TransactionTagsResponse :
Q extends 'api_keys' ? ApiKeys : Q extends 'api_keys' ? ApiKeys :
Q extends 'watchlist' ? Array<WatchlistAddress> : Q extends 'watchlist' ? WatchlistResponse :
Q extends 'verified_addresses' ? VerifiedAddressResponse : Q extends 'verified_addresses' ? VerifiedAddressResponse :
Q extends 'token_info_applications_config' ? TokenInfoApplicationConfig : Q extends 'token_info_applications_config' ? TokenInfoApplicationConfig :
Q extends 'token_info_applications' ? TokenInfoApplications : Q extends 'token_info_applications' ? TokenInfoApplications :
......
...@@ -8,6 +8,14 @@ export interface AddressTag { ...@@ -8,6 +8,14 @@ export interface AddressTag {
export type AddressTags = Array<AddressTag> export type AddressTags = Array<AddressTag>
export type AddressTagsResponse = {
items: AddressTags;
next_page_params: {
id: number;
items_count: number;
} | null;
}
export interface ApiKey { export interface ApiKey {
api_key: string; api_key: string;
name: string; name: string;
...@@ -48,6 +56,14 @@ export interface TransactionTag { ...@@ -48,6 +56,14 @@ export interface TransactionTag {
export type TransactionTags = Array<TransactionTag> export type TransactionTags = Array<TransactionTag>
export type TransactionTagsResponse = {
items: TransactionTags;
next_page_params: {
id: number;
items_count: number;
} | null;
}
export type Transactions = Array<Transaction> export type Transactions = Array<Transaction>
export interface UserInfo { export interface UserInfo {
...@@ -78,6 +94,14 @@ export interface WatchlistAddressNew { ...@@ -78,6 +94,14 @@ export interface WatchlistAddressNew {
export type WatchlistAddresses = Array<WatchlistAddress> export type WatchlistAddresses = Array<WatchlistAddress>
export type WatchlistResponse = {
items: WatchlistAddresses;
next_page_params: {
id: number;
items_count: number;
} | null;
}
export interface PublicTag { export interface PublicTag {
website: string; website: string;
tags: string; // tag_1;tag_2;tag_3 etc. tags: string; // tag_1;tag_2;tag_3 etc.
......
...@@ -2,24 +2,29 @@ import { Box, Button, Skeleton, useDisclosure } from '@chakra-ui/react'; ...@@ -2,24 +2,29 @@ import { Box, Button, Skeleton, useDisclosure } from '@chakra-ui/react';
import { useQueryClient } from '@tanstack/react-query'; import { useQueryClient } from '@tanstack/react-query';
import React, { useCallback, useState } from 'react'; import React, { useCallback, useState } from 'react';
import type { WatchlistAddress } from 'types/api/account'; import type { WatchlistAddress, WatchlistResponse } from 'types/api/account';
import { resourceKey } from 'lib/api/resources'; import { resourceKey } from 'lib/api/resources';
import useApiQuery from 'lib/api/useApiQuery'; import { getResourceKey } from 'lib/api/useApiQuery';
import useRedirectForInvalidAuthToken from 'lib/hooks/useRedirectForInvalidAuthToken'; import useRedirectForInvalidAuthToken from 'lib/hooks/useRedirectForInvalidAuthToken';
import { WATCH_LIST_ITEM_WITH_TOKEN_INFO } from 'stubs/account'; import { WATCH_LIST_ITEM_WITH_TOKEN_INFO } from 'stubs/account';
import AccountPageDescription from 'ui/shared/AccountPageDescription'; import AccountPageDescription from 'ui/shared/AccountPageDescription';
import DataFetchAlert from 'ui/shared/DataFetchAlert'; import ActionBar from 'ui/shared/ActionBar';
import DataListDisplay from 'ui/shared/DataListDisplay';
import PageTitle from 'ui/shared/Page/PageTitle'; import PageTitle from 'ui/shared/Page/PageTitle';
import Pagination from 'ui/shared/pagination/Pagination';
import useQueryWithPages from 'ui/shared/pagination/useQueryWithPages';
import AddressModal from 'ui/watchlist/AddressModal/AddressModal'; import AddressModal from 'ui/watchlist/AddressModal/AddressModal';
import DeleteAddressModal from 'ui/watchlist/DeleteAddressModal'; import DeleteAddressModal from 'ui/watchlist/DeleteAddressModal';
import WatchListItem from 'ui/watchlist/WatchlistTable/WatchListItem'; import WatchListItem from 'ui/watchlist/WatchlistTable/WatchListItem';
import WatchlistTable from 'ui/watchlist/WatchlistTable/WatchlistTable'; import WatchlistTable from 'ui/watchlist/WatchlistTable/WatchlistTable';
const WatchList: React.FC = () => { const WatchList: React.FC = () => {
const { data, isPlaceholderData, isError } = useApiQuery('watchlist', {
queryOptions: { const { data, isPlaceholderData, isError, pagination } = useQueryWithPages({
placeholderData: Array(3).fill(WATCH_LIST_ITEM_WITH_TOKEN_INFO), resourceName: 'watchlist',
options: {
placeholderData: { items: Array(5).fill(WATCH_LIST_ITEM_WITH_TOKEN_INFO), next_page_params: null },
}, },
}); });
const queryClient = useQueryClient(); const queryClient = useQueryClient();
...@@ -58,9 +63,11 @@ const WatchList: React.FC = () => { ...@@ -58,9 +63,11 @@ const WatchList: React.FC = () => {
}, [ deleteModalProps ]); }, [ deleteModalProps ]);
const onDeleteSuccess = useCallback(async() => { const onDeleteSuccess = useCallback(async() => {
queryClient.setQueryData([ resourceKey('watchlist') ], (prevData: Array<WatchlistAddress> | undefined) => { queryClient.setQueryData(getResourceKey('watchlist'), (prevData: WatchlistResponse | undefined) => {
return prevData?.filter((item) => item.id !== deleteModalData?.id); const newItems = prevData?.items.filter((item: WatchlistAddress) => item.id !== deleteModalData?.id);
}); return { ...prevData, items: newItems };
},
);
}, [ deleteModalData?.id, queryClient ]); }, [ deleteModalData?.id, queryClient ]);
const description = ( const description = (
...@@ -69,15 +76,17 @@ const WatchList: React.FC = () => { ...@@ -69,15 +76,17 @@ const WatchList: React.FC = () => {
</AccountPageDescription> </AccountPageDescription>
); );
if (isError) {
return <DataFetchAlert/>;
}
const content = (() => { const content = (() => {
const actionBar = pagination.isVisible ? (
<ActionBar mt={ -6 }>
<Pagination ml="auto" { ...pagination }/>
</ActionBar>
) : null;
const list = ( const list = (
<> <>
<Box display={{ base: 'block', lg: 'none' }}> <Box display={{ base: 'block', lg: 'none' }}>
{ data?.map((item, index) => ( { data?.items.map((item, index) => (
<WatchListItem <WatchListItem
key={ item.address_hash + (isPlaceholderData ? index : '') } key={ item.address_hash + (isPlaceholderData ? index : '') }
item={ item } item={ item }
...@@ -89,10 +98,11 @@ const WatchList: React.FC = () => { ...@@ -89,10 +98,11 @@ const WatchList: React.FC = () => {
</Box> </Box>
<Box display={{ base: 'none', lg: 'block' }}> <Box display={{ base: 'none', lg: 'block' }}>
<WatchlistTable <WatchlistTable
data={ data } data={ data?.items }
isLoading={ isPlaceholderData } isLoading={ isPlaceholderData }
onDeleteClick={ onDeleteClick } onDeleteClick={ onDeleteClick }
onEditClick={ onEditClick } onEditClick={ onEditClick }
top={ pagination.isVisible ? 80 : 0 }
/> />
</Box> </Box>
</> </>
...@@ -101,7 +111,13 @@ const WatchList: React.FC = () => { ...@@ -101,7 +111,13 @@ const WatchList: React.FC = () => {
return ( return (
<> <>
{ description } { description }
{ Boolean(data?.length) && list } <DataListDisplay
isError={ isError }
items={ data?.items }
emptyText=""
content={ list }
actionBar={ actionBar }
/>
<Skeleton mt={ 8 } isLoaded={ !isPlaceholderData } display="inline-block"> <Skeleton mt={ 8 } isLoaded={ !isPlaceholderData } display="inline-block">
<Button <Button
size="lg" size="lg"
......
import { import {
Table, Table,
Thead,
Tbody, Tbody,
Tr, Tr,
Th, Th,
...@@ -9,6 +8,8 @@ import React from 'react'; ...@@ -9,6 +8,8 @@ import React from 'react';
import type { AddressTags, AddressTag } from 'types/api/account'; import type { AddressTags, AddressTag } from 'types/api/account';
import TheadSticky from 'ui/shared/TheadSticky';
import AddressTagTableItem from './AddressTagTableItem'; import AddressTagTableItem from './AddressTagTableItem';
interface Props { interface Props {
...@@ -16,18 +17,19 @@ interface Props { ...@@ -16,18 +17,19 @@ interface Props {
onEditClick: (data: AddressTag) => void; onEditClick: (data: AddressTag) => void;
onDeleteClick: (data: AddressTag) => void; onDeleteClick: (data: AddressTag) => void;
isLoading: boolean; isLoading: boolean;
top: number;
} }
const AddressTagTable = ({ data, onDeleteClick, onEditClick, isLoading }: Props) => { const AddressTagTable = ({ data, onDeleteClick, onEditClick, isLoading, top }: Props) => {
return ( return (
<Table variant="simple" minWidth="600px"> <Table variant="simple" minWidth="600px">
<Thead> <TheadSticky top={ top }>
<Tr> <Tr>
<Th width="60%">Address</Th> <Th width="60%">Address</Th>
<Th width="40%">Private tag</Th> <Th width="40%">Private tag</Th>
<Th width="116px"></Th> <Th width="116px"></Th>
</Tr> </Tr>
</Thead> </TheadSticky>
<Tbody> <Tbody>
{ data?.map((item: AddressTag, index: number) => ( { data?.map((item: AddressTag, index: number) => (
<AddressTagTableItem <AddressTagTableItem
......
...@@ -2,10 +2,10 @@ import { Text } from '@chakra-ui/react'; ...@@ -2,10 +2,10 @@ import { Text } from '@chakra-ui/react';
import { useQueryClient } from '@tanstack/react-query'; import { useQueryClient } from '@tanstack/react-query';
import React, { useCallback } from 'react'; import React, { useCallback } from 'react';
import type { AddressTag, TransactionTag, AddressTags, TransactionTags } from 'types/api/account'; import type { AddressTag, TransactionTag, AddressTagsResponse, TransactionTagsResponse } from 'types/api/account';
import { resourceKey } from 'lib/api/resources';
import useApiFetch from 'lib/api/useApiFetch'; import useApiFetch from 'lib/api/useApiFetch';
import { getResourceKey } from 'lib/api/useApiQuery';
import DeleteModal from 'ui/shared/DeleteModal'; import DeleteModal from 'ui/shared/DeleteModal';
type Props = { type Props = {
...@@ -32,12 +32,15 @@ const DeletePrivateTagModal: React.FC<Props> = ({ isOpen, onClose, data, type }) ...@@ -32,12 +32,15 @@ const DeletePrivateTagModal: React.FC<Props> = ({ isOpen, onClose, data, type })
const onSuccess = useCallback(async() => { const onSuccess = useCallback(async() => {
if (type === 'address') { if (type === 'address') {
queryClient.setQueryData([ resourceKey('private_tags_address') ], (prevData: AddressTags | undefined) => { queryClient.setQueryData(getResourceKey('private_tags_address'), (prevData: AddressTagsResponse | undefined) => {
return prevData?.filter((item: AddressTag) => item.id !== id); const newItems = prevData?.items.filter((item: AddressTag) => item.id !== id);
return { ...prevData, items: newItems };
}); });
} else { } else {
queryClient.setQueryData([ resourceKey('private_tags_tx') ], (prevData: TransactionTags | undefined) => { queryClient.setQueryData(getResourceKey('private_tags_tx'), (prevData: TransactionTagsResponse | undefined) => {
return prevData?.filter((item: TransactionTag) => item.id !== id); const newItems = prevData?.items.filter((item: TransactionTag) => item.id !== id);
return { ...prevData, items: newItems };
}); });
} }
}, [ type, id, queryClient ]); }, [ type, id, queryClient ]);
......
...@@ -3,11 +3,13 @@ import React, { useCallback, useState } from 'react'; ...@@ -3,11 +3,13 @@ import React, { useCallback, useState } from 'react';
import type { AddressTag } from 'types/api/account'; import type { AddressTag } from 'types/api/account';
import useApiQuery from 'lib/api/useApiQuery';
import { PAGE_TYPE_DICT } from 'lib/mixpanel/getPageType'; import { PAGE_TYPE_DICT } from 'lib/mixpanel/getPageType';
import { PRIVATE_TAG_ADDRESS } from 'stubs/account'; import { PRIVATE_TAG_ADDRESS } from 'stubs/account';
import AccountPageDescription from 'ui/shared/AccountPageDescription'; import AccountPageDescription from 'ui/shared/AccountPageDescription';
import DataFetchAlert from 'ui/shared/DataFetchAlert'; import ActionBar from 'ui/shared/ActionBar';
import DataListDisplay from 'ui/shared/DataListDisplay';
import Pagination from 'ui/shared/pagination/Pagination';
import useQueryWithPages from 'ui/shared/pagination/useQueryWithPages';
import AddressModal from './AddressModal/AddressModal'; import AddressModal from './AddressModal/AddressModal';
import AddressTagListItem from './AddressTagTable/AddressTagListItem'; import AddressTagListItem from './AddressTagTable/AddressTagListItem';
...@@ -15,10 +17,11 @@ import AddressTagTable from './AddressTagTable/AddressTagTable'; ...@@ -15,10 +17,11 @@ import AddressTagTable from './AddressTagTable/AddressTagTable';
import DeletePrivateTagModal from './DeletePrivateTagModal'; import DeletePrivateTagModal from './DeletePrivateTagModal';
const PrivateAddressTags = () => { const PrivateAddressTags = () => {
const { data: addressTagsData, isError, isPlaceholderData, refetch } = useApiQuery('private_tags_address', { const { data: addressTagsData, isError, isPlaceholderData, refetch, pagination } = useQueryWithPages({
queryOptions: { resourceName: 'private_tags_address',
options: {
refetchOnMount: false, refetchOnMount: false,
placeholderData: Array(3).fill(PRIVATE_TAG_ADDRESS), placeholderData: { items: Array(5).fill(PRIVATE_TAG_ADDRESS), next_page_params: null },
}, },
}); });
...@@ -52,14 +55,10 @@ const PrivateAddressTags = () => { ...@@ -52,14 +55,10 @@ const PrivateAddressTags = () => {
deleteModalProps.onClose(); deleteModalProps.onClose();
}, [ deleteModalProps ]); }, [ deleteModalProps ]);
if (isError) {
return <DataFetchAlert/>;
}
const list = ( const list = (
<> <>
<Box display={{ base: 'block', lg: 'none' }}> <Box display={{ base: 'block', lg: 'none' }}>
{ addressTagsData?.map((item: AddressTag, index: number) => ( { addressTagsData?.items.map((item: AddressTag, index: number) => (
<AddressTagListItem <AddressTagListItem
item={ item } item={ item }
key={ item.id + (isPlaceholderData ? index : '') } key={ item.id + (isPlaceholderData ? index : '') }
...@@ -72,21 +71,34 @@ const PrivateAddressTags = () => { ...@@ -72,21 +71,34 @@ const PrivateAddressTags = () => {
<Box display={{ base: 'none', lg: 'block' }}> <Box display={{ base: 'none', lg: 'block' }}>
<AddressTagTable <AddressTagTable
isLoading={ isPlaceholderData } isLoading={ isPlaceholderData }
data={ addressTagsData } data={ addressTagsData?.items }
onDeleteClick={ onDeleteClick } onDeleteClick={ onDeleteClick }
onEditClick={ onEditClick } onEditClick={ onEditClick }
top={ pagination.isVisible ? 80 : 0 }
/> />
</Box> </Box>
</> </>
); );
const actionBar = pagination.isVisible ? (
<ActionBar mt={ -6 }>
<Pagination ml="auto" { ...pagination }/>
</ActionBar>
) : null;
return ( return (
<> <>
<AccountPageDescription> <AccountPageDescription>
Use private address tags to track any addresses of interest. Use private address tags to track any addresses of interest.
Private tags are saved in your account and are only visible when you are logged in. Private tags are saved in your account and are only visible when you are logged in.
</AccountPageDescription> </AccountPageDescription>
{ Boolean(addressTagsData?.length) && list } <DataListDisplay
isError={ isError }
items={ addressTagsData?.items }
emptyText=""
content={ list }
actionBar={ actionBar }
/>
<Skeleton mt={ 8 } isLoaded={ !isPlaceholderData } display="inline-block"> <Skeleton mt={ 8 } isLoaded={ !isPlaceholderData } display="inline-block">
<Button <Button
size="lg" size="lg"
......
...@@ -3,10 +3,12 @@ import React, { useCallback, useState } from 'react'; ...@@ -3,10 +3,12 @@ import React, { useCallback, useState } from 'react';
import type { TransactionTag } from 'types/api/account'; import type { TransactionTag } from 'types/api/account';
import useApiQuery from 'lib/api/useApiQuery';
import { PRIVATE_TAG_TX } from 'stubs/account'; import { PRIVATE_TAG_TX } from 'stubs/account';
import AccountPageDescription from 'ui/shared/AccountPageDescription'; import AccountPageDescription from 'ui/shared/AccountPageDescription';
import DataFetchAlert from 'ui/shared/DataFetchAlert'; import ActionBar from 'ui/shared/ActionBar';
import DataListDisplay from 'ui/shared/DataListDisplay';
import Pagination from 'ui/shared/pagination/Pagination';
import useQueryWithPages from 'ui/shared/pagination/useQueryWithPages';
import DeletePrivateTagModal from './DeletePrivateTagModal'; import DeletePrivateTagModal from './DeletePrivateTagModal';
import TransactionModal from './TransactionModal/TransactionModal'; import TransactionModal from './TransactionModal/TransactionModal';
...@@ -14,10 +16,11 @@ import TransactionTagListItem from './TransactionTagTable/TransactionTagListItem ...@@ -14,10 +16,11 @@ import TransactionTagListItem from './TransactionTagTable/TransactionTagListItem
import TransactionTagTable from './TransactionTagTable/TransactionTagTable'; import TransactionTagTable from './TransactionTagTable/TransactionTagTable';
const PrivateTransactionTags = () => { const PrivateTransactionTags = () => {
const { data: transactionTagsData, isPlaceholderData, isError } = useApiQuery('private_tags_tx', { const { data: transactionTagsData, isPlaceholderData, isError, pagination } = useQueryWithPages({
queryOptions: { resourceName: 'private_tags_tx',
options: {
refetchOnMount: false, refetchOnMount: false,
placeholderData: Array(3).fill(PRIVATE_TAG_TX), placeholderData: { items: Array(3).fill(PRIVATE_TAG_TX), next_page_params: null },
}, },
}); });
...@@ -54,14 +57,10 @@ const PrivateTransactionTags = () => { ...@@ -54,14 +57,10 @@ const PrivateTransactionTags = () => {
</AccountPageDescription> </AccountPageDescription>
); );
if (isError) {
return <DataFetchAlert/>;
}
const list = ( const list = (
<> <>
<Box display={{ base: 'block', lg: 'none' }}> <Box display={{ base: 'block', lg: 'none' }}>
{ transactionTagsData?.map((item, index) => ( { transactionTagsData?.items.map((item, index) => (
<TransactionTagListItem <TransactionTagListItem
key={ item.id + (isPlaceholderData ? index : '') } key={ item.id + (isPlaceholderData ? index : '') }
item={ item } item={ item }
...@@ -73,19 +72,31 @@ const PrivateTransactionTags = () => { ...@@ -73,19 +72,31 @@ const PrivateTransactionTags = () => {
</Box> </Box>
<Box display={{ base: 'none', lg: 'block' }}> <Box display={{ base: 'none', lg: 'block' }}>
<TransactionTagTable <TransactionTagTable
data={ transactionTagsData } data={ transactionTagsData?.items }
isLoading={ isPlaceholderData } isLoading={ isPlaceholderData }
onDeleteClick={ onDeleteClick } onDeleteClick={ onDeleteClick }
onEditClick={ onEditClick } onEditClick={ onEditClick }
top={ pagination.isVisible ? 80 : 0 }
/> />
</Box> </Box>
</> </>
); );
const actionBar = pagination.isVisible ? (
<ActionBar mt={ -6 }>
<Pagination ml="auto" { ...pagination }/>
</ActionBar>
) : null;
return ( return (
<> <>
{ description } { description }
{ Boolean(transactionTagsData?.length) && list } <DataListDisplay
isError={ isError }
items={ transactionTagsData?.items }
emptyText=""
content={ list }
actionBar={ actionBar }
/>
<Skeleton mt={ 8 } isLoaded={ !isPlaceholderData } display="inline-block"> <Skeleton mt={ 8 } isLoaded={ !isPlaceholderData } display="inline-block">
<Button <Button
size="lg" size="lg"
......
import { import {
Table, Table,
Thead,
Tbody, Tbody,
Tr, Tr,
Th, Th,
...@@ -9,6 +8,8 @@ import React from 'react'; ...@@ -9,6 +8,8 @@ import React from 'react';
import type { TransactionTags, TransactionTag } from 'types/api/account'; import type { TransactionTags, TransactionTag } from 'types/api/account';
import TheadSticky from 'ui/shared/TheadSticky';
import TransactionTagTableItem from './TransactionTagTableItem'; import TransactionTagTableItem from './TransactionTagTableItem';
interface Props { interface Props {
...@@ -16,18 +17,19 @@ interface Props { ...@@ -16,18 +17,19 @@ interface Props {
isLoading: boolean; isLoading: boolean;
onEditClick: (data: TransactionTag) => void; onEditClick: (data: TransactionTag) => void;
onDeleteClick: (data: TransactionTag) => void; onDeleteClick: (data: TransactionTag) => void;
top: number;
} }
const AddressTagTable = ({ data, isLoading, onDeleteClick, onEditClick }: Props) => { const AddressTagTable = ({ data, isLoading, onDeleteClick, onEditClick, top }: Props) => {
return ( return (
<Table variant="simple" minWidth="600px"> <Table variant="simple" minWidth="600px">
<Thead> <TheadSticky top={ top }>
<Tr> <Tr>
<Th width="75%">Transaction</Th> <Th width="75%">Transaction</Th>
<Th width="25%">Private tag</Th> <Th width="25%">Private tag</Th>
<Th width="108px"></Th> <Th width="108px"></Th>
</Tr> </Tr>
</Thead> </TheadSticky>
<Tbody> <Tbody>
{ data?.map((item, index) => ( { data?.map((item, index) => (
<TransactionTagTableItem <TransactionTagTableItem
......
...@@ -70,7 +70,7 @@ export default function useQueryWithPages<Resource extends PaginatedResources>({ ...@@ -70,7 +70,7 @@ export default function useQueryWithPages<Resource extends PaginatedResources>({
const queryResult = useApiQuery(resourceName, { const queryResult = useApiQuery(resourceName, {
pathParams, pathParams,
queryParams, queryParams: Object.keys(queryParams).length ? queryParams : undefined,
queryOptions: { queryOptions: {
staleTime: page === 1 ? 0 : Infinity, staleTime: page === 1 ? 0 : Infinity,
...options, ...options,
......
import { import {
Table, Table,
Thead,
Tbody, Tbody,
Tr, Tr,
Th, Th,
...@@ -9,6 +8,8 @@ import React from 'react'; ...@@ -9,6 +8,8 @@ import React from 'react';
import type { WatchlistAddress } from 'types/api/account'; import type { WatchlistAddress } from 'types/api/account';
import TheadSticky from 'ui/shared/TheadSticky';
import WatchlistTableItem from './WatchListTableItem'; import WatchlistTableItem from './WatchListTableItem';
interface Props { interface Props {
...@@ -16,19 +17,20 @@ interface Props { ...@@ -16,19 +17,20 @@ interface Props {
isLoading?: boolean; isLoading?: boolean;
onEditClick: (data: WatchlistAddress) => void; onEditClick: (data: WatchlistAddress) => void;
onDeleteClick: (data: WatchlistAddress) => void; onDeleteClick: (data: WatchlistAddress) => void;
top: number;
} }
const WatchlistTable = ({ data, isLoading, onDeleteClick, onEditClick }: Props) => { const WatchlistTable = ({ data, isLoading, onDeleteClick, onEditClick, top }: Props) => {
return ( return (
<Table variant="simple" minWidth="600px"> <Table variant="simple" minWidth="600px">
<Thead> <TheadSticky top={ top }>
<Tr> <Tr>
<Th width="70%">Address</Th> <Th width="70%">Address</Th>
<Th width="30%">Private tag</Th> <Th width="30%">Private tag</Th>
<Th width="160px">Email notification</Th> <Th width="160px">Email notification</Th>
<Th width="108px"></Th> <Th width="108px"></Th>
</Tr> </Tr>
</Thead> </TheadSticky>
<Tbody> <Tbody>
{ data?.map((item, index) => ( { data?.map((item, index) => (
<WatchlistTableItem <WatchlistTableItem
......
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