Commit aeb16bf0 authored by tom goriunov's avatar tom goriunov Committed by GitHub

Resolve BENS names from URL directly to address page (#2004)

* Resolve BENS names from URL directly to address page

Fixes #1965

* fix tests
parent d392e5c6
......@@ -5,7 +5,7 @@ import useApiQuery from 'lib/api/useApiQuery';
import parseMetaPayload from './parseMetaPayload';
export default function useAddressMetadataInfoQuery(addresses: Array<string>) {
export default function useAddressMetadataInfoQuery(addresses: Array<string>, isEnabled = true) {
const resource = 'address_metadata_info';
......@@ -16,7 +16,7 @@ export default function useAddressMetadataInfoQuery(addresses: Array<string>) {
tagsLimit: '20',
},
queryOptions: {
enabled: addresses.length > 0 && config.features.addressMetadata.isEnabled,
enabled: isEnabled && addresses.length > 0 && config.features.addressMetadata.isEnabled,
select: (data) => {
const addresses = Object.entries(data.addresses)
.map(([ address, { tags, reputation } ]) => {
......
const useFeatureValue = (name, fallback) => {
try {
const value = JSON.parse(localStorage.getItem(`pw_feature:${ name }`));
if (value === null) {
throw new Error();
}
return { isLoading: false, value };
} catch (error) {
return { isLoading: false, value: fallback };
......
......@@ -27,9 +27,10 @@ const getFilterValue = (getFilterValueFromQuery<NovesHistoryFilterValue>).bind(n
type Props = {
scrollRef?: React.RefObject<HTMLDivElement>;
shouldRender?: boolean;
isQueryEnabled?: boolean;
}
const AddressAccountHistory = ({ scrollRef, shouldRender = true }: Props) => {
const AddressAccountHistory = ({ scrollRef, shouldRender = true, isQueryEnabled = true }: Props) => {
const router = useRouter();
const isMounted = useIsMounted();
......@@ -42,6 +43,7 @@ const AddressAccountHistory = ({ scrollRef, shouldRender = true }: Props) => {
pathParams: { address: currentAddress },
scrollRef,
options: {
enabled: isQueryEnabled,
placeholderData: generateListStub<'noves_address_history'>(NOVES_TRANSLATE, 10, { hasNextPage: false, pageNumber: 1, pageSize: 10 }),
},
});
......
......@@ -27,9 +27,10 @@ import AddressBlocksValidatedTableItem from './blocksValidated/AddressBlocksVali
interface Props {
scrollRef?: React.RefObject<HTMLDivElement>;
shouldRender?: boolean;
isQueryEnabled?: boolean;
}
const AddressBlocksValidated = ({ scrollRef, shouldRender = true }: Props) => {
const AddressBlocksValidated = ({ scrollRef, shouldRender = true, isQueryEnabled = true }: Props) => {
const [ socketAlert, setSocketAlert ] = React.useState(false);
const queryClient = useQueryClient();
const router = useRouter();
......@@ -41,6 +42,7 @@ const AddressBlocksValidated = ({ scrollRef, shouldRender = true }: Props) => {
pathParams: { hash: addressHash },
scrollRef,
options: {
enabled: isQueryEnabled,
placeholderData: generateListStub<'address_blocks_validated'>(
BLOCK,
50,
......
......@@ -20,9 +20,10 @@ import AddressCoinBalanceHistory from './coinBalance/AddressCoinBalanceHistory';
type Props = {
shouldRender?: boolean;
isQueryEnabled?: boolean;
}
const AddressCoinBalance = ({ shouldRender = true }: Props) => {
const AddressCoinBalance = ({ shouldRender = true, isQueryEnabled = true }: Props) => {
const [ socketAlert, setSocketAlert ] = React.useState(false);
const queryClient = useQueryClient();
const router = useRouter();
......@@ -36,6 +37,7 @@ const AddressCoinBalance = ({ shouldRender = true }: Props) => {
pathParams: { hash: addressHash },
scrollRef,
options: {
enabled: isQueryEnabled,
placeholderData: generateListStub<'address_coin_balance'>(
ADDRESS_COIN_BALANCE,
50,
......
......@@ -26,8 +26,9 @@ const getFilterValue = (getFilterValueFromQuery<AddressFromToFilter>).bind(null,
type Props = {
scrollRef?: React.RefObject<HTMLDivElement>;
shouldRender?: boolean;
isQueryEnabled?: boolean;
}
const AddressInternalTxs = ({ scrollRef, shouldRender = true }: Props) => {
const AddressInternalTxs = ({ scrollRef, shouldRender = true, isQueryEnabled = true }: Props) => {
const router = useRouter();
const isMounted = useIsMounted();
......@@ -41,6 +42,7 @@ const AddressInternalTxs = ({ scrollRef, shouldRender = true }: Props) => {
filters: { filter: filterValue },
scrollRef,
options: {
enabled: isQueryEnabled,
placeholderData: generateListStub<'address_internal_txs'>(
INTERNAL_TX,
50,
......
......@@ -16,9 +16,10 @@ import AddressCsvExportLink from './AddressCsvExportLink';
type Props ={
scrollRef?: React.RefObject<HTMLDivElement>;
shouldRender?: boolean;
isQueryEnabled?: boolean;
}
const AddressLogs = ({ scrollRef, shouldRender = true }: Props) => {
const AddressLogs = ({ scrollRef, shouldRender = true, isQueryEnabled = true }: Props) => {
const router = useRouter();
const isMounted = useIsMounted();
......@@ -28,6 +29,7 @@ const AddressLogs = ({ scrollRef, shouldRender = true }: Props) => {
pathParams: { hash },
scrollRef,
options: {
enabled: isQueryEnabled,
placeholderData: generateListStub<'address_logs'>(LOG, 3, { next_page_params: {
block_number: 9005750,
index: 42,
......
......@@ -65,11 +65,12 @@ const matchFilters = (filters: Filters, tokenTransfer: TokenTransfer, address?:
type Props = {
scrollRef?: React.RefObject<HTMLDivElement>;
shouldRender?: boolean;
isQueryEnabled?: boolean;
// for tests only
overloadCount?: number;
}
const AddressTokenTransfers = ({ scrollRef, overloadCount = OVERLOAD_COUNT, shouldRender = true }: Props) => {
const AddressTokenTransfers = ({ scrollRef, overloadCount = OVERLOAD_COUNT, shouldRender = true, isQueryEnabled = true }: Props) => {
const router = useRouter();
const queryClient = useQueryClient();
const isMobile = useIsMobile();
......@@ -95,6 +96,7 @@ const AddressTokenTransfers = ({ scrollRef, overloadCount = OVERLOAD_COUNT, shou
filters: tokenFilter ? { token: tokenFilter } : filters,
scrollRef,
options: {
enabled: isQueryEnabled,
placeholderData: getTokenTransfersStub(undefined, {
block_number: 7793535,
index: 46,
......
......@@ -45,9 +45,10 @@ const getTokenFilterValue = (getFilterValuesFromQuery<NFTTokenType>).bind(null,
type Props = {
shouldRender?: boolean;
isQueryEnabled?: boolean;
}
const AddressTokens = ({ shouldRender = true }: Props) => {
const AddressTokens = ({ shouldRender = true, isQueryEnabled = true }: Props) => {
const router = useRouter();
const isMobile = useIsMobile();
const isMounted = useIsMounted();
......@@ -67,7 +68,7 @@ const AddressTokens = ({ shouldRender = true }: Props) => {
filters: { type: 'ERC-20' },
scrollRef,
options: {
enabled: !tab || tab === 'tokens_erc20',
enabled: isQueryEnabled && (!tab || tab === 'tokens_erc20'),
refetchOnMount: false,
placeholderData: generateListStub<'address_tokens'>(ADDRESS_TOKEN_BALANCE_ERC_20, 10, { next_page_params: null }),
},
......@@ -78,7 +79,7 @@ const AddressTokens = ({ shouldRender = true }: Props) => {
pathParams: { hash },
scrollRef,
options: {
enabled: tab === 'tokens_nfts' && nftDisplayType === 'collection',
enabled: isQueryEnabled && tab === 'tokens_nfts' && nftDisplayType === 'collection',
placeholderData: generateListStub<'address_collections'>(ADDRESS_COLLECTION, 10, { next_page_params: null }),
},
filters: { type: tokenTypes },
......@@ -89,7 +90,7 @@ const AddressTokens = ({ shouldRender = true }: Props) => {
pathParams: { hash },
scrollRef,
options: {
enabled: tab === 'tokens_nfts' && nftDisplayType === 'list',
enabled: isQueryEnabled && tab === 'tokens_nfts' && nftDisplayType === 'list',
placeholderData: generateListStub<'address_nfts'>(ADDRESS_NFT_1155, 10, { next_page_params: null }),
},
filters: { type: tokenTypes },
......
......@@ -49,11 +49,12 @@ const matchFilter = (filterValue: AddressFromToFilter, transaction: Transaction,
type Props = {
scrollRef?: React.RefObject<HTMLDivElement>;
shouldRender?: boolean;
isQueryEnabled?: boolean;
// for tests only
overloadCount?: number;
}
const AddressTxs = ({ scrollRef, overloadCount = OVERLOAD_COUNT, shouldRender = true }: Props) => {
const AddressTxs = ({ scrollRef, overloadCount = OVERLOAD_COUNT, shouldRender = true, isQueryEnabled = true }: Props) => {
const router = useRouter();
const queryClient = useQueryClient();
const isMounted = useIsMounted();
......@@ -74,6 +75,7 @@ const AddressTxs = ({ scrollRef, overloadCount = OVERLOAD_COUNT, shouldRender =
sorting: getSortParamsFromValue<TransactionsSortingValue, TransactionsSortingField, TransactionsSorting['order']>(sort),
scrollRef,
options: {
enabled: isQueryEnabled,
placeholderData: generateListStub<'address_txs'>(TX, 50, { next_page_params: {
block_number: 9005713,
index: 5,
......
......@@ -11,9 +11,10 @@ import UserOpsContent from 'ui/userOps/UserOpsContent';
type Props = {
scrollRef?: React.RefObject<HTMLDivElement>;
shouldRender?: boolean;
isQueryEnabled?: boolean;
}
const AddressUserOps = ({ scrollRef, shouldRender = true }: Props) => {
const AddressUserOps = ({ scrollRef, shouldRender = true, isQueryEnabled = true }: Props) => {
const router = useRouter();
const isMounted = useIsMounted();
......@@ -23,7 +24,7 @@ const AddressUserOps = ({ scrollRef, shouldRender = true }: Props) => {
resourceName: 'user_ops',
scrollRef,
options: {
enabled: Boolean(hash),
enabled: isQueryEnabled && Boolean(hash),
placeholderData: generateListStub<'user_ops'>(USER_OPS_ITEM, 50, { next_page_params: {
page_token: '10355938,0x5956a847d8089e254e02e5111cad6992b99ceb9e5c2dc4343fd53002834c4dc6',
page_size: 50,
......
......@@ -16,8 +16,9 @@ import BeaconChainWithdrawalsTable from 'ui/withdrawals/beaconChain/BeaconChainW
type Props = {
scrollRef?: React.RefObject<HTMLDivElement>;
shouldRender?: boolean;
isQueryEnabled?: boolean;
}
const AddressWithdrawals = ({ scrollRef, shouldRender = true }: Props) => {
const AddressWithdrawals = ({ scrollRef, shouldRender = true, isQueryEnabled = true }: Props) => {
const router = useRouter();
const isMounted = useIsMounted();
......@@ -28,6 +29,7 @@ const AddressWithdrawals = ({ scrollRef, shouldRender = true }: Props) => {
pathParams: { hash },
scrollRef,
options: {
enabled: isQueryEnabled,
placeholderData: generateListStub<'address_withdrawals'>(WITHDRAWAL, 50, { next_page_params: {
index: 5,
items_count: 50,
......
......@@ -22,15 +22,16 @@ export type AddressQuery = UseQueryResult<Address, ResourceError<{ status: numbe
interface Params {
hash: string;
isEnabled?: boolean;
}
export default function useAddressQuery({ hash }: Params): AddressQuery {
export default function useAddressQuery({ hash, isEnabled = true }: Params): AddressQuery {
const [ isRefetchEnabled, setRefetchEnabled ] = React.useState(false);
const apiQuery = useApiQuery<'address', { status: number }>('address', {
pathParams: { hash },
queryOptions: {
enabled: Boolean(hash),
enabled: isEnabled && Boolean(hash),
placeholderData: ADDRESS_INFO,
refetchOnMount: false,
retry: (failureCount, error) => {
......
import { useRouter } from 'next/router';
import React from 'react';
import config from 'configs/app';
import useApiQuery from 'lib/api/useApiQuery';
const DOMAIN_NAME_REGEXP = /.\../;
export default function useCheckDomainNameParam(hashOrDomainName: string) {
const router = useRouter();
const maybeDomainName = DOMAIN_NAME_REGEXP.test(hashOrDomainName);
const isQueryEnabled = config.features.nameService.isEnabled && maybeDomainName;
const [ isLoading, setIsLoading ] = React.useState(isQueryEnabled);
const domainLookupQuery = useApiQuery('domains_lookup', {
pathParams: { chainId: config.chain.id },
queryParams: {
name: hashOrDomainName,
only_active: false,
},
queryOptions: {
enabled: isQueryEnabled,
},
});
React.useEffect(() => {
if (domainLookupQuery.isPending) {
return;
}
const firstDomainAddress = domainLookupQuery.data?.items[0]?.resolved_address?.hash;
if (firstDomainAddress) {
router.replace({ pathname: '/address/[hash]', query: { hash: firstDomainAddress } });
} else {
setIsLoading(false);
}
}, [ domainLookupQuery.isPending, domainLookupQuery.data, router ]);
React.useEffect(() => {
if (!maybeDomainName) {
setIsLoading(false);
}
}, [ maybeDomainName ]);
return isLoading;
}
......@@ -33,6 +33,7 @@ import AddressQrCode from 'ui/address/details/AddressQrCode';
import AddressEnsDomains from 'ui/address/ensDomains/AddressEnsDomains';
import SolidityscanReport from 'ui/address/SolidityscanReport';
import useAddressQuery from 'ui/address/utils/useAddressQuery';
import useCheckDomainNameParam from 'ui/address/utils/useCheckDomainNameParam';
import AccountActionsMenu from 'ui/shared/AccountActionsMenu/AccountActionsMenu';
import TextAd from 'ui/shared/ad/TextAd';
import AddressAddToWallet from 'ui/shared/address/AddressAddToWallet';
......@@ -57,12 +58,13 @@ const AddressPageContent = () => {
const tabsScrollRef = React.useRef<HTMLDivElement>(null);
const hash = getQueryParamString(router.query.hash);
const addressQuery = useAddressQuery({ hash });
const areQueriesEnabled = !useCheckDomainNameParam(hash);
const addressQuery = useAddressQuery({ hash, isEnabled: areQueriesEnabled });
const addressTabsCountersQuery = useApiQuery('address_tabs_counters', {
pathParams: { hash },
queryOptions: {
enabled: Boolean(hash),
enabled: areQueriesEnabled && Boolean(hash),
placeholderData: ADDRESS_TABS_COUNTERS,
},
});
......@@ -70,13 +72,13 @@ const AddressPageContent = () => {
const userOpsAccountQuery = useApiQuery('user_ops_account', {
pathParams: { hash },
queryOptions: {
enabled: Boolean(hash) && config.features.userOps.isEnabled,
enabled: areQueriesEnabled && Boolean(hash) && config.features.userOps.isEnabled,
placeholderData: USER_OPS_ACCOUNT,
},
});
const addressesForMetadataQuery = React.useMemo(() => ([ hash ].filter(Boolean)), [ hash ]);
const addressMetadataQuery = useAddressMetadataInfoQuery(addressesForMetadataQuery);
const addressMetadataQuery = useAddressMetadataInfoQuery(addressesForMetadataQuery, areQueriesEnabled);
const addressEnsDomainsQuery = useApiQuery('addresses_lookup', {
pathParams: { chainId: config.chain.id },
......@@ -123,13 +125,13 @@ const AddressPageContent = () => {
id: 'txs',
title: 'Transactions',
count: addressTabsCountersQuery.data?.transactions_count,
component: <AddressTxs scrollRef={ tabsScrollRef } shouldRender={ !isTabsLoading }/>,
component: <AddressTxs scrollRef={ tabsScrollRef } shouldRender={ !isTabsLoading } isQueryEnabled={ areQueriesEnabled }/>,
},
txInterpretation.isEnabled && txInterpretation.provider === 'noves' ?
{
id: 'account_history',
title: 'Account history',
component: <AddressAccountHistory scrollRef={ tabsScrollRef } shouldRender={ !isTabsLoading }/>,
component: <AddressAccountHistory scrollRef={ tabsScrollRef } shouldRender={ !isTabsLoading } isQueryEnabled={ areQueriesEnabled }/>,
} :
undefined,
config.features.userOps.isEnabled && Boolean(userOpsAccountQuery.data?.total_ops) ?
......@@ -137,7 +139,7 @@ const AddressPageContent = () => {
id: 'user_ops',
title: 'User operations',
count: userOpsAccountQuery.data?.total_ops,
component: <AddressUserOps shouldRender={ !isTabsLoading }/>,
component: <AddressUserOps shouldRender={ !isTabsLoading } isQueryEnabled={ areQueriesEnabled }/>,
} :
undefined,
config.features.beaconChain.isEnabled && addressTabsCountersQuery.data?.withdrawals_count ?
......@@ -145,39 +147,39 @@ const AddressPageContent = () => {
id: 'withdrawals',
title: 'Withdrawals',
count: addressTabsCountersQuery.data?.withdrawals_count,
component: <AddressWithdrawals scrollRef={ tabsScrollRef } shouldRender={ !isTabsLoading }/>,
component: <AddressWithdrawals scrollRef={ tabsScrollRef } shouldRender={ !isTabsLoading } isQueryEnabled={ areQueriesEnabled }/>,
} :
undefined,
{
id: 'token_transfers',
title: 'Token transfers',
count: addressTabsCountersQuery.data?.token_transfers_count,
component: <AddressTokenTransfers scrollRef={ tabsScrollRef } shouldRender={ !isTabsLoading }/>,
component: <AddressTokenTransfers scrollRef={ tabsScrollRef } shouldRender={ !isTabsLoading } isQueryEnabled={ areQueriesEnabled }/>,
},
{
id: 'tokens',
title: 'Tokens',
count: addressTabsCountersQuery.data?.token_balances_count,
component: <AddressTokens shouldRender={ !isTabsLoading }/>,
component: <AddressTokens shouldRender={ !isTabsLoading } isQueryEnabled={ areQueriesEnabled }/>,
subTabs: TOKEN_TABS,
},
{
id: 'internal_txns',
title: 'Internal txns',
count: addressTabsCountersQuery.data?.internal_txs_count,
component: <AddressInternalTxs scrollRef={ tabsScrollRef } shouldRender={ !isTabsLoading }/>,
component: <AddressInternalTxs scrollRef={ tabsScrollRef } shouldRender={ !isTabsLoading } isQueryEnabled={ areQueriesEnabled }/>,
},
{
id: 'coin_balance_history',
title: 'Coin balance history',
component: <AddressCoinBalance shouldRender={ !isTabsLoading }/>,
component: <AddressCoinBalance shouldRender={ !isTabsLoading } isQueryEnabled={ areQueriesEnabled }/>,
},
config.chain.verificationType === 'validation' && addressTabsCountersQuery.data?.validations_count ?
{
id: 'blocks_validated',
title: 'Blocks validated',
count: addressTabsCountersQuery.data?.validations_count,
component: <AddressBlocksValidated scrollRef={ tabsScrollRef } shouldRender={ !isTabsLoading }/>,
component: <AddressBlocksValidated scrollRef={ tabsScrollRef } shouldRender={ !isTabsLoading } isQueryEnabled={ areQueriesEnabled }/>,
} :
undefined,
addressTabsCountersQuery.data?.logs_count ?
......@@ -185,7 +187,7 @@ const AddressPageContent = () => {
id: 'logs',
title: 'Logs',
count: addressTabsCountersQuery.data?.logs_count,
component: <AddressLogs scrollRef={ tabsScrollRef } shouldRender={ !isTabsLoading }/>,
component: <AddressLogs scrollRef={ tabsScrollRef } shouldRender={ !isTabsLoading } isQueryEnabled={ areQueriesEnabled }/>,
} :
undefined,
......@@ -203,11 +205,17 @@ const AddressPageContent = () => {
return 'Contract';
},
component: <AddressContract tabs={ contractTabs.tabs } shouldRender={ !isTabsLoading } isLoading={ contractTabs.isLoading }/>,
component: (
<AddressContract
tabs={ contractTabs.tabs }
shouldRender={ !isTabsLoading }
isLoading={ contractTabs.isLoading }
/>
),
subTabs: contractTabs.tabs.map(tab => tab.id),
} : undefined,
].filter(Boolean);
}, [ addressQuery.data, contractTabs, addressTabsCountersQuery.data, userOpsAccountQuery.data, isTabsLoading ]);
}, [ addressQuery.data, contractTabs, addressTabsCountersQuery.data, userOpsAccountQuery.data, isTabsLoading, areQueriesEnabled ]);
const tags: Array<EntityTag> = React.useMemo(() => {
return [
......
......@@ -3,8 +3,8 @@ import { useMemo } from 'react';
import useAddressMetadataInfoQuery from 'lib/address/useAddressMetadataInfoQuery';
export default function useAppActionData(address: string | undefined = '', isEnabled = false) {
const memoizedArray = useMemo(() => (address && isEnabled) ? [ address ] : [], [ address, isEnabled ]);
const { data } = useAddressMetadataInfoQuery(memoizedArray);
const memoizedArray = useMemo(() => address ? [ address ] : [], [ address ]);
const { data } = useAddressMetadataInfoQuery(memoizedArray, isEnabled);
const metadata = data?.addresses[address?.toLowerCase()];
const tag = metadata?.tags?.find(({ tagType }) => tagType === 'protocol');
if (tag?.meta?.appMarketplaceURL || tag?.meta?.appID) {
......
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