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

181 lines
6.2 KiB
TypeScript
Raw Normal View History

2022-10-10 19:16:13 -07:00
import { Serum3Market, PerpMarket } from '@blockworks-foundation/mango-v4'
2022-10-05 22:11:28 -07:00
import Change from '@components/shared/Change'
2022-10-26 03:49:05 -07:00
import TabUnderline from '@components/shared/TabUnderline'
2022-09-13 23:24:26 -07:00
import { Popover } from '@headlessui/react'
2022-09-26 04:53:49 -07:00
import { ChevronDownIcon } from '@heroicons/react/20/solid'
2022-09-13 23:24:26 -07:00
import mangoStore from '@store/mangoStore'
2022-11-17 04:53:42 -08:00
import useOraclePrice from 'hooks/useOraclePrice'
2022-09-13 23:24:26 -07:00
import { useTranslation } from 'next-i18next'
import { useCallback, useEffect, useMemo, useState } from 'react'
2022-09-13 23:24:26 -07:00
import { DEFAULT_MARKET_NAME } from 'utils/constants'
import { formatFixedDecimals } from 'utils/numbers'
2022-09-26 04:53:49 -07:00
import MarketLogos from './MarketLogos'
2022-09-13 23:24:26 -07:00
const MarketSelectDropdown = () => {
const selectedMarket = mangoStore((s) => s.selectedMarket.current)
const serumMarkets = mangoStore((s) => s.serumMarkets)
2022-10-10 19:16:13 -07:00
const perpMarkets = mangoStore((s) => s.perpMarkets)
2022-09-13 23:24:26 -07:00
const set = mangoStore((s) => s.set)
2022-10-26 03:49:05 -07:00
const [activeTab, setActiveTab] = useState('perp')
2022-09-13 23:24:26 -07:00
const handleSelectMarket = useCallback(
2022-10-10 19:16:13 -07:00
(market: Serum3Market | PerpMarket, close: any) => {
2022-09-13 23:24:26 -07:00
set((s) => {
s.selectedMarket.current = market
})
close()
},
[set]
)
return (
<Popover>
{({ close, open }) => (
2022-09-21 21:25:24 -07:00
<div
className="relative flex flex-col overflow-visible"
2022-09-24 03:20:49 -07:00
id="trade-step-one"
2022-09-21 21:25:24 -07:00
>
2022-09-25 20:12:37 -07:00
<Popover.Button className="default-transition flex w-full items-center justify-between hover:text-th-primary">
2022-10-10 19:16:13 -07:00
<>
{selectedMarket ? <MarketLogos market={selectedMarket} /> : null}
</>
2022-09-29 21:21:23 -07:00
<div className="text-xl font-bold text-th-fgd-1 md:text-base">
2022-09-14 21:12:00 -07:00
{selectedMarket?.name || DEFAULT_MARKET_NAME}
2022-09-13 23:24:26 -07:00
</div>
<ChevronDownIcon
className={`${
open ? 'rotate-180' : 'rotate-360'
2022-09-14 21:12:00 -07:00
} mt-0.5 ml-2 h-6 w-6 flex-shrink-0 text-th-fgd-3`}
2022-09-13 23:24:26 -07:00
/>
</Popover.Button>
2022-10-26 03:49:05 -07:00
<Popover.Panel className="absolute -left-5 top-[46px] z-50 mr-4 w-screen bg-th-bkg-2 pb-2 pt-4 sm:w-56 md:top-[37px]">
<TabUnderline
activeValue={activeTab}
onChange={(v) => setActiveTab(v)}
small
values={['perp', 'spot']}
/>
{activeTab === 'spot'
? serumMarkets?.length
? serumMarkets.map((m) => {
return (
<div
key={m.publicKey.toString()}
className="default-transition flex items-center py-2 px-4 hover:cursor-pointer hover:bg-th-bkg-2"
onClick={() => handleSelectMarket(m, close)}
>
<MarketLogos market={m} />
<span
className={
m.name === selectedMarket?.name
? 'text-th-primary'
: ''
}
2022-10-10 19:16:13 -07:00
>
2022-10-26 03:49:05 -07:00
{m.name}
</span>
</div>
)
})
: null
: null}
{activeTab === 'perp'
? perpMarkets?.length
? perpMarkets.map((m) => {
return (
<div
key={m.publicKey.toString()}
className="default-transition flex items-center py-2 px-4 hover:cursor-pointer hover:bg-th-bkg-2"
onClick={() => handleSelectMarket(m, close)}
>
<MarketLogos market={m} />
<span
className={
m.name === selectedMarket?.name
? 'text-th-primary'
: ''
}
2022-10-10 19:16:13 -07:00
>
2022-10-26 03:49:05 -07:00
{m.name}
</span>
</div>
)
})
: null
: null}
2022-09-13 23:24:26 -07:00
</Popover.Panel>
</div>
)}
</Popover>
)
}
const AdvancedMarketHeader = () => {
2022-10-03 03:38:05 -07:00
const { t } = useTranslation(['common', 'trade'])
2022-09-13 23:24:26 -07:00
const selectedMarket = mangoStore((s) => s.selectedMarket.current)
const serumMarketPrices = mangoStore((s) => s.serumMarketPrices.data)
2022-11-17 04:53:42 -08:00
const loadSerumMarketPrices = mangoStore((s) => s.serumMarketPrices.loading)
2022-11-09 17:48:03 -08:00
const actions = mangoStore((s) => s.actions)
const serumMarkets = mangoStore((s) => s.serumMarkets)
2022-11-17 04:53:42 -08:00
const oraclePrice = useOraclePrice()
2022-11-09 17:48:03 -08:00
useEffect(() => {
if (serumMarkets.length) {
actions.fetchSerumMarketPrices()
}
}, [actions, serumMarkets])
2022-09-13 23:24:26 -07:00
const marketPrices = useMemo(() => {
if (selectedMarket instanceof Serum3Market) {
const prices = serumMarketPrices.find(
(m) =>
m.length &&
m[0].address === selectedMarket.serumMarketExternal.toString()
)
return prices
}
// need to handle perp
2022-11-09 17:48:03 -08:00
}, [selectedMarket, serumMarketPrices])
2022-09-13 23:24:26 -07:00
const change = useMemo(() => {
2022-11-17 04:53:42 -08:00
if (marketPrices && oraclePrice) {
return (
2022-11-17 04:53:42 -08:00
((oraclePrice - marketPrices[0].value) / marketPrices[0].value) * 100
)
}
return 0
}, [marketPrices])
2022-09-13 23:24:26 -07:00
return (
2022-09-16 03:49:10 -07:00
<div className="flex h-16 items-center bg-th-bkg-1 px-5 md:h-12">
<div className="md:pr-6 lg:pb-0">
2022-09-13 23:24:26 -07:00
<div className="flex items-center">
<MarketSelectDropdown />
</div>
</div>
2022-09-21 21:25:24 -07:00
<div id="trade-step-two" className="ml-6 flex-col">
2022-10-03 03:38:05 -07:00
<div className="text-xs text-th-fgd-4">{t('trade:oracle-price')}</div>
2022-11-17 04:53:42 -08:00
<div className="font-mono text-xs text-th-fgd-2">
{oraclePrice ? (
`$${formatFixedDecimals(oraclePrice)}`
) : (
<span className="text-th-fgd-4"></span>
)}
</div>
2022-09-13 23:24:26 -07:00
</div>
<div className="ml-6 flex-col">
2022-09-16 03:49:10 -07:00
<div className="text-xs text-th-fgd-4">{t('rolling-change')}</div>
{change ? (
<Change change={change} size="small" />
2022-11-17 04:53:42 -08:00
) : loadSerumMarketPrices ? (
<span className="text-th-fgd-4"></span>
) : (
<div className="font-mono text-xs">{t('unavailable')}</div>
)}
2022-09-13 23:24:26 -07:00
</div>
</div>
)
}
export default AdvancedMarketHeader