diff --git a/components/shared/Change.tsx b/components/shared/Change.tsx index 3a266d37..7259468f 100644 --- a/components/shared/Change.tsx +++ b/components/shared/Change.tsx @@ -40,7 +40,7 @@ const Change = ({ ? 'text-th-up' : change < 0 ? 'text-th-down' - : 'text-th-fgd-4' + : 'text-th-fgd-2' }`} > {prefix ? prefix : ''} diff --git a/components/stats/SpotMarketsTable.tsx b/components/stats/SpotMarketsTable.tsx index dc1aeac7..b0d910cb 100644 --- a/components/stats/SpotMarketsTable.tsx +++ b/components/stats/SpotMarketsTable.tsx @@ -1,23 +1,49 @@ import { useTranslation } from 'next-i18next' -import { useMemo } from 'react' +import { useCallback } from 'react' import { useViewport } from '../../hooks/useViewport' import { COLORS } from '../../styles/colors' import { breakpoints } from '../../utils/theme' import ContentBox from '../shared/ContentBox' import MarketLogos from '@components/trade/MarketLogos' import useMangoGroup from 'hooks/useMangoGroup' -import { Table, Td, Th, TrBody, TrHead } from '@components/shared/TableElements' +import { + SortableColumnHeader, + Table, + Td, + Th, + TrBody, + TrHead, +} from '@components/shared/TableElements' import FormatNumericValue from '@components/shared/FormatNumericValue' import { floorToDecimal, getDecimalCount, numberCompacter } from 'utils/numbers' import SimpleAreaChart from '@components/shared/SimpleAreaChart' import { Disclosure, Transition } from '@headlessui/react' import { ChevronDownIcon } from '@heroicons/react/20/solid' -import MarketChange from '@components/shared/MarketChange' import useThemeWrapper from 'hooks/useThemeWrapper' import useListedMarketsWithMarketData, { SerumMarketWithMarketData, } from 'hooks/useListedMarketsWithMarketData' import { sortSpotMarkets } from 'utils/markets' +import { useSortableData } from 'hooks/useSortableData' +import Change from '@components/shared/Change' +import { Bank } from '@blockworks-foundation/mango-v4' + +type TableData = { + baseBank: Bank | undefined + change: number + market: SerumMarketWithMarketData + marketName: string + price: number + priceHistory: + | { + price: number + time: string + }[] + | undefined + quoteBank: Bank | undefined + volume: number + isUp: boolean +} const SpotMarketsTable = () => { const { t } = useTranslation('common') @@ -28,6 +54,64 @@ const SpotMarketsTable = () => { const { serumMarketsWithData, isLoading, isFetching } = useListedMarketsWithMarketData() + const formatedTableData = useCallback( + (markets: SerumMarketWithMarketData[]) => { + const formatted = [] + for (const m of markets) { + const baseBank = group?.getFirstBankByTokenIndex(m.baseTokenIndex) + const quoteBank = group?.getFirstBankByTokenIndex(m.quoteTokenIndex) + const market = group?.getSerum3ExternalMarket(m.serumMarketExternal) + let price = 0 + if (baseBank && market && quoteBank) { + price = floorToDecimal( + baseBank.uiPrice / quoteBank.uiPrice, + getDecimalCount(market.tickSize), + ).toNumber() + } + + const pastPrice = m?.marketData?.price_24h || 0 + + const priceHistory = m?.marketData?.price_history + + const volume = m?.marketData?.quote_volume_24h || 0 + + const change = volume > 0 ? ((price - pastPrice) / pastPrice) * 100 : 0 + + const marketName = m.name + + const isUp = + price && priceHistory && priceHistory.length + ? price >= priceHistory[0].price + : false + + const data = { + baseBank, + change, + market: m, + marketName, + price, + priceHistory, + quoteBank, + volume, + isUp, + } + formatted.push(data) + } + return formatted + }, + [group], + ) + + const { + items: tableData, + requestSort, + sortConfig, + } = useSortableData( + formatedTableData( + sortSpotMarkets(serumMarketsWithData, 'quote_volume_24h'), + ), + ) + const loadingMarketData = isLoading || isFetching return ( @@ -36,142 +120,152 @@ const SpotMarketsTable = () => { - - - + + + - + - {sortSpotMarkets(serumMarketsWithData, 'quote_volume_24h').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() - } + {tableData.map((data) => { + const { + baseBank, + change, + market, + marketName, + price, + priceHistory, + quoteBank, + volume, + isUp, + } = data - const priceHistory = mkt?.marketData?.price_history - - const volumeData = mkt?.marketData?.quote_volume_24h - - const volume = volumeData ? volumeData : 0 - - const isUp = - price && priceHistory && priceHistory.length - ? price >= priceHistory[0].price - : false - - return ( - - - - - - + + + + - - ) - }, - )} + + )} +

+ + + + ) + })}
{t('market')}{t('price')}{t('rolling-change')} + requestSort('marketName')} + sortConfig={sortConfig} + title={t('market')} + /> + +
+ requestSort('price')} + sortConfig={sortConfig} + title={t('price')} + /> +
+
+
+ requestSort('change')} + sortConfig={sortConfig} + title={t('rolling-change')} + /> +
+
{t('trade:24h-volume')} +
+ requestSort('volume')} + sortConfig={sortConfig} + title={t('trade:24h-volume')} + /> +
+
-
- -

{mkt.name}

-
-
-
-

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

-
-
-
- -
-
- {!loadingMarketData ? ( - priceHistory && priceHistory.length ? ( -
- -
- ) : baseBank?.name === 'USDC' || - baseBank?.name === 'USDT' ? null : ( -

- {t('unavailable')} -

- ) - ) : ( -
- )} -
-
-

- {volume ? ( - - {numberCompacter.format(volume)}{' '} + return ( + +

+
+ +

{marketName}

+
+
+
+

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

+
+
+
+ +
+
+ {!loadingMarketData ? ( + priceHistory && priceHistory.length ? ( +
+ +
+ ) : baseBank?.name === 'USDC' || + baseBank?.name === 'USDT' ? null : ( +

{t('unavailable')}

+ ) + ) : ( +
+ )} +
+
+

+ {volume ? ( + + {numberCompacter.format(volume)}{' '} + + {quoteBank?.name} - ) : ( - - 0{' '} - - {quoteBank?.name} - + + ) : ( + + 0{' '} + + {quoteBank?.name} - )} -

-
-
) : (
- {sortSpotMarkets(serumMarketsWithData, 'quote_volume_24h').map( - (market) => { - return ( - - ) - }, - )} + {tableData.map((data) => { + return ( + + ) + })}
)} @@ -181,37 +275,26 @@ const SpotMarketsTable = () => { export default SpotMarketsTable const MobileSpotMarketItem = ({ - market, + data, loadingMarketData, }: { - market: SerumMarketWithMarketData + data: TableData loadingMarketData: boolean }) => { const { t } = useTranslation('common') - const { group } = useMangoGroup() const { theme } = useThemeWrapper() - 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 priceHistory = market?.marketData?.price_history - - const volueData = market?.marketData?.quote_volume_24h - - const volume = volueData ? volueData : 0 - - const isUp = - price && priceHistory && priceHistory.length - ? price >= priceHistory[0].price - : false + const { + baseBank, + change, + market, + marketName, + price, + priceHistory, + quoteBank, + volume, + isUp, + } = data return ( @@ -225,7 +308,7 @@ const MobileSpotMarketItem = ({
-

{market.name}

+

{marketName}

{!loadingMarketData ? ( @@ -245,7 +328,7 @@ const MobileSpotMarketItem = ({ ) : (
)} - +