// import ChartRangeButtons from '@components/shared/ChartRangeButtons' import Change from '@components/shared/Change' import FavoriteMarketButton from '@components/shared/FavoriteMarketButton' import SheenLoader from '@components/shared/SheenLoader' import { getOneDayPerpStats } from '@components/stats/PerpMarketsOverviewTable' import { Popover } from '@headlessui/react' import { ChevronDownIcon } from '@heroicons/react/20/solid' import mangoStore from '@store/mangoStore' import { useBirdeyeMarketPrices } from 'hooks/useBirdeyeMarketPrices' import useMangoGroup from 'hooks/useMangoGroup' import useSelectedMarket from 'hooks/useSelectedMarket' import { useTranslation } from 'next-i18next' import Link from 'next/link' import { useMemo, useState } from 'react' import { DEFAULT_MARKET_NAME } from 'utils/constants' import { floorToDecimal, formatCurrencyValue, formatNumericValue, getDecimalCount, } from 'utils/numbers' import MarketLogos from './MarketLogos' import SoonBadge from '@components/shared/SoonBadge' import TabButtons from '@components/shared/TabButtons' import { PerpMarket } from '@blockworks-foundation/mango-v4' const MARKET_LINK_WRAPPER_CLASSES = 'flex items-center justify-between px-4 md:pl-6 md:pr-4' const MARKET_LINK_CLASSES = 'mr-1 -ml-3 flex w-full items-center justify-between rounded-md py-2 px-3 focus:outline-none focus-visible:text-th-active md:hover:cursor-pointer md:hover:bg-th-bkg-3 md:hover:text-th-fgd-1' const MARKET_LINK_DISABLED_CLASSES = 'mr-2 -ml-3 flex w-full items-center justify-between rounded-md py-2 px-3 md:hover:cursor-not-allowed' const MarketSelectDropdown = () => { const { t } = useTranslation('common') const { selectedMarket } = useSelectedMarket() const [spotOrPerp, setSpotOrPerp] = useState( selectedMarket instanceof PerpMarket ? 'perp' : 'spot' ) const serumMarkets = mangoStore((s) => s.serumMarkets) const allPerpMarkets = mangoStore((s) => s.perpMarkets) const perpStats = mangoStore((s) => s.perpStats.data) const loadingPerpStats = mangoStore((s) => s.perpStats.loading) const { group } = useMangoGroup() const { data: birdeyePrices, isLoading: loadingPrices } = useBirdeyeMarketPrices() const [spotBaseFilter, setSpotBaseFilter] = useState('All') const perpMarkets = useMemo(() => { return allPerpMarkets .filter( (p) => p.publicKey.toString() !== '9Y8paZ5wUpzLFfQuHz8j2RtPrKsDtHx9sbgFmWb5abCw' ) .sort((a, b) => a.oracleLastUpdatedSlot == 0 ? -1 : a.name.localeCompare(b.name) ) }, [allPerpMarkets]) const spotBaseTokens: string[] = useMemo(() => { if (serumMarkets.length) { const baseTokens: string[] = ['All'] serumMarkets.map((m) => { const base = m.name.split('/')[1] if (!baseTokens.includes(base)) { baseTokens.push(base) } }) return baseTokens.sort((a, b) => a.localeCompare(b)) } return ['All'] }, [serumMarkets]) const serumMarketsToShow = useMemo(() => { if (!serumMarkets || !serumMarkets.length) return [] if (spotBaseFilter !== 'All') { return serumMarkets.filter((m) => { const base = m.name.split('/')[1] return base === spotBaseFilter }) } else { return serumMarkets } }, [serumMarkets, spotBaseFilter]) return ( {({ open, close }) => (
{selectedMarket ? : null}
{selectedMarket?.name || DEFAULT_MARKET_NAME}
setSpotOrPerp(v)} values={[ ['perp', 0], ['spot', 0], ]} fillWidth />
{spotOrPerp === 'perp' && perpMarkets?.length ? perpMarkets.map((m) => { const changeData = getOneDayPerpStats(perpStats, m.name) const isComingSoon = m.oracleLastUpdatedSlot == 0 const change = changeData.length ? ((m.uiPrice - changeData[0].price) / changeData[0].price) * 100 : 0 return (
{!isComingSoon ? ( <> { close() }} shallow={true} >
{m.name}
{formatCurrencyValue( m.uiPrice, getDecimalCount(m.tickSize) )} {!loadingPerpStats ? ( ) : (
)}
) : (
{m.name}
)}
) }) : null} {spotOrPerp === 'spot' && serumMarkets?.length ? ( <>
{spotBaseTokens.map((tab) => ( ))}
{serumMarketsToShow .map((x) => x) .sort((a, b) => a.name.localeCompare(b.name)) .map((m) => { const birdeyeData = birdeyePrices?.length ? birdeyePrices.find( (market) => market.mint === m.serumMarketExternal.toString() ) : null const baseBank = group?.getFirstBankByTokenIndex( m.baseTokenIndex ) const quoteBank = group?.getFirstBankByTokenIndex( m.quoteTokenIndex ) const market = group?.getSerum3ExternalMarket( m.serumMarketExternal ) let price if (baseBank && market && quoteBank) { price = floorToDecimal( baseBank.uiPrice / quoteBank.uiPrice, getDecimalCount(market.tickSize) ).toNumber() } const change = birdeyeData && price ? ((price - birdeyeData.data[0].value) / birdeyeData.data[0].value) * 100 : 0 return (
{ close() }} shallow={true} >
{m.name}
{price && market?.tickSize ? ( {quoteBank?.name === 'USDC' ? '$' : ''} {getDecimalCount(market.tickSize) <= 6 ? formatNumericValue( price, getDecimalCount(market.tickSize) ) : price.toExponential(3)}{' '} {quoteBank?.name !== 'USDC' ? ( {quoteBank?.name} ) : null} ) : null} {!loadingPrices ? ( change ? ( ) : ( ) ) : (
)}
) })} ) : null}
)} ) } export default MarketSelectDropdown