diff --git a/ui/address/AddressDetails.tsx b/ui/address/AddressDetails.tsx
index a95b1ea55b..c0e690b889 100644
--- a/ui/address/AddressDetails.tsx
+++ b/ui/address/AddressDetails.tsx
@@ -10,7 +10,6 @@ import useApiQuery from 'lib/api/useApiQuery';
import getQueryParamString from 'lib/router/getQueryParamString';
import { ADDRESS_COUNTERS } from 'stubs/address';
import AddressCounterItem from 'ui/address/details/AddressCounterItem';
-import AddressHeadingInfo from 'ui/shared/AddressHeadingInfo';
import DataFetchAlert from 'ui/shared/DataFetchAlert';
import DetailsInfoItem from 'ui/shared/DetailsInfoItem';
import DetailsSponsoredItem from 'ui/shared/DetailsSponsoredItem';
@@ -83,62 +82,76 @@ const AddressDetails = ({ addressQuery, scrollRef }: Props) => {
}
return (
-
-
-
-
- { data.is_contract && data.creation_tx_hash && data.creator_address_hash && (
-
+
+ { data.is_contract && data.creation_tx_hash && data.creator_address_hash && (
+
+
+ at txn
+
+
+ ) }
+ { data.is_contract && data.implementation_address && (
+
+
-
- at txn
-
-
- ) }
- { data.is_contract && data.implementation_address && (
-
-
-
- ) }
-
- { data.has_tokens && (
-
- { addressQuery.data ? : 0 }
-
- ) }
+ noIcon
+ />
+
+ ) }
+
+ { data.has_tokens && (
+ { addressQuery.data ? : 0 }
+
+ ) }
+
+ { addressQuery.data ? (
+
+ ) :
+ 0 }
+
+ { data.has_token_transfers && (
+
{ addressQuery.data ? (
{
) :
0 }
- { data.has_token_transfers && (
-
- { addressQuery.data ? (
-
- ) :
- 0 }
-
- ) }
+ ) }
+
+ { addressQuery.data ? (
+
+ ) :
+ 0 }
+
+ { data.has_validated_blocks && (
{ addressQuery.data ? (
{
) :
0 }
- { data.has_validated_blocks && (
-
- { addressQuery.data ? (
-
- ) :
- 0 }
-
- ) }
- { data.block_number_balance_updated_at && (
-
+
-
-
- ) }
-
-
-
+ />
+
+ ) }
+
+
);
};
diff --git a/ui/address/__screenshots__/AddressDetails.pw.tsx_default_contract-mobile-1.png b/ui/address/__screenshots__/AddressDetails.pw.tsx_default_contract-mobile-1.png
index 110cb3e209..532df5851c 100644
Binary files a/ui/address/__screenshots__/AddressDetails.pw.tsx_default_contract-mobile-1.png and b/ui/address/__screenshots__/AddressDetails.pw.tsx_default_contract-mobile-1.png differ
diff --git a/ui/address/__screenshots__/AddressDetails.pw.tsx_default_token-1.png b/ui/address/__screenshots__/AddressDetails.pw.tsx_default_token-1.png
index 06144209d2..28d70e3dfe 100644
Binary files a/ui/address/__screenshots__/AddressDetails.pw.tsx_default_token-1.png and b/ui/address/__screenshots__/AddressDetails.pw.tsx_default_token-1.png differ
diff --git a/ui/address/__screenshots__/AddressDetails.pw.tsx_default_validator-mobile-1.png b/ui/address/__screenshots__/AddressDetails.pw.tsx_default_validator-mobile-1.png
index 9f776fde0e..4a98354191 100644
Binary files a/ui/address/__screenshots__/AddressDetails.pw.tsx_default_validator-mobile-1.png and b/ui/address/__screenshots__/AddressDetails.pw.tsx_default_validator-mobile-1.png differ
diff --git a/ui/address/__screenshots__/AddressDetails.pw.tsx_mobile_contract-mobile-1.png b/ui/address/__screenshots__/AddressDetails.pw.tsx_mobile_contract-mobile-1.png
index 9ed0454258..5f80ab8c8e 100644
Binary files a/ui/address/__screenshots__/AddressDetails.pw.tsx_mobile_contract-mobile-1.png and b/ui/address/__screenshots__/AddressDetails.pw.tsx_mobile_contract-mobile-1.png differ
diff --git a/ui/address/__screenshots__/AddressDetails.pw.tsx_mobile_validator-mobile-1.png b/ui/address/__screenshots__/AddressDetails.pw.tsx_mobile_validator-mobile-1.png
index e00a04ecbb..65a58209b3 100644
Binary files a/ui/address/__screenshots__/AddressDetails.pw.tsx_mobile_validator-mobile-1.png and b/ui/address/__screenshots__/AddressDetails.pw.tsx_mobile_validator-mobile-1.png differ
diff --git a/ui/address/details/AddressFavoriteButton.tsx b/ui/address/details/AddressFavoriteButton.tsx
index b9d0453389..b3c3c7cdad 100644
--- a/ui/address/details/AddressFavoriteButton.tsx
+++ b/ui/address/details/AddressFavoriteButton.tsx
@@ -3,6 +3,7 @@ import { useQueryClient } from '@tanstack/react-query';
import { useRouter } from 'next/router';
import React from 'react';
+import config from 'configs/app';
import starFilledIcon from 'icons/star_filled.svg';
import starOutlineIcon from 'icons/star_outline.svg';
import { getResourceKey } from 'lib/api/useApiQuery';
@@ -15,7 +16,7 @@ import DeleteAddressModal from 'ui/watchlist/DeleteAddressModal';
interface Props {
className?: string;
hash: string;
- watchListId: number | null;
+ watchListId: number | null | undefined;
}
const AddressFavoriteButton = ({ className, hash, watchListId }: Props) => {
@@ -24,6 +25,7 @@ const AddressFavoriteButton = ({ className, hash, watchListId }: Props) => {
const queryClient = useQueryClient();
const router = useRouter();
const isAccountActionAllowed = useIsAccountActionAllowed();
+ const onFocusCapture = usePreventFocusAfterModalClosing();
const handleClick = React.useCallback(() => {
if (!isAccountActionAllowed()) {
@@ -54,6 +56,10 @@ const AddressFavoriteButton = ({ className, hash, watchListId }: Props) => {
};
}, [ hash, watchListId ]);
+ if (!config.features.account.isEnabled) {
+ return null;
+ }
+
return (
<>
@@ -68,7 +74,7 @@ const AddressFavoriteButton = ({ className, hash, watchListId }: Props) => {
flexShrink={ 0 }
onClick={ handleClick }
icon={ }
- onFocusCapture={ usePreventFocusAfterModalClosing() }
+ onFocusCapture={ onFocusCapture }
/>
{
pr="6px"
onClick={ onOpen }
icon={ }
+ flexShrink={ 0 }
/>
diff --git a/ui/pages/Address.tsx b/ui/pages/Address.tsx
index 7f1264373e..60ce914b4c 100644
--- a/ui/pages/Address.tsx
+++ b/ui/pages/Address.tsx
@@ -1,4 +1,4 @@
-import { Box, Icon } from '@chakra-ui/react';
+import { Box, Flex, Icon } from '@chakra-ui/react';
import { useRouter } from 'next/router';
import React from 'react';
@@ -10,7 +10,6 @@ import iconSuccess from 'icons/status/success.svg';
import useApiQuery from 'lib/api/useApiQuery';
import { useAppContext } from 'lib/contexts/app';
import useContractTabs from 'lib/hooks/useContractTabs';
-import useIsMobile from 'lib/hooks/useIsMobile';
import useIsSafeAddress from 'lib/hooks/useIsSafeAddress';
import getQueryParamString from 'lib/router/getQueryParamString';
import { ADDRESS_INFO, ADDRESS_TABS_COUNTERS } from 'stubs/address';
@@ -24,7 +23,12 @@ import AddressTokens from 'ui/address/AddressTokens';
import AddressTokenTransfers from 'ui/address/AddressTokenTransfers';
import AddressTxs from 'ui/address/AddressTxs';
import AddressWithdrawals from 'ui/address/AddressWithdrawals';
+import AddressFavoriteButton from 'ui/address/details/AddressFavoriteButton';
+import AddressQrCode from 'ui/address/details/AddressQrCode';
+import AccountActionsMenu from 'ui/shared/AccountActionsMenu/AccountActionsMenu';
import TextAd from 'ui/shared/ad/TextAd';
+import AddressAddToWallet from 'ui/shared/address/AddressAddToWallet';
+import AddressEntity from 'ui/shared/entities/address/AddressEntity';
import EntityTags from 'ui/shared/EntityTags';
import NetworkExplorers from 'ui/shared/NetworkExplorers';
import PageTitle from 'ui/shared/Page/PageTitle';
@@ -41,7 +45,6 @@ const TOKEN_TABS = Object.values(tokenTabsByType);
const AddressPageContent = () => {
const router = useRouter();
- const isMobile = useIsMobile();
const appProps = useAppContext();
const tabsScrollRef = React.useRef(null);
@@ -148,14 +151,11 @@ const AddressPageContent = () => {
data={ addressQuery.data }
isLoading={ addressQuery.isPlaceholderData }
tagsBefore={ [
- addressQuery.data?.is_contract ? { label: 'contract', display_name: 'Contract' } : { label: 'eoa', display_name: 'EOA' },
+ !addressQuery.data?.is_contract ? { label: 'eoa', display_name: 'EOA' } : undefined,
addressQuery.data?.implementation_address ? { label: 'proxy', display_name: 'Proxy' } : undefined,
addressQuery.data?.token ? { label: 'token', display_name: 'Token' } : undefined,
isSafeAddress ? { label: 'safe', display_name: 'Multisig: Safe' } : undefined,
] }
- contentAfter={
-
- }
/>
);
@@ -174,6 +174,30 @@ const AddressPageContent = () => {
};
}, [ appProps.referrer ]);
+ const isLoading = addressQuery.isPlaceholderData;
+
+ const titleSecondRow = (
+
+
+ { !isLoading && addressQuery.data?.is_contract && addressQuery.data.token &&
+ }
+ { !isLoading && !addressQuery.data?.is_contract && config.features.account.isEnabled && (
+
+ ) }
+
+
+
+
+ );
+
return (
<>
@@ -181,7 +205,8 @@ const AddressPageContent = () => {
title={ `${ addressQuery.data?.is_contract ? 'Contract' : 'Address' } details` }
backLink={ backLink }
contentAfter={ tags }
- isLoading={ addressQuery.isPlaceholderData }
+ secondRow={ titleSecondRow }
+ isLoading={ isLoading }
/>
{ /* should stay before tabs to scroll up with pagination */ }
diff --git a/ui/pages/Block.tsx b/ui/pages/Block.tsx
index ce509b5e17..c880c372c4 100644
--- a/ui/pages/Block.tsx
+++ b/ui/pages/Block.tsx
@@ -1,3 +1,4 @@
+import { chakra, Skeleton } from '@chakra-ui/react';
import { useRouter } from 'next/router';
import React from 'react';
@@ -16,6 +17,7 @@ import { WITHDRAWAL } from 'stubs/withdrawals';
import BlockDetails from 'ui/block/BlockDetails';
import BlockWithdrawals from 'ui/block/BlockWithdrawals';
import TextAd from 'ui/shared/ad/TextAd';
+import AddressEntity from 'ui/shared/entities/address/AddressEntity';
import NetworkExplorers from 'ui/shared/NetworkExplorers';
import PageTitle from 'ui/shared/Page/PageTitle';
import Pagination from 'ui/shared/pagination/Pagination';
@@ -112,6 +114,24 @@ const BlockPageContent = () => {
}, [ appProps.referrer ]);
const title = blockQuery.data?.type === 'reorg' ? `Reorged block #${ blockQuery.data?.height }` : `Block #${ blockQuery.data?.height }`;
+ const titleSecondRow = (
+ <>
+
+
+ { config.chain.verificationType === 'validation' ? 'Validated by' : 'Mined by' }
+
+
+
+
+ >
+ );
return (
<>
@@ -119,7 +139,7 @@ const BlockPageContent = () => {
}
+ secondRow={ titleSecondRow }
isLoading={ blockQuery.isPlaceholderData }
/>
{ blockQuery.isPlaceholderData ? : (
diff --git a/ui/pages/Token.tsx b/ui/pages/Token.tsx
index 860eaa9cc6..a2e3dd8c58 100644
--- a/ui/pages/Token.tsx
+++ b/ui/pages/Token.tsx
@@ -1,4 +1,4 @@
-import { Box, Icon, Tooltip } from '@chakra-ui/react';
+import { Box, Flex, Icon, Tooltip } from '@chakra-ui/react';
import { useQueryClient } from '@tanstack/react-query';
import { useRouter } from 'next/router';
import React, { useEffect } from 'react';
@@ -23,8 +23,11 @@ import * as addressStubs from 'stubs/address';
import * as tokenStubs from 'stubs/token';
import { generateListStub } from 'stubs/utils';
import AddressContract from 'ui/address/AddressContract';
+import AddressQrCode from 'ui/address/details/AddressQrCode';
+import AccountActionsMenu from 'ui/shared/AccountActionsMenu/AccountActionsMenu';
import TextAd from 'ui/shared/ad/TextAd';
-import AddressHeadingInfo from 'ui/shared/AddressHeadingInfo';
+import AddressAddToWallet from 'ui/shared/address/AddressAddToWallet';
+import AddressEntity from 'ui/shared/entities/address/AddressEntity';
import * as TokenEntity from 'ui/shared/entities/token/TokenEntity';
import EntityTags from 'ui/shared/EntityTags';
import NetworkExplorers from 'ui/shared/NetworkExplorers';
@@ -261,41 +264,56 @@ const TokenPageContent = () => {
[ { label: verifiedInfoQuery.data.projectSector, display_name: verifiedInfoQuery.data.projectSector } ] :
undefined
}
- contentAfter={
-
- }
flexGrow={ 1 }
/>
>
);
+ const isLoading = tokenQuery.isPlaceholderData || contractQuery.isPlaceholderData;
+
+ const titleSecondRow = (
+
+
+ { !isLoading && tokenQuery.data && }
+
+
+
+
+
+
+
+ );
+
return (
<>
) : null }
contentAfter={ titleContentAfter }
+ secondRow={ titleSecondRow }
/>
-
-
+
+
{ /* should stay before tabs to scroll up with pagination */ }
- { tokenQuery.isPlaceholderData || contractQuery.isPlaceholderData ?
+ { isLoading ?
:
(
{
throw Error('Token instance fetch failed', { cause: tokenInstanceQuery.error });
}
- const nftShieldIcon = tokenInstanceQuery.isPlaceholderData ?
- :
- ;
const tokenTag = { tokenInstanceQuery.data?.token.type };
+
const address = {
hash: hash || '',
is_contract: true,
@@ -130,6 +130,9 @@ const TokenInstanceContent = () => {
watchlist_names: [],
watchlist_address_id: null,
};
+
+ const isLoading = tokenInstanceQuery.isPlaceholderData;
+
const appLink = (() => {
if (!tokenInstanceQuery.data?.external_app_url) {
return null;
@@ -141,20 +144,15 @@ const TokenInstanceContent = () => {
new URL('https://' + tokenInstanceQuery.data.external_app_url);
return (
-
- View in app
-
- { url.hostname || tokenInstanceQuery.data.external_app_url }
-
-
+
+ { url.hostname || tokenInstanceQuery.data.external_app_url }
+
);
} catch (error) {
return (
-
-
+
View in app
-
-
+
);
}
})();
@@ -167,27 +165,44 @@ const TokenInstanceContent = () => {
pagination = holdersQuery.pagination;
}
+ const titleSecondRow = (
+
+
+ { !isLoading && tokenInstanceQuery.data && }
+
+
+ { appLink }
+
+ );
+
return (
<>
-
-
- { appLink }
-
-
+
{ /* should stay before tabs to scroll up with pagination */ }
- { tokenInstanceQuery.isPlaceholderData ? : (
+ { isLoading ? : (
{
const router = useRouter();
const appProps = useAppContext();
- const isMobile = useIsMobile();
const hash = getQueryParamString(router.query.hash);
@@ -57,9 +57,6 @@ const TransactionPageContent = () => {
- }
/>
);
@@ -76,6 +73,14 @@ const TransactionPageContent = () => {
};
}, [ appProps.referrer ]);
+ const titleSecondRow = (
+ <>
+
+ { !data?.tx_tag && }
+
+ >
+ );
+
return (
<>
@@ -83,6 +88,7 @@ const TransactionPageContent = () => {
title="Transaction details"
backLink={ backLink }
contentAfter={ tags }
+ secondRow={ titleSecondRow }
/>
{ isPlaceholderData ? (
<>
diff --git a/ui/pages/__screenshots__/Token.pw.tsx_default_base-view-1.png b/ui/pages/__screenshots__/Token.pw.tsx_default_base-view-1.png
index 82421444ee..9b891a087c 100644
Binary files a/ui/pages/__screenshots__/Token.pw.tsx_default_base-view-1.png and b/ui/pages/__screenshots__/Token.pw.tsx_default_base-view-1.png differ
diff --git a/ui/pages/__screenshots__/Token.pw.tsx_default_bridged-token-1.png b/ui/pages/__screenshots__/Token.pw.tsx_default_bridged-token-1.png
index c65a292d52..4de5603803 100644
Binary files a/ui/pages/__screenshots__/Token.pw.tsx_default_bridged-token-1.png and b/ui/pages/__screenshots__/Token.pw.tsx_default_bridged-token-1.png differ
diff --git a/ui/pages/__screenshots__/Token.pw.tsx_default_mobile-base-view-1.png b/ui/pages/__screenshots__/Token.pw.tsx_default_mobile-base-view-1.png
index 8022377d15..7df7185254 100644
Binary files a/ui/pages/__screenshots__/Token.pw.tsx_default_mobile-base-view-1.png and b/ui/pages/__screenshots__/Token.pw.tsx_default_mobile-base-view-1.png differ
diff --git a/ui/pages/__screenshots__/Token.pw.tsx_default_mobile-with-verified-info-1.png b/ui/pages/__screenshots__/Token.pw.tsx_default_mobile-with-verified-info-1.png
index f12a0c52de..04c40fa49b 100644
Binary files a/ui/pages/__screenshots__/Token.pw.tsx_default_mobile-with-verified-info-1.png and b/ui/pages/__screenshots__/Token.pw.tsx_default_mobile-with-verified-info-1.png differ
diff --git a/ui/pages/__screenshots__/Token.pw.tsx_default_with-verified-info-1.png b/ui/pages/__screenshots__/Token.pw.tsx_default_with-verified-info-1.png
index 32e8e0c8d3..918eb61308 100644
Binary files a/ui/pages/__screenshots__/Token.pw.tsx_default_with-verified-info-1.png and b/ui/pages/__screenshots__/Token.pw.tsx_default_with-verified-info-1.png differ
diff --git a/ui/privateTags/TransactionModal/TransactionForm.tsx b/ui/privateTags/TransactionModal/TransactionForm.tsx
index c6ccf3625a..35097aeee3 100644
--- a/ui/privateTags/TransactionModal/TransactionForm.tsx
+++ b/ui/privateTags/TransactionModal/TransactionForm.tsx
@@ -21,7 +21,7 @@ import TransactionInput from 'ui/shared/TransactionInput';
const TAG_MAX_LENGTH = 35;
type Props = {
- data?: TransactionTag;
+ data?: Partial;
onClose: () => void;
onSuccess: () => Promise;
setAlertVisible: (isAlertVisible: boolean) => void;
diff --git a/ui/privateTags/TransactionModal/TransactionModal.tsx b/ui/privateTags/TransactionModal/TransactionModal.tsx
index eefdefef2a..668119e88c 100644
--- a/ui/privateTags/TransactionModal/TransactionModal.tsx
+++ b/ui/privateTags/TransactionModal/TransactionModal.tsx
@@ -11,10 +11,11 @@ import TransactionForm from './TransactionForm';
type Props = {
isOpen: boolean;
onClose: () => void;
- data?: TransactionTag;
+ onSuccess?: () => Promise;
+ data?: Partial;
}
-const AddressModal: React.FC = ({ isOpen, onClose, data }) => {
+const AddressModal: React.FC = ({ isOpen, onClose, onSuccess, data }) => {
const title = data ? 'Edit transaction tag' : 'New transaction tag';
const text = !data ? 'Label any transaction with a private transaction tag (up to 35 chars) to customize your explorer experience.' : '';
@@ -28,13 +29,14 @@ const AddressModal: React.FC = ({ isOpen, onClose, data }) => {
}, [ data?.id, isOpen ]);
const handleSuccess = React.useCallback(async() => {
+ onSuccess?.();
if (!data?.id) {
mixpanel.logEvent(
mixpanel.EventTypes.PRIVATE_TAG,
{ Action: 'Submit', 'Page type': PAGE_TYPE_DICT['/account/tag-address'], 'Tag type': 'Tx' },
);
}
- }, [ data?.id ]);
+ }, [ data?.id, onSuccess ]);
const renderForm = useCallback(() => {
return ;
diff --git a/ui/shared/AddressActions/Menu.tsx b/ui/shared/AccountActionsMenu/AccountActionsMenu.tsx
similarity index 62%
rename from ui/shared/AddressActions/Menu.tsx
rename to ui/shared/AccountActionsMenu/AccountActionsMenu.tsx
index a7b29d00f2..b8fdb8fac2 100644
--- a/ui/shared/AddressActions/Menu.tsx
+++ b/ui/shared/AccountActionsMenu/AccountActionsMenu.tsx
@@ -1,4 +1,4 @@
-import { Button, Menu, MenuButton, MenuList, Icon, Flex, Skeleton } from '@chakra-ui/react';
+import { Button, Menu, MenuButton, MenuList, Icon, Flex, Skeleton, chakra } from '@chakra-ui/react';
import { useRouter } from 'next/router';
import React from 'react';
@@ -8,28 +8,34 @@ import useIsAccountActionAllowed from 'lib/hooks/useIsAccountActionAllowed';
import * as mixpanel from 'lib/mixpanel/index';
import getQueryParamString from 'lib/router/getQueryParamString';
-import PrivateTagMenuItem from './PrivateTagMenuItem';
-import PublicTagMenuItem from './PublicTagMenuItem';
-import TokenInfoMenuItem from './TokenInfoMenuItem';
+import PrivateTagMenuItem from './items/PrivateTagMenuItem';
+import PublicTagMenuItem from './items/PublicTagMenuItem';
+import TokenInfoMenuItem from './items/TokenInfoMenuItem';
interface Props {
isLoading?: boolean;
+ className?: string;
}
-const AddressActions = ({ isLoading }: Props) => {
+const AccountActionsMenu = ({ isLoading, className }: Props) => {
const router = useRouter();
const hash = getQueryParamString(router.query.hash);
const isTokenPage = router.pathname === '/token/[hash]';
+ const isTxPage = router.pathname === '/tx/[hash]';
const isAccountActionAllowed = useIsAccountActionAllowed();
const handleButtonClick = React.useCallback(() => {
mixpanel.logEvent(mixpanel.EventTypes.PAGE_WIDGET, { Type: 'Address actions (more button)' });
}, []);
+ if (!config.features.account.isEnabled) {
+ return null;
+ }
+
return (
);
};
-export default React.memo(AddressActions);
+export default React.memo(chakra(AccountActionsMenu));
diff --git a/ui/shared/AddressActions/PrivateTagMenuItem.tsx b/ui/shared/AccountActionsMenu/items/PrivateTagMenuItem.tsx
similarity index 56%
rename from ui/shared/AddressActions/PrivateTagMenuItem.tsx
rename to ui/shared/AccountActionsMenu/items/PrivateTagMenuItem.tsx
index 95352dcf0a..4450dcd2b1 100644
--- a/ui/shared/AddressActions/PrivateTagMenuItem.tsx
+++ b/ui/shared/AccountActionsMenu/items/PrivateTagMenuItem.tsx
@@ -4,25 +4,28 @@ import { useRouter } from 'next/router';
import React from 'react';
import type { Address } from 'types/api/address';
+import type { Transaction } from 'types/api/transaction';
import iconPrivateTags from 'icons/privattags.svg';
import { getResourceKey } from 'lib/api/useApiQuery';
import getPageType from 'lib/mixpanel/getPageType';
-import PrivateTagModal from 'ui/privateTags/AddressModal/AddressModal';
+import AddressModal from 'ui/privateTags/AddressModal/AddressModal';
+import TransactionModal from 'ui/privateTags/TransactionModal/TransactionModal';
interface Props {
className?: string;
hash: string;
onBeforeClick: () => boolean;
+ type?: 'address' | 'tx';
}
-const PrivateTagMenuItem = ({ className, hash, onBeforeClick }: Props) => {
+const PrivateTagMenuItem = ({ className, hash, onBeforeClick, type = 'address' }: Props) => {
const modal = useDisclosure();
const queryClient = useQueryClient();
const router = useRouter();
- const queryKey = getResourceKey('address', { pathParams: { hash } });
- const addressData = queryClient.getQueryData(queryKey);
+ const queryKey = getResourceKey(type === 'tx' ? 'tx' : 'address', { pathParams: { hash } });
+ const queryData = queryClient.getQueryData(queryKey);
const handleClick = React.useCallback(() => {
if (!onBeforeClick()) {
@@ -37,17 +40,23 @@ const PrivateTagMenuItem = ({ className, hash, onBeforeClick }: Props) => {
modal.onClose();
}, [ queryClient, queryKey, modal ]);
- const formData = React.useMemo(() => {
- return {
- address_hash: hash,
- };
- }, [ hash ]);
-
- if (addressData?.private_tags?.length) {
+ if (
+ queryData &&
+ (
+ ('private_tags' in queryData && queryData.private_tags?.length) ||
+ ('tx_tag' in queryData && queryData.tx_tag)
+ )
+ ) {
return null;
}
const pageType = getPageType(router.pathname);
+ const modalProps = {
+ isOpen: modal.isOpen,
+ onClose: modal.onClose,
+ onSuccess: handleAddPrivateTag,
+ pageType,
+ };
return (
<>
@@ -55,13 +64,10 @@ const PrivateTagMenuItem = ({ className, hash, onBeforeClick }: Props) => {
Add private tag
-
+ { type === 'tx' ?
+ :
+
+ }
>
);
};
diff --git a/ui/shared/AddressActions/PublicTagMenuItem.tsx b/ui/shared/AccountActionsMenu/items/PublicTagMenuItem.tsx
similarity index 100%
rename from ui/shared/AddressActions/PublicTagMenuItem.tsx
rename to ui/shared/AccountActionsMenu/items/PublicTagMenuItem.tsx
diff --git a/ui/shared/AddressActions/TokenInfoMenuItem.tsx b/ui/shared/AccountActionsMenu/items/TokenInfoMenuItem.tsx
similarity index 100%
rename from ui/shared/AddressActions/TokenInfoMenuItem.tsx
rename to ui/shared/AccountActionsMenu/items/TokenInfoMenuItem.tsx
diff --git a/ui/shared/AddressHeadingInfo.tsx b/ui/shared/AddressHeadingInfo.tsx
deleted file mode 100644
index 9e79b49b28..0000000000
--- a/ui/shared/AddressHeadingInfo.tsx
+++ /dev/null
@@ -1,77 +0,0 @@
-import { Flex } from '@chakra-ui/react';
-import React from 'react';
-
-import type { Address } from 'types/api/address';
-import type { TokenInfo } from 'types/api/token';
-
-import config from 'configs/app';
-import useIsSafeAddress from 'lib/hooks/useIsSafeAddress';
-import stripTrailingSlash from 'lib/stripTrailingSlash';
-import AddressFavoriteButton from 'ui/address/details/AddressFavoriteButton';
-import AddressQrCode from 'ui/address/details/AddressQrCode';
-import AddressAddToWallet from 'ui/shared/address/AddressAddToWallet';
-import AddressActionsMenu from 'ui/shared/AddressActions/Menu';
-import AddressEntity from 'ui/shared/entities/address/AddressEntity';
-import LinkExternal from 'ui/shared/LinkExternal';
-
-interface Props {
- address?: Pick;
- token?: TokenInfo | null;
- isLinkDisabled?: boolean;
- isLoading?: boolean;
-}
-
-const AddressHeadingInfo = ({ address, token, isLinkDisabled, isLoading }: Props) => {
- const isSafeAddress = useIsSafeAddress(!isLoading && address?.is_contract ? address.hash : undefined);
-
- if (!address) {
- return null;
- }
-
- const tokenOriginalLink = (() => {
- const feature = config.features.bridgedTokens;
- if (!token?.foreign_address || !token.origin_chain_id || !feature.isEnabled) {
- return null;
- }
-
- const chainBaseUrl = feature.chains.find(({ id }) => id === token.origin_chain_id)?.base_url;
-
- if (!chainBaseUrl) {
- return null;
- }
-
- try {
- const url = new URL(stripTrailingSlash(chainBaseUrl) + '/' + token.foreign_address);
- return (
-
- Original token
-
- );
- } catch (error) {
- return null;
- }
- })();
-
- return (
-
-
- { !isLoading && address?.is_contract && token && }
- { !isLoading && !address.is_contract && config.features.account.isEnabled && (
-
- ) }
-
- { config.features.account.isEnabled && }
- { tokenOriginalLink }
-
- );
-};
-
-export default AddressHeadingInfo;
diff --git a/ui/shared/LinkExternal.tsx b/ui/shared/LinkExternal.tsx
index 329a66aed7..2ffd5f4d23 100644
--- a/ui/shared/LinkExternal.tsx
+++ b/ui/shared/LinkExternal.tsx
@@ -16,25 +16,42 @@ const LinkExternal = ({ href, children, className, isLoading, variant }: Props)
const subtleLinkBg = useColorModeValue('gray.100', 'gray.700');
const styleProps: ChakraProps = (() => {
+ const commonProps = {
+ fontSize: 'sm',
+ lineHeight: 5,
+ display: 'inline-block',
+ alignItems: 'center',
+ };
+
switch (variant) {
case 'subtle': {
return {
+ ...commonProps,
px: '10px',
- py: '5px',
+ py: '6px',
bgColor: subtleLinkBg,
borderRadius: 'base',
};
}
default:{
- return {};
+ return commonProps;
}
}
})();
if (isLoading) {
+ if (variant === 'subtle') {
+ return (
+
+ { children }
+
+
+ );
+ }
+
return (
-
+
{ children }
@@ -42,7 +59,7 @@ const LinkExternal = ({ href, children, className, isLoading, variant }: Props)
}
return (
-
+
{ children }
diff --git a/ui/shared/NetworkExplorers.tsx b/ui/shared/NetworkExplorers.tsx
index ea4a8a5b25..d187bd6203 100644
--- a/ui/shared/NetworkExplorers.tsx
+++ b/ui/shared/NetworkExplorers.tsx
@@ -12,10 +12,9 @@ interface Props {
className?: string;
type: keyof TNetworkExplorer['paths'];
pathParam: string;
- hideText?: boolean;
}
-const NetworkExplorers = ({ className, type, pathParam, hideText }: Props) => {
+const NetworkExplorers = ({ className, type, pathParam }: Props) => {
const { isOpen, onToggle, onClose } = useDisclosure();
const explorersLinks = config.UI.explorers.items
@@ -41,11 +40,11 @@ const NetworkExplorers = ({ className, type, pathParam, hideText }: Props) => {
aria-label="Verify in other explorers"
fontWeight={ 500 }
px={ 2 }
- h="30px"
+ h="32px"
+ flexShrink={ 0 }
>
-
- { !hideText && Explorers }
-
+
+
diff --git a/ui/shared/Page/PageTitle.tsx b/ui/shared/Page/PageTitle.tsx
index 9d1879a6c5..9167e7e87e 100644
--- a/ui/shared/Page/PageTitle.tsx
+++ b/ui/shared/Page/PageTitle.tsx
@@ -16,6 +16,7 @@ type Props = {
beforeTitle?: React.ReactNode;
afterTitle?: React.ReactNode;
contentAfter?: React.ReactNode;
+ secondRow?: React.ReactNode;
isLoading?: boolean;
withTextAd?: boolean;
}
@@ -31,7 +32,7 @@ const BackLink = (props: BackLinkProp & { isLoading?: boolean }) => {
return ;
}
- const icon = ;
+ const icon = ;
if ('url' in props) {
return (
@@ -52,7 +53,7 @@ const BackLink = (props: BackLinkProp & { isLoading?: boolean }) => {
);
};
-const PageTitle = ({ title, contentAfter, withTextAd, backLink, className, isLoading, afterTitle, beforeTitle }: Props) => {
+const PageTitle = ({ title, contentAfter, withTextAd, backLink, className, isLoading, afterTitle, beforeTitle, secondRow }: Props) => {
const tooltip = useDisclosure();
const isMobile = useIsMobile();
const [ isTextTruncated, setIsTextTruncated ] = React.useState(false);
@@ -90,57 +91,62 @@ const PageTitle = ({ title, contentAfter, withTextAd, backLink, className, isLoa
}, [ updatedTruncateState ]);
return (
-
-
- { backLink && }
- { beforeTitle }
-
-
+
+
+ { backLink && }
+ { beforeTitle }
+
-
-
- { title }
-
-
-
-
- { afterTitle }
+
+
+ { title }
+
+
+
+
+ { afterTitle }
+
+ { contentAfter }
+ { withTextAd && }
- { contentAfter }
- { withTextAd && }
+ { secondRow && (
+
+ { secondRow }
+
+ ) }
);
};
diff --git a/ui/shared/Page/__screenshots__/PageTitle.pw.tsx_default_default-view-mobile-1.png b/ui/shared/Page/__screenshots__/PageTitle.pw.tsx_default_default-view-mobile-1.png
index 37ff077127..8e5096497b 100644
Binary files a/ui/shared/Page/__screenshots__/PageTitle.pw.tsx_default_default-view-mobile-1.png and b/ui/shared/Page/__screenshots__/PageTitle.pw.tsx_default_default-view-mobile-1.png differ
diff --git a/ui/shared/Page/__screenshots__/PageTitle.pw.tsx_default_with-long-name-and-many-tags-mobile-1.png b/ui/shared/Page/__screenshots__/PageTitle.pw.tsx_default_with-long-name-and-many-tags-mobile-1.png
index 0783f8bc45..d8878240f6 100644
Binary files a/ui/shared/Page/__screenshots__/PageTitle.pw.tsx_default_with-long-name-and-many-tags-mobile-1.png and b/ui/shared/Page/__screenshots__/PageTitle.pw.tsx_default_with-long-name-and-many-tags-mobile-1.png differ
diff --git a/ui/shared/Page/__screenshots__/PageTitle.pw.tsx_default_with-text-ad-mobile-1.png b/ui/shared/Page/__screenshots__/PageTitle.pw.tsx_default_with-text-ad-mobile-1.png
index 3b9bd03c07..9a03708d13 100644
Binary files a/ui/shared/Page/__screenshots__/PageTitle.pw.tsx_default_with-text-ad-mobile-1.png and b/ui/shared/Page/__screenshots__/PageTitle.pw.tsx_default_with-text-ad-mobile-1.png differ
diff --git a/ui/shared/Page/__screenshots__/PageTitle.pw.tsx_mobile_default-view-mobile-1.png b/ui/shared/Page/__screenshots__/PageTitle.pw.tsx_mobile_default-view-mobile-1.png
index 400f85c7bd..04be035dd4 100644
Binary files a/ui/shared/Page/__screenshots__/PageTitle.pw.tsx_mobile_default-view-mobile-1.png and b/ui/shared/Page/__screenshots__/PageTitle.pw.tsx_mobile_default-view-mobile-1.png differ
diff --git a/ui/shared/Page/__screenshots__/PageTitle.pw.tsx_mobile_with-long-name-and-many-tags-mobile-1.png b/ui/shared/Page/__screenshots__/PageTitle.pw.tsx_mobile_with-long-name-and-many-tags-mobile-1.png
index da099aed19..11886cf45b 100644
Binary files a/ui/shared/Page/__screenshots__/PageTitle.pw.tsx_mobile_with-long-name-and-many-tags-mobile-1.png and b/ui/shared/Page/__screenshots__/PageTitle.pw.tsx_mobile_with-long-name-and-many-tags-mobile-1.png differ
diff --git a/ui/shared/Page/__screenshots__/PageTitle.pw.tsx_mobile_with-text-ad-mobile-1.png b/ui/shared/Page/__screenshots__/PageTitle.pw.tsx_mobile_with-text-ad-mobile-1.png
index 6c8c7bd202..01d7d12f52 100644
Binary files a/ui/shared/Page/__screenshots__/PageTitle.pw.tsx_mobile_with-text-ad-mobile-1.png and b/ui/shared/Page/__screenshots__/PageTitle.pw.tsx_mobile_with-text-ad-mobile-1.png differ
diff --git a/ui/shared/Page/specs/DefaultView.tsx b/ui/shared/Page/specs/DefaultView.tsx
index 4511f40aef..23db4033fd 100644
--- a/ui/shared/Page/specs/DefaultView.tsx
+++ b/ui/shared/Page/specs/DefaultView.tsx
@@ -4,7 +4,8 @@ import React from 'react';
import type { TokenInfo } from 'types/api/token';
import iconVerifiedToken from 'icons/verified_token.svg';
-import useIsMobile from 'lib/hooks/useIsMobile';
+import * as addressMock from 'mocks/address/address';
+import AddressEntity from 'ui/shared/entities/address/AddressEntity';
import * as TokenEntity from 'ui/shared/entities/token/TokenEntity';
import EntityTags from 'ui/shared/EntityTags';
import NetworkExplorers from 'ui/shared/NetworkExplorers';
@@ -12,8 +13,6 @@ import NetworkExplorers from 'ui/shared/NetworkExplorers';
import PageTitle from '../PageTitle';
const DefaultView = () => {
- const isMobile = useIsMobile();
-
const tokenData: TokenInfo = {
address: '0x363574E6C5C71c343d7348093D84320c76d5Dd29',
circulating_market_cap: '117629601.61913824',
@@ -39,12 +38,23 @@ const DefaultView = () => {
tagsBefore={ [
{ label: 'example', display_name: 'Example label' },
] }
- contentAfter={ }
flexGrow={ 1 }
/>
>
);
+ const secondRow = (
+ <>
+
+
+ >
+ );
+
return (
{
) }
backLink={ backLink }
contentAfter={ contentAfter }
+ secondRow={ secondRow }
/>
);
};
diff --git a/ui/shared/Page/specs/LongNameAndManyTags.tsx b/ui/shared/Page/specs/LongNameAndManyTags.tsx
index d9fca18d90..665d328e4a 100644
--- a/ui/shared/Page/specs/LongNameAndManyTags.tsx
+++ b/ui/shared/Page/specs/LongNameAndManyTags.tsx
@@ -5,7 +5,6 @@ import React from 'react';
import type { TokenInfo } from 'types/api/token';
import iconVerifiedToken from 'icons/verified_token.svg';
-import useIsMobile from 'lib/hooks/useIsMobile';
import { publicTag, privateTag, watchlistName } from 'mocks/address/tag';
import * as TokenEntity from 'ui/shared/entities/token/TokenEntity';
import EntityTags from 'ui/shared/EntityTags';
@@ -14,8 +13,6 @@ import NetworkExplorers from 'ui/shared/NetworkExplorers';
import PageTitle from '../PageTitle';
const LongNameAndManyTags = () => {
- const isMobile = useIsMobile();
-
const tokenData: TokenInfo = {
address: '0xa77A39CC9680B10C00af5D4ABFc92e1F07406c64',
circulating_market_cap: null,
@@ -45,7 +42,7 @@ const LongNameAndManyTags = () => {
{ label: 'after_1', display_name: 'Another tag' },
{ label: 'after_2', display_name: 'And yet more' },
] }
- contentAfter={ }
+ contentAfter={ }
flexGrow={ 1 }
/>
>
diff --git a/ui/shared/address/AddressAddToWallet.tsx b/ui/shared/address/AddressAddToWallet.tsx
index e1eb02225d..a9c640b300 100644
--- a/ui/shared/address/AddressAddToWallet.tsx
+++ b/ui/shared/address/AddressAddToWallet.tsx
@@ -1,4 +1,4 @@
-import { Box, chakra, Icon, Skeleton, Tooltip } from '@chakra-ui/react';
+import { Box, chakra, Icon, IconButton, Skeleton, Tooltip } from '@chakra-ui/react';
import React from 'react';
import type { TokenInfo } from 'types/api/token';
@@ -16,10 +16,11 @@ interface Props {
className?: string;
token: TokenInfo;
isLoading?: boolean;
+ variant?: 'icon' | 'button';
iconSize?: number;
}
-const AddressAddToWallet = ({ className, token, isLoading, iconSize = 6 }: Props) => {
+const AddressAddToWallet = ({ className, token, isLoading, variant = 'icon', iconSize = 6 }: Props) => {
const toast = useToast();
const { provider, wallet } = useProvider();
const addOrSwitchChain = useAddOrSwitchChain();
@@ -86,9 +87,26 @@ const AddressAddToWallet = ({ className, token, isLoading, iconSize = 6 }: Props
return null;
}
+ if (variant === 'button') {
+ return (
+
+ }
+ flexShrink={ 0 }
+ />
+
+ );
+ }
+
return (
-
+
diff --git a/ui/token/TokenDetails.tsx b/ui/token/TokenDetails.tsx
index 5acd950a51..388546a67b 100644
--- a/ui/token/TokenDetails.tsx
+++ b/ui/token/TokenDetails.tsx
@@ -86,7 +86,6 @@ const TokenDetails = ({ tokenQuery }: Props) => {
return (
-
- Project info
+
+ Info
);
diff --git a/ui/token/TokenVerifiedInfo.tsx b/ui/token/TokenVerifiedInfo.tsx
index 5e15db2c6d..13765829dc 100644
--- a/ui/token/TokenVerifiedInfo.tsx
+++ b/ui/token/TokenVerifiedInfo.tsx
@@ -1,4 +1,4 @@
-import { Flex, Skeleton } from '@chakra-ui/react';
+import { Skeleton } from '@chakra-ui/react';
import type { UseQueryResult } from '@tanstack/react-query';
import React from 'react';
@@ -25,9 +25,9 @@ const TokenVerifiedInfo = ({ verifiedInfoQuery }: Props) => {
if (isLoading) {
return (
<>
-
-
-
+
+
+
>
);
}
@@ -40,7 +40,9 @@ const TokenVerifiedInfo = ({ verifiedInfoQuery }: Props) => {
try {
const url = new URL(data.projectWebsite);
return (
- { url.host }
+
+ { url.host }
+
);
} catch (error) {
return null;
@@ -55,7 +57,7 @@ const TokenVerifiedInfo = ({ verifiedInfoQuery }: Props) => {
);
})();
- return { content };
+ return content;
};
export default React.memo(TokenVerifiedInfo);
diff --git a/ui/tokenInstance/TokenInstanceDetails.tsx b/ui/tokenInstance/TokenInstanceDetails.tsx
index 5837601ae8..aae2b1302c 100644
--- a/ui/tokenInstance/TokenInstanceDetails.tsx
+++ b/ui/tokenInstance/TokenInstanceDetails.tsx
@@ -8,7 +8,6 @@ import DetailsInfoItem from 'ui/shared/DetailsInfoItem';
import DetailsInfoItemDivider from 'ui/shared/DetailsInfoItemDivider';
import DetailsSponsoredItem from 'ui/shared/DetailsSponsoredItem';
import AddressEntity from 'ui/shared/entities/address/AddressEntity';
-import TokenEntity from 'ui/shared/entities/token/TokenEntity';
import HashStringShortenDynamic from 'ui/shared/HashStringShortenDynamic';
import NftMedia from 'ui/shared/nft/NftMedia';
import TokenNftMarketplaces from 'ui/token/TokenNftMarketplaces';
@@ -37,7 +36,7 @@ const TokenInstanceDetails = ({ data, scrollRef, isLoading }: Props) => {
return (
<>
-
+
{
templateColumns={{ base: 'minmax(0, 1fr)', lg: '200px minmax(0, 1fr)' }}
overflow="hidden"
>
-
-
-
{ data.is_unique && data.owner && (