mirror of
https://github.com/luxfi/explore.git
synced 2026-09-24 00:28:18 +00:00
* Support redirect to a correct view from search * show domains on address page * migrate to new API version to display address domains * another api update * new design for chain widget on home page + tests * chain widget styles for mobile devices * ecosystems page * update types * add ecosystems to navigation * address portfolio: pt.1 * portfolio tokens list * filter portfolio by chain * skip redirect when navigating to search result by clicking on "show all results" link * net worth block design * add filter input to chain select and fix tokens table * calculate address portfolio * adjust card logic * support custom token types in multichain explorer * handle case when new worth is 0 * add text filter to tokens list * fixes * demo envs * portfolio tests * ecosystems test * change signature for getTokenTypes function * fix adding token to the wallet from the list * lazy load all address domains * show contract creator and implementations info * fix tests * add poor reputation tokens toggle * tweaks * dim celo native tokens * disable env validator * fix tests * remove tokens with 0 usd value from top tokens * fixes * preserve selected chain when switching tabs on address page * add hints to stats widgets on home page * update envs for demo * fix portfolio cards and home page * update styles for contract creator and implementations * fix select issues * add chains from cluster to network menu * hide csv export link on empty logs page * update screenshots * rollback select fix * update cut length calculation for portfolio cards * fix chain select * update screenshots * fix tests * more fixes * add sorting to ecosystems table * fix test * fixes * fix loading state in ecosystems page * review fixes * fix tests
135 lines
5.4 KiB
TypeScript
135 lines
5.4 KiB
TypeScript
import { Grid } from '@chakra-ui/react';
|
|
import type { UseQueryResult } from '@tanstack/react-query';
|
|
import { useRouter } from 'next/router';
|
|
import type { Channel } from 'phoenix';
|
|
import React from 'react';
|
|
|
|
import type { Address } from 'types/api/address';
|
|
import type { AddressImplementation } from 'types/api/addressParams';
|
|
import type { SmartContract } from 'types/api/contract';
|
|
|
|
import type { ResourceError } from 'lib/api/resources';
|
|
import useApiQuery from 'lib/api/useApiQuery';
|
|
import { useMultichainContext } from 'lib/contexts/multichain';
|
|
import getQueryParamString from 'lib/router/getQueryParamString';
|
|
import * as stubs from 'stubs/contract';
|
|
import RoutedTabs from 'toolkit/components/RoutedTabs/RoutedTabs';
|
|
import DataFetchAlert from 'ui/shared/DataFetchAlert';
|
|
|
|
import ContractDetailsAlerts from './alerts/ContractDetailsAlerts';
|
|
import ContractSourceAddressSelector from './ContractSourceAddressSelector';
|
|
import ContractDetailsInfo from './info/ContractDetailsInfo';
|
|
import ContractDetailsInfoCreator from './info/ContractDetailsInfoCreator';
|
|
import ContractDetailsInfoImplementations from './info/ContractDetailsInfoImplementations';
|
|
import useContractDetailsTabs from './useContractDetailsTabs';
|
|
|
|
const TAB_LIST_PROPS = { flexWrap: 'wrap', rowGap: 2 };
|
|
const LEFT_SLOT_PROPS = { w: { base: '100%', lg: 'auto' } };
|
|
|
|
type Props = {
|
|
addressData: Address;
|
|
channel: Channel | undefined;
|
|
mainContractQuery: UseQueryResult<SmartContract, ResourceError>;
|
|
};
|
|
|
|
const ContractDetails = ({ addressData, channel, mainContractQuery }: Props) => {
|
|
const router = useRouter();
|
|
const sourceAddress = getQueryParamString(router.query.source_address);
|
|
const multichainContext = useMultichainContext();
|
|
|
|
const sourceItems: Array<AddressImplementation> = React.useMemo(() => {
|
|
const currentAddressDefaultName = addressData?.proxy_type === 'eip7702' ? 'Current address' : 'Current contract';
|
|
const currentAddressItem = { address_hash: addressData.hash, name: addressData?.name || currentAddressDefaultName };
|
|
if (!addressData || !addressData.implementations || addressData.implementations.length === 0) {
|
|
return [ currentAddressItem ];
|
|
}
|
|
|
|
return [
|
|
currentAddressItem,
|
|
...(addressData?.implementations.filter((item) => item.address_hash !== addressData.hash && item.name) || []),
|
|
];
|
|
}, [ addressData ]);
|
|
|
|
const [ selectedItem, setSelectedItem ] = React.useState<AddressImplementation | undefined>(undefined);
|
|
|
|
React.useEffect(() => {
|
|
if (!mainContractQuery.isPlaceholderData) {
|
|
setSelectedItem(sourceItems.find((item) => item.address_hash === sourceAddress) || sourceItems[0]);
|
|
}
|
|
}, [ mainContractQuery.isPlaceholderData, sourceAddress, sourceItems ]);
|
|
|
|
const contractQuery = useApiQuery('general:contract', {
|
|
pathParams: { hash: selectedItem?.address_hash },
|
|
queryOptions: {
|
|
enabled: Boolean(selectedItem?.address_hash && !mainContractQuery.isPlaceholderData && selectedItem.address_hash !== addressData.hash),
|
|
refetchOnMount: false,
|
|
placeholderData: addressData?.is_verified ? stubs.CONTRACT_CODE_VERIFIED : stubs.CONTRACT_CODE_UNVERIFIED,
|
|
},
|
|
});
|
|
const { data, isPlaceholderData, isError } = selectedItem?.address_hash !== addressData.hash ? contractQuery : mainContractQuery;
|
|
|
|
const tabs = useContractDetailsTabs({ data, isLoading: isPlaceholderData, addressData, sourceAddress: selectedItem?.address_hash });
|
|
|
|
if (isError) {
|
|
return <DataFetchAlert/>;
|
|
}
|
|
|
|
const addressSelector = sourceItems.length > 1 && selectedItem ? (
|
|
<ContractSourceAddressSelector
|
|
isLoading={ mainContractQuery.isPlaceholderData }
|
|
label="Source code"
|
|
items={ sourceItems }
|
|
selectedItem={ selectedItem }
|
|
onItemSelect={ setSelectedItem }
|
|
mr={{ lg: 8 }}
|
|
/>
|
|
) : null;
|
|
|
|
return (
|
|
<>
|
|
<ContractDetailsAlerts
|
|
data={ mainContractQuery.data }
|
|
isLoading={ mainContractQuery.isPlaceholderData }
|
|
addressData={ addressData }
|
|
channel={ channel }
|
|
/>
|
|
{ mainContractQuery.data?.is_verified && (
|
|
<ContractDetailsInfo
|
|
data={ mainContractQuery.data }
|
|
isLoading={ mainContractQuery.isPlaceholderData }
|
|
addressData={ addressData }
|
|
/>
|
|
) }
|
|
{ !mainContractQuery.data?.is_verified && multichainContext && (
|
|
<Grid templateColumns={{ base: 'auto 1fr', lg: 'auto 1fr auto 1fr' }} rowGap={ 4 } columnGap={ 3 } mb={ 8 } _empty={{ display: 'none' }}>
|
|
{ addressData.creator_address_hash && addressData.creation_transaction_hash && (
|
|
<ContractDetailsInfoCreator
|
|
addressHash={ addressData.creator_address_hash }
|
|
txHash={ addressData.creation_transaction_hash }
|
|
creationStatus={ addressData.creation_status }
|
|
isLoading={ mainContractQuery.isPlaceholderData }
|
|
/>
|
|
) }
|
|
{ addressData.implementations && addressData.implementations.length > 0 && !mainContractQuery.isPlaceholderData && (
|
|
<ContractDetailsInfoImplementations
|
|
implementations={ addressData.implementations }
|
|
proxyType={ addressData.proxy_type }
|
|
/>
|
|
) }
|
|
</Grid>
|
|
) }
|
|
<RoutedTabs
|
|
tabs={ tabs }
|
|
isLoading={ isPlaceholderData }
|
|
variant="segmented"
|
|
size="sm"
|
|
leftSlot={ addressSelector }
|
|
listProps={ TAB_LIST_PROPS }
|
|
leftSlotProps={ LEFT_SLOT_PROPS }
|
|
/>
|
|
</>
|
|
);
|
|
};
|
|
|
|
export default ContractDetails;
|