add spot markets to stats
This commit is contained in:
parent
67ef7d626b
commit
dc80b9d94b
|
@ -0,0 +1,197 @@
|
|||
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 { formatFixedDecimals } from '../../utils/numbers'
|
||||
import { breakpoints } from '../../utils/theme'
|
||||
import ContentBox from '../shared/ContentBox'
|
||||
import Change from '../shared/Change'
|
||||
import SimpleAreaChart from '../shared/SimpleAreaChart'
|
||||
import MarketLogos from '@components/trade/MarketLogos'
|
||||
|
||||
const SpotMarketsTable = () => {
|
||||
const { t } = useTranslation('common')
|
||||
const coingeckoPrices = mangoStore((s) => s.coingeckoPrices.data)
|
||||
const loadingCoingeckoPrices = mangoStore((s) => s.coingeckoPrices.loading)
|
||||
const group = mangoStore((s) => s.group)
|
||||
const serumMarkets = mangoStore((s) => s.serumMarkets)
|
||||
const { theme } = useTheme()
|
||||
const { width } = useViewport()
|
||||
const showTableView = width ? width > breakpoints.md : false
|
||||
|
||||
return (
|
||||
<ContentBox hideBorder hidePadding>
|
||||
{showTableView ? (
|
||||
<table className="-mt-1 min-w-full">
|
||||
<thead>
|
||||
<tr>
|
||||
<th className="text-left">{t('market')}</th>
|
||||
<th className="text-right">{t('price')}</th>
|
||||
<th className="hidden text-right lg:block"></th>
|
||||
<th className="text-right">{t('rolling-change')}</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{serumMarkets.map((market) => {
|
||||
const bank = group?.getFirstBankByTokenIndex(
|
||||
market.baseTokenIndex
|
||||
)
|
||||
const oraclePrice = bank?.uiPrice
|
||||
|
||||
const coingeckoData = coingeckoPrices.find((asset) =>
|
||||
bank?.name === 'soETH'
|
||||
? asset.symbol === 'ETH'
|
||||
: asset.symbol === bank?.name
|
||||
)
|
||||
|
||||
const change = coingeckoData
|
||||
? ((coingeckoData.prices[coingeckoData.prices.length - 1][1] -
|
||||
coingeckoData.prices[0][1]) /
|
||||
coingeckoData.prices[0][1]) *
|
||||
100
|
||||
: 0
|
||||
|
||||
const chartData = coingeckoData ? coingeckoData.prices : undefined
|
||||
|
||||
return (
|
||||
<tr key={market.publicKey.toString()}>
|
||||
<td>
|
||||
<div className="flex items-center">
|
||||
<MarketLogos serumMarket={market} />
|
||||
<p className="font-body tracking-wide">{market.name}</p>
|
||||
</div>
|
||||
</td>
|
||||
<td>
|
||||
<div className="flex flex-col text-right">
|
||||
<p>{formatFixedDecimals(oraclePrice!, true)}</p>
|
||||
</div>
|
||||
</td>
|
||||
<td>
|
||||
{!loadingCoingeckoPrices ? (
|
||||
chartData !== undefined ? (
|
||||
<SimpleAreaChart
|
||||
color={
|
||||
change >= 0
|
||||
? COLORS.GREEN[theme]
|
||||
: COLORS.RED[theme]
|
||||
}
|
||||
data={chartData}
|
||||
height={40}
|
||||
name={bank!.name}
|
||||
width={104}
|
||||
xKey="0"
|
||||
yKey="1"
|
||||
/>
|
||||
) : bank?.name === 'USDC' ||
|
||||
bank?.name === 'USDT' ? null : (
|
||||
<p className="mb-0 text-th-fgd-4">{t('unavailable')}</p>
|
||||
)
|
||||
) : (
|
||||
<div className="h-10 w-[104px] animate-pulse rounded bg-th-bkg-3" />
|
||||
)}
|
||||
</td>
|
||||
<td>
|
||||
<div className="flex flex-col items-end">
|
||||
<Change change={change} />
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
)
|
||||
})}
|
||||
</tbody>
|
||||
</table>
|
||||
) : (
|
||||
<div>
|
||||
{serumMarkets.map((market) => {
|
||||
return (
|
||||
<MobileSpotMarketItem
|
||||
key={market.publicKey.toString()}
|
||||
market={market}
|
||||
/>
|
||||
)
|
||||
})}
|
||||
</div>
|
||||
)}
|
||||
</ContentBox>
|
||||
)
|
||||
}
|
||||
|
||||
export default SpotMarketsTable
|
||||
|
||||
const MobileSpotMarketItem = ({ market }: { market: Serum3Market }) => {
|
||||
const { t } = useTranslation('common')
|
||||
const coingeckoPrices = mangoStore((s) => s.coingeckoPrices.data)
|
||||
const loadingCoingeckoPrices = mangoStore((s) => s.coingeckoPrices.loading)
|
||||
const group = mangoStore((s) => s.group)
|
||||
const { theme } = useTheme()
|
||||
const bank = group?.getFirstBankByTokenIndex(market.baseTokenIndex)
|
||||
|
||||
const coingeckoData = useMemo(() => {
|
||||
if (!loadingCoingeckoPrices && bank) {
|
||||
return coingeckoPrices.find((asset) =>
|
||||
bank.name === 'soETH'
|
||||
? asset.symbol === 'ETH'
|
||||
: asset.symbol === bank?.name
|
||||
)
|
||||
}
|
||||
return null
|
||||
}, [loadingCoingeckoPrices, bank])
|
||||
|
||||
const change = useMemo(() => {
|
||||
if (coingeckoData) {
|
||||
return (
|
||||
((coingeckoData.prices[coingeckoData.prices.length - 1][1] -
|
||||
coingeckoData.prices[0][1]) /
|
||||
coingeckoData.prices[0][1]) *
|
||||
100
|
||||
)
|
||||
}
|
||||
return 0
|
||||
}, [coingeckoData])
|
||||
|
||||
const chartData = useMemo(() => {
|
||||
if (coingeckoData) {
|
||||
return coingeckoData.prices
|
||||
}
|
||||
return undefined
|
||||
}, [coingeckoData])
|
||||
|
||||
return (
|
||||
<div className="border-b border-th-bkg-3 px-6 py-4">
|
||||
<div className="flex items-center justify-between">
|
||||
<div className="flex items-center">
|
||||
<MarketLogos serumMarket={market} />
|
||||
<div>
|
||||
<p className="text-th-fgd-1">{market.name}</p>
|
||||
<div className="flex items-center space-x-3">
|
||||
<p className="font-mono">
|
||||
{formatFixedDecimals(bank?.uiPrice!, true)}
|
||||
</p>
|
||||
<Change change={change} />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{!loadingCoingeckoPrices ? (
|
||||
chartData !== undefined ? (
|
||||
<SimpleAreaChart
|
||||
color={change >= 0 ? COLORS.GREEN[theme] : COLORS.RED[theme]}
|
||||
data={chartData}
|
||||
height={40}
|
||||
name={bank!.name}
|
||||
width={104}
|
||||
xKey="0"
|
||||
yKey="1"
|
||||
/>
|
||||
) : bank?.name === 'USDC' || bank?.name === 'USDT' ? null : (
|
||||
<p className="mb-0 text-th-fgd-4">{t('unavailable')}</p>
|
||||
)
|
||||
) : (
|
||||
<div className="h-10 w-[104px] animate-pulse rounded bg-th-bkg-3" />
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
|
@ -0,0 +1,37 @@
|
|||
import TabButtons from '@components/shared/TabButtons'
|
||||
import { useMemo, useState } from 'react'
|
||||
import SpotMarketsTable from './SpotMarketsTable'
|
||||
import TokenStats from './TokenStats'
|
||||
|
||||
const TABS = ['tokens', 'spot']
|
||||
|
||||
const StatsPage = () => {
|
||||
const [activeTab, setActiveTab] = useState('tokens')
|
||||
const tabsWithCount: [string, number][] = useMemo(() => {
|
||||
return TABS.map((t) => [t, 0])
|
||||
}, [])
|
||||
return (
|
||||
<div className="pb-20 md:pb-16">
|
||||
<TabButtons
|
||||
activeValue={activeTab}
|
||||
onChange={(v) => setActiveTab(v)}
|
||||
values={tabsWithCount}
|
||||
showBorders
|
||||
/>
|
||||
<TabContent activeTab={activeTab} />
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default StatsPage
|
||||
|
||||
const TabContent = ({ activeTab }: { activeTab: string }) => {
|
||||
switch (activeTab) {
|
||||
case 'tokens':
|
||||
return <TokenStats />
|
||||
case 'spot':
|
||||
return <SpotMarketsTable />
|
||||
default:
|
||||
return <TokenStats />
|
||||
}
|
||||
}
|
|
@ -69,7 +69,7 @@ const TokenList = () => {
|
|||
play
|
||||
delay={0.05}
|
||||
duration={1}
|
||||
numbers={formatFixedDecimals(totalDepositValue!, true)}
|
||||
numbers={formatFixedDecimals(totalDepositValue || 0.0, true)}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -84,7 +84,7 @@ const TokenList = () => {
|
|||
play
|
||||
delay={0.05}
|
||||
duration={1}
|
||||
numbers={formatFixedDecimals(totalBorrowValue!, true)}
|
||||
numbers={formatFixedDecimals(totalBorrowValue || 0.0, true)}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -94,7 +94,6 @@ const TokenList = () => {
|
|||
<thead>
|
||||
<tr>
|
||||
<th className="text-left">{t('token')}</th>
|
||||
<th className="text-right">{t('price')}</th>
|
||||
<th className="text-right">{t('total-deposits')}</th>
|
||||
<th className="text-right">{t('total-borrows')}</th>
|
||||
<th>
|
||||
|
@ -132,7 +131,6 @@ const TokenList = () => {
|
|||
<tbody>
|
||||
{banks.map(({ key, value }) => {
|
||||
const bank = value[0]
|
||||
const oraclePrice = bank.uiPrice
|
||||
|
||||
let logoURI
|
||||
if (jupiterTokens.length) {
|
||||
|
@ -155,12 +153,6 @@ const TokenList = () => {
|
|||
<p className="font-body tracking-wide">{bank.name}</p>
|
||||
</div>
|
||||
</td>
|
||||
<td>
|
||||
<div className="flex flex-col text-right">
|
||||
<p>{formatFixedDecimals(oraclePrice!, true)}</p>
|
||||
</div>
|
||||
</td>
|
||||
|
||||
<td>
|
||||
<div className="flex flex-col text-right">
|
||||
<p>{formatFixedDecimals(bank.uiDeposits())}</p>
|
||||
|
@ -221,7 +213,6 @@ const TokenList = () => {
|
|||
<div>
|
||||
{banks.map(({ key, value }) => {
|
||||
const bank = value[0]
|
||||
const oraclePrice = bank.uiPrice
|
||||
let logoURI
|
||||
if (jupiterTokens.length) {
|
||||
logoURI = jupiterTokens.find(
|
||||
|
@ -281,12 +272,6 @@ const TokenList = () => {
|
|||
leaveTo="opacity-0"
|
||||
>
|
||||
<div className="mt-4 grid grid-cols-2 gap-4 border-t border-th-bkg-3 pt-4">
|
||||
<div className="col-span-1">
|
||||
<p className="text-xs text-th-fgd-3">{t('price')}</p>
|
||||
<p className="font-mono text-th-fgd-1">
|
||||
${formatDecimal(oraclePrice!, 2)}
|
||||
</p>
|
||||
</div>
|
||||
<div className="col-span-1">
|
||||
<p className="text-xs text-th-fgd-3">{t('rates')}</p>
|
||||
<p className="space-x-2">
|
||||
|
|
|
@ -1,8 +1,6 @@
|
|||
import StatsPage from '@components/stats/StatsPage'
|
||||
import type { NextPage } from 'next'
|
||||
import { useTranslation } from 'next-i18next'
|
||||
import { serverSideTranslations } from 'next-i18next/serverSideTranslations'
|
||||
import { useRouter } from 'next/router'
|
||||
import TokenStats from '../components/stats/TokenStats'
|
||||
|
||||
export async function getStaticProps({ locale }: { locale: string }) {
|
||||
return {
|
||||
|
@ -13,19 +11,7 @@ export async function getStaticProps({ locale }: { locale: string }) {
|
|||
}
|
||||
|
||||
const Stats: NextPage = () => {
|
||||
const { t } = useTranslation('common')
|
||||
const router = useRouter()
|
||||
const { pathname, asPath, query } = router
|
||||
|
||||
return (
|
||||
<div className="pb-20 md:pb-16">
|
||||
<div className="grid grid-cols-12">
|
||||
<div className="col-span-12">
|
||||
<TokenStats />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
return <StatsPage />
|
||||
}
|
||||
|
||||
export default Stats
|
||||
|
|
|
@ -73,6 +73,7 @@
|
|||
"sell": "Sell",
|
||||
"settings": "Settings",
|
||||
"show-zero-balances": "Show Zero Balances",
|
||||
"spot": "Spot",
|
||||
"stats": "Stats",
|
||||
"swap": "Swap",
|
||||
"time": "Time",
|
||||
|
@ -90,6 +91,7 @@
|
|||
"transaction": "Transaction",
|
||||
"unavailable": "Unavailable",
|
||||
"update": "Update",
|
||||
"updating-account-name": "Updating Account Name...",
|
||||
"utilization": "Utilization",
|
||||
"value": "Value",
|
||||
"wallet-balance": "Wallet Balance",
|
||||
|
|
|
@ -73,6 +73,7 @@
|
|||
"sell": "Sell",
|
||||
"settings": "Settings",
|
||||
"show-zero-balances": "Show Zero Balances",
|
||||
"spot": "Spot",
|
||||
"stats": "Stats",
|
||||
"swap": "Swap",
|
||||
"time": "Time",
|
||||
|
@ -90,6 +91,7 @@
|
|||
"transaction": "Transaction",
|
||||
"unavailable": "Unavailable",
|
||||
"update": "Update",
|
||||
"updating-account-name": "Updating Account Name...",
|
||||
"utilization": "Utilization",
|
||||
"value": "Value",
|
||||
"wallet-balance": "Wallet Balance",
|
||||
|
|
|
@ -73,6 +73,7 @@
|
|||
"sell": "Sell",
|
||||
"settings": "Settings",
|
||||
"show-zero-balances": "Show Zero Balances",
|
||||
"spot": "Spot",
|
||||
"stats": "Stats",
|
||||
"swap": "Swap",
|
||||
"time": "Time",
|
||||
|
@ -90,6 +91,7 @@
|
|||
"transaction": "Transaction",
|
||||
"unavailable": "Unavailable",
|
||||
"update": "Update",
|
||||
"updating-account-name": "Updating Account Name...",
|
||||
"utilization": "Utilization",
|
||||
"value": "Value",
|
||||
"wallet-balance": "Wallet Balance",
|
||||
|
|
|
@ -73,6 +73,7 @@
|
|||
"sell": "Sell",
|
||||
"settings": "Settings",
|
||||
"show-zero-balances": "Show Zero Balances",
|
||||
"spot": "Spot",
|
||||
"stats": "Stats",
|
||||
"swap": "Swap",
|
||||
"time": "Time",
|
||||
|
@ -90,6 +91,7 @@
|
|||
"transaction": "Transaction",
|
||||
"unavailable": "Unavailable",
|
||||
"update": "Update",
|
||||
"updating-account-name": "Updating Account Name...",
|
||||
"utilization": "Utilization",
|
||||
"value": "Value",
|
||||
"wallet-balance": "Wallet Balance",
|
||||
|
|
Loading…
Reference in New Issue