improve swap history indicators on swap chart
This commit is contained in:
parent
02cf848587
commit
c5a0efa781
|
@ -1,4 +1,4 @@
|
|||
import { useEffect, useMemo, useState } from 'react'
|
||||
import { MouseEventHandler, useEffect, useMemo, useState } from 'react'
|
||||
import dayjs from 'dayjs'
|
||||
import relativeTime from 'dayjs/plugin/relativeTime'
|
||||
import {
|
||||
|
@ -14,7 +14,7 @@ import {
|
|||
} from 'recharts'
|
||||
import FlipNumbers from 'react-flip-numbers'
|
||||
import ContentBox from '../shared/ContentBox'
|
||||
import { formatNumericValue } from '../../utils/numbers'
|
||||
import { formatCurrencyValue, formatNumericValue } from '../../utils/numbers'
|
||||
import SheenLoader from '../shared/SheenLoader'
|
||||
import { COLORS } from '../../styles/colors'
|
||||
import { useTheme } from 'next-themes'
|
||||
|
@ -94,10 +94,25 @@ interface ExtendedReferenceDotProps extends ReferenceDotProps {
|
|||
swapHistory: SwapHistoryItem[]
|
||||
swapMarketName: string
|
||||
flipPrices: boolean
|
||||
mouseEnter: (
|
||||
swap: SwapHistoryItem | undefined,
|
||||
coingeckoPrice: string | number | undefined
|
||||
) => void
|
||||
mouseLeave: MouseEventHandler
|
||||
}
|
||||
|
||||
const SwapHistoryArrows = (props: ExtendedReferenceDotProps) => {
|
||||
const { cx, cy, x, swapHistory, swapMarketName, flipPrices } = props
|
||||
const {
|
||||
cx,
|
||||
cy,
|
||||
x,
|
||||
y,
|
||||
swapHistory,
|
||||
swapMarketName,
|
||||
flipPrices,
|
||||
mouseEnter,
|
||||
mouseLeave,
|
||||
} = props
|
||||
const swapDetails = swapHistory.find(
|
||||
(swap) => dayjs(swap.block_datetime).unix() * 1000 === x
|
||||
)
|
||||
|
@ -113,27 +128,32 @@ const SwapHistoryArrows = (props: ExtendedReferenceDotProps) => {
|
|||
const buy = {
|
||||
pathCoords: 'M11 0.858312L0.857867 15.0004H21.1421L11 0.858312Z',
|
||||
fill: 'var(--up)',
|
||||
yOffset: 1,
|
||||
yOffset: 0,
|
||||
}
|
||||
|
||||
const sell = {
|
||||
pathCoords:
|
||||
'M11 14.1427L21.1421 0.000533306L0.857865 0.000529886L11 14.1427Z',
|
||||
fill: 'var(--down)',
|
||||
yOffset: -11,
|
||||
yOffset: -15,
|
||||
}
|
||||
|
||||
const sideArrowProps =
|
||||
side === 'buy' ? (!flipPrices ? buy : sell) : !flipPrices ? sell : buy
|
||||
|
||||
const coingeckoPrice = y ? Number(y) : 0
|
||||
return cx && cy ? (
|
||||
<svg
|
||||
width="14.67"
|
||||
height="10"
|
||||
className="cursor-pointer"
|
||||
width="20"
|
||||
height="15"
|
||||
viewBox="0 0 20 15"
|
||||
fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
x={cx - 8}
|
||||
x={cx - 11}
|
||||
y={cy + sideArrowProps.yOffset}
|
||||
onMouseEnter={() => mouseEnter(swapDetails, coingeckoPrice)}
|
||||
onMouseLeave={mouseLeave}
|
||||
>
|
||||
<path
|
||||
d={sideArrowProps.pathCoords}
|
||||
|
@ -165,6 +185,113 @@ const SwapTokenChart = () => {
|
|||
const swapHistory = mangoStore((s) => s.mangoAccount.swapHistory.data)
|
||||
const loadSwapHistory = mangoStore((s) => s.mangoAccount.swapHistory.loading)
|
||||
const [showSwaps, setShowSwaps] = useState(true)
|
||||
const [swapTooltipData, setSwapTooltipData] =
|
||||
useState<SwapHistoryItem | null>(null)
|
||||
const [swapTooltipCoingeckoPrice, setSwapTooltipCoingeckoPrice] = useState<
|
||||
string | number | undefined
|
||||
>(undefined)
|
||||
|
||||
const handleSwapMouseEnter = (
|
||||
swap: SwapHistoryItem | undefined,
|
||||
coingeckoPrice: string | number | undefined
|
||||
) => {
|
||||
if (swap) {
|
||||
setSwapTooltipData(swap)
|
||||
}
|
||||
if (coingeckoPrice) {
|
||||
setSwapTooltipCoingeckoPrice(coingeckoPrice)
|
||||
}
|
||||
}
|
||||
|
||||
const handleSwapMouseLeave = () => {
|
||||
setSwapTooltipData(null)
|
||||
}
|
||||
|
||||
const renderTooltipContent = (swap: SwapHistoryItem) => {
|
||||
const {
|
||||
swap_in_amount,
|
||||
swap_in_symbol,
|
||||
swap_out_price_usd,
|
||||
swap_out_amount,
|
||||
swap_out_symbol,
|
||||
} = swap
|
||||
|
||||
const swapOutValue = swap_out_price_usd * swap_out_amount
|
||||
|
||||
const baseMarketToken = swapMarketName.split('/')[0]
|
||||
|
||||
const swapSide =
|
||||
swap_in_symbol === baseMarketToken
|
||||
? !flipPrices
|
||||
? 'sell'
|
||||
: 'buy'
|
||||
: !flipPrices
|
||||
? 'buy'
|
||||
: 'sell'
|
||||
|
||||
const buy = {
|
||||
price: swap_in_amount / swap_out_amount,
|
||||
priceSymbol: swap_in_symbol,
|
||||
amount: swap_out_amount,
|
||||
side: 'buy',
|
||||
symbol: swap_out_symbol,
|
||||
value: swapOutValue,
|
||||
}
|
||||
|
||||
const sell = {
|
||||
price: swap_out_amount / swap_in_amount,
|
||||
priceSymbol: swap_out_symbol,
|
||||
amount: swap_in_amount,
|
||||
side: 'sell',
|
||||
symbol: swap_in_symbol,
|
||||
value: swapOutValue,
|
||||
}
|
||||
|
||||
const swapProps =
|
||||
swapSide === 'buy' ? (!flipPrices ? buy : sell) : !flipPrices ? sell : buy
|
||||
|
||||
const { amount, price, priceSymbol, side, symbol, value } = swapProps
|
||||
|
||||
let coingeckoPercentageDifference = 0
|
||||
if (
|
||||
swapTooltipCoingeckoPrice &&
|
||||
typeof swapTooltipCoingeckoPrice === 'number'
|
||||
) {
|
||||
const difference = ((price - swapTooltipCoingeckoPrice) / price) * 100
|
||||
coingeckoPercentageDifference = difference
|
||||
}
|
||||
|
||||
const betterThanCoingecko =
|
||||
swapSide === 'buy'
|
||||
? flipPrices
|
||||
? coingeckoPercentageDifference > 0
|
||||
: coingeckoPercentageDifference < 0
|
||||
: flipPrices
|
||||
? coingeckoPercentageDifference < 0
|
||||
: coingeckoPercentageDifference > 0
|
||||
|
||||
return (
|
||||
<>
|
||||
<p className="text-center text-th-fgd-2">{`${t(
|
||||
side
|
||||
)} ${amount} ${symbol} at ${formatNumericValue(
|
||||
price
|
||||
)} ${priceSymbol} for ${formatCurrencyValue(value)}`}</p>
|
||||
{coingeckoPercentageDifference ? (
|
||||
<p
|
||||
className={`mt-0.5 text-center text-xs ${
|
||||
betterThanCoingecko ? 'text-th-up' : 'text-th-down'
|
||||
}`}
|
||||
>
|
||||
<span className="font-mono">
|
||||
{coingeckoPercentageDifference.toFixed(2)}%
|
||||
</span>{' '}
|
||||
{betterThanCoingecko ? 'better than' : 'worse than'} Coingecko
|
||||
</p>
|
||||
) : null}
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
const {
|
||||
data: coingeckoDataQuery,
|
||||
|
@ -206,8 +333,8 @@ const SwapTokenChart = () => {
|
|||
)
|
||||
return []
|
||||
const chartSymbols = [
|
||||
formatTokenSymbol(inputBank.name),
|
||||
formatTokenSymbol(outputBank.name),
|
||||
inputBank.name === 'ETH (Portal)' ? 'ETH' : inputBank.name,
|
||||
outputBank.name === 'ETH (Portal)' ? 'ETH' : outputBank.name,
|
||||
]
|
||||
return swapHistory
|
||||
.filter(
|
||||
|
@ -298,8 +425,8 @@ const SwapTokenChart = () => {
|
|||
|
||||
const swapMarketName = useMemo(() => {
|
||||
if (!inputBank || !outputBank) return ''
|
||||
const inputSymbol = formatTokenSymbol(inputBank.name?.toUpperCase())
|
||||
const outputSymbol = formatTokenSymbol(outputBank.name?.toUpperCase())
|
||||
const inputSymbol = formatTokenSymbol(inputBank.name)
|
||||
const outputSymbol = formatTokenSymbol(outputBank.name)
|
||||
return ['usd-coin', 'tether'].includes(inputCoingeckoId || '')
|
||||
? !flipPrices
|
||||
? `${outputSymbol}/${inputSymbol}`
|
||||
|
@ -324,7 +451,12 @@ const SwapTokenChart = () => {
|
|||
</SheenLoader>
|
||||
</>
|
||||
) : chartData?.length && baseTokenId && quoteTokenId ? (
|
||||
<div className="relative">
|
||||
<div className="relative h-full">
|
||||
{swapTooltipData ? (
|
||||
<div className="absolute left-1/2 bottom-2 z-10 w-full -translate-x-1/2 rounded-md border border-th-bkg-3 bg-th-bkg-1 px-4 py-2">
|
||||
{renderTooltipContent(swapTooltipData)}
|
||||
</div>
|
||||
) : null}
|
||||
<div className="flex items-start justify-between">
|
||||
<div>
|
||||
{inputBank && outputBank ? (
|
||||
|
@ -496,6 +628,8 @@ const SwapTokenChart = () => {
|
|||
swapHistory={swapHistory}
|
||||
swapMarketName={swapMarketName}
|
||||
flipPrices={flipPrices}
|
||||
mouseEnter={handleSwapMouseEnter}
|
||||
mouseLeave={handleSwapMouseLeave}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
|
|
Loading…
Reference in New Issue