mango-v4-ui/components/trade/AdvancedMarketHeader.tsx

221 lines
8.0 KiB
TypeScript
Raw Normal View History

2023-05-30 17:05:02 -07:00
import { PerpMarket, Serum3Market } from '@blockworks-foundation/mango-v4'
2023-03-28 19:01:53 -07:00
import { IconButton, LinkButton } from '@components/shared/Button'
2023-05-02 10:47:26 -07:00
import { getOneDayPerpStats } from '@components/stats/PerpMarketsOverviewTable'
2023-03-28 19:01:53 -07:00
import { ChartBarIcon, InformationCircleIcon } from '@heroicons/react/20/solid'
2023-02-09 19:20:46 -08:00
import mangoStore from '@store/mangoStore'
2022-11-20 12:20:27 -08:00
import useSelectedMarket from 'hooks/useSelectedMarket'
2022-09-13 23:24:26 -07:00
import { useTranslation } from 'next-i18next'
import { useEffect, useMemo, useState } from 'react'
2023-04-25 13:21:32 -07:00
import { numberCompacter } from 'utils/numbers'
2022-11-30 07:46:20 -08:00
import MarketSelectDropdown from './MarketSelectDropdown'
import PerpFundingRate from './PerpFundingRate'
2023-04-03 16:20:59 -07:00
import SheenLoader from '@components/shared/SheenLoader'
2023-04-26 19:36:00 -07:00
import PerpMarketDetailsModal from '@components/modals/PerpMarketDetailsModal'
2023-04-03 20:49:28 -07:00
import useMangoGroup from 'hooks/useMangoGroup'
2023-04-25 13:21:32 -07:00
import OraclePrice from './OraclePrice'
2023-04-26 20:39:49 -07:00
import SpotMarketDetailsModal from '@components/modals/SpotMarketDetailsModal'
2023-05-30 17:05:02 -07:00
import { useQuery } from '@tanstack/react-query'
2023-05-31 05:15:50 -07:00
import { MANGO_DATA_OPENBOOK_URL } from 'utils/constants'
import { TickerData } from 'types'
2023-06-13 18:09:15 -07:00
import ManualRefresh from '@components/shared/ManualRefresh'
import { useViewport } from 'hooks/useViewport'
import { breakpoints } from 'utils/theme'
2023-07-13 22:47:05 -07:00
import MarketChange from '@components/shared/MarketChange'
2023-05-30 17:05:02 -07:00
2023-05-31 05:15:50 -07:00
export const fetchSpotVolume = async () => {
2023-05-30 17:05:02 -07:00
try {
2023-05-31 05:15:50 -07:00
const data = await fetch(`${MANGO_DATA_OPENBOOK_URL}/coingecko/tickers`)
2023-05-30 17:05:02 -07:00
const res = await data.json()
return res
} catch (e) {
console.log('Failed to fetch spot volume data', e)
}
}
2023-03-04 21:47:29 -08:00
2023-01-18 18:42:29 -08:00
const AdvancedMarketHeader = ({
showChart,
setShowChart,
}: {
showChart?: boolean
setShowChart?: (x: boolean) => void
}) => {
2022-10-03 03:38:05 -07:00
const { t } = useTranslation(['common', 'trade'])
2023-02-09 19:20:46 -08:00
const perpStats = mangoStore((s) => s.perpStats.data)
2023-07-13 22:47:05 -07:00
const { serumOrPerpMarket, selectedMarket } = useSelectedMarket()
2023-02-09 19:20:46 -08:00
const selectedMarketName = mangoStore((s) => s.selectedMarket.name)
2023-03-28 19:01:53 -07:00
const [showMarketDetails, setShowMarketDetails] = useState(false)
2023-04-03 20:49:28 -07:00
const { group } = useMangoGroup()
2023-06-13 18:09:15 -07:00
const { width } = useViewport()
const isMobile = width ? width < breakpoints.md : false
2023-05-30 17:05:02 -07:00
const {
data: spotVolumeData,
isLoading: loadingSpotVolume,
isFetching: fetchingSpotVolume,
} = useQuery(['spot-volume', selectedMarketName], () => fetchSpotVolume(), {
cacheTime: 1000 * 60 * 10,
staleTime: 1000 * 60,
retry: 3,
refetchOnWindowFocus: false,
enabled: selectedMarket instanceof Serum3Market,
})
const spotMarketVolume = useMemo(() => {
if (!spotVolumeData || !spotVolumeData.length) return
return spotVolumeData.find(
(mkt: TickerData) => mkt.ticker_id === selectedMarketName
)
}, [selectedMarketName, spotVolumeData])
2023-02-09 19:20:46 -08:00
useEffect(() => {
2023-04-03 20:49:28 -07:00
if (group) {
2023-02-09 19:20:46 -08:00
const actions = mangoStore.getState().actions
actions.fetchPerpStats()
}
2023-04-03 20:49:28 -07:00
}, [group])
2023-02-09 19:20:46 -08:00
2023-05-31 17:17:31 -07:00
const oneDayPerpStats = useMemo(() => {
if (
!perpStats ||
!perpStats.length ||
!selectedMarketName ||
!selectedMarketName.includes('PERP')
)
return []
return getOneDayPerpStats(perpStats, selectedMarketName)
}, [perpStats, selectedMarketName])
2023-06-04 18:06:03 -07:00
const perpVolume = useMemo(() => {
if (!oneDayPerpStats.length) return
return (
oneDayPerpStats[oneDayPerpStats.length - 1].cumulative_quote_volume -
oneDayPerpStats[0].cumulative_quote_volume
)
}, [oneDayPerpStats])
2023-05-31 17:17:31 -07:00
2022-09-13 23:24:26 -07:00
return (
2023-03-28 19:01:53 -07:00
<>
<div className="flex flex-col bg-th-bkg-1 md:h-12 md:flex-row md:items-center">
<div className="w-full pl-4 md:w-auto md:py-0 md:pl-6 lg:pb-0">
2023-03-28 19:01:53 -07:00
<MarketSelectDropdown />
</div>
<div className="hide-scroll flex w-full items-center justify-between overflow-x-auto border-t border-th-bkg-3 py-2 px-5 md:border-t-0 md:py-0 md:px-0 md:pr-6">
<div className="flex items-center">
2023-04-25 13:21:32 -07:00
<>
2023-07-13 22:47:05 -07:00
<OraclePrice />
2023-04-25 13:21:32 -07:00
</>
2023-03-28 19:01:53 -07:00
<div className="ml-6 flex-col whitespace-nowrap">
2023-05-11 21:08:06 -07:00
<div className="mb-0.5 text-xs text-th-fgd-4">
{t('rolling-change')}
</div>
2023-07-13 22:47:05 -07:00
<MarketChange market={selectedMarket} size="small" />
2023-01-18 18:42:29 -08:00
</div>
2023-03-28 19:01:53 -07:00
{serumOrPerpMarket instanceof PerpMarket ? (
<>
2023-06-04 18:06:03 -07:00
<div className="ml-6 flex-col whitespace-nowrap text-xs">
2023-05-31 17:17:31 -07:00
<div className="mb-0.5 text-th-fgd-4 ">
{t('trade:24h-volume')}
</div>
{perpVolume ? (
<span className="font-mono">
${numberCompacter.format(perpVolume)}{' '}
</span>
) : (
'-'
)}
2023-06-04 18:06:03 -07:00
</div>
2023-04-17 09:25:59 -07:00
<PerpFundingRate />
2023-03-28 19:01:53 -07:00
<div className="ml-6 flex-col whitespace-nowrap text-xs">
2023-05-11 21:08:06 -07:00
<div className="mb-0.5 text-th-fgd-4 ">
2023-03-28 19:01:53 -07:00
{t('trade:open-interest')}
</div>
<span className="font-mono">
$
{numberCompacter.format(
serumOrPerpMarket.baseLotsToUi(
serumOrPerpMarket.openInterest
) * serumOrPerpMarket.uiPrice
)}
<span className="mx-1">|</span>
{numberCompacter.format(
serumOrPerpMarket.baseLotsToUi(
serumOrPerpMarket.openInterest
)
)}{' '}
<span className="font-body text-th-fgd-3">
{serumOrPerpMarket.name.split('-')[0]}
</span>
</span>
2023-03-28 19:01:53 -07:00
</div>
</>
2023-05-30 17:05:02 -07:00
) : (
<div className="ml-6 flex-col whitespace-nowrap text-xs">
<div className="mb-0.5 text-th-fgd-4 ">
{t('trade:24h-volume')}
</div>
{!loadingSpotVolume && !fetchingSpotVolume ? (
spotMarketVolume ? (
<span className="font-mono">
{numberCompacter.format(spotMarketVolume.target_volume)}{' '}
2023-05-31 17:17:31 -07:00
<span className="font-body text-th-fgd-3">
2023-06-29 21:00:28 -07:00
{selectedMarketName?.split('/')[1]}
2023-05-30 17:05:02 -07:00
</span>
</span>
) : (
'-'
)
) : (
<SheenLoader className="mt-0.5">
<div className="h-3.5 w-12 bg-th-bkg-2" />
</SheenLoader>
)}
</div>
)}
2023-03-28 19:01:53 -07:00
</div>
<div className="ml-6 flex items-center space-x-4">
2023-06-13 18:09:15 -07:00
<ManualRefresh
hideBg={isMobile}
size={isMobile ? undefined : 'small'}
/>
2023-04-26 20:39:49 -07:00
<LinkButton
className="flex items-center whitespace-nowrap text-th-fgd-3"
onClick={() => setShowMarketDetails(true)}
>
<InformationCircleIcon className="h-5 w-5 flex-shrink-0 md:mr-1.5 md:h-4 md:w-4" />
<span className="hidden text-xs md:inline">
{t('trade:market-details', { market: '' })}
</span>
</LinkButton>
2023-03-28 19:01:53 -07:00
{setShowChart ? (
<IconButton
className={showChart ? 'text-th-active' : 'text-th-fgd-2'}
onClick={() => setShowChart(!showChart)}
hideBg
>
<ChartBarIcon className="h-5 w-5" />
</IconButton>
) : null}
</div>
2023-03-28 19:01:53 -07:00
</div>
2022-12-06 21:25:37 -08:00
</div>
2023-03-28 19:01:53 -07:00
{showMarketDetails ? (
2023-04-26 20:39:49 -07:00
selectedMarket instanceof PerpMarket ? (
<PerpMarketDetailsModal
isOpen={showMarketDetails}
onClose={() => setShowMarketDetails(false)}
market={selectedMarket}
/>
) : (
<SpotMarketDetailsModal
isOpen={showMarketDetails}
onClose={() => setShowMarketDetails(false)}
market={selectedMarket}
/>
)
2023-03-28 19:01:53 -07:00
) : null}
</>
2022-09-13 23:24:26 -07:00
)
}
export default AdvancedMarketHeader