2023-10-04 04:52:39 -07:00
|
|
|
|
import { ActionsMenu } from '@components/TokenList'
|
|
|
|
|
import Button from '@components/shared/Button'
|
|
|
|
|
import Change from '@components/shared/Change'
|
|
|
|
|
import FormatNumericValue from '@components/shared/FormatNumericValue'
|
|
|
|
|
import TokenLogo from '@components/shared/TokenLogo'
|
|
|
|
|
import { goToTokenPage } from '@components/stats/tokens/TokenOverviewTable'
|
|
|
|
|
import Decimal from 'decimal.js'
|
|
|
|
|
import useMangoGroup from 'hooks/useMangoGroup'
|
|
|
|
|
import { useRouter } from 'next/router'
|
|
|
|
|
import { useTranslation } from 'react-i18next'
|
|
|
|
|
import { numberCompacter } from 'utils/numbers'
|
|
|
|
|
import { BankWithMarketData } from './Spot'
|
2023-10-04 16:04:51 -07:00
|
|
|
|
import Tooltip from '@components/shared/Tooltip'
|
|
|
|
|
import SimpleAreaChart from '@components/shared/SimpleAreaChart'
|
|
|
|
|
import { COLORS } from 'styles/colors'
|
|
|
|
|
import useThemeWrapper from 'hooks/useThemeWrapper'
|
2023-10-06 03:33:15 -07:00
|
|
|
|
import dayjs from 'dayjs'
|
2023-10-10 18:28:27 -07:00
|
|
|
|
import TokenReduceOnlyDesc from '@components/shared/TokenReduceOnlyDesc'
|
2023-10-04 04:52:39 -07:00
|
|
|
|
|
|
|
|
|
const SpotCards = ({ tokens }: { tokens: BankWithMarketData[] }) => {
|
|
|
|
|
const { t } = useTranslation(['common', 'explore', 'trade'])
|
|
|
|
|
const { group } = useMangoGroup()
|
2023-10-04 16:04:51 -07:00
|
|
|
|
const { theme } = useThemeWrapper()
|
2023-10-04 04:52:39 -07:00
|
|
|
|
const router = useRouter()
|
|
|
|
|
return (
|
|
|
|
|
<div className="grid grid-cols-12 gap-4 px-4 py-6 md:px-6 2xl:px-12">
|
|
|
|
|
{tokens.map((token) => {
|
|
|
|
|
const { bank } = token
|
|
|
|
|
|
|
|
|
|
const availableVaultBalance = group
|
|
|
|
|
? group.getTokenVaultBalanceByMintUi(bank.mint) -
|
|
|
|
|
bank.uiDeposits() * bank.minVaultToDepositsRatio
|
|
|
|
|
: 0
|
|
|
|
|
const available = Decimal.max(
|
|
|
|
|
0,
|
|
|
|
|
availableVaultBalance.toFixed(bank.mintDecimals),
|
2023-11-07 15:27:12 -08:00
|
|
|
|
).mul(bank.uiPrice)
|
2023-10-04 04:52:39 -07:00
|
|
|
|
const depositRate = bank.getDepositRateUi()
|
|
|
|
|
const borrowRate = bank.getBorrowRateUi()
|
|
|
|
|
const assetWeight = bank.scaledInitAssetWeight(bank.price).toFixed(2)
|
2023-10-06 03:33:15 -07:00
|
|
|
|
const pastPrice = token.market?.marketData?.price_24h
|
|
|
|
|
const volume = token.market?.marketData?.quote_volume_24h || 0
|
|
|
|
|
const change =
|
|
|
|
|
volume > 0 && pastPrice
|
|
|
|
|
? ((bank.uiPrice - pastPrice) / pastPrice) * 100
|
|
|
|
|
: 0
|
|
|
|
|
|
|
|
|
|
const chartData =
|
|
|
|
|
token.market?.marketData?.price_history
|
|
|
|
|
.sort((a, b) => a.time.localeCompare(b.time))
|
|
|
|
|
.concat([{ price: bank.uiPrice, time: dayjs().toISOString() }]) ||
|
|
|
|
|
[]
|
|
|
|
|
|
2023-10-04 04:52:39 -07:00
|
|
|
|
return (
|
|
|
|
|
<div
|
|
|
|
|
className="col-span-12 rounded-lg border border-th-bkg-3 p-6 md:col-span-6 xl:col-span-4 2xl:col-span-3"
|
|
|
|
|
key={bank.tokenIndex}
|
|
|
|
|
>
|
2023-10-04 16:04:51 -07:00
|
|
|
|
<div className="mb-4 flex items-center justify-between border-b border-th-bkg-3 pb-4">
|
|
|
|
|
<div className="flex items-center space-x-3">
|
|
|
|
|
<TokenLogo bank={bank} size={32} />
|
|
|
|
|
<div>
|
2023-10-10 18:28:27 -07:00
|
|
|
|
<h3 className="mb-1 text-base leading-none">
|
|
|
|
|
{bank.name}
|
|
|
|
|
<span className="ml-1.5">
|
|
|
|
|
<TokenReduceOnlyDesc bank={bank} />
|
|
|
|
|
</span>
|
|
|
|
|
</h3>
|
2023-10-04 16:04:51 -07:00
|
|
|
|
<div className="flex items-center space-x-3">
|
|
|
|
|
<span className="font-mono">
|
|
|
|
|
<FormatNumericValue value={bank.uiPrice} isUsd />
|
|
|
|
|
</span>
|
|
|
|
|
{token.market ? (
|
2023-10-06 03:33:15 -07:00
|
|
|
|
<Change change={change} suffix="%" />
|
2023-10-04 16:04:51 -07:00
|
|
|
|
) : null}
|
|
|
|
|
</div>
|
2023-10-04 04:52:39 -07:00
|
|
|
|
</div>
|
|
|
|
|
</div>
|
2023-10-06 03:33:15 -07:00
|
|
|
|
{chartData.length ? (
|
2023-10-04 16:04:51 -07:00
|
|
|
|
<div className="h-10 w-20">
|
|
|
|
|
<SimpleAreaChart
|
|
|
|
|
color={
|
2023-10-06 03:33:15 -07:00
|
|
|
|
chartData[0].price <= bank.uiPrice
|
2023-10-04 16:04:51 -07:00
|
|
|
|
? COLORS.UP[theme]
|
|
|
|
|
: COLORS.DOWN[theme]
|
|
|
|
|
}
|
2023-10-06 03:33:15 -07:00
|
|
|
|
data={chartData}
|
2023-10-04 16:04:51 -07:00
|
|
|
|
name={bank.name}
|
|
|
|
|
xKey="time"
|
|
|
|
|
yKey="price"
|
|
|
|
|
/>
|
|
|
|
|
</div>
|
|
|
|
|
) : null}
|
2023-10-04 04:52:39 -07:00
|
|
|
|
</div>
|
|
|
|
|
<div className="grid grid-cols-2 gap-4">
|
|
|
|
|
<div>
|
2023-10-04 16:04:51 -07:00
|
|
|
|
<p className="mb-1">{t('trade:24h-volume')}</p>
|
2023-10-04 04:52:39 -07:00
|
|
|
|
<p className="font-mono text-th-fgd-2">
|
|
|
|
|
{!token.market ? (
|
|
|
|
|
'–'
|
|
|
|
|
) : token.market?.marketData?.quote_volume_24h ? (
|
|
|
|
|
<span>
|
|
|
|
|
{numberCompacter.format(
|
|
|
|
|
token.market.marketData.quote_volume_24h,
|
|
|
|
|
)}{' '}
|
|
|
|
|
<span className="font-body text-th-fgd-4">USDC</span>
|
|
|
|
|
</span>
|
|
|
|
|
) : (
|
|
|
|
|
<span>
|
|
|
|
|
0 <span className="font-body text-th-fgd-4">USDC</span>
|
|
|
|
|
</span>
|
|
|
|
|
)}
|
|
|
|
|
</p>
|
|
|
|
|
</div>
|
|
|
|
|
<div>
|
2023-10-04 16:04:51 -07:00
|
|
|
|
<Tooltip
|
|
|
|
|
content={t('tooltip-available', { token: bank.name })}
|
|
|
|
|
placement="top-start"
|
|
|
|
|
>
|
|
|
|
|
<p className="tooltip-underline mb-1">{t('available')}</p>
|
|
|
|
|
</Tooltip>
|
2023-10-04 04:52:39 -07:00
|
|
|
|
<span className="font-mono text-th-fgd-2">
|
2023-11-07 15:27:12 -08:00
|
|
|
|
<FormatNumericValue value={available} isUsd />
|
2023-10-04 04:52:39 -07:00
|
|
|
|
</span>
|
|
|
|
|
</div>
|
|
|
|
|
<div>
|
2023-10-04 16:04:51 -07:00
|
|
|
|
<Tooltip
|
2023-10-10 19:39:06 -07:00
|
|
|
|
content={t('tooltip-collateral-weight', { token: bank.name })}
|
2023-10-04 16:04:51 -07:00
|
|
|
|
placement="top-start"
|
|
|
|
|
>
|
|
|
|
|
<p className="tooltip-underline mb-1">
|
|
|
|
|
{t('explore:collateral-weight')}
|
|
|
|
|
</p>
|
|
|
|
|
</Tooltip>
|
2023-10-04 04:52:39 -07:00
|
|
|
|
<span className="font-mono text-th-fgd-2">{assetWeight}x</span>
|
|
|
|
|
</div>
|
|
|
|
|
<div>
|
2023-10-04 16:04:51 -07:00
|
|
|
|
<Tooltip
|
|
|
|
|
content={t('tooltip-interest-rates')}
|
|
|
|
|
placement="top-start"
|
|
|
|
|
>
|
|
|
|
|
<p className="tooltip-underline mb-1">{t('rates')}</p>
|
|
|
|
|
</Tooltip>
|
2023-10-04 04:52:39 -07:00
|
|
|
|
<div className="flex space-x-1.5 font-mono">
|
|
|
|
|
<p className="text-th-up">
|
|
|
|
|
<FormatNumericValue value={depositRate} decimals={2} />%
|
|
|
|
|
</p>
|
|
|
|
|
<span className="text-th-fgd-4">|</span>
|
|
|
|
|
<p className="text-th-down">
|
|
|
|
|
<FormatNumericValue value={borrowRate} decimals={2} />%
|
|
|
|
|
</p>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
<Button
|
|
|
|
|
className="mt-3"
|
|
|
|
|
onClick={() => goToTokenPage(bank.name.split(' ')[0], router)}
|
|
|
|
|
secondary
|
|
|
|
|
>
|
|
|
|
|
{t('details')}
|
|
|
|
|
</Button>
|
|
|
|
|
<div className="relative mt-3">
|
|
|
|
|
<ActionsMenu bank={bank} showText />
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
)
|
|
|
|
|
})}
|
|
|
|
|
</div>
|
|
|
|
|
)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export default SpotCards
|