import FavoriteMarketButton from '@components/shared/FavoriteMarketButton' import { Popover } from '@headlessui/react' import { ChevronDownIcon } from '@heroicons/react/20/solid' 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 { floorToDecimal, formatCurrencyValue, formatNumericValue, getDecimalCount, numberCompacter, } 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' import Loading from '@components/shared/Loading' import MarketChange from '@components/shared/MarketChange' import SheenLoader from '@components/shared/SheenLoader' // import Select from '@components/forms/Select' import useListedMarketsWithMarketData from 'hooks/useListedMarketsWithMarketData' import { AllowedKeys, sortPerpMarkets, sortSpotMarkets } from 'utils/markets' const MARKET_LINK_CLASSES = 'grid grid-cols-3 md:grid-cols-4 flex items-center w-full py-2 px-4 rounded-r-md 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 = 'flex w-full items-center justify-between py-2 px-4 md:hover:cursor-not-allowed' // const SORT_KEYS = [ // 'quote_volume_24h', // 'quote_volume_1h', // 'change_24h', // 'change_1h', // ] const MarketSelectDropdown = () => { const { t } = useTranslation('common') const { selectedMarket } = useSelectedMarket() const [spotOrPerp, setSpotOrPerp] = useState( selectedMarket instanceof PerpMarket ? 'perp' : 'spot', ) const [sortByKey] = useState('quote_volume_24h') const { group } = useMangoGroup() const [spotBaseFilter, setSpotBaseFilter] = useState('All') const { perpMarketsWithData, serumMarketsWithData, isLoading, isFetching } = useListedMarketsWithMarketData() const perpMarketsToShow = useMemo(() => { if (!perpMarketsWithData.length) return [] return sortPerpMarkets(perpMarketsWithData, sortByKey) }, [perpMarketsWithData, sortByKey]) const spotBaseTokens: string[] = useMemo(() => { if (serumMarketsWithData.length) { const baseTokens: string[] = ['All'] serumMarketsWithData.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'] }, [serumMarketsWithData]) const serumMarketsToShow = useMemo(() => { if (!serumMarketsWithData.length) return [] if (spotBaseFilter !== 'All') { const filteredMarkets = serumMarketsWithData.filter((m) => { const base = m.name.split('/')[1] return base === spotBaseFilter }) return sortSpotMarkets(filteredMarkets, sortByKey) } else { return sortSpotMarkets(serumMarketsWithData, sortByKey) } }, [serumMarketsWithData, sortByKey, spotBaseFilter]) const loadingMarketData = isLoading || isFetching return ( {({ open, close }) => (
{selectedMarket ? ( ) : ( )}
{selectedMarket?.name || ( {t('loading')} )}
setSpotOrPerp(v)} values={[ ['perp', 0], ['spot', 0], ]} fillWidth />
{spotOrPerp === 'perp' && perpMarketsToShow.length ? ( <>

{t('market')}

{t('price')}

{t('rolling-change')}

{t('daily-volume')}

{perpMarketsToShow.map((m) => { const isComingSoon = m.oracleLastUpdatedSlot == 0 const volumeData = m?.marketData?.quote_volume_24h const volume = volumeData ? volumeData : 0 return (
{!isComingSoon ? ( <> { close() }} shallow={true} >
{m.name}
{formatCurrencyValue( m.uiPrice, getDecimalCount(m.tickSize), )}
{loadingMarketData ? (
) : ( {volume ? ( ${numberCompacter.format(volume)} ) : ( $0 )} )}
) : (
{m.name}
)}
) })} ) : null} {spotOrPerp === 'spot' && serumMarketsToShow.length ? ( <>
{spotBaseTokens.map((tab) => ( ))}
{/* need to sort out change before enabling more sorting options */} {/*
*/}

{t('market')}

{t('price')}

{t('rolling-change')}

{t('daily-volume')}

{serumMarketsToShow.map((m) => { 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 volumeData = m?.marketData?.quote_volume_24h const volume = volumeData ? volumeData : 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}
{loadingMarketData ? (
) : ( {quoteBank?.name === 'USDC' ? '$' : ''} {volume ? numberCompacter.format(volume) : 0} {quoteBank?.name !== 'USDC' ? ( {' '} {quoteBank?.name} ) : null} )}
) })} ) : null}
)} ) } export default MarketSelectDropdown