mirror of
https://github.com/luxfi/explore.git
synced 2026-09-24 00:28:18 +00:00
Merge branch 'main' of github.com:blockscout/frontend into long-skeleton
This commit is contained in:
@@ -0,0 +1,38 @@
|
||||
import React from 'react';
|
||||
|
||||
import type { Address } from 'types/api/address';
|
||||
|
||||
import notEmpty from 'lib/notEmpty';
|
||||
import ContractCode from 'ui/address/contract/ContractCode';
|
||||
import ContractRead from 'ui/address/contract/ContractRead';
|
||||
import ContractWrite from 'ui/address/contract/ContractWrite';
|
||||
|
||||
export default function useContractTabs(data: Address | undefined) {
|
||||
return React.useMemo(() => {
|
||||
return [
|
||||
{ id: 'contact_code', title: 'Code', component: <ContractCode addressHash={ data?.hash }/> },
|
||||
// this is not implemented in api yet
|
||||
// data?.has_decompiled_code ?
|
||||
// { id: 'contact_decompiled_code', title: 'Decompiled code', component: <div>Decompiled code</div> } :
|
||||
// undefined,
|
||||
data?.has_methods_read ?
|
||||
{ id: 'read_contract', title: 'Read contract', component: <ContractRead addressHash={ data?.hash }/> } :
|
||||
undefined,
|
||||
data?.has_methods_read_proxy ?
|
||||
{ id: 'read_proxy', title: 'Read proxy', component: <ContractRead addressHash={ data?.hash } isProxy/> } :
|
||||
undefined,
|
||||
data?.has_custom_methods_read ?
|
||||
{ id: 'read_custom_methods', title: 'Read custom', component: <ContractRead addressHash={ data?.hash } isCustomAbi/> } :
|
||||
undefined,
|
||||
data?.has_methods_write ?
|
||||
{ id: 'write_contract', title: 'Write contract', component: <ContractWrite addressHash={ data?.hash }/> } :
|
||||
undefined,
|
||||
data?.has_methods_write_proxy ?
|
||||
{ id: 'write_proxy', title: 'Write proxy', component: <ContractWrite addressHash={ data?.hash } isProxy/> } :
|
||||
undefined,
|
||||
data?.has_custom_methods_write ?
|
||||
{ id: 'write_custom_methods', title: 'Write custom', component: <ContractWrite addressHash={ data?.hash } isCustomAbi/> } :
|
||||
undefined,
|
||||
].filter(notEmpty);
|
||||
}, [ data ]);
|
||||
}
|
||||
@@ -17,6 +17,7 @@ import RoutedTabs from 'ui/shared/RoutedTabs/RoutedTabs';
|
||||
|
||||
interface Props {
|
||||
tabs: Array<RoutedSubTab>;
|
||||
addressHash?: string;
|
||||
}
|
||||
|
||||
export const currentChain: Chain = {
|
||||
@@ -58,12 +59,12 @@ const TAB_LIST_PROPS = {
|
||||
columnGap: 3,
|
||||
};
|
||||
|
||||
const AddressContract = ({ tabs }: Props) => {
|
||||
const AddressContract = ({ addressHash, tabs }: Props) => {
|
||||
const modalZIndex = useToken<string>('zIndices', 'modal');
|
||||
|
||||
return (
|
||||
<WagmiConfig client={ wagmiClient }>
|
||||
<ContractContextProvider>
|
||||
<ContractContextProvider addressHash={ addressHash }>
|
||||
<RoutedTabs tabs={ tabs } variant="outline" colorScheme="gray" size="sm" tabListProps={ TAB_LIST_PROPS }/>
|
||||
</ContractContextProvider>
|
||||
<Web3Modal
|
||||
|
||||
@@ -92,7 +92,7 @@ const AddressDetails = ({ addressQuery, scrollRef }: Props) => {
|
||||
<Text fontSize="sm">Verify with other explorers</Text>
|
||||
{ explorers.map((explorer) => {
|
||||
const url = new URL(explorer.paths.address + '/' + addressHash, explorer.baseUrl);
|
||||
return <LinkExternal key={ explorer.baseUrl } title={ explorer.title } href={ url.toString() }/>;
|
||||
return <LinkExternal key={ explorer.baseUrl } href={ url.toString() }>{ explorer.title }</LinkExternal>;
|
||||
}) }
|
||||
</Flex>
|
||||
) }
|
||||
|
||||
@@ -23,7 +23,7 @@ test('verified with changed byte code +@mobile +@dark-mode', async({ mount, page
|
||||
|
||||
const component = await mount(
|
||||
<TestApp>
|
||||
<ContractCode/>
|
||||
<ContractCode addressHash={ addressHash }/>
|
||||
</TestApp>,
|
||||
{ hooksConfig },
|
||||
);
|
||||
@@ -39,7 +39,7 @@ test('verified with multiple sources +@mobile', async({ mount, page }) => {
|
||||
|
||||
await mount(
|
||||
<TestApp>
|
||||
<ContractCode/>
|
||||
<ContractCode addressHash={ addressHash }/>
|
||||
</TestApp>,
|
||||
{ hooksConfig },
|
||||
);
|
||||
@@ -57,7 +57,7 @@ test('verified via sourcify', async({ mount, page }) => {
|
||||
|
||||
await mount(
|
||||
<TestApp>
|
||||
<ContractCode/>
|
||||
<ContractCode addressHash={ addressHash }/>
|
||||
</TestApp>,
|
||||
{ hooksConfig },
|
||||
);
|
||||
@@ -73,7 +73,7 @@ test('self destructed', async({ mount, page }) => {
|
||||
|
||||
await mount(
|
||||
<TestApp>
|
||||
<ContractCode/>
|
||||
<ContractCode addressHash={ addressHash }/>
|
||||
</TestApp>,
|
||||
{ hooksConfig },
|
||||
);
|
||||
@@ -90,7 +90,7 @@ test('with twin address alert +@mobile', async({ mount, page }) => {
|
||||
|
||||
const component = await mount(
|
||||
<TestApp>
|
||||
<ContractCode/>
|
||||
<ContractCode addressHash={ addressHash }/>
|
||||
</TestApp>,
|
||||
{ hooksConfig },
|
||||
);
|
||||
@@ -106,7 +106,7 @@ test('with proxy address alert +@mobile', async({ mount, page }) => {
|
||||
|
||||
const component = await mount(
|
||||
<TestApp>
|
||||
<ContractCode/>
|
||||
<ContractCode addressHash={ addressHash }/>
|
||||
</TestApp>,
|
||||
{ hooksConfig },
|
||||
);
|
||||
@@ -122,7 +122,7 @@ test('non verified', async({ mount, page }) => {
|
||||
|
||||
const component = await mount(
|
||||
<TestApp>
|
||||
<ContractCode/>
|
||||
<ContractCode addressHash={ addressHash }/>
|
||||
</TestApp>,
|
||||
{ hooksConfig },
|
||||
);
|
||||
|
||||
@@ -1,11 +1,9 @@
|
||||
import { Flex, Skeleton, Button, Grid, GridItem, Text, Alert, Link, chakra, Box } from '@chakra-ui/react';
|
||||
import { useRouter } from 'next/router';
|
||||
import { route } from 'nextjs-routes';
|
||||
import React from 'react';
|
||||
|
||||
import useApiQuery from 'lib/api/useApiQuery';
|
||||
import dayjs from 'lib/date/dayjs';
|
||||
import getQueryParamString from 'lib/router/getQueryParamString';
|
||||
import Address from 'ui/shared/address/Address';
|
||||
import AddressIcon from 'ui/shared/address/AddressIcon';
|
||||
import AddressLink from 'ui/shared/address/AddressLink';
|
||||
@@ -16,6 +14,10 @@ import RawDataSnippet from 'ui/shared/RawDataSnippet';
|
||||
|
||||
import ContractSourceCode from './ContractSourceCode';
|
||||
|
||||
type Props = {
|
||||
addressHash?: string;
|
||||
}
|
||||
|
||||
const InfoItem = chakra(({ label, value, className }: { label: string; value: string; className?: string }) => (
|
||||
<GridItem display="flex" columnGap={ 6 } wordBreak="break-all" className={ className }>
|
||||
<Text w="170px" flexShrink={ 0 } fontWeight={ 500 }>{ label }</Text>
|
||||
@@ -23,10 +25,7 @@ const InfoItem = chakra(({ label, value, className }: { label: string; value: st
|
||||
</GridItem>
|
||||
));
|
||||
|
||||
const ContractCode = () => {
|
||||
const router = useRouter();
|
||||
|
||||
const addressHash = getQueryParamString(router.query.hash);
|
||||
const ContractCode = ({ addressHash }: Props) => {
|
||||
const { data, isLoading, isError } = useApiQuery('contract', {
|
||||
pathParams: { hash: addressHash },
|
||||
queryOptions: {
|
||||
@@ -62,7 +61,7 @@ const ContractCode = () => {
|
||||
ml="auto"
|
||||
mr={ 3 }
|
||||
as="a"
|
||||
href={ route({ pathname: '/address/[hash]/contract_verification', query: { hash: addressHash } }) }
|
||||
href={ route({ pathname: '/address/[hash]/contract_verification', query: { hash: addressHash || '' } }) }
|
||||
>
|
||||
Verify & publish
|
||||
</Button>
|
||||
@@ -115,7 +114,7 @@ const ContractCode = () => {
|
||||
{ data.is_verified_via_sourcify && (
|
||||
<Alert status="warning" whiteSpace="pre-wrap" flexWrap="wrap">
|
||||
<span>This contract has been { data.is_partially_verified ? 'partially ' : '' }verified via Sourcify. </span>
|
||||
{ data.sourcify_repo_url && <LinkExternal href={ data.sourcify_repo_url } title="View contract in Sourcify repository" fontSize="md"/> }
|
||||
{ data.sourcify_repo_url && <LinkExternal href={ data.sourcify_repo_url } fontSize="md">View contract in Sourcify repository</LinkExternal> }
|
||||
</Alert>
|
||||
) }
|
||||
{ data.is_changed_bytecode && (
|
||||
@@ -131,7 +130,9 @@ const ContractCode = () => {
|
||||
<AddressLink type="address" hash={ data.verified_twin_address_hash } truncation="constant" ml={ 2 }/>
|
||||
</Address>
|
||||
<chakra.span mt={ 1 }>All functions displayed below are from ABI of that contract. In order to verify current contract, proceed with </chakra.span>
|
||||
<LinkInternal href={ route({ pathname: '/address/[hash]/contract_verification', query: { hash: addressHash } }) }>Verify & Publish</LinkInternal>
|
||||
<LinkInternal href={ route({ pathname: '/address/[hash]/contract_verification', query: { hash: addressHash || '' } }) }>
|
||||
Verify & Publish
|
||||
</LinkInternal>
|
||||
<span> page</span>
|
||||
</Alert>
|
||||
) }
|
||||
|
||||
@@ -28,7 +28,7 @@ test('base view +@mobile +@dark-mode', async({ mount, page }) => {
|
||||
|
||||
const component = await mount(
|
||||
<TestApp>
|
||||
<ContractRead/>
|
||||
<ContractRead addressHash={ addressHash }/>
|
||||
</TestApp>,
|
||||
{ hooksConfig },
|
||||
);
|
||||
@@ -57,7 +57,7 @@ test('error result', async({ mount, page }) => {
|
||||
|
||||
const component = await mount(
|
||||
<TestApp>
|
||||
<ContractRead/>
|
||||
<ContractRead addressHash={ addressHash }/>
|
||||
</TestApp>,
|
||||
{ hooksConfig },
|
||||
);
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
import { Alert, Flex } from '@chakra-ui/react';
|
||||
import { useRouter } from 'next/router';
|
||||
import React from 'react';
|
||||
import { useAccount } from 'wagmi';
|
||||
|
||||
@@ -7,7 +6,6 @@ import type { SmartContractReadMethod, SmartContractQueryMethodRead } from 'type
|
||||
|
||||
import useApiFetch from 'lib/api/useApiFetch';
|
||||
import useApiQuery from 'lib/api/useApiQuery';
|
||||
import getQueryParamString from 'lib/router/getQueryParamString';
|
||||
import ContractMethodsAccordion from 'ui/address/contract/ContractMethodsAccordion';
|
||||
import ContentLoader from 'ui/shared/ContentLoader';
|
||||
import DataFetchAlert from 'ui/shared/DataFetchAlert';
|
||||
@@ -20,17 +18,15 @@ import ContractMethodConstant from './ContractMethodConstant';
|
||||
import ContractReadResult from './ContractReadResult';
|
||||
|
||||
interface Props {
|
||||
addressHash?: string;
|
||||
isProxy?: boolean;
|
||||
isCustomAbi?: boolean;
|
||||
}
|
||||
|
||||
const ContractRead = ({ isProxy, isCustomAbi }: Props) => {
|
||||
const router = useRouter();
|
||||
const ContractRead = ({ addressHash, isProxy, isCustomAbi }: Props) => {
|
||||
const apiFetch = useApiFetch();
|
||||
const { address: userAddress } = useAccount();
|
||||
|
||||
const addressHash = getQueryParamString(router.query.hash);
|
||||
|
||||
const { data, isLoading, isError } = useApiQuery(isProxy ? 'contract_methods_read_proxy' : 'contract_methods_read', {
|
||||
pathParams: { hash: addressHash },
|
||||
queryParams: {
|
||||
|
||||
@@ -23,7 +23,7 @@ test('base view +@mobile', async({ mount, page }) => {
|
||||
|
||||
const component = await mount(
|
||||
<TestApp>
|
||||
<ContractWrite/>
|
||||
<ContractWrite addressHash={ addressHash }/>
|
||||
</TestApp>,
|
||||
{ hooksConfig },
|
||||
);
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
import _capitalize from 'lodash/capitalize';
|
||||
import { useRouter } from 'next/router';
|
||||
import React from 'react';
|
||||
import { useAccount, useSigner } from 'wagmi';
|
||||
|
||||
@@ -7,7 +6,6 @@ import type { SmartContractWriteMethod } from 'types/api/contract';
|
||||
|
||||
import config from 'configs/app/config';
|
||||
import useApiQuery from 'lib/api/useApiQuery';
|
||||
import getQueryParamString from 'lib/router/getQueryParamString';
|
||||
import ContractMethodsAccordion from 'ui/address/contract/ContractMethodsAccordion';
|
||||
import ContentLoader from 'ui/shared/ContentLoader';
|
||||
import DataFetchAlert from 'ui/shared/DataFetchAlert';
|
||||
@@ -21,14 +19,12 @@ import ContractWriteResult from './ContractWriteResult';
|
||||
import { getNativeCoinValue, isExtendedError } from './utils';
|
||||
|
||||
interface Props {
|
||||
addressHash?: string;
|
||||
isProxy?: boolean;
|
||||
isCustomAbi?: boolean;
|
||||
}
|
||||
|
||||
const ContractWrite = ({ isProxy, isCustomAbi }: Props) => {
|
||||
const router = useRouter();
|
||||
|
||||
const addressHash = getQueryParamString(router.query.hash);
|
||||
const ContractWrite = ({ addressHash, isProxy, isCustomAbi }: Props) => {
|
||||
const { data: signer } = useSigner();
|
||||
const { isConnected } = useAccount();
|
||||
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
import { useQueryClient } from '@tanstack/react-query';
|
||||
import type { Contract } from 'ethers';
|
||||
import { useRouter } from 'next/router';
|
||||
import React from 'react';
|
||||
import { useContract, useProvider, useSigner } from 'wagmi';
|
||||
|
||||
@@ -9,6 +8,7 @@ import type { Address } from 'types/api/address';
|
||||
import useApiQuery, { getResourceKey } from 'lib/api/useApiQuery';
|
||||
|
||||
type ProviderProps = {
|
||||
addressHash?: string;
|
||||
children: React.ReactNode;
|
||||
}
|
||||
|
||||
@@ -24,13 +24,11 @@ const ContractContext = React.createContext<TContractContext>({
|
||||
custom: null,
|
||||
});
|
||||
|
||||
export function ContractContextProvider({ children }: ProviderProps) {
|
||||
const router = useRouter();
|
||||
export function ContractContextProvider({ addressHash, children }: ProviderProps) {
|
||||
const provider = useProvider();
|
||||
const { data: signer } = useSigner();
|
||||
const queryClient = useQueryClient();
|
||||
|
||||
const addressHash = router.query.hash?.toString();
|
||||
const { data: contractInfo } = useApiQuery('contract', {
|
||||
pathParams: { hash: addressHash },
|
||||
queryOptions: {
|
||||
|
||||
+4
-32
@@ -8,6 +8,7 @@ import type { RoutedTab } from 'ui/shared/RoutedTabs/types';
|
||||
import iconSuccess from 'icons/status/success.svg';
|
||||
import useApiQuery from 'lib/api/useApiQuery';
|
||||
import { useAppContext } from 'lib/appContext';
|
||||
import useContractTabs from 'lib/hooks/useContractTabs';
|
||||
import notEmpty from 'lib/notEmpty';
|
||||
import getQueryParamString from 'lib/router/getQueryParamString';
|
||||
import AddressBlocksValidated from 'ui/address/AddressBlocksValidated';
|
||||
@@ -19,9 +20,6 @@ import AddressLogs from 'ui/address/AddressLogs';
|
||||
import AddressTokens from 'ui/address/AddressTokens';
|
||||
import AddressTokenTransfers from 'ui/address/AddressTokenTransfers';
|
||||
import AddressTxs from 'ui/address/AddressTxs';
|
||||
import ContractCode from 'ui/address/contract/ContractCode';
|
||||
import ContractRead from 'ui/address/contract/ContractRead';
|
||||
import ContractWrite from 'ui/address/contract/ContractWrite';
|
||||
import AdBanner from 'ui/shared/ad/AdBanner';
|
||||
import TextAd from 'ui/shared/ad/TextAd';
|
||||
import Page from 'ui/shared/Page/Page';
|
||||
@@ -58,33 +56,7 @@ const AddressPageContent = () => {
|
||||
...(addressQuery.data?.watchlist_names || []),
|
||||
].map((tag) => <Tag key={ tag.label }>{ tag.display_name }</Tag>);
|
||||
|
||||
const contractTabs = React.useMemo(() => {
|
||||
return [
|
||||
{ id: 'contact_code', title: 'Code', component: <ContractCode/> },
|
||||
// this is not implemented in api yet
|
||||
// addressQuery.data?.has_decompiled_code ?
|
||||
// { id: 'contact_decompiled_code', title: 'Decompiled code', component: <div>Decompiled code</div> } :
|
||||
// undefined,
|
||||
addressQuery.data?.has_methods_read ?
|
||||
{ id: 'read_contract', title: 'Read contract', component: <ContractRead/> } :
|
||||
undefined,
|
||||
addressQuery.data?.has_methods_read_proxy ?
|
||||
{ id: 'read_proxy', title: 'Read proxy', component: <ContractRead isProxy/> } :
|
||||
undefined,
|
||||
addressQuery.data?.has_custom_methods_read ?
|
||||
{ id: 'read_custom_methods', title: 'Read custom', component: <ContractRead isCustomAbi/> } :
|
||||
undefined,
|
||||
addressQuery.data?.has_methods_write ?
|
||||
{ id: 'write_contract', title: 'Write contract', component: <ContractWrite/> } :
|
||||
undefined,
|
||||
addressQuery.data?.has_methods_write_proxy ?
|
||||
{ id: 'write_proxy', title: 'Write proxy', component: <ContractWrite isProxy/> } :
|
||||
undefined,
|
||||
addressQuery.data?.has_custom_methods_write ?
|
||||
{ id: 'write_custom_methods', title: 'Write custom', component: <ContractWrite isCustomAbi/> } :
|
||||
undefined,
|
||||
].filter(notEmpty);
|
||||
}, [ addressQuery.data ]);
|
||||
const contractTabs = useContractTabs(addressQuery.data);
|
||||
|
||||
const tabs: Array<RoutedTab> = React.useMemo(() => {
|
||||
return [
|
||||
@@ -113,11 +85,11 @@ const AddressPageContent = () => {
|
||||
|
||||
return 'Contract';
|
||||
},
|
||||
component: <AddressContract tabs={ contractTabs }/>,
|
||||
component: <AddressContract tabs={ contractTabs } addressHash={ hash }/>,
|
||||
subTabs: contractTabs.map(tab => tab.id),
|
||||
} : undefined,
|
||||
].filter(notEmpty);
|
||||
}, [ addressQuery.data, contractTabs ]);
|
||||
}, [ addressQuery.data, contractTabs, hash ]);
|
||||
|
||||
const tagsNode = tags.length > 0 ? <Flex columnGap={ 2 }>{ tags }</Flex> : null;
|
||||
|
||||
|
||||
+39
-10
@@ -1,14 +1,18 @@
|
||||
import { Skeleton, Box, Flex, SkeletonCircle } from '@chakra-ui/react';
|
||||
import { Skeleton, Box, Flex, SkeletonCircle, Icon } from '@chakra-ui/react';
|
||||
import { useRouter } from 'next/router';
|
||||
import React, { useEffect } from 'react';
|
||||
|
||||
import type { RoutedTab } from 'ui/shared/RoutedTabs/types';
|
||||
|
||||
import iconSuccess from 'icons/status/success.svg';
|
||||
import useApiQuery from 'lib/api/useApiQuery';
|
||||
import { useAppContext } from 'lib/appContext';
|
||||
import useContractTabs from 'lib/hooks/useContractTabs';
|
||||
import useIsMobile from 'lib/hooks/useIsMobile';
|
||||
import useQueryWithPages from 'lib/hooks/useQueryWithPages';
|
||||
import notEmpty from 'lib/notEmpty';
|
||||
import trimTokenSymbol from 'lib/token/trimTokenSymbol';
|
||||
import AddressContract from 'ui/address/AddressContract';
|
||||
import AdBanner from 'ui/shared/ad/AdBanner';
|
||||
import TextAd from 'ui/shared/ad/TextAd';
|
||||
import Page from 'ui/shared/Page/Page';
|
||||
@@ -36,8 +40,10 @@ const TokenPageContent = () => {
|
||||
|
||||
const scrollRef = React.useRef<HTMLDivElement>(null);
|
||||
|
||||
const hashString = router.query.hash?.toString();
|
||||
|
||||
const tokenQuery = useApiQuery('token', {
|
||||
pathParams: { hash: router.query.hash?.toString() },
|
||||
pathParams: { hash: hashString },
|
||||
queryOptions: { enabled: Boolean(router.query.hash) },
|
||||
});
|
||||
|
||||
@@ -58,7 +64,7 @@ const TokenPageContent = () => {
|
||||
|
||||
const transfersQuery = useQueryWithPages({
|
||||
resourceName: 'token_transfers',
|
||||
pathParams: { hash: router.query.hash?.toString() },
|
||||
pathParams: { hash: hashString },
|
||||
scrollRef,
|
||||
options: {
|
||||
enabled: Boolean(router.query.hash && (!router.query.tab || router.query.tab === 'token_transfers') && tokenQuery.data),
|
||||
@@ -67,7 +73,7 @@ const TokenPageContent = () => {
|
||||
|
||||
const holdersQuery = useQueryWithPages({
|
||||
resourceName: 'token_holders',
|
||||
pathParams: { hash: router.query.hash?.toString() },
|
||||
pathParams: { hash: hashString },
|
||||
scrollRef,
|
||||
options: {
|
||||
enabled: Boolean(router.query.hash && router.query.tab === 'holders' && tokenQuery.data),
|
||||
@@ -76,21 +82,44 @@ const TokenPageContent = () => {
|
||||
|
||||
const inventoryQuery = useQueryWithPages({
|
||||
resourceName: 'token_inventory',
|
||||
pathParams: { hash: router.query.hash?.toString() },
|
||||
pathParams: { hash: hashString },
|
||||
scrollRef,
|
||||
options: {
|
||||
enabled: Boolean(router.query.hash && router.query.tab === 'inventory' && tokenQuery.data),
|
||||
},
|
||||
});
|
||||
|
||||
const contractQuery = useApiQuery('address', {
|
||||
pathParams: { hash: hashString },
|
||||
queryOptions: { enabled: Boolean(router.query.hash) },
|
||||
});
|
||||
|
||||
const contractTabs = useContractTabs(contractQuery.data);
|
||||
|
||||
const tabs: Array<RoutedTab> = [
|
||||
{ id: 'token_transfers', title: 'Token transfers', component: <TokenTransfer transfersQuery={ transfersQuery }/> },
|
||||
{ id: 'holders', title: 'Holders', component: <TokenHolders tokenQuery={ tokenQuery } holdersQuery={ holdersQuery }/> },
|
||||
];
|
||||
(tokenQuery.data?.type === 'ERC-1155' || tokenQuery.data?.type === 'ERC-721') ?
|
||||
{ id: 'inventory', title: 'Inventory', component: <TokenInventory inventoryQuery={ inventoryQuery }/> } :
|
||||
undefined,
|
||||
contractQuery.data?.is_contract ? {
|
||||
id: 'contract',
|
||||
title: () => {
|
||||
if (contractQuery.data.is_verified) {
|
||||
return (
|
||||
<>
|
||||
<span>Contract</span>
|
||||
<Icon as={ iconSuccess } boxSize="14px" color="green.500" ml={ 1 }/>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
if (tokenQuery.data?.type === 'ERC-1155' || tokenQuery.data?.type === 'ERC-721') {
|
||||
tabs.push({ id: 'inventory', title: 'Inventory', component: <TokenInventory inventoryQuery={ inventoryQuery }/> });
|
||||
}
|
||||
return 'Contract';
|
||||
},
|
||||
component: <AddressContract tabs={ contractTabs } addressHash={ hashString }/>,
|
||||
subTabs: contractTabs.map(tab => tab.id),
|
||||
} : undefined,
|
||||
].filter(notEmpty);
|
||||
|
||||
let hasPagination;
|
||||
let pagination;
|
||||
@@ -151,7 +180,7 @@ const TokenPageContent = () => {
|
||||
{ /* should stay before tabs to scroll up whith pagination */ }
|
||||
<Box ref={ scrollRef }></Box>
|
||||
|
||||
{ tokenQuery.isLoading ? <SkeletonTabs/> : (
|
||||
{ tokenQuery.isLoading || contractQuery.isLoading ? <SkeletonTabs/> : (
|
||||
<RoutedTabs
|
||||
tabs={ tabs }
|
||||
tabListProps={ tabListProps }
|
||||
|
||||
@@ -46,7 +46,7 @@ const TransactionPageContent = () => {
|
||||
.filter((explorer) => explorer.paths.tx)
|
||||
.map((explorer) => {
|
||||
const url = new URL(explorer.paths.tx + '/' + hash, explorer.baseUrl);
|
||||
return <LinkExternal key={ explorer.baseUrl } title={ `Open in ${ explorer.title }` } href={ url.toString() }/>;
|
||||
return <LinkExternal key={ explorer.baseUrl } href={ url.toString() }>{ `Open in ${ explorer.title }` }</LinkExternal>;
|
||||
});
|
||||
|
||||
const additionals = (
|
||||
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 41 KiB After Width: | Height: | Size: 42 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 40 KiB After Width: | Height: | Size: 42 KiB |
@@ -5,14 +5,14 @@ import arrowIcon from 'icons/arrows/north-east.svg';
|
||||
|
||||
interface Props {
|
||||
href: string;
|
||||
title: string;
|
||||
className?: string;
|
||||
children: React.ReactNode;
|
||||
}
|
||||
|
||||
const LinkExternal = ({ href, title, className }: Props) => {
|
||||
const LinkExternal = ({ href, children, className }: Props) => {
|
||||
return (
|
||||
<Link className={ className } fontSize="sm" display="inline-flex" alignItems="center" target="_blank" href={ href }>
|
||||
{ title }
|
||||
{ children }
|
||||
<Icon as={ arrowIcon } boxSize={ 4 }/>
|
||||
</Link>
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user