diff --git a/src/components/Header/groups/EarnNavGroup.tsx b/src/components/Header/groups/EarnNavGroup.tsx index 2dfdee206e..3baad2ee91 100644 --- a/src/components/Header/groups/EarnNavGroup.tsx +++ b/src/components/Header/groups/EarnNavGroup.tsx @@ -47,7 +47,7 @@ const EarnNavGroup = () => { to={`${APP_PATHS.POOLS}/${networkInfo.route}`} style={{ width: '100%' }} > - + Pools @@ -61,14 +61,14 @@ const EarnNavGroup = () => { data-testid="farms-nav-link" to={`${APP_PATHS.FARMS}/${networkInfo.route}`} > - + Farms - + My Earnings @@ -82,7 +82,7 @@ const EarnNavGroup = () => { data-testid="my-pools-nav-link" to={`${APP_PATHS.MY_POOLS}/${networkInfo.route}`} > - + My Pools diff --git a/src/components/Header/groups/KyberDaoGroup.tsx b/src/components/Header/groups/KyberDaoGroup.tsx index 918647cfc6..2da86eba10 100644 --- a/src/components/Header/groups/KyberDaoGroup.tsx +++ b/src/components/Header/groups/KyberDaoGroup.tsx @@ -38,18 +38,18 @@ const KyberDAONavGroup = () => { } dropdownContent={ - + Stake KNC - + Vote { mixpanelHandler(MIXPANEL_TYPE.GAS_REFUND_SOURCE_CLICK, { source: 'KyberDAO_tab' }) }} @@ -61,7 +61,7 @@ const KyberDAONavGroup = () => { id="kyberdao-feature-request" href="https://kyberswap.canny.io/feature-request" target="_blank" - style={{ gap: '4px' }} + style={{ gap: '12px' }} onClick={() => { mixpanelHandler(MIXPANEL_TYPE.KYBER_DAO_FEATURE_REQUEST_CLICK) }} diff --git a/src/components/KyberAITokenBanner/index.tsx b/src/components/KyberAITokenBanner/index.tsx index 5ee3825895..828f643f6e 100644 --- a/src/components/KyberAITokenBanner/index.tsx +++ b/src/components/KyberAITokenBanner/index.tsx @@ -22,9 +22,9 @@ import useTheme from 'hooks/useTheme' import KyberScoreMeter from 'pages/TrueSightV2/components/KyberScoreMeter' import { NETWORK_TO_CHAINID } from 'pages/TrueSightV2/constants' import { SUPPORTED_NETWORK_KYBERAI } from 'pages/TrueSightV2/constants/index' -import { useTokenDetailQuery } from 'pages/TrueSightV2/hooks/useKyberAIData' +import { useTokenOverviewQuery } from 'pages/TrueSightV2/hooks/useKyberAIData' import { calculateValueToColor } from 'pages/TrueSightV2/utils' -import { useIsWhiteListKyberAI } from 'state/user/hooks' +import { useIsWhiteListKyberAI, useShowKyberAIBanner } from 'state/user/hooks' import { MEDIA_WIDTHS } from 'theme' const KyberAITokenBanner = ({ @@ -36,6 +36,8 @@ const KyberAITokenBanner = ({ }) => { const { chainId, account } = useActiveWeb3React() const { isWhiteList } = useIsWhiteListKyberAI() + const isShowKyberAIBanner = useShowKyberAIBanner() + const navigate = useNavigate() const { mixpanelHandler } = useMixpanel() const chain = Object.keys(NETWORK_TO_CHAINID).find(i => NETWORK_TO_CHAINID[i] === chainId) @@ -47,19 +49,25 @@ const KyberAITokenBanner = ({ const { isStableCoin } = useStableCoins(chainId) - const { data: tokenInputOverview } = useTokenDetailQuery( + const { data: tokenInputOverview } = useTokenOverviewQuery( { address: token0?.address, chain }, - { skip: !token0?.address || !account || !isWhiteList || !chain, refetchOnMountOrArgChange: true }, + { + skip: !token0?.address || !account || !isWhiteList || !chain || !isShowKyberAIBanner, + refetchOnMountOrArgChange: true, + }, ) - const { data: tokenOutputOverview } = useTokenDetailQuery( + const { data: tokenOutputOverview } = useTokenOverviewQuery( { address: token1?.address, chain }, - { skip: !token1?.address || !account || !isWhiteList || !chain, refetchOnMountOrArgChange: true }, + { + skip: !token1?.address || !account || !isWhiteList || !chain || !isShowKyberAIBanner, + refetchOnMountOrArgChange: true, + }, ) - const { data: tokenNativeOverview } = useTokenDetailQuery( + const { data: tokenNativeOverview } = useTokenOverviewQuery( { address: NativeCurrencies[chainId].wrapped.address, chain }, - { skip: !account || !isWhiteList || !chain, refetchOnMountOrArgChange: true }, + { skip: !account || !isWhiteList || !chain || !isShowKyberAIBanner, refetchOnMountOrArgChange: true }, ) const token: { kyberScore?: number; label?: string; address?: string; logo?: string; symbol?: string } | undefined = diff --git a/src/pages/App.tsx b/src/pages/App.tsx index 06a7ec8e40..acb2fe4ee2 100644 --- a/src/pages/App.tsx +++ b/src/pages/App.tsx @@ -394,7 +394,7 @@ export default function App() { } /> diff --git a/src/pages/ProAmmPools/KyberAIModalInPool.tsx b/src/pages/ProAmmPools/KyberAIModalInPool.tsx index a2bfdee408..3360fc1521 100644 --- a/src/pages/ProAmmPools/KyberAIModalInPool.tsx +++ b/src/pages/ProAmmPools/KyberAIModalInPool.tsx @@ -19,7 +19,7 @@ import useTheme from 'hooks/useTheme' import KyberScoreMeter from 'pages/TrueSightV2/components/KyberScoreMeter' import SimpleTooltip from 'pages/TrueSightV2/components/SimpleTooltip' import { SUPPORTED_NETWORK_KYBERAI } from 'pages/TrueSightV2/constants/index' -import { useTokenDetailQuery } from 'pages/TrueSightV2/hooks/useKyberAIData' +import { useTokenOverviewQuery } from 'pages/TrueSightV2/hooks/useKyberAIData' import { calculateValueToColor, formatTokenPrice, navigateToSwapPage } from 'pages/TrueSightV2/utils' import { useIsWhiteListKyberAI } from 'state/user/hooks' @@ -99,11 +99,11 @@ const KyberAIModalInPool = ({ currency0, currency1 }: { currency0?: Currency; cu const [tab, setTab] = useState(TokenTabType.First) const [openTruesightModal, setOpenTruesightModal] = useState(false) - const { data: token0Overview } = useTokenDetailQuery( + const { data: token0Overview } = useTokenOverviewQuery( { address: currency0?.wrapped?.address, chain: SUPPORTED_NETWORK_KYBERAI[chainId] }, { skip: !currency0?.wrapped?.address && !isWhiteList, refetchOnMountOrArgChange: true }, ) - const { data: token1Overview } = useTokenDetailQuery( + const { data: token1Overview } = useTokenOverviewQuery( { address: currency1?.wrapped?.address, chain: SUPPORTED_NETWORK_KYBERAI[chainId] }, { skip: !currency1?.wrapped?.address && !isWhiteList, refetchOnMountOrArgChange: true }, ) diff --git a/src/pages/TrueSightV2/components/CexRekt.tsx b/src/pages/TrueSightV2/components/CexRekt.tsx index aa13785b55..c8b6703139 100644 --- a/src/pages/TrueSightV2/components/CexRekt.tsx +++ b/src/pages/TrueSightV2/components/CexRekt.tsx @@ -27,11 +27,14 @@ const Card = styled.div` export default function CexRekt() { const above768 = useMedia(`(min-width:${MEDIA_WIDTHS.upToSmall}px)`) const { address, chain } = useParams() - const { data } = useCexesLiquidationQuery({ - tokenAddress: address, - chartSize: '1m', - chain, - }) + const { data } = useCexesLiquidationQuery( + { + tokenAddress: address, + chartSize: '1m', + chain, + }, + { skip: !chain || !address }, + ) return ( <> diff --git a/src/pages/TrueSightV2/components/DisplaySettings.tsx b/src/pages/TrueSightV2/components/DisplaySettings.tsx index a538e47723..1f1f66ebda 100644 --- a/src/pages/TrueSightV2/components/DisplaySettings.tsx +++ b/src/pages/TrueSightV2/components/DisplaySettings.tsx @@ -19,7 +19,7 @@ import { ApplicationModal } from 'state/application/actions' import { useToggleModal } from 'state/application/hooks' import { useTokenAnalysisSettings, useUpdateTokenAnalysisSettings } from 'state/user/hooks' -import useKyberAITokenOverview from '../hooks/useKyberAITokenOverview' +import useKyberAIAssetOverview from '../hooks/useKyberAIAssetOverview' import { HeaderButton } from '../pages/SingleToken' import { DiscoverTokenTab } from '../types' @@ -112,7 +112,7 @@ export default function DisplaySettings({ currentTab }: { currentTab: DiscoverTo const storedTokenAnalysisSettings = useTokenAnalysisSettings() const updateTokenAnalysisSettings = useUpdateTokenAnalysisSettings() const toggleTutorial = useToggleModal(ApplicationModal.KYBERAI_TUTORIAL) - const { data: token } = useKyberAITokenOverview() + const { data: token } = useKyberAIAssetOverview() const { chain } = useParams() const ref = useRef(null) useOnClickOutside(ref, () => { diff --git a/src/pages/TrueSightV2/components/KyberAIShareModal.tsx b/src/pages/TrueSightV2/components/KyberAIShareModal.tsx index 153f06d6c5..b808b1b9e5 100644 --- a/src/pages/TrueSightV2/components/KyberAIShareModal.tsx +++ b/src/pages/TrueSightV2/components/KyberAIShareModal.tsx @@ -24,7 +24,7 @@ import { downloadImage } from 'utils/index' import { getProxyTokenLogo } from 'utils/tokenInfo' import { NETWORK_IMAGE_URL } from '../constants' -import useKyberAITokenOverview from '../hooks/useKyberAITokenOverview' +import useKyberAIAssetOverview from '../hooks/useKyberAIAssetOverview' import KyberSwapShareLogo from './KyberSwapShareLogo' import LoadingTextAnimation from './LoadingTextAnimation' import { InfoWrapper, LegendWrapper } from './chart' @@ -208,7 +208,7 @@ export default function KyberAIShareModal({ }) { const theme = useTheme() const { chain } = useParams() - const { data: tokenOverview } = useKyberAITokenOverview() + const { data: tokenOverview } = useKyberAIAssetOverview() const ref = useRef(null) const refMobile = useRef(null) diff --git a/src/pages/TrueSightV2/components/KyberAIWidget.tsx b/src/pages/TrueSightV2/components/KyberAIWidget.tsx index 37e77c908b..32e5549dd6 100644 --- a/src/pages/TrueSightV2/components/KyberAIWidget.tsx +++ b/src/pages/TrueSightV2/components/KyberAIWidget.tsx @@ -214,8 +214,9 @@ export default function Widget() { page: 1, pageSize: 5, }, - { refetchOnMountOrArgChange: true, skip: !isWhiteList }, + { refetchOnMountOrArgChange: true, skip: !isWhiteList || !showWidget }, ) + if (!account) return <> return ( diff --git a/src/pages/TrueSightV2/components/MultipleChainDropdown.tsx b/src/pages/TrueSightV2/components/MultipleChainDropdown.tsx index fac2caac39..0c82854688 100644 --- a/src/pages/TrueSightV2/components/MultipleChainDropdown.tsx +++ b/src/pages/TrueSightV2/components/MultipleChainDropdown.tsx @@ -73,13 +73,12 @@ const MultipleChainDropdown = React.forwardRef( ( props: { show: boolean - menuLeft?: number tokens?: Array<{ address: string; logo: string; chain: string }> onChainClick: (chain: string, address: string) => void }, ref, ) => { - const { show, menuLeft, tokens, onChainClick } = props + const { show, tokens, onChainClick } = props const theme = useTheme() if (isMobile) { return ( @@ -167,7 +166,7 @@ const MultipleChainDropdown = React.forwardRef( className={show ? 'show' : ''} gap="8px" color={theme.text} - style={{ left: menuLeft !== undefined ? `${menuLeft}px` : undefined }} + style={{ right: 0 }} ref={ref} onClick={e => e.stopPropagation()} > diff --git a/src/pages/TrueSightV2/components/NetworkSelect.tsx b/src/pages/TrueSightV2/components/NetworkSelect.tsx index 364fd54517..d85924efcd 100644 --- a/src/pages/TrueSightV2/components/NetworkSelect.tsx +++ b/src/pages/TrueSightV2/components/NetworkSelect.tsx @@ -1,18 +1,19 @@ import { ChainId } from '@kyberswap/ks-sdk-core' import { Trans } from '@lingui/macro' +import { AnimatePresence, motion } from 'framer-motion' import { useRef, useState } from 'react' import { X } from 'react-feather' -import { Flex, Image, Text } from 'rebass' +import { Image, Text } from 'rebass' import styled from 'styled-components' import { ReactComponent as ChevronDown } from 'assets/svg/down.svg' -import { OptionsContainer } from 'components' import Kyber from 'components/Icons/Kyber' +import Row, { RowFit } from 'components/Row' import { NETWORKS_INFO } from 'constants/networks' import { useOnClickOutside } from 'hooks/useOnClickOutside' import useTheme from 'hooks/useTheme' -import { SUPPORTED_NETWORK_KYBERAI } from '../constants' +import { NETWORK_TO_CHAINID, SUPPORTED_NETWORK_KYBERAI } from '../constants' const NetworkSelectContainer = styled.div` display: flex; @@ -24,9 +25,42 @@ const NetworkSelectContainer = styled.div` background: ${({ theme }) => theme.background}; min-width: 160px; cursor: pointer; + + :hover { + z-index: 10; + filter: brightness(1.2); + } +` + +const DropdownWrapper = styled(motion.div)` + position: absolute; + width: 100%; + border-radius: 10px; + background-color: ${({ theme }) => theme.buttonGray}; + left: 0; + top: calc(100% + 2px); + padding: 4px; + z-index: 10; + display: flex; + flex-direction: column; + gap: 4px; +` + +const DropdownItem = styled(Row)` + height: 32px; + padding: 4px 8px; + gap: 8px; + border-radius: 4px; + font-size: 14px; + cursor: pointer; + :hover { + filter: brightness(1.2); + background-color: ${({ theme }) => theme.background}; + } ` -const NetworkSelect = ({ filter, setFilter }: { filter?: ChainId; setFilter: (c?: ChainId) => void }) => { +const NetworkSelect = ({ filter, setFilter }: { filter?: string; setFilter: (c?: string) => void }) => { + console.log('🚀 ~ file: NetworkSelect.tsx:63 ~ NetworkSelect ~ filter:', filter) const theme = useTheme() const [isShowOptions, setIsShowOptions] = useState(false) @@ -36,23 +70,28 @@ const NetworkSelect = ({ filter, setFilter }: { filter?: ChainId; setFilter: (c? return ( { setIsShowOptions(prev => !prev) }} ref={containerRef} > - + {filter ? ( - + ) : ( - + )} - {filter ? NETWORKS_INFO[filter].name : All Chains} + {filter ? NETWORKS_INFO[NETWORK_TO_CHAINID[filter]].name : All Chains} - - + + {filter ? ( )} - - - {isShowOptions && ( - - {Object.keys(SUPPORTED_NETWORK_KYBERAI).map((network, index) => ( - { - setFilter(+network as ChainId) - }} - > - - - {NETWORKS_INFO[+network as ChainId].name} - - - ))} - - )} + + + {isShowOptions && ( + + {Object.keys(SUPPORTED_NETWORK_KYBERAI).map((chainId, index) => ( + { + setFilter(SUPPORTED_NETWORK_KYBERAI[+chainId as ChainId]) + }} + > + + + {NETWORKS_INFO[+chainId as ChainId].name} + + + ))} + + )} + ) } diff --git a/src/pages/TrueSightV2/components/SearchWithDropDown.tsx b/src/pages/TrueSightV2/components/SearchWithDropDown.tsx index a543996385..d75259ae01 100644 --- a/src/pages/TrueSightV2/components/SearchWithDropDown.tsx +++ b/src/pages/TrueSightV2/components/SearchWithDropDown.tsx @@ -18,19 +18,17 @@ import { useOnClickOutside } from 'hooks/useOnClickOutside' import useTheme from 'hooks/useTheme' import { MEDIA_WIDTHS } from 'theme' -import { KYBERAI_LISTYPE_TO_MIXPANEL, NETWORK_IMAGE_URL } from '../constants' +import { KYBERAI_LISTYPE_TO_MIXPANEL } from '../constants' import { useLazySearchTokenQuery, useSearchTokenQuery, useTokenListQuery } from '../hooks/useKyberAIData' import { ITokenList, ITokenSearchResult, KyberAIListType } from '../types' import { formatTokenPrice } from '../utils' const formatTokenType = (token: ITokenList): ITokenSearchResult => { - const token0 = token.tokens[0] return { - address: token0.address, + assetId: token.asset_id, name: token.name, symbol: token.symbol, - logo: token0.logo, - chain: token0.chain, + logo: token.tokens[0].logo, price: token.price, priceChange24h: token.percent_change_24h, kyberScore: { @@ -206,7 +204,7 @@ const TokenItem = ({ token, onClick }: { token: ITokenSearchResult; onClick?: () { onClick?.() - navigate(`${APP_PATHS.KYBERAI_EXPLORE}/${token.chain}/${token.address}`) + navigate(`${APP_PATHS.KYBERAI_EXPLORE}/${token.assetId}`) }} > @@ -231,13 +229,13 @@ const TokenItem = ({ token, onClick }: { token: ITokenSearchResult; onClick?: () backgroundColor: theme.tableHeader, }} > - eth + /> */} @@ -322,7 +320,7 @@ const SearchWithDropdown = () => { ) const [history, setHistory] = useLocalStorage>('kyberai-search-history') const saveToHistory = (token: ITokenSearchResult) => { - if (!(history && history.findIndex(t => t.address === token.address && t.chain === token.chain) >= 0)) { + if (!(history && history.some(t => t.assetId === token.assetId))) { setHistory([token, ...(history || [])].slice(0, 3)) } } @@ -333,7 +331,7 @@ const SearchWithDropdown = () => { const fetchHistoryTokenInfo = async () => { const results = await Promise.all( history.map(t => { - return getTokenData({ q: t.address, size: 1 }, true).unwrap() + return getTokenData({ q: t.assetId, size: 1 }, true).unwrap() }), ) setHistory(results.map(res => res[0])) @@ -407,7 +405,7 @@ const SearchWithDropdown = () => { {searchResult.map(item => ( { setExpanded(false) diff --git a/src/pages/TrueSightV2/components/SwitchVariantDropdown.tsx b/src/pages/TrueSightV2/components/SwitchVariantDropdown.tsx new file mode 100644 index 0000000000..6257aeb224 --- /dev/null +++ b/src/pages/TrueSightV2/components/SwitchVariantDropdown.tsx @@ -0,0 +1,149 @@ +import { AnimatePresence, motion } from 'framer-motion' +import { useRef, useState } from 'react' +import Skeleton, { SkeletonTheme } from 'react-loading-skeleton' +import { useSearchParams } from 'react-router-dom' +import { Text } from 'rebass' +import styled from 'styled-components' + +import { ReactComponent as Down } from 'assets/svg/down.svg' +import Icon from 'components/Icons/Icon' +import Row, { RowFit } from 'components/Row' +import { ICON_ID } from 'constants/index' +import { useOnClickOutside } from 'hooks/useOnClickOutside' +import useTheme from 'hooks/useTheme' + +import useKyberAIAssetOverview from '../hooks/useKyberAIAssetOverview' + +const Wrapper = styled.div` + position: relative; +` +const SelectButton = styled(RowFit)` + height: 36px; + border-radius: 99px; + padding: 8px 12px; + background-color: ${({ theme }) => theme.buttonGray}; + gap: 8px; + cursor: pointer; + font-size: 14px; + width: 145px; + + :hover { + z-index: 10; + filter: brightness(1.2); + } +` + +const DropdownWrapper = styled(motion.div)` + position: absolute; + width: 100%; + border-radius: 10px; + background-color: ${({ theme }) => theme.buttonGray}; + left: 0; + top: calc(100% + 2px); + padding: 4px; + z-index: 10; + display: flex; + flex-direction: column; + gap: 4px; +` + +const DropdownItem = styled(Row)` + height: 32px; + padding: 4px 8px; + gap: 8px; + border-radius: 4px; + font-size: 14px; + cursor: pointer; + :hover { + filter: brightness(1.2); + background-color: ${({ theme }) => theme.background}; + } +` + +const VARIANTS: { [key: string]: { icon_id: ICON_ID; title: string } } = { + ethereum: { icon_id: 'eth-mono', title: 'Ethereum' }, + bsc: { icon_id: 'bnb-mono', title: 'Binance' }, + avalanche: { icon_id: 'ava-mono', title: 'Avalanche' }, + polygon: { icon_id: 'matic-mono', title: 'Polygon' }, + arbitrum: { icon_id: 'arbitrum-mono', title: 'Arbitrum' }, + fantom: { icon_id: 'fantom-mono', title: 'Fantom' }, + optimism: { icon_id: 'optimism-mono', title: 'Optimism' }, +} + +export default function SwitchVariantDropdown({ + variants, + isLoading, +}: { + variants?: { chain: string; address: string }[] + isLoading?: boolean +}) { + const theme = useTheme() + const [show, setShow] = useState(false) + const ref = useRef(null) + const [, setSearchParams] = useSearchParams() + const { chain, address } = useKyberAIAssetOverview() + useOnClickOutside(ref, () => setShow(false)) + const variant = variants?.find(item => item.address.toLowerCase() === address && item.chain.toLowerCase() === chain) + if (!variant && isLoading) { + return ( + + + + ) + } + + const setChainAndAdress = (variant: { chain: string; address: string }) => { + setSearchParams({ chain: variant.chain, address: variant.address }) + } + const variantInfo = !!variant ? VARIANTS[variant?.chain] : undefined + + return ( + + setShow(true)}> + + {variantInfo && ( + <> + + {variantInfo.title}{' '} + + )} + + + + + {show && !!variants?.length && ( + + {variants?.map(item => { + const itemVariant = VARIANTS[item.chain] + return ( + { + setShow(false) + setChainAndAdress(item) + }} + > + + {itemVariant.title} + + ) + })} + + )} + + + ) +} diff --git a/src/pages/TrueSightV2/components/TimeFrameLegend.tsx b/src/pages/TrueSightV2/components/TimeFrameLegend.tsx index f1b9df1bc0..9bb47749a9 100644 --- a/src/pages/TrueSightV2/components/TimeFrameLegend.tsx +++ b/src/pages/TrueSightV2/components/TimeFrameLegend.tsx @@ -3,7 +3,7 @@ import styled, { css } from 'styled-components' import { MIXPANEL_TYPE, useMixpanelKyberAI } from 'hooks/useMixpanel' -import useKyberAITokenOverview from '../hooks/useKyberAITokenOverview' +import useKyberAIAssetOverview from '../hooks/useKyberAIAssetOverview' import { KyberAITimeframe } from '../types' const TimeFrameWrapper = styled.div` @@ -72,7 +72,7 @@ const TimeFrameLegend = ({ const ref = useRef(null) const [left, setLeft] = useState(0) const [width, setWidth] = useState(0) - const { data: token } = useKyberAITokenOverview() + const { data: token } = useKyberAIAssetOverview() const handleSelect = (t: KyberAITimeframe) => { const wrapperEl = ref.current?.closest('section-wrapper') diff --git a/src/pages/TrueSightV2/components/TokenListVariants.tsx b/src/pages/TrueSightV2/components/TokenListVariants.tsx index 0bc5a4c6e0..ce3a4a807b 100644 --- a/src/pages/TrueSightV2/components/TokenListVariants.tsx +++ b/src/pages/TrueSightV2/components/TokenListVariants.tsx @@ -1,4 +1,20 @@ +import { useTheme } from 'styled-components' + import Icon from 'components/Icons/Icon' +import Row from 'components/Row' +import { ICON_ID } from 'constants/index' + +const VARIANTS: { [key: string]: { icon_id: ICON_ID; title: string } } = { + ethereum: { icon_id: 'eth-mono', title: 'Ethereum' }, + bsc: { icon_id: 'bnb-mono', title: 'Binance' }, + avalanche: { icon_id: 'ava-mono', title: 'Avalanche' }, + polygon: { icon_id: 'matic-mono', title: 'Polygon' }, + arbitrum: { icon_id: 'arbitrum-mono', title: 'Arbitrum' }, + fantom: { icon_id: 'fantom-mono', title: 'Fantom' }, + optimism: { icon_id: 'optimism-mono', title: 'Optimism' }, +} + +const MAX_ICONS_SHOWING = 8 export default function TokenListVariants({ tokens, @@ -7,29 +23,16 @@ export default function TokenListVariants({ tokens: Array<{ address: string; logo: string; chain: string }> iconSize?: number }) { + const theme = useTheme() return ( - <> + {tokens.map((item, index) => { + if (index > MAX_ICONS_SHOWING) return + if (index === MAX_ICONS_SHOWING) return ... const key = item.address + '_' + index - switch (item.chain) { - case 'ethereum': - return - case 'bsc': - return - case 'avalanche': - return - case 'polygon': - return - case 'arbitrum': - return - case 'fantom': - return - case 'optimism': - return - default: - return <> - } + const variant = VARIANTS[item.chain] + return })} - + ) } diff --git a/src/pages/TrueSightV2/components/TokenOverview.tsx b/src/pages/TrueSightV2/components/TokenOverview.tsx index 27324dc590..cfe195c72f 100644 --- a/src/pages/TrueSightV2/components/TokenOverview.tsx +++ b/src/pages/TrueSightV2/components/TokenOverview.tsx @@ -21,7 +21,7 @@ import { getEtherscanLink, shortenAddress } from 'utils' import { ShareButton } from '.' import { MIXPANEL_KYBERAI_TAG, NETWORK_IMAGE_URL, NETWORK_TO_CHAINID } from '../constants' -import { ITokenOverview } from '../types' +import { IAssetOverview } from '../types' import { calculateValueToColor, formatLocaleStringNum, formatTokenPrice } from '../utils' import ChevronIcon from './ChevronIcon' import KyberAIShareModal from './KyberAIShareModal' @@ -143,7 +143,7 @@ const ExternalLink = ({ href, className, children }: { href: string; className?: ) } -export const TokenOverview = ({ data, isLoading }: { data?: ITokenOverview; isLoading?: boolean }) => { +export const TokenOverview = ({ data, isLoading }: { data?: IAssetOverview; isLoading?: boolean }) => { const theme = useTheme() const { chain } = useParams() const mixpanelHandler = useMixpanelKyberAI() diff --git a/src/pages/TrueSightV2/components/chart/datafeed.tsx b/src/pages/TrueSightV2/components/chart/datafeed.tsx index 1157417494..bccef89c3a 100644 --- a/src/pages/TrueSightV2/components/chart/datafeed.tsx +++ b/src/pages/TrueSightV2/components/chart/datafeed.tsx @@ -13,13 +13,13 @@ import { import { getTradingViewTimeZone } from 'components/TradingViewChart/utils' import { useLazyChartingDataQuery } from 'pages/TrueSightV2/hooks/useKyberAIData' import { defaultExplorePageToken } from 'pages/TrueSightV2/pages/SingleToken' -import { ITokenOverview, OHLCData } from 'pages/TrueSightV2/types' +import { IAssetOverview, OHLCData } from 'pages/TrueSightV2/types' const configurationData = { supported_resolutions: ['1H', '4H', '1D', '4D'], } -export const useDatafeed = (isBTC: boolean, token?: ITokenOverview) => { +export const useDatafeed = (isBTC: boolean, token?: IAssetOverview) => { const intervalRef = useRef() const { chain, address } = useParams() const [getChartingData, { isLoading }] = useLazyChartingDataQuery() diff --git a/src/pages/TrueSightV2/components/chart/index.tsx b/src/pages/TrueSightV2/components/chart/index.tsx index 16fa66b24a..88099fc5d3 100644 --- a/src/pages/TrueSightV2/components/chart/index.tsx +++ b/src/pages/TrueSightV2/components/chart/index.tsx @@ -4,7 +4,6 @@ import { rgba } from 'polished' import React, { ReactNode, useCallback, useContext, useEffect, useLayoutEffect, useMemo, useRef, useState } from 'react' import { isMobile } from 'react-device-detect' import { Info } from 'react-feather' -import { useParams } from 'react-router-dom' import { useMedia } from 'react-use' import { Text } from 'rebass' import { @@ -41,6 +40,7 @@ import { useActiveWeb3React } from 'hooks' import useTheme from 'hooks/useTheme' import { KYBERAI_CHART_ID, NETWORK_TO_CHAINID } from 'pages/TrueSightV2/constants' import { CHART_STATES_ACTION_TYPE, useChartStatesContext } from 'pages/TrueSightV2/hooks/useChartStatesReducer' +import useKyberAIAssetOverview from 'pages/TrueSightV2/hooks/useKyberAIAssetOverview' import { useCexesLiquidationQuery, useHolderListQuery, @@ -50,7 +50,6 @@ import { useTradingVolumeQuery, useTransferInformationQuery, } from 'pages/TrueSightV2/hooks/useKyberAIData' -import useKyberAITokenOverview from 'pages/TrueSightV2/hooks/useKyberAITokenOverview' import { defaultExplorePageToken } from 'pages/TrueSightV2/pages/SingleToken' import { TechnicalAnalysisContext } from 'pages/TrueSightV2/pages/TechnicalAnalysis' import { @@ -297,7 +296,7 @@ const roundNumberUp = (number: number) => { export const NumberofTradesChart = ({ noAnimation }: { noAnimation?: boolean }) => { const theme = useTheme() - const { chain, address } = useParams() + const { chain, address } = useKyberAIAssetOverview() const { state, dispatch } = useChartStatesContext(KYBERAI_CHART_ID.NUMBER_OF_TRADES, { timeframe: KyberAITimeframe.ONE_MONTH, showOptions: ['showSell', 'showBuy', 'showTotalTrade'], @@ -328,11 +327,14 @@ export const NumberofTradesChart = ({ noAnimation }: { noAnimation?: boolean }) }[timeframe as string] || 604800) return [from, now, timerange] }, [timeframe]) - const { data, isLoading } = useTradingVolumeQuery({ - chain: chain || defaultExplorePageToken.chain, - address: address || defaultExplorePageToken.address, - params: { from, to }, - }) + const { data, isLoading } = useTradingVolumeQuery( + { + chain: chain, + address: address, + params: { from, to }, + }, + { skip: !address || !chain }, + ) const dataRange = useMemo(() => { if (!data) return undefined @@ -615,7 +617,7 @@ export const NumberofTradesChart = ({ noAnimation }: { noAnimation?: boolean }) export const TradingVolumeChart = ({ noAnimation }: { noAnimation?: boolean }) => { const theme = useTheme() - const { chain, address } = useParams() + const { chain, address } = useKyberAIAssetOverview() const { state, dispatch } = useChartStatesContext(KYBERAI_CHART_ID.TRADING_VOLUME, { timeframe: KyberAITimeframe.ONE_MONTH, showOptions: ['showSell', 'showBuy', 'showTotalVolume'], @@ -938,7 +940,7 @@ export const TradingVolumeChart = ({ noAnimation }: { noAnimation?: boolean }) = export const NetflowToWhaleWallets = ({ tab, noAnimation }: { tab?: ChartTab; noAnimation?: boolean }) => { const theme = useTheme() - const { chain, address } = useParams() + const { chain, address } = useKyberAIAssetOverview() const { state, dispatch } = useChartStatesContext(KYBERAI_CHART_ID.NETFLOW_TO_WHALE_WALLET, { timeframe: KyberAITimeframe.ONE_WEEK, showOptions: ['showInflow', 'showOutflow', 'showNetflow'], @@ -1381,7 +1383,7 @@ export const NetflowToWhaleWallets = ({ tab, noAnimation }: { tab?: ChartTab; no export const NetflowToCentralizedExchanges = ({ tab, noAnimation }: { tab?: ChartTab; noAnimation?: boolean }) => { const theme = useTheme() - const { chain, address } = useParams() + const { chain, address } = useKyberAIAssetOverview() const { state, dispatch } = useChartStatesContext(KYBERAI_CHART_ID.NETFLOW_TO_CEX, { timeframe: KyberAITimeframe.ONE_WEEK, showOptions: ['showInflow', 'showOutflow', 'showNetflow'], @@ -1773,7 +1775,7 @@ export const NetflowToCentralizedExchanges = ({ tab, noAnimation }: { tab?: Char export const NumberofTransfers = ({ tab }: { tab: ChartTab }) => { const theme = useTheme() - const { chain, address } = useParams() + const { chain, address } = useKyberAIAssetOverview() const { state, dispatch } = useChartStatesContext(KYBERAI_CHART_ID.NUMBER_OF_TRANSFERS, { timeframe: KyberAITimeframe.ONE_MONTH, noData: true, @@ -1962,7 +1964,7 @@ export const NumberofTransfers = ({ tab }: { tab: ChartTab }) => { export const NumberofHolders = () => { const theme = useTheme() - const { chain, address } = useParams() + const { chain, address } = useKyberAIAssetOverview() const { state, dispatch } = useChartStatesContext(KYBERAI_CHART_ID.NUMBER_OF_HOLDERS, { timeframe: KyberAITimeframe.ONE_MONTH, noData: true, @@ -2138,7 +2140,7 @@ export const NumberofHolders = () => { const COLORS = ['#00a2f7', '#31CB9E', '#FFBB28', '#F3841E', '#FF537B', '#27AE60', '#78d5ff', '#8088E5'] const CustomLabel = ({ x, y, cx, cy, name, address, percentage, sumPercentage }: any) => { let customY = y - const { chain } = useParams() + const { chain } = useKyberAIAssetOverview() if (Math.abs(cx - x) < 30) { customY = cy - y > 0 ? y - 8 : y + 8 } @@ -2177,22 +2179,11 @@ const CustomLabelLine = (props: any) => { )} ) - // if (percentage > 0.01) { - // return ( - // - // ) - // } else { - // return - // } } export const HoldersChartWrapper = ({ noAnimation }: { noAnimation?: boolean }) => { const theme = useTheme() const above768 = useMedia(`(min-width:${MEDIA_WIDTHS.upToSmall}px)`) - const { chain, address } = useParams() + const { chain, address } = useKyberAIAssetOverview() const { dispatch } = useChartStatesContext(KYBERAI_CHART_ID.HOLDER_PIE_CHART, { noData: true, }) @@ -2268,7 +2259,7 @@ export const HoldersChartWrapper = ({ noAnimation }: { noAnimation?: boolean }) export const LiquidOnCentralizedExchanges = ({ noAnimation }: { noAnimation?: boolean }) => { const theme = useTheme() const { account } = useActiveWeb3React() - const { chain, address } = useParams() + const { chain, address } = useKyberAIAssetOverview() const { state, dispatch } = useChartStatesContext(KYBERAI_CHART_ID.LIQUID_ON_CEX, { timeframe: KyberAITimeframe.ONE_MONTH, noData: true, @@ -2303,7 +2294,7 @@ export const LiquidOnCentralizedExchanges = ({ noAnimation }: { noAnimation?: bo }, { skip: !address || !chain }, ) - const { data: tokenOverview } = useKyberAITokenOverview() + const { data: tokenOverview } = useKyberAIAssetOverview() const [showLong, setShowLong] = useState(true) const [showShort, setShowShort] = useState(true) const [showPrice, setShowPrice] = useState(true) @@ -2655,7 +2646,7 @@ export const Prochart = ({ const [fullscreen, setFullscreen] = useState(false) const [loading, setLoading] = useState(false) const userLocale = useUserLocale() - const { data } = useKyberAITokenOverview() + const { data } = useKyberAIAssetOverview() const datafeed = useDatafeed(isBTC || false, data) const { SRLevels, currentPrice, resolution, setResolution, showSRLevels } = useContext(TechnicalAnalysisContext) diff --git a/src/pages/TrueSightV2/components/index.tsx b/src/pages/TrueSightV2/components/index.tsx index 9433823bba..b7745c44d1 100644 --- a/src/pages/TrueSightV2/components/index.tsx +++ b/src/pages/TrueSightV2/components/index.tsx @@ -18,7 +18,7 @@ import { CloseIcon, MEDIA_WIDTHS } from 'theme' import { openFullscreen } from 'utils/index' import { MIXPANEL_KYBERAI_TAG } from '../constants' -import useKyberAITokenOverview from '../hooks/useKyberAITokenOverview' +import useKyberAIAssetOverview from '../hooks/useKyberAIAssetOverview' import { ChartTab } from '../types' import KyberAIShareModal from './KyberAIShareModal' @@ -144,7 +144,7 @@ export const SectionWrapper = ({ const theme = useTheme() const mixpanelHandler = useMixpanelKyberAI() const { chain } = useParams() - const { data: token } = useKyberAITokenOverview() + const { data: token } = useKyberAIAssetOverview() const ref = useRef(null) const above768 = useMedia(`(min-width:${MEDIA_WIDTHS.upToSmall}px)`) const [showText, setShowText] = useState(above768 ? true : false) diff --git a/src/pages/TrueSightV2/components/shareContent/ExploreTopShareContent.tsx b/src/pages/TrueSightV2/components/shareContent/ExploreTopShareContent.tsx index 1cf0e72697..c66e11bac1 100644 --- a/src/pages/TrueSightV2/components/shareContent/ExploreTopShareContent.tsx +++ b/src/pages/TrueSightV2/components/shareContent/ExploreTopShareContent.tsx @@ -9,7 +9,7 @@ import Column from 'components/Column' import Divider from 'components/Divider' import Row, { RowFit } from 'components/Row' import { useTokenListQuery } from 'pages/TrueSightV2/hooks/useKyberAIData' -import { ITokenOverview, KyberAIListType } from 'pages/TrueSightV2/types' +import { IAssetOverview, KyberAIListType } from 'pages/TrueSightV2/types' import { calculateValueToColor, formatTokenPrice } from 'pages/TrueSightV2/utils' import ChevronIcon from '../ChevronIcon' @@ -72,7 +72,7 @@ const PriceChart7Days = ({ ) } -export default function ExploreShareContent({ token, mobileMode }: { token?: ITokenOverview; mobileMode?: boolean }) { +export default function ExploreShareContent({ token, mobileMode }: { token?: IAssetOverview; mobileMode?: boolean }) { const theme = useTheme() const { data } = useTokenListQuery( { type: KyberAIListType.ALL, page: 1, pageSize: 5, keywords: token?.address }, diff --git a/src/pages/TrueSightV2/components/shareContent/KyberScoreShareContent.tsx b/src/pages/TrueSightV2/components/shareContent/KyberScoreShareContent.tsx index d921e784f1..fcd4e2d202 100644 --- a/src/pages/TrueSightV2/components/shareContent/KyberScoreShareContent.tsx +++ b/src/pages/TrueSightV2/components/shareContent/KyberScoreShareContent.tsx @@ -5,7 +5,7 @@ import { Text } from 'rebass' import Column from 'components/Column' import Row from 'components/Row' import useTheme from 'hooks/useTheme' -import { ITokenOverview } from 'pages/TrueSightV2/types' +import { IAssetOverview } from 'pages/TrueSightV2/types' import { calculateValueToColor, formatTokenPrice } from 'pages/TrueSightV2/utils' import KyberScoreMeter from '../KyberScoreMeter' @@ -15,7 +15,7 @@ export default function KyberScoreShareContent({ token, mobileMode, }: { - token?: ITokenOverview + token?: IAssetOverview mobileMode?: boolean }) { const theme = useTheme() diff --git a/src/pages/TrueSightV2/components/table/index.tsx b/src/pages/TrueSightV2/components/table/index.tsx index e3bc1fdc7c..61b88974ae 100644 --- a/src/pages/TrueSightV2/components/table/index.tsx +++ b/src/pages/TrueSightV2/components/table/index.tsx @@ -6,7 +6,7 @@ import { ReactNode, useCallback, useContext, useEffect, useMemo, useRef, useStat import { isMobile } from 'react-device-detect' import { Info } from 'react-feather' import Skeleton, { SkeletonTheme } from 'react-loading-skeleton' -import { useNavigate, useParams } from 'react-router-dom' +import { useNavigate } from 'react-router-dom' import { Text } from 'rebass' import styled, { DefaultTheme, css } from 'styled-components' @@ -25,6 +25,7 @@ import { useOnClickOutside } from 'hooks/useOnClickOutside' import useTheme from 'hooks/useTheme' import { NETWORK_IMAGE_URL, NETWORK_TO_CHAINID } from 'pages/TrueSightV2/constants' import useIsReachMaxLimitWatchedToken from 'pages/TrueSightV2/hooks/useIsReachMaxLimitWatchedToken' +import useKyberAIAssetOverview from 'pages/TrueSightV2/hooks/useKyberAIAssetOverview' import { useAddToWatchlistMutation, useFundingRateQuery, @@ -32,7 +33,6 @@ import { useLiveDexTradesQuery, useRemoveFromWatchlistMutation, } from 'pages/TrueSightV2/hooks/useKyberAIData' -import useKyberAITokenOverview from 'pages/TrueSightV2/hooks/useKyberAITokenOverview' import { TechnicalAnalysisContext } from 'pages/TrueSightV2/pages/TechnicalAnalysis' import { IHolderList, IKyberScoreChart, ILiveTrade, ITokenList, KyberAITimeframe } from 'pages/TrueSightV2/types' import { @@ -172,9 +172,8 @@ const LoadingHandleWrapper = ({ export const Top10HoldersTable = () => { const theme = useTheme() - const { chain, address } = useParams() - const { data, isLoading } = useHolderListQuery({ address, chain }) - const { data: tokenOverview } = useKyberAITokenOverview() + const { data: tokenOverview, chain, address } = useKyberAIAssetOverview() + const { data, isLoading } = useHolderListQuery({ address, chain }, { skip: !chain || !address }) return ( 0} height="400px"> @@ -373,8 +372,8 @@ function colorRateText(value: number, theme: DefaultTheme) { export const FundingRateTable = ({ mobileMode }: { mobileMode?: boolean }) => { const theme = useTheme() - const { chain, address } = useParams() - const { data, isLoading } = useFundingRateQuery({ address, chain }) + const { chain, address } = useKyberAIAssetOverview() + const { data, isLoading } = useFundingRateQuery({ address, chain }, { skip: !chain || !address }) if (mobileMode) { return ( @@ -458,15 +457,15 @@ export const FundingRateTable = ({ mobileMode }: { mobileMode?: boolean }) => { export const LiveDEXTrades = () => { const theme = useTheme() const [currentPage, setCurrentPage] = useState(1) - const { chain, address } = useParams() + const { data: tokenOverview, chain, address } = useKyberAIAssetOverview() + const { data, isLoading } = useLiveDexTradesQuery( { chain, address, }, - { pollingInterval: 10000 }, + { pollingInterval: 10000, skip: !chain || !address }, ) - const { data: tokenOverview } = useKyberAITokenOverview() return ( <> @@ -596,44 +595,27 @@ const WidgetTokenRow = ({ const latestKyberScore: IKyberScoreChart | undefined = token?.ks_3d?.[token.ks_3d.length - 1] const hasMutipleChain = token?.tokens?.length > 1 - const [showMenu, setShowMenu] = useState(false) const [showSwapMenu, setShowSwapMenu] = useState(false) - const [menuLeft, setMenuLeft] = useState(undefined) const [isWatched, setIsWatched] = useState(!!token.isWatched) const [loadingStar, setLoadingStar] = useState(false) const [addToWatchlist] = useAddToWatchlistMutation() const [removeFromWatchlist] = useRemoveFromWatchlistMutation() const rowRef = useRef(null) - const menuRef = useRef(null) - useOnClickOutside(rowRef, () => setShowMenu(false)) useOnClickOutside(rowRef, () => setShowSwapMenu(false)) - const handleRowClick = (e: any) => { - if (hasMutipleChain) { - const left = e.clientX - (rowRef.current?.getBoundingClientRect()?.left || 0) - const rowWidth = rowRef.current?.getBoundingClientRect()?.width || 0 - const menuWidth = menuRef.current?.getBoundingClientRect()?.width || 0 - if (left !== undefined) { - setMenuLeft(Math.min(left, rowWidth - menuWidth)) - setShowMenu(true) - } - } else { - navigate(`${APP_PATHS.KYBERAI_EXPLORE}/${token.tokens[0].chain}/${token.tokens[0].address}`) - onClick?.() - } + const handleRowClick = () => { + navigate( + `${APP_PATHS.KYBERAI_EXPLORE}/${token.asset_id}?chain=${token.tokens[0].chain}&address=${token.tokens[0].address}`, + ) + onClick?.() } const handleSwapClick = (e: any) => { e.stopPropagation() if (hasMutipleChain) { - const left = - e.clientX - - (rowRef.current?.getBoundingClientRect()?.left || 0) - - (menuRef.current?.getBoundingClientRect()?.width || 0) setShowSwapMenu(true) - setMenuLeft(left) } else { navigateToSwapPage({ address: token.tokens[0].address, chain: token.tokens[0].chain }) } @@ -804,22 +786,7 @@ const WidgetTokenRow = ({ {hasMutipleChain && ( <> - { - onClick?.() - navigate(`${APP_PATHS.KYBERAI_EXPLORE}/${chain}/${address}`) - }} - /> - + )} @@ -1024,7 +991,7 @@ export const Top10HoldersShareModalTable = ({ startIndex?: number }) => { const theme = useTheme() - const { data: tokenOverview } = useKyberAITokenOverview() + const { data: tokenOverview } = useKyberAIAssetOverview() return ( @@ -1091,7 +1058,7 @@ export const LiveTradesInShareModalTable = ({ mobileMode?: boolean }) => { const theme = useTheme() - const { data: tokenOverview } = useKyberAITokenOverview() + const { data: tokenOverview } = useKyberAIAssetOverview() return ( diff --git a/src/pages/TrueSightV2/hooks/useIsReachMaxLimitWatchedToken.tsx b/src/pages/TrueSightV2/hooks/useIsReachMaxLimitWatchedToken.tsx index 9a06730b1f..cbf9e8902b 100644 --- a/src/pages/TrueSightV2/hooks/useIsReachMaxLimitWatchedToken.tsx +++ b/src/pages/TrueSightV2/hooks/useIsReachMaxLimitWatchedToken.tsx @@ -1,17 +1,24 @@ import { useMemo } from 'react' +import { useIsWhiteListKyberAI } from 'state/user/hooks' + import { ITokenList, KyberAIListType } from '../types' import { useTokenListQuery } from './useKyberAIData' const MAX_LIMIT_WATCHED_TOKEN = 30 export default function useIsReachMaxLimitWatchedToken(tokenCount?: number) { - const { data } = useTokenListQuery({ - type: KyberAIListType.ALL, - chain: 'all', - page: 1, - pageSize: 30, - watchlist: true, - }) + const { isWhiteList } = useIsWhiteListKyberAI() + + const { data } = useTokenListQuery( + { + type: KyberAIListType.ALL, + chain: 'all', + page: 1, + pageSize: 30, + watchlist: true, + }, + { skip: !isWhiteList }, + ) const watchedCount = useMemo(() => { let count = 0 diff --git a/src/pages/TrueSightV2/hooks/useKyberAIAssetOverview.tsx b/src/pages/TrueSightV2/hooks/useKyberAIAssetOverview.tsx new file mode 100644 index 0000000000..557d492a6d --- /dev/null +++ b/src/pages/TrueSightV2/hooks/useKyberAIAssetOverview.tsx @@ -0,0 +1,22 @@ +import { useParams } from 'react-router' +import { useSearchParams } from 'react-router-dom' + +import { useIsWhiteListKyberAI } from 'state/user/hooks' + +import { useAssetOverviewQuery } from './useKyberAIData' + +export default function useKyberAIAssetOverview() { + const { isWhiteList } = useIsWhiteListKyberAI() + const { assetId } = useParams() + + const [searchParams] = useSearchParams() + + const result = useAssetOverviewQuery({ assetId }, { skip: !assetId || !isWhiteList }) + + return { + data: result.data, + isLoading: result.isLoading, + address: searchParams.get('address') || undefined, + chain: searchParams.get('chain') || undefined, + } +} diff --git a/src/pages/TrueSightV2/hooks/useKyberAIData.tsx b/src/pages/TrueSightV2/hooks/useKyberAIData.tsx index b3a1a74b62..7f28e3e64a 100644 --- a/src/pages/TrueSightV2/hooks/useKyberAIData.tsx +++ b/src/pages/TrueSightV2/hooks/useKyberAIData.tsx @@ -4,6 +4,7 @@ import baseQueryOauth from 'services/baseQueryOauth' import { BFF_API } from 'constants/env' import { + IAssetOverview, ILiquidCEX, ILiveTrade, INetflowToCEX, @@ -12,7 +13,6 @@ import { INumberOfTrades, INumberOfTransfers, ITokenList, - ITokenOverview, ITokenSearchResult, ITradingVolume, KyberAIListType, @@ -57,7 +57,6 @@ const kyberAIApi = createApi({ }, providesTags: (result, error, arg) => (arg.watchlist === true ? ['myWatchList', 'tokenList'] : ['tokenList']), }), - //2. addToWatchlist: builder.mutation({ query: (params: { tokenAddress: string; chain: string }) => ({ url: `/watchlist`, @@ -66,7 +65,6 @@ const kyberAIApi = createApi({ }), invalidatesTags: (res, err, params) => [{ type: 'tokenOverview', id: params.tokenAddress }, 'myWatchList'], }), - //3. removeFromWatchlist: builder.mutation({ query: (params: { tokenAddress: string; chain: string }) => ({ url: `/watchlist`, @@ -79,9 +77,20 @@ const kyberAIApi = createApi({ 'tokenList', ], }), - + assetOverview: builder.query({ + query: ({ assetId }: { assetId?: string }) => ({ + url: `/assets/${assetId}`, + }), + transformResponse: (res: any) => { + // If token is stablecoin remove its kyberscore value + if (res.data && res.data.tags?.includes('stablecoin')) { + return { ...res.data, kyberScore: { ks3d: null, label: '', score: 0 } } + } + return res.data + }, + }), //4. - tokenDetail: builder.query({ + tokenOverview: builder.query({ query: ({ chain, address }: { chain?: string; address?: string }) => ({ url: `/overview/${chain}/${address}`, }), @@ -92,7 +101,6 @@ const kyberAIApi = createApi({ } return res.data }, - providesTags: result => [{ type: 'tokenOverview', id: result?.address }], }), //5. numberOfTrades: builder.query({ @@ -172,7 +180,7 @@ const kyberAIApi = createApi({ //11. chartingData: builder.query< OHLCData[], - { chain: string; address: string; from: number; to: number; candleSize: string; currency: string } + { chain?: string; address?: string; from: number; to: number; candleSize: string; currency: string } >({ query: ({ chain, address, from, to, candleSize, currency }) => ({ url: `/ohlcv/${chain}/${address}`, @@ -259,7 +267,8 @@ const kyberAIApi = createApi({ }) export const { - useTokenDetailQuery, + useAssetOverviewQuery, + useTokenOverviewQuery, useNumberOfTradesQuery, useTradingVolumeQuery, useNetflowToWhaleWalletsQuery, diff --git a/src/pages/TrueSightV2/hooks/useKyberAITokenOverview.tsx b/src/pages/TrueSightV2/hooks/useKyberAITokenOverview.tsx deleted file mode 100644 index 5548573a65..0000000000 --- a/src/pages/TrueSightV2/hooks/useKyberAITokenOverview.tsx +++ /dev/null @@ -1,13 +0,0 @@ -import { useParams } from 'react-router' - -import { useIsWhiteListKyberAI } from 'state/user/hooks' - -import { useTokenDetailQuery } from './useKyberAIData' - -export default function useKyberAITokenOverview() { - const { isWhiteList } = useIsWhiteListKyberAI() - const { chain, address } = useParams() - const result = useTokenDetailQuery({ chain, address }, { skip: !chain || !address || !isWhiteList }) - - return result -} diff --git a/src/pages/TrueSightV2/pages/SingleToken.tsx b/src/pages/TrueSightV2/pages/SingleToken.tsx index f47f5cfbe5..8e01028a24 100644 --- a/src/pages/TrueSightV2/pages/SingleToken.tsx +++ b/src/pages/TrueSightV2/pages/SingleToken.tsx @@ -1,16 +1,17 @@ import { Trans, t } from '@lingui/macro' import { rgba } from 'polished' import { stringify } from 'querystring' -import { ReactNode, useEffect, useLayoutEffect, useRef, useState } from 'react' +import React, { ReactNode, useCallback, useEffect, useRef, useState } from 'react' import { ChevronLeft } from 'react-feather' -import { useLocation, useNavigate, useParams } from 'react-router-dom' +import Skeleton, { SkeletonTheme } from 'react-loading-skeleton' +import { useLocation, useNavigate, useParams, useSearchParams } from 'react-router-dom' import { useMedia } from 'react-use' import { Text } from 'rebass' import styled, { css } from 'styled-components' import { ButtonPrimary } from 'components/Button' +import Column from 'components/Column' import Icon from 'components/Icons/Icon' -import { DotsLoader } from 'components/Loader/DotsLoader' import Row, { RowBetween, RowFit } from 'components/Row' import { APP_PATHS } from 'constants/index' import { useActiveWeb3React } from 'hooks' @@ -18,20 +19,22 @@ import { MIXPANEL_TYPE, useMixpanelKyberAI } from 'hooks/useMixpanel' import useTheme from 'hooks/useTheme' import { PROFILE_MANAGE_ROUTES } from 'pages/NotificationCenter/const' import { MEDIA_WIDTHS } from 'theme' +import { escapeScriptHtml } from 'utils/string' import DisplaySettings from '../components/DisplaySettings' import FeedbackSurvey from '../components/FeedbackSurvey' import KyberAIShareModal from '../components/KyberAIShareModal' import SimpleTooltip from '../components/SimpleTooltip' +import SwitchVariantDropdown from '../components/SwitchVariantDropdown' import { TokenOverview } from '../components/TokenOverview' import { StarWithAnimation } from '../components/WatchlistStar' import ExploreShareContent from '../components/shareContent/ExploreTopShareContent' import { MIXPANEL_KYBERAI_TAG, NETWORK_IMAGE_URL, NETWORK_TO_CHAINID } from '../constants' import useChartStatesReducer, { ChartStatesContext } from '../hooks/useChartStatesReducer' import useIsReachMaxLimitWatchedToken from '../hooks/useIsReachMaxLimitWatchedToken' +import useKyberAIAssetOverview from '../hooks/useKyberAIAssetOverview' import { useAddToWatchlistMutation, useRemoveFromWatchlistMutation } from '../hooks/useKyberAIData' -import useKyberAITokenOverview from '../hooks/useKyberAITokenOverview' -import { DiscoverTokenTab, ITokenOverview } from '../types' +import { DiscoverTokenTab, IAssetOverview } from '../types' import { navigateToSwapPage } from '../utils' import OnChainAnalysis from './OnChainAnalysis' import TechnicalAnalysis from './TechnicalAnalysis' @@ -154,9 +157,10 @@ const TabButton = styled.div<{ active?: boolean }>` export const defaultExplorePageToken = { chain: 'ethereum', address: '0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2', + assetId: 19277, } -const StyledTokenDescription = styled.div<{ show?: boolean }>` +const StyledTokenDescription = styled.span<{ show?: boolean }>` text-overflow: ellipsis; overflow: hidden; font-size: 12px; @@ -184,11 +188,15 @@ const TokenDescription = ({ description }: { description: string }) => { const theme = useTheme() const [show, setShow] = useState(true) const [isTextExceeded, setIsTextExceeded] = useState(false) - const ref = useRef(null) - useLayoutEffect(() => { - setIsTextExceeded((!!description && ref.current && ref.current?.clientWidth <= ref.current?.scrollWidth) || false) - }, [description]) + const ref = useCallback( + (el: HTMLDivElement) => { + if (el && !!description) { + setIsTextExceeded(el.clientHeight > 18 || el.scrollWidth > el.clientWidth || false) + } + }, + [description], + ) useEffect(() => { const hideBtn = document.getElementById('hide-token-description-span') @@ -201,19 +209,30 @@ const TokenDescription = ({ description }: { description: string }) => { return ( - ${t`Hide`}` - : ''), - }} - /> + + + {isTextExceeded && show && ( + setShow(false)} + > + Hide + + )} + {isTextExceeded && !show && ( { ) } -const TokenNameGroup = ({ token, isLoading }: { token?: ITokenOverview; isLoading?: boolean }) => { +const TokenNameGroup = ({ token, isLoading }: { token?: IAssetOverview; isLoading?: boolean }) => { const { account } = useActiveWeb3React() const theme = useTheme() const mixpanelHandler = useMixpanelKyberAI() const navigate = useNavigate() const location = useLocation() const above768 = useMedia(`(min-width:${MEDIA_WIDTHS.upToSmall}px)`) - const { chain } = useParams() + const { chain, address } = useKyberAIAssetOverview() const reachedMaxLimit = useIsReachMaxLimitWatchedToken() const [addToWatchlist, { isLoading: loadingAddtoWatchlist }] = useAddToWatchlistMutation() const [removeFromWatchlist, { isLoading: loadingRemovefromWatchlist }] = useRemoveFromWatchlistMutation() const [isWatched, setIsWatched] = useState(false) const handleStarClick = () => { - if (!token || !chain || !account) return + if (!token || !chain || !address || !account) return if (isWatched) { mixpanelHandler(MIXPANEL_TYPE.KYBERAI_ADD_TOKEN_TO_WATCHLIST, { token_name: token.symbol?.toUpperCase(), source: 'explore', option: 'remove', }) - removeFromWatchlist({ - tokenAddress: token?.address, + tokenAddress: address, chain, }).then(() => setIsWatched(false)) } else { @@ -268,7 +286,7 @@ const TokenNameGroup = ({ token, isLoading }: { token?: ITokenOverview; isLoadin source: 'explore', option: 'add', }) - addToWatchlist({ tokenAddress: token?.address, chain }).then(() => setIsWatched(true)) + addToWatchlist({ tokenAddress: address, chain }).then(() => setIsWatched(true)) } } } @@ -300,7 +318,6 @@ const TokenNameGroup = ({ token, isLoading }: { token?: ITokenOverview; isLoadin loading={loadingAddtoWatchlist || loadingRemovefromWatchlist} size={16} disabled={!isWatched && reachedMaxLimit} - onClick={handleStarClick} wrapperStyle={{ color: isWatched ? theme.primary : theme.subText, backgroundColor: isWatched ? theme.primary + '33' : theme.darkMode ? theme.buttonGray : theme.background, @@ -308,19 +325,32 @@ const TokenNameGroup = ({ token, isLoading }: { token?: ITokenOverview; isLoadin width: above768 ? '36px' : '32px', borderRadius: '100%', }} + onClick={handleStarClick} />
- + {token?.logo ? ( + + ) : ( + + )}
{isLoading ? ( - + ) : ( - <> + token && ( {token?.name} ({token?.symbol.toUpperCase()}) - + ) )} ) } -const SettingButtons = ({ token, onShareClick }: { token?: ITokenOverview; onShareClick: () => void }) => { +const SettingButtons = ({ onShareClick }: { token?: IAssetOverview; onShareClick: () => void }) => { const theme = useTheme() const navigate = useNavigate() - const { chain } = useParams() + const { chain, address } = useKyberAIAssetOverview() return ( <> @@ -364,7 +403,7 @@ const SettingButtons = ({ token, onShareClick }: { token?: ITokenOverview; onSha onClick={() => navigate( `${APP_PATHS.PROFILE_MANAGE}${PROFILE_MANAGE_ROUTES.CREATE_ALERT}?${stringify({ - inputCurrency: token?.address ?? '', + inputCurrency: address ?? '', chainId: chain ? NETWORK_TO_CHAINID[chain] : '', })}`, ) @@ -441,20 +480,21 @@ const TokenHeader = ({ isLoading, onShareClick, }: { - token?: ITokenOverview + token?: IAssetOverview isLoading?: boolean onShareClick: () => void }) => { const mixpanelHandler = useMixpanelKyberAI() const above768 = useMedia(`(min-width:${MEDIA_WIDTHS.upToSmall}px)`) - const { chain } = useParams() + const { chain, address } = useKyberAIAssetOverview() return above768 ? ( - + + @@ -481,7 +521,7 @@ const TokenHeader = ({ - + (DiscoverTokenTab.TechnicalAnalysis) - const { data: token, isLoading } = useKyberAITokenOverview() + const { data: token, isLoading, chain: chainParam, address: addressParam } = useKyberAIAssetOverview() const [viewAllTag, setViewAllTag] = useState(false) useEffect(() => { - if (!chain || !address) { - navigate(APP_PATHS.KYBERAI_EXPLORE + `/${defaultExplorePageToken.chain}/${defaultExplorePageToken.address}`) + if (!assetId) { + navigate(APP_PATHS.KYBERAI_EXPLORE + `/${defaultExplorePageToken.assetId}`) setTimeout(() => { const element = document.querySelector('#kyberai-search') as HTMLInputElement element?.focus({ @@ -530,17 +571,44 @@ export default function SingleToken() { }) }, 750) } - }, [chain, address, navigate]) + }, [assetId, navigate]) useEffect(() => { window.scrollTo(0, 0) }, []) + useEffect(() => { + if ((!chainParam || !addressParam) && token?.addresses && token.addresses[0].address && token.addresses[0].chain) { + setSearchParams({ chain: token.addresses[0].chain, address: token.addresses[0].address }) + } + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [token?.addresses]) + return ( setShowShare(true)} /> - {isLoading ? : } + {isLoading ? ( + + + + + + + + + + + ) : ( + + )} @@ -553,7 +621,7 @@ export default function SingleToken() { onClick={() => { mixpanelHandler(MIXPANEL_TYPE.KYBERAI_EXPLORING_VIEW_ALL_CLICK, { token_name: token?.symbol?.toUpperCase(), - network: chain, + network: chainParam, }) setViewAllTag(true) }} @@ -575,7 +643,7 @@ export default function SingleToken() { onClick={() => { mixpanelHandler(MIXPANEL_TYPE.KYBERAI_EXPLORING_ANALYSIS_TYPE_CLICK, { token_name: token?.symbol?.toUpperCase(), - network: chain, + network: chainParam, option: tab === DiscoverTokenTab.OnChainAnalysis ? 'onchain_analysis' : 'technical_analysis', }) setCurrentTab(tab) @@ -609,7 +677,7 @@ export default function SingleToken() { onShareClick={social => mixpanelHandler(MIXPANEL_TYPE.KYBERAI_SHARE_TOKEN_CLICK, { token_name: token?.symbol?.toUpperCase(), - network: chain, + network: chainParam, source: MIXPANEL_KYBERAI_TAG.EXPLORE_SHARE_THIS_TOKEN, share_via: social, }) diff --git a/src/pages/TrueSightV2/pages/TechnicalAnalysis.tsx b/src/pages/TrueSightV2/pages/TechnicalAnalysis.tsx index 2393bf5cf1..5be2aa2547 100644 --- a/src/pages/TrueSightV2/pages/TechnicalAnalysis.tsx +++ b/src/pages/TrueSightV2/pages/TechnicalAnalysis.tsx @@ -1,6 +1,5 @@ import { Trans, t } from '@lingui/macro' import { createContext, useCallback, useMemo, useState } from 'react' -import { useParams } from 'react-router-dom' import { Text } from 'rebass' import styled, { useTheme } from 'styled-components' @@ -23,11 +22,10 @@ import ProchartShareContent from '../components/shareContent/ProchartShareConten import SupportResistanceShareContent from '../components/shareContent/SupportResistanceShareContent' import { FundingRateTable, LiveDEXTrades, SupportResistanceLevel } from '../components/table' import { KYBERAI_CHART_ID, NETWORK_TO_CHAINID } from '../constants' +import useKyberAIAssetOverview from '../hooks/useKyberAIAssetOverview' import { useChartingDataQuery } from '../hooks/useKyberAIData' -import useKyberAITokenOverview from '../hooks/useKyberAITokenOverview' import { ChartTab, ISRLevel, KyberAITimeframe, OHLCData } from '../types' import { navigateToLimitPage } from '../utils' -import { defaultExplorePageToken } from './SingleToken' const Wrapper = styled.div` padding: 20px 0; @@ -82,23 +80,24 @@ export const TechnicalAnalysisContext = createContext() const [prochartDataURL, setProchartDataURL] = useState() const [liveChartTab, setLiveChartTab] = useState(ChartTab.First) const [showSRLevels, setShowSRLevels] = useState(true) const [priceChartResolution, setPriceChartResolution] = useState('4h') const now = Math.floor(Date.now() / 60000) * 60 - const { data, isLoading } = useChartingDataQuery({ - chain: chain || defaultExplorePageToken.chain, - address: address || defaultExplorePageToken.address, - from: now - ({ '1h': 1080000, '4h': 4320000, '1d': 12960000 }[priceChartResolution] || 1080000), - to: now, - candleSize: priceChartResolution, - currency: liveChartTab === ChartTab.First ? 'USD' : 'BTC', - }) - - const { data: tokenOverview } = useKyberAITokenOverview() + const { data, isLoading } = useChartingDataQuery( + { + chain: chain, + address: address, + from: now - ({ '1h': 1080000, '4h': 4320000, '1d': 12960000 }[priceChartResolution] || 1080000), + to: now, + candleSize: priceChartResolution, + currency: liveChartTab === ChartTab.First ? 'USD' : 'BTC', + }, + { skip: !chain || !address }, + ) const SRLevels: ISRLevel[] = useMemo(() => { if (isLoading && !data) return [] diff --git a/src/pages/TrueSightV2/pages/TokenAnalysisList.tsx b/src/pages/TrueSightV2/pages/TokenAnalysisList.tsx index c37d2bba0d..91b60f8b62 100644 --- a/src/pages/TrueSightV2/pages/TokenAnalysisList.tsx +++ b/src/pages/TrueSightV2/pages/TokenAnalysisList.tsx @@ -1,9 +1,8 @@ -import { ChainId } from '@kyberswap/ks-sdk-core' import { Trans, t } from '@lingui/macro' import dayjs from 'dayjs' import { motion } from 'framer-motion' import { rgba } from 'polished' -import { ReactNode, useEffect, useRef, useState } from 'react' +import React, { ReactNode, useEffect, useRef, useState } from 'react' import { Info } from 'react-feather' import Skeleton, { SkeletonTheme } from 'react-loading-skeleton' import { useLocation, useNavigate, useSearchParams } from 'react-router-dom' @@ -39,7 +38,7 @@ import TokenListVariants from '../components/TokenListVariants' import { StarWithAnimation } from '../components/WatchlistStar' import KyberScoreChart from '../components/chart/KyberScoreChart' import TokenAnalysisListShareContent from '../components/shareContent/TokenAnalysisListShareContent' -import { KYBERAI_LISTYPE_TO_MIXPANEL, SUPPORTED_NETWORK_KYBERAI } from '../constants' +import { KYBERAI_LISTYPE_TO_MIXPANEL, NETWORK_TO_CHAINID } from '../constants' import useIsReachMaxLimitWatchedToken from '../hooks/useIsReachMaxLimitWatchedToken' import { useAddToWatchlistMutation, useRemoveFromWatchlistMutation, useTokenListQuery } from '../hooks/useKyberAIData' import { IKyberScoreChart, ITokenList, KyberAIListType } from '../types' @@ -460,7 +459,7 @@ const TokenListDraggableTabs = ({ tab, setTab }: { tab: KyberAIListType; setTab: ) } -const TokenRow = ({ +const TokenRow = React.memo(function TokenRow({ token, currentTab, index, @@ -472,43 +471,32 @@ const TokenRow = ({ index: number isScrolling?: boolean listType: KyberAIListType -}) => { +}) { const navigate = useNavigate() const location = useLocation() const mixpanelHandler = useMixpanelKyberAI() const { account } = useActiveWeb3React() const theme = useTheme() - const [showMenu, setShowMenu] = useState(false) + const reachedMaxLimit = useIsReachMaxLimitWatchedToken() const [showSwapMenu, setShowSwapMenu] = useState(false) - const [menuLeft, setMenuLeft] = useState(undefined) const [addToWatchlist] = useAddToWatchlistMutation() const [removeFromWatchlist] = useRemoveFromWatchlistMutation() - const reachedMaxLimit = useIsReachMaxLimitWatchedToken(token?.tokens.length) const [isWatched, setIsWatched] = useState(false) const [loadingStar, setLoadingStar] = useState(false) const rowRef = useRef(null) - const menuRef = useRef(null) - useOnClickOutside(menuRef, () => setShowMenu(false)) - useOnClickOutside(menuRef, () => setShowSwapMenu(false)) + useOnClickOutside(rowRef, () => setShowSwapMenu(false)) const above768 = useMedia(`(min-width:${MEDIA_WIDTHS.upToSmall}px)`) const hasMutipleChain = token.tokens.length > 1 - const handleRowClick = (e: any) => { - if (hasMutipleChain) { - const left = e.clientX - (rowRef.current?.getBoundingClientRect()?.left || 0) - const rowWidth = rowRef.current?.getBoundingClientRect()?.width || 0 - const menuWidth = menuRef.current?.getBoundingClientRect()?.width || 0 - if (left !== undefined) { - setMenuLeft(Math.min(left, rowWidth - menuWidth)) - setShowMenu(true) - } - } else { - navigate(`${APP_PATHS.KYBERAI_EXPLORE}/${token.tokens[0].chain}/${token.tokens[0].address}`, { + const handleRowClick = () => { + navigate( + `${APP_PATHS.KYBERAI_EXPLORE}/${token.asset_id}?chain=${token.tokens[0].chain}&address=${token.tokens[0].address}`, + { state: { from: location }, - }) - } + }, + ) } const handleWatchlistClick = (e: any) => { @@ -548,7 +536,7 @@ const TokenRow = ({ const latestKyberScore: IKyberScoreChart | undefined = token?.ks_3d?.[token.ks_3d.length - 1] return ( - + {token.symbol}{' '} - - - + @@ -665,14 +651,12 @@ const TokenRow = ({ source: KYBERAI_LISTYPE_TO_MIXPANEL[listType], option: 'explore', }) - if (hasMutipleChain) { - setMenuLeft(undefined) - setShowMenu(true) - } else { - navigate(`${APP_PATHS.KYBERAI_EXPLORE}/${token.tokens[0].chain}/${token.tokens[0].address}`, { + navigate( + `${APP_PATHS.KYBERAI_EXPLORE}/${token.asset_id}?chain=${token.tokens[0].chain}&address=${token.tokens[0].address}`, + { state: { from: location }, - }) - } + }, + ) }} > @@ -689,7 +673,6 @@ const TokenRow = ({ option: 'swap', }) if (hasMutipleChain) { - setMenuLeft(undefined) setShowSwapMenu(true) } else { navigateToSwapPage(token.tokens[0]) @@ -701,20 +684,8 @@ const TokenRow = ({ {hasMutipleChain && ( <> - - navigate(`${APP_PATHS.KYBERAI_EXPLORE}/${chain}/${address}`, { - state: { from: location }, - }) - } - /> { if (chain && address) { @@ -728,7 +699,7 @@ const TokenRow = ({ ) -} +}) const LoadingRowSkeleton = ({ hasExtraCol }: { hasExtraCol?: boolean }) => { return ( <> @@ -771,21 +742,21 @@ export default function TokenAnalysisList() { const [searchParams, setSearchParams] = useSearchParams() const listTypeParam = (searchParams.get('listType') as KyberAIListType) || KyberAIListType.BULLISH const page = +(searchParams.get('page') || 1) - const chain = searchParams.get('chain') || 'all' + const chain = searchParams.get('chain') || undefined const pageSize = 25 const { data, isLoading, isFetching, isError } = useTokenListQuery( listTypeParam === KyberAIListType.MYWATCHLIST ? { type: KyberAIListType.ALL, - chain: (chain && SUPPORTED_NETWORK_KYBERAI[Number(chain) as ChainId]) || 'all', + chain: chain || 'all', page, pageSize, watchlist: true, } : { type: listTypeParam, - chain: (chain && SUPPORTED_NETWORK_KYBERAI[Number(chain) as ChainId]) || 'all', + chain: chain || 'all', page, pageSize, }, @@ -801,18 +772,18 @@ export default function TokenAnalysisList() { searchParams.set('page', page.toString()) setSearchParams(searchParams) } - const handleChainChange = (chainId?: ChainId) => { - if (!chainId) { + const handleChainChange = (chainName?: string) => { + if (!chainName) { searchParams.delete('chain') mixpanelHandler(MIXPANEL_TYPE.KYBERAI_RANKING_SWITCH_CHAIN_CLICK, { source: KYBERAI_LISTYPE_TO_MIXPANEL[listType], network: 'All', }) } else { - searchParams.set('chain', chainId.toString()) + searchParams.set('chain', chainName) mixpanelHandler(MIXPANEL_TYPE.KYBERAI_RANKING_SWITCH_CHAIN_CLICK, { source: KYBERAI_LISTYPE_TO_MIXPANEL[listType], - network: NETWORKS_INFO[chainId].name, + network: NETWORKS_INFO[NETWORK_TO_CHAINID[chainName]].name, }) } searchParams.set('page', '1') @@ -872,7 +843,7 @@ export default function TokenAnalysisList() { > - + @@ -967,15 +938,6 @@ export default function TokenAnalysisList() { [KyberAIListType.TRENDING_SOON]: 'First Discovered On', }[listType as string] || ''} - {/* {sortedColumn === SORT_FIELD.VOLUME ? ( - !sortDirection ? ( - - ) : ( - - ) - ) : ( - '' - )} */} )} @@ -1054,7 +1016,7 @@ export default function TokenAnalysisList() { listData.map((token: ITokenList, index: number) => ( price: number percent_change_24h: number @@ -103,11 +104,10 @@ export interface IFundingRate { } export interface ITokenSearchResult { - address: string name: string symbol: string logo: string - chain: string + assetId: string price: number priceChange24h: number kyberScore?: {