import { Serum3Market } from '@blockworks-foundation/mango-v4' import { useTranslation } from 'next-i18next' import { useTheme } from 'next-themes' import { useMemo } from 'react' import { useViewport } from '../../hooks/useViewport' import mangoStore from '@store/mangoStore' import { COLORS } from '../../styles/colors' import { breakpoints } from '../../utils/theme' import ContentBox from '../shared/ContentBox' import Change from '../shared/Change' import MarketLogos from '@components/trade/MarketLogos' import useMangoGroup from 'hooks/useMangoGroup' import { Table, Td, Th, TrBody, TrHead } from '@components/shared/TableElements' import FormatNumericValue from '@components/shared/FormatNumericValue' import { useBirdeyeMarketPrices } from 'hooks/useBirdeyeMarketPrices' import { floorToDecimal, getDecimalCount, numberCompacter } from 'utils/numbers' import SimpleAreaChart from '@components/shared/SimpleAreaChart' import { useQuery } from '@tanstack/react-query' import { fetchSpotVolume } from '@components/trade/AdvancedMarketHeader' import { TickerData } from 'types' import { Disclosure, Transition } from '@headlessui/react' import { ChevronDownIcon } from '@heroicons/react/20/solid' const SpotMarketsTable = () => { const { t } = useTranslation('common') const { group } = useMangoGroup() const serumMarkets = mangoStore((s) => s.serumMarkets) const { theme } = useTheme() const { width } = useViewport() const showTableView = width ? width > breakpoints.md : false const { data: birdeyePrices, isLoading: loadingPrices } = useBirdeyeMarketPrices() const { data: spotVolumeData } = useQuery( ['spot-market-volume'], () => fetchSpotVolume(), { cacheTime: 1000 * 60 * 10, staleTime: 1000 * 60, retry: 3, refetchOnWindowFocus: false, } ) return ( {showTableView ? ( {serumMarkets .slice() .sort((a, b) => a.name.localeCompare(b.name)) .map((mkt) => { const baseBank = group?.getFirstBankByTokenIndex( mkt.baseTokenIndex ) const quoteBank = group?.getFirstBankByTokenIndex( mkt.quoteTokenIndex ) const market = group?.getSerum3ExternalMarket( mkt.serumMarketExternal ) let price if (baseBank && market && quoteBank) { price = floorToDecimal( baseBank.uiPrice / quoteBank.uiPrice, getDecimalCount(market.tickSize) ).toNumber() } let tickerData: TickerData | undefined if (spotVolumeData && spotVolumeData.length) { tickerData = spotVolumeData.find( (m: TickerData) => m.ticker_id === mkt.name ) } const birdeyeData = birdeyePrices.find( (m) => m.mint === mkt.serumMarketExternal.toString() ) const change = birdeyeData && price ? ((price - birdeyeData.data[0].value) / birdeyeData.data[0].value) * 100 : 0 const chartData = birdeyeData ? birdeyeData.data : undefined return ( ) })}
{t('market')} {t('price')} {t('rolling-change')} {t('trade:24h-volume')}

{mkt.name}

{price ? ( <> {' '} {quoteBank?.name !== 'USDC' ? ( {quoteBank?.name} ) : null} ) : ( '–' )}

{!loadingPrices ? ( chartData !== undefined ? (
= 0 ? COLORS.UP[theme] : COLORS.DOWN[theme] } data={chartData} name={baseBank!.name + quoteBank!.name} xKey="unixTime" yKey="value" />
) : baseBank?.name === 'USDC' || baseBank?.name === 'USDT' ? null : (

{t('unavailable')}

) ) : (
)}

{tickerData ? ( {numberCompacter.format( parseFloat(tickerData.target_volume) )}{' '} {quoteBank?.name} ) : ( '–' )}

) : (
{serumMarkets .slice() .sort((a, b) => a.name.localeCompare(b.name)) .map((market) => { return ( ) })}
)}
) } export default SpotMarketsTable const MobileSpotMarketItem = ({ market, spotVolumeData, }: { market: Serum3Market spotVolumeData: TickerData[] | undefined }) => { const { t } = useTranslation('common') const { data: birdeyePrices, isLoading: loadingPrices } = useBirdeyeMarketPrices() const { group } = useMangoGroup() const { theme } = useTheme() const baseBank = group?.getFirstBankByTokenIndex(market.baseTokenIndex) const quoteBank = group?.getFirstBankByTokenIndex(market.quoteTokenIndex) const serumMarket = group?.getSerum3ExternalMarket(market.serumMarketExternal) const price = useMemo(() => { if (!baseBank || !quoteBank || !serumMarket) return 0 return floorToDecimal( baseBank.uiPrice / quoteBank.uiPrice, getDecimalCount(serumMarket.tickSize) ).toNumber() }, [baseBank, quoteBank, serumMarket]) const birdeyeData = useMemo(() => { if (!loadingPrices) { return birdeyePrices.find( (m) => m.mint === market.serumMarketExternal.toString() ) } return null }, [loadingPrices]) const change = useMemo(() => { if (birdeyeData && price) { return ( ((price - birdeyeData.data[0].value) / birdeyeData.data[0].value) * 100 ) } return 0 }, [birdeyeData, price]) const chartData = useMemo(() => { if (birdeyeData) { return birdeyeData.data } return undefined }, [birdeyeData]) let tickerData: TickerData | undefined if (spotVolumeData && spotVolumeData.length) { tickerData = spotVolumeData.find( (m: TickerData) => m.ticker_id === market.name ) } return ( {({ open }) => ( <>

{market.name}

{!loadingPrices ? ( chartData !== undefined ? (
= 0 ? COLORS.UP[theme] : COLORS.DOWN[theme] } data={chartData} name={baseBank!.name + quoteBank!.name} xKey="unixTime" yKey="value" />
) : (

{t('unavailable')}

) ) : (
)}

{t('price')}

{price ? ( <> {' '} {quoteBank?.name !== 'USDC' ? ( {quoteBank?.name} ) : null} ) : ( '-' )}

{t('trade:24h-volume')}

{tickerData ? ( {numberCompacter.format( parseFloat(tickerData.target_volume) )}{' '} {quoteBank?.name} ) : ( '–' )}

)} ) }