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
155 lines
6.3 KiB
TypeScript
155 lines
6.3 KiB
TypeScript
import { Flex, useToken } from '@chakra-ui/react';
|
|
import type { UseQueryResult } from '@tanstack/react-query';
|
|
import React from 'react';
|
|
|
|
import type { Address } from 'types/api/address';
|
|
import type { TokenInfo, TokenVerifiedInfo as TTokenVerifiedInfo } from 'types/api/token';
|
|
import type { EntityTag } from 'ui/shared/EntityTags/types';
|
|
|
|
import config from 'configs/app';
|
|
import useAddressMetadataInfoQuery from 'lib/address/useAddressMetadataInfoQuery';
|
|
import type { ResourceError } from 'lib/api/resources';
|
|
import { useMultichainContext } from 'lib/contexts/multichain';
|
|
import { getTokenTypeName } from 'lib/token/tokenTypes';
|
|
import { Tooltip } from 'toolkit/chakra/tooltip';
|
|
import AddressAlerts from 'ui/address/details/AddressAlerts';
|
|
import AddressQrCode from 'ui/address/details/AddressQrCode';
|
|
import AccountActionsMenu from 'ui/shared/AccountActionsMenu/AccountActionsMenu';
|
|
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/EntityTags';
|
|
import formatUserTags from 'ui/shared/EntityTags/formatUserTags';
|
|
import sortEntityTags from 'ui/shared/EntityTags/sortEntityTags';
|
|
import IconSvg from 'ui/shared/IconSvg';
|
|
import NetworkExplorers from 'ui/shared/NetworkExplorers';
|
|
import PageTitle from 'ui/shared/Page/PageTitle';
|
|
|
|
import TokenVerifiedInfo from './TokenVerifiedInfo';
|
|
|
|
const PREDEFINED_TAG_PRIORITY = 100;
|
|
|
|
interface Props {
|
|
tokenQuery: UseQueryResult<TokenInfo, ResourceError<unknown>>;
|
|
addressQuery: UseQueryResult<Address, ResourceError<unknown>>;
|
|
verifiedInfoQuery: UseQueryResult<TTokenVerifiedInfo, ResourceError<unknown>>;
|
|
hash: string;
|
|
}
|
|
|
|
const TokenPageTitle = ({ tokenQuery, addressQuery, verifiedInfoQuery, hash }: Props) => {
|
|
const multichainContext = useMultichainContext();
|
|
const addressHash = !tokenQuery.isPlaceholderData ? (tokenQuery.data?.address_hash || '') : '';
|
|
|
|
const addressesForMetadataQuery = React.useMemo(() => ([ hash ].filter(Boolean)), [ hash ]);
|
|
const addressMetadataQuery = useAddressMetadataInfoQuery(addressesForMetadataQuery);
|
|
|
|
const isLoading = tokenQuery.isPlaceholderData ||
|
|
addressQuery.isPlaceholderData ||
|
|
(config.features.verifiedTokens.isEnabled && verifiedInfoQuery.isPending);
|
|
|
|
const tokenSymbolText = tokenQuery.data?.symbol ? ` (${ tokenQuery.data.symbol })` : '';
|
|
|
|
const [ bridgedTokenTagBgColor ] = useToken('colors', 'blue.500');
|
|
const [ bridgedTokenTagTextColor ] = useToken('colors', 'white');
|
|
|
|
const tags: Array<EntityTag> = React.useMemo(() => {
|
|
return [
|
|
tokenQuery.data ? {
|
|
slug: tokenQuery.data?.type,
|
|
name: getTokenTypeName(tokenQuery.data.type, multichainContext?.chain?.app_config),
|
|
tagType: 'custom' as const,
|
|
ordinal: PREDEFINED_TAG_PRIORITY,
|
|
} : undefined,
|
|
config.features.bridgedTokens.isEnabled && tokenQuery.data?.is_bridged ?
|
|
{
|
|
slug: 'bridged',
|
|
name: 'Bridged',
|
|
tagType: 'custom' as const,
|
|
ordinal: PREDEFINED_TAG_PRIORITY,
|
|
meta: { bgColor: bridgedTokenTagBgColor, textColor: bridgedTokenTagTextColor },
|
|
} :
|
|
undefined,
|
|
...formatUserTags(addressQuery.data),
|
|
verifiedInfoQuery.data?.projectSector ?
|
|
{ slug: verifiedInfoQuery.data.projectSector, name: verifiedInfoQuery.data.projectSector, tagType: 'custom' as const, ordinal: -30 } :
|
|
undefined,
|
|
...(addressMetadataQuery.data?.addresses?.[hash.toLowerCase()]?.tags.filter(tag => tag.tagType !== 'note') || []),
|
|
].filter(Boolean).sort(sortEntityTags);
|
|
}, [
|
|
addressMetadataQuery.data?.addresses,
|
|
addressQuery.data,
|
|
bridgedTokenTagBgColor,
|
|
bridgedTokenTagTextColor,
|
|
tokenQuery.data,
|
|
verifiedInfoQuery.data?.projectSector,
|
|
hash,
|
|
multichainContext?.chain?.app_config,
|
|
]);
|
|
|
|
const contentAfter = (
|
|
<>
|
|
{ tokenQuery.data && <TokenEntity.Reputation value={ tokenQuery.data.reputation } ml={ 0 }/> }
|
|
{ verifiedInfoQuery.data?.tokenAddress && (
|
|
<Tooltip content={ `Information on this token has been verified by ${ config.chain.name }` }>
|
|
<IconSvg name="certified" color="green.500" boxSize={ 6 } cursor="pointer"/>
|
|
</Tooltip>
|
|
) }
|
|
<EntityTags
|
|
isLoading={ isLoading || (config.features.addressMetadata.isEnabled && addressMetadataQuery.isPending) }
|
|
tags={ tags }
|
|
addressHash={ addressQuery.data?.hash }
|
|
flexGrow={ 1 }
|
|
/>
|
|
</>
|
|
);
|
|
|
|
const secondRow = (
|
|
<Flex alignItems="center" w="100%" minW={ 0 } columnGap={ 2 } rowGap={ 2 } flexWrap={{ base: 'wrap', lg: 'nowrap' }}>
|
|
{ addressQuery.data && (
|
|
<AddressEntity
|
|
address={{ ...addressQuery.data, name: '' }}
|
|
isLoading={ isLoading }
|
|
variant="subheading"
|
|
icon={ multichainContext?.chain ? {
|
|
shield: { name: 'pie_chart', isLoading },
|
|
} : undefined }
|
|
/>
|
|
) }
|
|
{ !isLoading && tokenQuery.data && <AddressAddToWallet token={ tokenQuery.data } variant="button"/> }
|
|
{ addressQuery.data && <AddressQrCode hash={ addressQuery.data.hash } isLoading={ isLoading }/> }
|
|
<AccountActionsMenu isLoading={ isLoading }/>
|
|
<Flex ml={{ base: 0, lg: 'auto' }} columnGap={ 2 } flexGrow={{ base: 1, lg: 0 }}>
|
|
<TokenVerifiedInfo verifiedInfoQuery={ verifiedInfoQuery }/>
|
|
<NetworkExplorers type="token" pathParam={ addressHash } ml={{ base: 'auto', lg: 0 }}/>
|
|
</Flex>
|
|
</Flex>
|
|
);
|
|
|
|
return (
|
|
<>
|
|
<PageTitle
|
|
title={ `${ tokenQuery.data?.name || 'Unnamed token' }${ tokenSymbolText }` }
|
|
isLoading={ tokenQuery.isPlaceholderData }
|
|
beforeTitle={ tokenQuery.data ? (
|
|
<TokenEntity.Icon
|
|
token={ tokenQuery.data }
|
|
isLoading={ tokenQuery.isPlaceholderData }
|
|
variant="heading"
|
|
chain={ multichainContext?.chain }
|
|
/>
|
|
) : null }
|
|
contentAfter={ contentAfter }
|
|
secondRow={ secondRow }
|
|
/>
|
|
{ !addressMetadataQuery.isPending && (
|
|
<AddressAlerts
|
|
tags={ addressMetadataQuery.data?.addresses?.[hash.toLowerCase()]?.tags }
|
|
isScamToken={ tokenQuery.data?.reputation === 'scam' }
|
|
/>
|
|
) }
|
|
</>
|
|
);
|
|
};
|
|
|
|
export default TokenPageTitle;
|