wip
This commit is contained in:
parent
30ba236553
commit
771ee63ea5
|
@ -1,17 +1,27 @@
|
|||
import { useWallet } from '@solana/wallet-adapter-react'
|
||||
|
||||
import MangoAccount from '../components/MangoAccount'
|
||||
import TokenList from './TokenList'
|
||||
import AccountActions from './AccountActions'
|
||||
import Swap from './swap/Swap'
|
||||
import SwapTokenChart from './swap/SwapTokenChart'
|
||||
import mangoStore from '../store/state'
|
||||
|
||||
const Home = () => {
|
||||
const { connected } = useWallet()
|
||||
const inputTokenInfo = mangoStore((s) => s.inputTokenInfo)
|
||||
const outputTokenInfo = mangoStore((s) => s.outputTokenInfo)
|
||||
|
||||
return (
|
||||
<div className="mt-8">
|
||||
<div className="flex-col space-y-4">
|
||||
<div className="mx-auto flex max-w-7xl justify-center space-x-4">
|
||||
<MangoAccount />
|
||||
<div className="w-full space-y-6">
|
||||
<SwapTokenChart
|
||||
inputTokenId={inputTokenInfo?.extensions?.coingeckoId}
|
||||
outputTokenId={outputTokenInfo?.extensions?.coingeckoId}
|
||||
/>
|
||||
<TokenList />
|
||||
</div>
|
||||
<div className="space-y-6">
|
||||
<Swap />
|
||||
{connected ? <AccountActions /> : null}
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
import Image from 'next/image'
|
||||
|
||||
import mangoStore from '../store/state'
|
||||
import { formatDecimal } from '../utils/numbers'
|
||||
import { formatDecimal, numberFormat } from '../utils/numbers'
|
||||
import ContentBox from './shared/ContentBox'
|
||||
|
||||
const MangoAccount = () => {
|
||||
const TokenList = () => {
|
||||
const mangoAccount = mangoStore((s) => s.mangoAccount)
|
||||
const group = mangoStore((s) => s.group)
|
||||
|
||||
|
@ -19,18 +19,20 @@ const MangoAccount = () => {
|
|||
<table className="mt-4 min-w-full">
|
||||
<thead>
|
||||
<tr>
|
||||
<th className="pr-12 text-sm">Asset</th>
|
||||
<th className="pr-12 text-sm">Price</th>
|
||||
<th className="pr-12 text-sm">Deposits/Lend</th>
|
||||
<th className="pr-12 text-sm">Borrows</th>
|
||||
<th className="pr-12 text-sm">Balance</th>
|
||||
<th className="text-left text-sm">Asset</th>
|
||||
<th className="text-right text-sm">Deposits</th>
|
||||
<th className="text-right text-sm">APR</th>
|
||||
<th className="text-right text-sm">Borrows</th>
|
||||
<th className="text-right text-sm">APR</th>
|
||||
<th className="text-right text-sm">Balance</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{banks.map((bank) => {
|
||||
const oraclePrice = bank.value.price
|
||||
return (
|
||||
<tr key={bank.key}>
|
||||
<td className="pr-12 pt-4">
|
||||
<td className="pt-4">
|
||||
<div className="flex items-center">
|
||||
<div className="mr-4 flex min-w-[30px] items-center">
|
||||
<Image
|
||||
|
@ -40,15 +42,15 @@ const MangoAccount = () => {
|
|||
src={`/icons/${bank.value.name.toLowerCase()}.svg`}
|
||||
/>
|
||||
</div>
|
||||
<div>
|
||||
<div className="flex flex-col">
|
||||
<div>{bank.value.name}</div>
|
||||
<div className="text-sm text-th-fgd-4">
|
||||
${formatDecimal(oraclePrice.toNumber(), 2)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</td>
|
||||
<td className="pr-12 pt-4 text-right">
|
||||
<div className="">${bank.value.price?.toFixed(2)}</div>
|
||||
</td>
|
||||
<td className="pr-12 pt-4">
|
||||
<td className="pt-4">
|
||||
<div className="flex flex-col text-right">
|
||||
<div>
|
||||
{formatDecimal(
|
||||
|
@ -56,6 +58,10 @@ const MangoAccount = () => {
|
|||
bank.value.mintDecimals
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</td>
|
||||
<td className="pt-4">
|
||||
<div className="flex flex-col text-right">
|
||||
<div className="text-green-500">
|
||||
{formatDecimal(
|
||||
bank.value.getDepositRate().toNumber(),
|
||||
|
@ -65,7 +71,7 @@ const MangoAccount = () => {
|
|||
</div>
|
||||
</div>
|
||||
</td>
|
||||
<td className="pr-12 pt-4">
|
||||
<td className="pt-4">
|
||||
<div className="flex flex-col text-right">
|
||||
<div>
|
||||
{formatDecimal(
|
||||
|
@ -73,6 +79,10 @@ const MangoAccount = () => {
|
|||
bank.value.mintDecimals
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</td>
|
||||
<td className="pt-4">
|
||||
<div className="flex flex-col text-right">
|
||||
<div className="text-red-500">
|
||||
{formatDecimal(
|
||||
bank.value.getBorrowRate().toNumber(),
|
||||
|
@ -82,20 +92,19 @@ const MangoAccount = () => {
|
|||
</div>
|
||||
</div>
|
||||
</td>
|
||||
<td className="pr-12 pt-4 text-right">
|
||||
<td className="pt-4 text-right">
|
||||
<div className="px-2">
|
||||
{mangoAccount
|
||||
? formatDecimal(
|
||||
mangoAccount.deposits(bank.value),
|
||||
bank.value.mintDecimals
|
||||
)
|
||||
? formatDecimal(mangoAccount.getUi(bank.value))
|
||||
: '-'}
|
||||
</div>
|
||||
<div className="px-2">
|
||||
<div className="px-2 text-sm text-th-fgd-4">
|
||||
$
|
||||
{mangoAccount
|
||||
? formatDecimal(
|
||||
mangoAccount.borrows(bank.value),
|
||||
bank.value.mintDecimals
|
||||
mangoAccount.getUi(bank.value) *
|
||||
oraclePrice.toNumber(),
|
||||
2
|
||||
)
|
||||
: '-'}
|
||||
</div>
|
||||
|
@ -111,4 +120,4 @@ const MangoAccount = () => {
|
|||
)
|
||||
}
|
||||
|
||||
export default MangoAccount
|
||||
export default TokenList
|
|
@ -0,0 +1,20 @@
|
|||
const LineChartIcon = ({ className }: { className: string }) => {
|
||||
return (
|
||||
<svg
|
||||
className={`${className}`}
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="32"
|
||||
height="32"
|
||||
viewBox="0 0 32 32"
|
||||
fill="currentColor"
|
||||
>
|
||||
<path
|
||||
fillRule="evenodd"
|
||||
clipRule="evenodd"
|
||||
d="M2.766 24.073a1.5 1.5 0 0 1 .098-2.12l9.875-8.999a1.5 1.5 0 0 1 1.99-.028l3.493 3.008 8.892-8.105a1.5 1.5 0 1 1 2.021 2.217l-9.875 9a1.5 1.5 0 0 1-1.989.028l-3.493-3.007-8.893 8.104a1.5 1.5 0 0 1-2.119-.098Z"
|
||||
/>
|
||||
</svg>
|
||||
)
|
||||
}
|
||||
|
||||
export default LineChartIcon
|
|
@ -21,11 +21,6 @@ type JupiterRoutesProps = {
|
|||
setAmountOut: (x?: number) => void
|
||||
}
|
||||
|
||||
type Routes = {
|
||||
routesInfos: RouteInfo[]
|
||||
cached: boolean
|
||||
}
|
||||
|
||||
const parseJupiterRoute = async (
|
||||
jupiter: Jupiter,
|
||||
selectedRoute: RouteInfo,
|
||||
|
@ -49,16 +44,7 @@ const parseJupiterRoute = async (
|
|||
}
|
||||
|
||||
const getBestRoute = (routesInfos: RouteInfo[]) => {
|
||||
const routesInfosWithoutRaydium = routesInfos.filter((r) => {
|
||||
if (r.marketInfos.length > 1) {
|
||||
for (const mkt of r.marketInfos) {
|
||||
if (mkt.amm.label === 'Raydium' || mkt.amm.label === 'Serum')
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
})
|
||||
return routesInfosWithoutRaydium[0]
|
||||
return routesInfos[0]
|
||||
}
|
||||
|
||||
const JupiterRoutes = ({
|
||||
|
@ -71,7 +57,7 @@ const JupiterRoutes = ({
|
|||
setAmountOut,
|
||||
}: JupiterRoutesProps) => {
|
||||
const [jupiter, setJupiter] = useState<Jupiter>()
|
||||
const [routes, setRoutes] = useState<Routes>()
|
||||
const [routes, setRoutes] = useState<RouteInfo[]>()
|
||||
const [selectedRoute, setSelectedRoute] = useState<RouteInfo>()
|
||||
const [showRoutesModal, setShowRoutesModal] = useState(false)
|
||||
const [outputTokenInfo, setOutputTokenInfo] = useState<TokenInfo>()
|
||||
|
@ -121,18 +107,28 @@ const JupiterRoutes = ({
|
|||
inputAmount: amountIn * 10 ** inputBank.mintDecimals, // raw input amount of tokens
|
||||
slippage, // The slippage in % terms
|
||||
filterTopNResult: 10,
|
||||
onlyDirectRoutes: true,
|
||||
})
|
||||
|
||||
setRoutes(computedRoutes)
|
||||
const bestRoute = getBestRoute(computedRoutes!.routesInfos)
|
||||
setSelectedRoute(bestRoute)
|
||||
|
||||
const tokenOut = tokens.find(
|
||||
// @ts-ignore
|
||||
(t) => t.address === outputBank.mint.toString()
|
||||
(t: any) => t.address === outputBank.mint.toString()
|
||||
)
|
||||
setOutputTokenInfo(tokenOut)
|
||||
setAmountOut(toUiDecimals(bestRoute.outAmount, tokenOut.decimals))
|
||||
const routesInfosWithoutRaydium = computedRoutes?.routesInfos.filter(
|
||||
(r) => {
|
||||
if (r.marketInfos.length > 1) {
|
||||
for (const mkt of r.marketInfos) {
|
||||
if (mkt.amm.label === 'Raydium') return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
)
|
||||
if (routesInfosWithoutRaydium?.length) {
|
||||
setRoutes(routesInfosWithoutRaydium)
|
||||
const bestRoute = getBestRoute(computedRoutes!.routesInfos)
|
||||
setSelectedRoute(bestRoute)
|
||||
setAmountOut(toUiDecimals(bestRoute.outAmount, tokenOut.decimals))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -150,7 +146,7 @@ const JupiterRoutes = ({
|
|||
{submitting ? <Loading className="mr-2 h-5 w-5" /> : null} Swap
|
||||
</Button>
|
||||
</div>
|
||||
{routes?.routesInfos.length && selectedRoute && outputTokenInfo ? (
|
||||
{routes?.length && selectedRoute && outputTokenInfo ? (
|
||||
<>
|
||||
<div
|
||||
role="button"
|
||||
|
@ -160,7 +156,7 @@ const JupiterRoutes = ({
|
|||
}}
|
||||
>
|
||||
<SelectedRoute
|
||||
routes={routes.routesInfos}
|
||||
routes={routes}
|
||||
selectedRoute={selectedRoute}
|
||||
inputTokenSymbol={inputToken}
|
||||
/>
|
||||
|
@ -180,8 +176,9 @@ const JupiterRoutes = ({
|
|||
<RoutesModal
|
||||
show={showRoutesModal}
|
||||
onClose={() => setShowRoutesModal(false)}
|
||||
setSelectedRoute={setSelectedRoute}
|
||||
selectedRoute={selectedRoute}
|
||||
routes={routes.routesInfos}
|
||||
routes={routes}
|
||||
inputTokenSymbol={inputToken}
|
||||
outputTokenInfo={outputTokenInfo}
|
||||
/>
|
||||
|
|
|
@ -1,11 +1,13 @@
|
|||
import { RouteInfo } from '@jup-ag/core'
|
||||
import { Dispatch, SetStateAction } from 'react'
|
||||
import mangoStore from '../../store/state'
|
||||
import { TokenInfo } from '../../types/jupiter'
|
||||
import { formatDecimal } from '../../utils/numbers'
|
||||
import Modal from '../shared/Modal'
|
||||
|
||||
type RoutesModalProps = {
|
||||
onClose: (x: boolean) => void
|
||||
onClose: () => void
|
||||
setSelectedRoute: Dispatch<SetStateAction<RouteInfo | undefined>>
|
||||
show: boolean
|
||||
routes: RouteInfo[]
|
||||
selectedRoute: RouteInfo
|
||||
|
@ -18,12 +20,19 @@ const RoutesModal = ({
|
|||
show,
|
||||
routes,
|
||||
selectedRoute,
|
||||
setSelectedRoute,
|
||||
inputTokenSymbol,
|
||||
outputTokenInfo,
|
||||
}: RoutesModalProps) => {
|
||||
const tokens = mangoStore.getState().jupiterTokens
|
||||
|
||||
const handleSelectRoute = (route: RouteInfo) => {
|
||||
setSelectedRoute(route)
|
||||
onClose()
|
||||
}
|
||||
|
||||
return (
|
||||
<Modal isOpen={show} onClose={() => onClose(false)}>
|
||||
<Modal isOpen={show} onClose={() => onClose()}>
|
||||
<div className="mb-4 text-center text-lg font-bold text-th-fgd-1">
|
||||
{routes?.length} routes found
|
||||
</div>
|
||||
|
@ -41,7 +50,7 @@ const RoutesModal = ({
|
|||
>
|
||||
<button
|
||||
className="w-full p-4"
|
||||
// onClick={() => handleSelectRoute(route)}
|
||||
onClick={() => handleSelectRoute(route)}
|
||||
>
|
||||
<div className="flex items-center justify-between">
|
||||
<div className="flex flex-col text-left">
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
import { useState, ChangeEvent, SelectHTMLAttributes } from 'react'
|
||||
import { useState, ChangeEvent } from 'react'
|
||||
import { TransactionInstruction } from '@solana/web3.js'
|
||||
import { ArrowDownIcon, SwitchVerticalIcon } from '@heroicons/react/solid'
|
||||
|
||||
import mangoStore from '../../store/state'
|
||||
import ContentBox from '../shared/ContentBox'
|
||||
|
@ -7,10 +8,7 @@ import { notify } from '../../utils/notifications'
|
|||
import JupiterRoutes from './JupiterRoutes'
|
||||
import TokenSelect from '../TokenSelect'
|
||||
import useDebounce from '../shared/useDebounce'
|
||||
|
||||
const numberFormat = new Intl.NumberFormat('en', {
|
||||
maximumSignificantDigits: 7,
|
||||
})
|
||||
import { numberFormat } from '../../utils/numbers'
|
||||
|
||||
const Swap = () => {
|
||||
const [amountIn, setAmountIn] = useState('')
|
||||
|
@ -20,19 +18,34 @@ const Swap = () => {
|
|||
const [submitting, setSubmitting] = useState(false)
|
||||
const [slippage, setSlippage] = useState(0.1)
|
||||
const debouncedAmountIn = useDebounce(amountIn, 300)
|
||||
const set = mangoStore.getState().set
|
||||
const tokens = mangoStore((s) => s.jupiterTokens)
|
||||
|
||||
const handleAmountInChange = (e: ChangeEvent<HTMLInputElement>) => {
|
||||
setAmountIn(e.target.value)
|
||||
}
|
||||
|
||||
const handleTokenInSelect = (e: ChangeEvent<HTMLSelectElement>) => {
|
||||
const inputTokenInfo = tokens.find((t: any) => t.symbol === e.target.value)
|
||||
set((s) => {
|
||||
s.inputTokenInfo = inputTokenInfo
|
||||
})
|
||||
setInputToken(e.target.value)
|
||||
}
|
||||
|
||||
const handleTokenOutSelect = (e: ChangeEvent<HTMLSelectElement>) => {
|
||||
const outputTokenInfo = tokens.find((t: any) => t.symbol === e.target.value)
|
||||
set((s) => {
|
||||
s.outputTokenInfo = outputTokenInfo
|
||||
})
|
||||
setOutputToken(e.target.value)
|
||||
}
|
||||
|
||||
const handleSwitchTokens = () => {
|
||||
setInputToken(outputToken)
|
||||
setOutputToken(inputToken)
|
||||
}
|
||||
|
||||
const handleSwap = async (
|
||||
userDefinedInstructions: TransactionInstruction[]
|
||||
) => {
|
||||
|
@ -49,20 +62,19 @@ const Swap = () => {
|
|||
mangoAccount,
|
||||
inputToken,
|
||||
amountIn: parseFloat(amountIn),
|
||||
outputToken: 'USDC',
|
||||
outputToken,
|
||||
userDefinedInstructions,
|
||||
})
|
||||
console.log('Success swapping:', tx)
|
||||
// notify({
|
||||
// title: 'Transaction confirmed',
|
||||
// type: 'success',
|
||||
// txid: tx,
|
||||
// })
|
||||
notify({
|
||||
title: 'Transaction confirmed',
|
||||
type: 'success',
|
||||
txid: tx,
|
||||
})
|
||||
|
||||
await actions.reloadAccount()
|
||||
} catch (e: any) {
|
||||
console.log('Error swapping:', e)
|
||||
|
||||
notify({
|
||||
title: 'Transaction failed',
|
||||
description: e.message,
|
||||
|
@ -77,19 +89,38 @@ const Swap = () => {
|
|||
return (
|
||||
<ContentBox className="max-w-md">
|
||||
<div className="">
|
||||
<div className="mt-1 flex justify-between rounded-md bg-th-bkg-1 py-2 px-6">
|
||||
<TokenSelect token={inputToken} onChange={handleTokenInSelect} />
|
||||
<div>
|
||||
<input
|
||||
type="text"
|
||||
name="amountIn"
|
||||
id="amountIn"
|
||||
className="tex-th-fgd-2 w-full rounded-lg border-none bg-transparent text-right text-2xl focus:ring-0"
|
||||
placeholder="0.00"
|
||||
value={amountIn}
|
||||
onChange={handleAmountInChange}
|
||||
/>
|
||||
<div className="mt-1 flex-col rounded-md bg-th-bkg-1 py-2 px-6">
|
||||
<div className="flex justify-between">
|
||||
<TokenSelect token={inputToken} onChange={handleTokenInSelect} />
|
||||
<div>
|
||||
<input
|
||||
type="text"
|
||||
name="amountIn"
|
||||
id="amountIn"
|
||||
className="tex-th-fgd-2 w-full rounded-lg border-none bg-transparent text-right text-2xl focus:ring-0"
|
||||
placeholder="0.00"
|
||||
value={amountIn}
|
||||
onChange={handleAmountInChange}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<label
|
||||
htmlFor="default-range"
|
||||
className="block text-sm font-medium text-gray-900 dark:text-gray-300"
|
||||
></label>
|
||||
<input
|
||||
id="default-range"
|
||||
type="range"
|
||||
className="mb-6 h-1 w-full cursor-pointer appearance-none rounded-lg bg-th-bkg-3"
|
||||
></input>
|
||||
</div>
|
||||
</div>
|
||||
<div className="-my-5 flex justify-center">
|
||||
<button onClick={handleSwitchTokens}>
|
||||
<ArrowDownIcon className="h-10 w-10 rounded-full border-4 border-th-bkg-1 bg-th-bkg-2 p-1.5 text-th-fgd-3 md:hover:text-th-primary" />
|
||||
{/* <SwitchVerticalIcon className="default-transition h-10 w-10 rounded-full border-4 border-th-bkg-1 bg-th-bkg-2 p-1.5 text-th-fgd-3 md:hover:text-th-primary" /> */}
|
||||
</button>
|
||||
</div>
|
||||
<div className="mt-4 flex items-center justify-between rounded-md py-2 px-6">
|
||||
<TokenSelect token={outputToken} onChange={handleTokenOutSelect} />
|
||||
|
|
|
@ -0,0 +1,298 @@
|
|||
import { FunctionComponent, useEffect, useMemo, useState } from 'react'
|
||||
import dayjs from 'dayjs'
|
||||
import relativeTime from 'dayjs/plugin/relativeTime'
|
||||
import { AreaChart, Area, XAxis, YAxis, Tooltip } from 'recharts'
|
||||
import useDimensions from 'react-cool-dimensions'
|
||||
import LineChartIcon from '../icons/LineChartIcon'
|
||||
import ContentBox from '../shared/ContentBox'
|
||||
|
||||
dayjs.extend(relativeTime)
|
||||
|
||||
interface SwapTokenChartProps {
|
||||
inputTokenId?: string
|
||||
outputTokenId?: string
|
||||
}
|
||||
|
||||
export const numberFormatter = Intl.NumberFormat('en', {
|
||||
minimumFractionDigits: 1,
|
||||
maximumFractionDigits: 5,
|
||||
})
|
||||
|
||||
export const numberCompacter = Intl.NumberFormat('en', {
|
||||
notation: 'compact',
|
||||
maximumFractionDigits: 2,
|
||||
})
|
||||
|
||||
const SwapTokenChart: FunctionComponent<SwapTokenChartProps> = ({
|
||||
inputTokenId,
|
||||
outputTokenId,
|
||||
}) => {
|
||||
const [chartData, setChartData] = useState([])
|
||||
const [hideChart, setHideChart] = useState(false)
|
||||
const [baseTokenId, setBaseTokenId] = useState('')
|
||||
const [quoteTokenId, setQuoteTokenId] = useState('')
|
||||
const [inputTokenInfo, setInputTokenInfo] = useState<any>(null)
|
||||
const [outputTokenInfo, setOutputTokenInfo] = useState<any>(null)
|
||||
const [mouseData, setMouseData] = useState<any>(null)
|
||||
const [daysToShow, setDaysToShow] = useState(1)
|
||||
const { observe, width, height } = useDimensions()
|
||||
|
||||
const handleMouseMove = (coords: any) => {
|
||||
if (coords.activePayload) {
|
||||
setMouseData(coords.activePayload[0].payload)
|
||||
}
|
||||
}
|
||||
|
||||
const handleMouseLeave = () => {
|
||||
setMouseData(null)
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
if (!inputTokenId || !outputTokenId) {
|
||||
return
|
||||
}
|
||||
if (['usd-coin', 'tether'].includes(inputTokenId)) {
|
||||
setBaseTokenId(outputTokenId)
|
||||
setQuoteTokenId(inputTokenId)
|
||||
} else {
|
||||
setBaseTokenId(inputTokenId)
|
||||
setQuoteTokenId(outputTokenId)
|
||||
}
|
||||
}, [inputTokenId, outputTokenId])
|
||||
|
||||
// Use ohlc data
|
||||
|
||||
const getChartData = async () => {
|
||||
const inputResponse = await fetch(
|
||||
`https://api.coingecko.com/api/v3/coins/${baseTokenId}/ohlc?vs_currency=usd&days=${daysToShow}`
|
||||
)
|
||||
const outputResponse = await fetch(
|
||||
`https://api.coingecko.com/api/v3/coins/${quoteTokenId}/ohlc?vs_currency=usd&days=${daysToShow}`
|
||||
)
|
||||
const inputData = await inputResponse.json()
|
||||
const outputData = await outputResponse.json()
|
||||
|
||||
let data: any[] = []
|
||||
if (Array.isArray(inputData)) {
|
||||
data = data.concat(inputData)
|
||||
}
|
||||
if (Array.isArray(outputData)) {
|
||||
data = data.concat(outputData)
|
||||
}
|
||||
|
||||
const formattedData = data.reduce((a, c) => {
|
||||
const found = a.find((price: any) => price.time === c[0])
|
||||
if (found) {
|
||||
if (['usd-coin', 'tether'].includes(quoteTokenId)) {
|
||||
found.price = found.inputPrice / c[4]
|
||||
} else {
|
||||
found.price = c[4] / found.inputPrice
|
||||
}
|
||||
} else {
|
||||
a.push({ time: c[0], inputPrice: c[4] })
|
||||
}
|
||||
return a
|
||||
}, [])
|
||||
formattedData[formattedData.length - 1].time = Date.now()
|
||||
setChartData(formattedData.filter((d: any) => d.price))
|
||||
}
|
||||
|
||||
// Alternative chart data. Needs a timestamp tolerance to get data points for each asset
|
||||
|
||||
// const getChartData = async () => {
|
||||
// const now = Date.now() / 1000
|
||||
// const inputResponse = await fetch(
|
||||
// `https://api.coingecko.com/api/v3/coins/${inputTokenId}/market_chart/range?vs_currency=usd&from=${
|
||||
// now - 1 * 86400
|
||||
// }&to=${now}`
|
||||
// )
|
||||
|
||||
// const outputResponse = await fetch(
|
||||
// `https://api.coingecko.com/api/v3/coins/${outputTokenId}/market_chart/range?vs_currency=usd&from=${
|
||||
// now - 1 * 86400
|
||||
// }&to=${now}`
|
||||
// )
|
||||
// const inputData = await inputResponse.json()
|
||||
// const outputData = await outputResponse.json()
|
||||
|
||||
// const data = inputData?.prices.concat(outputData?.prices)
|
||||
|
||||
// const formattedData = data.reduce((a, c) => {
|
||||
// const found = a.find(
|
||||
// (price) => c[0] >= price.time - 120000 && c[0] <= price.time + 120000
|
||||
// )
|
||||
// if (found) {
|
||||
// found.price = found.inputPrice / c[1]
|
||||
// } else {
|
||||
// a.push({ time: c[0], inputPrice: c[1] })
|
||||
// }
|
||||
// return a
|
||||
// }, [])
|
||||
// setChartData(formattedData.filter((d) => d.price))
|
||||
// }
|
||||
|
||||
const getInputTokenInfo = async () => {
|
||||
const response = await fetch(
|
||||
`https://api.coingecko.com/api/v3/coins/${inputTokenId}?localization=false&tickers=false&developer_data=false&sparkline=false
|
||||
`
|
||||
)
|
||||
const data = await response.json()
|
||||
setInputTokenInfo(data)
|
||||
}
|
||||
|
||||
const getOutputTokenInfo = async () => {
|
||||
const response = await fetch(
|
||||
`https://api.coingecko.com/api/v3/coins/${outputTokenId}?localization=false&tickers=false&developer_data=false&sparkline=false
|
||||
`
|
||||
)
|
||||
const data = await response.json()
|
||||
setOutputTokenInfo(data)
|
||||
}
|
||||
|
||||
useMemo(() => {
|
||||
if (baseTokenId && quoteTokenId) {
|
||||
getChartData()
|
||||
}
|
||||
}, [daysToShow, baseTokenId, quoteTokenId])
|
||||
|
||||
useMemo(() => {
|
||||
if (baseTokenId) {
|
||||
getInputTokenInfo()
|
||||
}
|
||||
if (quoteTokenId) {
|
||||
getOutputTokenInfo()
|
||||
}
|
||||
}, [baseTokenId, quoteTokenId])
|
||||
|
||||
const chartChange = chartData.length
|
||||
? ((chartData[chartData.length - 1]['price'] - chartData[0]['price']) /
|
||||
chartData[0]['price']) *
|
||||
100
|
||||
: 0
|
||||
|
||||
return (
|
||||
<ContentBox>
|
||||
{chartData.length && baseTokenId && quoteTokenId ? (
|
||||
<div className="">
|
||||
<div className="flex items-start justify-between">
|
||||
<div>
|
||||
{inputTokenInfo && outputTokenInfo ? (
|
||||
<div className="text-sm text-th-fgd-3">
|
||||
{`${outputTokenInfo?.symbol?.toUpperCase()}/${inputTokenInfo?.symbol?.toUpperCase()}`}
|
||||
</div>
|
||||
) : null}
|
||||
{mouseData ? (
|
||||
<>
|
||||
<div className="text-lg font-bold text-th-fgd-1">
|
||||
{numberFormatter.format(mouseData['price'])}
|
||||
<span
|
||||
className={`ml-2 text-xs ${
|
||||
chartChange >= 0 ? 'text-th-green' : 'text-th-red'
|
||||
}`}
|
||||
>
|
||||
{chartChange.toFixed(2)}%
|
||||
</span>
|
||||
</div>
|
||||
<div className="text-xs font-normal text-th-fgd-3">
|
||||
{dayjs(mouseData['time']).format('DD MMM YY, h:mma')}
|
||||
</div>
|
||||
</>
|
||||
) : (
|
||||
<>
|
||||
<div className="text-lg font-bold text-th-fgd-1">
|
||||
{numberFormatter.format(
|
||||
chartData[chartData.length - 1]['price']
|
||||
)}
|
||||
<span
|
||||
className={`ml-2 text-xs ${
|
||||
chartChange >= 0 ? 'text-th-green' : 'text-th-red'
|
||||
}`}
|
||||
>
|
||||
{chartChange.toFixed(2)}%
|
||||
</span>
|
||||
</div>
|
||||
<div className="text-xs font-normal text-th-fgd-3">
|
||||
{dayjs(chartData[chartData.length - 1]['time']).format(
|
||||
'DD MMM YY, h:mma'
|
||||
)}
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
<div className="flex justify-end">
|
||||
<button
|
||||
className={`px-3 py-2 text-xs font-bold text-th-fgd-4 focus:outline-none md:hover:text-th-primary ${
|
||||
daysToShow === 1 && 'text-th-primary'
|
||||
}`}
|
||||
onClick={() => setDaysToShow(1)}
|
||||
>
|
||||
24H
|
||||
</button>
|
||||
<button
|
||||
className={`px-3 py-2 text-xs font-bold text-th-fgd-4 focus:outline-none md:hover:text-th-primary ${
|
||||
daysToShow === 7 && 'text-th-primary'
|
||||
}`}
|
||||
onClick={() => setDaysToShow(7)}
|
||||
>
|
||||
7D
|
||||
</button>
|
||||
<button
|
||||
className={`px-3 py-2 text-xs font-bold text-th-fgd-4 focus:outline-none md:hover:text-th-primary ${
|
||||
daysToShow === 30 && 'text-th-primary'
|
||||
}`}
|
||||
onClick={() => setDaysToShow(30)}
|
||||
>
|
||||
30D
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
{!hideChart ? (
|
||||
<div className="mt-6 h-36 w-full" ref={observe}>
|
||||
<AreaChart
|
||||
width={width}
|
||||
height={height}
|
||||
data={chartData}
|
||||
onMouseMove={handleMouseMove}
|
||||
onMouseLeave={handleMouseLeave}
|
||||
>
|
||||
<Tooltip
|
||||
cursor={{
|
||||
strokeOpacity: 0,
|
||||
}}
|
||||
content={<></>}
|
||||
/>
|
||||
{/* <defs>
|
||||
<linearGradient id="gradientArea" x1="0" y1="0" x2="0" y2="1">
|
||||
<stop offset="0%" stopColor="#ffba24" stopOpacity={0.9} />
|
||||
<stop offset="90%" stopColor="#ffba24" stopOpacity={0} />
|
||||
</linearGradient>
|
||||
</defs> */}
|
||||
<Area
|
||||
isAnimationActive={true}
|
||||
type="monotone"
|
||||
dataKey="price"
|
||||
stroke="#ffba24"
|
||||
fill="url(#gradientArea)"
|
||||
/>
|
||||
<XAxis dataKey="time" hide />
|
||||
<YAxis
|
||||
dataKey="price"
|
||||
type="number"
|
||||
domain={['dataMin', 'dataMax']}
|
||||
hide
|
||||
/>
|
||||
</AreaChart>
|
||||
</div>
|
||||
) : null}
|
||||
</div>
|
||||
) : (
|
||||
<div className="mt-4 rounded-md bg-th-bkg-3 p-4 text-center text-th-fgd-3 md:mt-0">
|
||||
<LineChartIcon className="mx-auto h-6 w-6 text-th-primary" />
|
||||
Chart not available
|
||||
</div>
|
||||
)}
|
||||
</ContentBox>
|
||||
)
|
||||
}
|
||||
|
||||
export default SwapTokenChart
|
|
@ -20,13 +20,16 @@
|
|||
"@solana/wallet-adapter-react-ui": "^0.9.6",
|
||||
"@solana/wallet-adapter-wallets": "^0.16.0",
|
||||
"@tailwindcss/forms": "^0.5.0",
|
||||
"dayjs": "^1.11.3",
|
||||
"immer": "^9.0.12",
|
||||
"lodash.debounce": "^4.0.8",
|
||||
"next": "12.1.5",
|
||||
"next-themes": "^0.1.1",
|
||||
"process": "^0.11.10",
|
||||
"react": "18.0.0",
|
||||
"react-cool-dimensions": "^2.0.7",
|
||||
"react-dom": "18.0.0",
|
||||
"recharts": "^2.1.12",
|
||||
"zustand": "^3.7.2"
|
||||
},
|
||||
"peerDependencies": {
|
||||
|
|
|
@ -35,6 +35,12 @@ const loadJupTokens = async () => {
|
|||
set((s) => {
|
||||
s.jupiterTokens = result
|
||||
})
|
||||
const inputTokenInfo = result.find((t: any) => t.symbol === 'SOL')
|
||||
const outputTokenInfo = result.find((t: any) => t.symbol === 'USDC')
|
||||
set((s) => {
|
||||
s.inputTokenInfo = inputTokenInfo
|
||||
s.outputTokenInfo = outputTokenInfo
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
|
|
|
@ -47,6 +47,8 @@ export type MangoStore = {
|
|||
notificationIdCounter: number
|
||||
notifications: Array<Notification>
|
||||
serumOrders: Order[] | undefined
|
||||
inputTokenInfo: any
|
||||
outputTokenInfo: any
|
||||
set: (x: (x: MangoStore) => void) => void
|
||||
wallet: {
|
||||
tokens: TokenAccount[]
|
||||
|
@ -67,11 +69,13 @@ const mangoStore = create<MangoStore>(
|
|||
connection,
|
||||
group: undefined,
|
||||
client: MangoClient.connect(provider, CLUSTER, MANGO_V4_ID[CLUSTER]),
|
||||
inputTokenInfo: undefined,
|
||||
jupiterTokens: [],
|
||||
mangoAccount: undefined,
|
||||
markets: undefined,
|
||||
notificationIdCounter: 0,
|
||||
notifications: [],
|
||||
outputTokenInfo: undefined,
|
||||
serumOrders: undefined,
|
||||
set: (fn) => set(produce(fn)),
|
||||
wallet: {
|
||||
|
|
|
@ -69,4 +69,32 @@
|
|||
|
||||
body {
|
||||
@apply font-body tracking-wider;
|
||||
}
|
||||
|
||||
input[type=range]::-webkit-slider-thumb {
|
||||
-webkit-appearance: none;
|
||||
height: 16px;
|
||||
width: 16px;
|
||||
border-radius: 100%;
|
||||
background: var(--primary);
|
||||
cursor: pointer;
|
||||
margin-top: -1px; /* You need to specify a margin in Chrome, but in Firefox and IE it is automatic */
|
||||
}
|
||||
|
||||
/* All the same stuff for Firefox */
|
||||
input[type=range]::-moz-range-thumb {
|
||||
height: 16px;
|
||||
width: 16px;
|
||||
border-radius: 100%;
|
||||
background: var(--primary);
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
/* All the same stuff for IE */
|
||||
input[type=range]::-ms-thumb {
|
||||
height: 16px;
|
||||
width: 16px;
|
||||
border-radius: 100%;
|
||||
background: var(--primary);
|
||||
cursor: pointer;
|
||||
}
|
|
@ -1,4 +1,11 @@
|
|||
import { RouteInfo } from '@jup-ag/core'
|
||||
|
||||
export type TokenInfo = {
|
||||
decimals: number
|
||||
symbol: string
|
||||
}
|
||||
|
||||
export type Routes = {
|
||||
routesInfos: RouteInfo[]
|
||||
cached: boolean
|
||||
}
|
||||
|
|
|
@ -13,3 +13,7 @@ export const formatDecimal = (
|
|||
if (decimals === 6) return digits6.format(value)
|
||||
if (decimals === 9) return digits9.format(value)
|
||||
}
|
||||
|
||||
export const numberFormat = new Intl.NumberFormat('en', {
|
||||
maximumSignificantDigits: 7,
|
||||
})
|
||||
|
|
191
yarn.lock
191
yarn.lock
|
@ -10,6 +10,13 @@
|
|||
core-js-pure "^3.20.2"
|
||||
regenerator-runtime "^0.13.4"
|
||||
|
||||
"@babel/runtime@^7.1.2", "@babel/runtime@^7.10.5", "@babel/runtime@^7.12.5", "@babel/runtime@^7.17.2":
|
||||
version "7.18.6"
|
||||
resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.18.6.tgz#6a1ef59f838debd670421f8c7f2cbb8da9751580"
|
||||
integrity sha512-t9wi7/AW6XtKahAe20Yw0/mMljKq0B1r2fPdvaAdV/KPDZewFXdaaa6K7lxmZBZ8FBNpCiAT6iHPmd6QO9bKfQ==
|
||||
dependencies:
|
||||
regenerator-runtime "^0.13.4"
|
||||
|
||||
"@babel/runtime@^7.10.2", "@babel/runtime@^7.16.0", "@babel/runtime@^7.16.3", "@babel/runtime@^7.6.2":
|
||||
version "7.17.9"
|
||||
resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.17.9.tgz#d19fbf802d01a8cb6cf053a64e472d42c434ba72"
|
||||
|
@ -17,16 +24,9 @@
|
|||
dependencies:
|
||||
regenerator-runtime "^0.13.4"
|
||||
|
||||
"@babel/runtime@^7.10.5", "@babel/runtime@^7.12.5", "@babel/runtime@^7.17.2":
|
||||
version "7.18.6"
|
||||
resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.18.6.tgz#6a1ef59f838debd670421f8c7f2cbb8da9751580"
|
||||
integrity sha512-t9wi7/AW6XtKahAe20Yw0/mMljKq0B1r2fPdvaAdV/KPDZewFXdaaa6K7lxmZBZ8FBNpCiAT6iHPmd6QO9bKfQ==
|
||||
dependencies:
|
||||
regenerator-runtime "^0.13.4"
|
||||
|
||||
"@blockworks-foundation/mango-v4@git+https://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:x-oauth-basic@github.com/blockworks-foundation/mango-v4.git":
|
||||
version "0.0.1"
|
||||
resolved "git+https://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:x-oauth-basic@github.com/blockworks-foundation/mango-v4.git#0ff269c38c72229a33a79a7fc37f400456a35c73"
|
||||
resolved "git+https://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:x-oauth-basic@github.com/blockworks-foundation/mango-v4.git#c829fdf59d4aaf75733278d5c209acc42b02fcb4"
|
||||
dependencies:
|
||||
"@project-serum/anchor" "^0.24.2"
|
||||
"@project-serum/serum" "^0.13.65"
|
||||
|
@ -1696,6 +1696,11 @@ cipher-base@^1.0.0, cipher-base@^1.0.1, cipher-base@^1.0.3:
|
|||
inherits "^2.0.1"
|
||||
safe-buffer "^5.0.1"
|
||||
|
||||
classnames@^2.2.5:
|
||||
version "2.3.1"
|
||||
resolved "https://registry.yarnpkg.com/classnames/-/classnames-2.3.1.tgz#dfcfa3891e306ec1dad105d0e88f4417b8535e8e"
|
||||
integrity sha512-OlQdbZ7gLfGarSqxesMesDa5uz7KFbID8Kpq/SxIoNGDqY8lSYs0D+hhtBXhcdB3rcbXArFr7vlHheLk1voeNA==
|
||||
|
||||
color-convert@^2.0.1:
|
||||
version "2.0.1"
|
||||
resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-2.0.1.tgz#72d3a68d598c9bdb3af2ad1e84f21d896abd4de3"
|
||||
|
@ -1767,6 +1772,11 @@ crypto-hash@^1.3.0:
|
|||
resolved "https://registry.yarnpkg.com/crypto-hash/-/crypto-hash-1.3.0.tgz#b402cb08f4529e9f4f09346c3e275942f845e247"
|
||||
integrity sha512-lyAZ0EMyjDkVvz8WOeVnuCPvKVBXcMv1l5SVqO1yC7PzTwrD/pPje/BIRbWhMoPe436U+Y2nD7f5bFx0kt+Sbg==
|
||||
|
||||
css-unit-converter@^1.1.1:
|
||||
version "1.1.2"
|
||||
resolved "https://registry.yarnpkg.com/css-unit-converter/-/css-unit-converter-1.1.2.tgz#4c77f5a1954e6dbff60695ecb214e3270436ab21"
|
||||
integrity sha512-IiJwMC8rdZE0+xiEZHeru6YoONC4rfPMqGm2W85jMIbkFvv5nFTwJVFHam2eFrN6txmoUYFAFXiv8ICVeTO0MA==
|
||||
|
||||
cssesc@^3.0.0:
|
||||
version "3.0.0"
|
||||
resolved "https://registry.yarnpkg.com/cssesc/-/cssesc-3.0.0.tgz#37741919903b868565e1c09ea747445cd18983ee"
|
||||
|
@ -1777,11 +1787,77 @@ csstype@^3.0.2:
|
|||
resolved "https://registry.yarnpkg.com/csstype/-/csstype-3.0.11.tgz#d66700c5eacfac1940deb4e3ee5642792d85cd33"
|
||||
integrity sha512-sa6P2wJ+CAbgyy4KFssIb/JNMLxFvKF1pCYCSXS8ZMuqZnMsrxqI2E5sPyoTpxoPU/gVZMzr2zjOfg8GIZOMsw==
|
||||
|
||||
d3-array@2, d3-array@^2.3.0:
|
||||
version "2.12.1"
|
||||
resolved "https://registry.yarnpkg.com/d3-array/-/d3-array-2.12.1.tgz#e20b41aafcdffdf5d50928004ececf815a465e81"
|
||||
integrity sha512-B0ErZK/66mHtEsR1TkPEEkwdy+WDesimkM5gpZr5Dsg54BiTA5RXtYW5qTLIAcekaS9xfZrzBLF/OAkB3Qn1YQ==
|
||||
dependencies:
|
||||
internmap "^1.0.0"
|
||||
|
||||
"d3-color@1 - 2":
|
||||
version "2.0.0"
|
||||
resolved "https://registry.yarnpkg.com/d3-color/-/d3-color-2.0.0.tgz#8d625cab42ed9b8f601a1760a389f7ea9189d62e"
|
||||
integrity sha512-SPXi0TSKPD4g9tw0NMZFnR95XVgUZiBH+uUTqQuDu1OsE2zomHU7ho0FISciaPvosimixwHFl3WHLGabv6dDgQ==
|
||||
|
||||
"d3-format@1 - 2":
|
||||
version "2.0.0"
|
||||
resolved "https://registry.yarnpkg.com/d3-format/-/d3-format-2.0.0.tgz#a10bcc0f986c372b729ba447382413aabf5b0767"
|
||||
integrity sha512-Ab3S6XuE/Q+flY96HXT0jOXcM4EAClYFnRGY5zsjRGNy6qCYrQsMffs7cV5Q9xejb35zxW5hf/guKw34kvIKsA==
|
||||
|
||||
"d3-interpolate@1.2.0 - 2", d3-interpolate@^2.0.0:
|
||||
version "2.0.1"
|
||||
resolved "https://registry.yarnpkg.com/d3-interpolate/-/d3-interpolate-2.0.1.tgz#98be499cfb8a3b94d4ff616900501a64abc91163"
|
||||
integrity sha512-c5UhwwTs/yybcmTpAVqwSFl6vrQ8JZJoT5F7xNFK9pymv5C0Ymcc9/LIJHtYIggg/yS9YHw8i8O8tgb9pupjeQ==
|
||||
dependencies:
|
||||
d3-color "1 - 2"
|
||||
|
||||
"d3-path@1 - 2":
|
||||
version "2.0.0"
|
||||
resolved "https://registry.yarnpkg.com/d3-path/-/d3-path-2.0.0.tgz#55d86ac131a0548adae241eebfb56b4582dd09d8"
|
||||
integrity sha512-ZwZQxKhBnv9yHaiWd6ZU4x5BtCQ7pXszEV9CU6kRgwIQVQGLMv1oiL4M+MK/n79sYzsj+gcgpPQSctJUsLN7fA==
|
||||
|
||||
d3-scale@^3.0.0:
|
||||
version "3.3.0"
|
||||
resolved "https://registry.yarnpkg.com/d3-scale/-/d3-scale-3.3.0.tgz#28c600b29f47e5b9cd2df9749c206727966203f3"
|
||||
integrity sha512-1JGp44NQCt5d1g+Yy+GeOnZP7xHo0ii8zsQp6PGzd+C1/dl0KGsp9A7Mxwp+1D1o4unbTTxVdU/ZOIEBoeZPbQ==
|
||||
dependencies:
|
||||
d3-array "^2.3.0"
|
||||
d3-format "1 - 2"
|
||||
d3-interpolate "1.2.0 - 2"
|
||||
d3-time "^2.1.1"
|
||||
d3-time-format "2 - 3"
|
||||
|
||||
d3-shape@^2.0.0:
|
||||
version "2.1.0"
|
||||
resolved "https://registry.yarnpkg.com/d3-shape/-/d3-shape-2.1.0.tgz#3b6a82ccafbc45de55b57fcf956c584ded3b666f"
|
||||
integrity sha512-PnjUqfM2PpskbSLTJvAzp2Wv4CZsnAgTfcVRTwW03QR3MkXF8Uo7B1y/lWkAsmbKwuecto++4NlsYcvYpXpTHA==
|
||||
dependencies:
|
||||
d3-path "1 - 2"
|
||||
|
||||
"d3-time-format@2 - 3":
|
||||
version "3.0.0"
|
||||
resolved "https://registry.yarnpkg.com/d3-time-format/-/d3-time-format-3.0.0.tgz#df8056c83659e01f20ac5da5fdeae7c08d5f1bb6"
|
||||
integrity sha512-UXJh6EKsHBTjopVqZBhFysQcoXSv/5yLONZvkQ5Kk3qbwiUYkdX17Xa1PT6U1ZWXGGfB1ey5L8dKMlFq2DO0Ag==
|
||||
dependencies:
|
||||
d3-time "1 - 2"
|
||||
|
||||
"d3-time@1 - 2", d3-time@^2.1.1:
|
||||
version "2.1.1"
|
||||
resolved "https://registry.yarnpkg.com/d3-time/-/d3-time-2.1.1.tgz#e9d8a8a88691f4548e68ca085e5ff956724a6682"
|
||||
integrity sha512-/eIQe/eR4kCQwq7yxi7z4c6qEXf2IYGcjoWB5OOQy4Tq9Uv39/947qlDcN2TLkiTzQWzvnsuYPB9TrWaNfipKQ==
|
||||
dependencies:
|
||||
d3-array "2"
|
||||
|
||||
damerau-levenshtein@^1.0.7:
|
||||
version "1.0.8"
|
||||
resolved "https://registry.yarnpkg.com/damerau-levenshtein/-/damerau-levenshtein-1.0.8.tgz#b43d286ccbd36bc5b2f7ed41caf2d0aba1f8a6e7"
|
||||
integrity sha512-sdQSFB7+llfUcQHUQO3+B8ERRj0Oa4w9POWMI/puGtuf7gFywGmkaLCElnudfTiKZV+NvHqL0ifzdrI8Ro7ESA==
|
||||
|
||||
dayjs@^1.11.3:
|
||||
version "1.11.3"
|
||||
resolved "https://registry.yarnpkg.com/dayjs/-/dayjs-1.11.3.tgz#4754eb694a624057b9ad2224b67b15d552589258"
|
||||
integrity sha512-xxwlswWOlGhzgQ4TKzASQkUhqERI3egRNqgV4ScR8wlANA/A9tZ7miXa44vTTKEq5l7vWoL5G57bG3zA+Kow0A==
|
||||
|
||||
debug@4.3.2:
|
||||
version "4.3.2"
|
||||
resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.2.tgz#f0a49c18ac8779e31d4a0c6029dfb76873c7428b"
|
||||
|
@ -1810,7 +1886,7 @@ debug@^4.1.1, debug@^4.3.2:
|
|||
dependencies:
|
||||
ms "2.1.2"
|
||||
|
||||
decimal.js-light@^2.5.1:
|
||||
decimal.js-light@^2.4.1, decimal.js-light@^2.5.1:
|
||||
version "2.5.1"
|
||||
resolved "https://registry.yarnpkg.com/decimal.js-light/-/decimal.js-light-2.5.1.tgz#134fd32508f19e208f4fb2f8dac0d2626a867934"
|
||||
integrity sha512-qIMFpTMZmny+MMIitAB6D7iVPEorVw6YQRWkvarTkT4tBeSLLiHzcwj6q0MmYSFCiVpiqPJTJEYIrpcPzVEIvg==
|
||||
|
@ -1888,6 +1964,13 @@ doctrine@^3.0.0:
|
|||
dependencies:
|
||||
esutils "^2.0.2"
|
||||
|
||||
dom-helpers@^3.4.0:
|
||||
version "3.4.0"
|
||||
resolved "https://registry.yarnpkg.com/dom-helpers/-/dom-helpers-3.4.0.tgz#e9b369700f959f62ecde5a6babde4bccd9169af8"
|
||||
integrity sha512-LnuPJ+dwqKDIyotW1VzmOZ5TONUN7CwkCR5hrgawTUbkBGYdeoNLZo6nNfGkCrjtE1nXXaj7iMMpDa8/d9WoIA==
|
||||
dependencies:
|
||||
"@babel/runtime" "^7.1.2"
|
||||
|
||||
dot-case@^3.0.4:
|
||||
version "3.0.4"
|
||||
resolved "https://registry.yarnpkg.com/dot-case/-/dot-case-3.0.4.tgz#9b2b670d00a431667a8a75ba29cd1b98809ce751"
|
||||
|
@ -2365,7 +2448,7 @@ event-stream@=3.3.4:
|
|||
stream-combiner "~0.0.4"
|
||||
through "~2.3.1"
|
||||
|
||||
eventemitter3@^4.0.0, eventemitter3@^4.0.4, eventemitter3@^4.0.7:
|
||||
eventemitter3@^4.0.0, eventemitter3@^4.0.1, eventemitter3@^4.0.4, eventemitter3@^4.0.7:
|
||||
version "4.0.7"
|
||||
resolved "https://registry.yarnpkg.com/eventemitter3/-/eventemitter3-4.0.7.tgz#2de9b68f6528d5644ef5c59526a1b4a07306169f"
|
||||
integrity sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==
|
||||
|
@ -2408,6 +2491,11 @@ fast-deep-equal@^3.1.1, fast-deep-equal@^3.1.3:
|
|||
resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz#3a7d56b559d6cbc3eb512325244e619a65c6c525"
|
||||
integrity sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==
|
||||
|
||||
fast-equals@^2.0.0:
|
||||
version "2.0.4"
|
||||
resolved "https://registry.yarnpkg.com/fast-equals/-/fast-equals-2.0.4.tgz#3add9410585e2d7364c2deeb6a707beadb24b927"
|
||||
integrity sha512-caj/ZmjHljPrZtbzJ3kfH5ia/k4mTJe/qSiXAGzxZWRZgsgDV0cvNaQULqUX8t0/JVlzzEdYOwCN5DmzTxoD4w==
|
||||
|
||||
fast-glob@^3.2.11, fast-glob@^3.2.9:
|
||||
version "3.2.11"
|
||||
resolved "https://registry.yarnpkg.com/fast-glob/-/fast-glob-3.2.11.tgz#a1172ad95ceb8a16e20caa5c5e56480e5129c1d9"
|
||||
|
@ -2755,6 +2843,11 @@ internal-slot@^1.0.3:
|
|||
has "^1.0.3"
|
||||
side-channel "^1.0.4"
|
||||
|
||||
internmap@^1.0.0:
|
||||
version "1.0.1"
|
||||
resolved "https://registry.yarnpkg.com/internmap/-/internmap-1.0.1.tgz#0017cc8a3b99605f0302f2b198d272e015e5df95"
|
||||
integrity sha512-lDB5YccMydFBtasVtxnZ3MRBHuaoE8GKsppq+EchKL2U4nK/DmEpPHNH8MZe5HkMtpSiTSOZwfN0tzYjO/lJEw==
|
||||
|
||||
is-arguments@^1.0.4:
|
||||
version "1.1.1"
|
||||
resolved "https://registry.yarnpkg.com/is-arguments/-/is-arguments-1.1.1.tgz#15b3f88fda01f2a97fec84ca761a560f123efa9b"
|
||||
|
@ -3088,7 +3181,7 @@ lodash.merge@^4.6.2:
|
|||
resolved "https://registry.yarnpkg.com/lodash.merge/-/lodash.merge-4.6.2.tgz#558aa53b43b661e1925a0afdfa36a9a1085fe57a"
|
||||
integrity sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==
|
||||
|
||||
lodash@^4.17.20, lodash@^4.17.21:
|
||||
lodash@^4.17.19, lodash@^4.17.20, lodash@^4.17.21:
|
||||
version "4.17.21"
|
||||
resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c"
|
||||
integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==
|
||||
|
@ -3544,6 +3637,11 @@ postcss-selector-parser@^6.0.10, postcss-selector-parser@^6.0.6:
|
|||
cssesc "^3.0.0"
|
||||
util-deprecate "^1.0.2"
|
||||
|
||||
postcss-value-parser@^3.3.0:
|
||||
version "3.3.1"
|
||||
resolved "https://registry.yarnpkg.com/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz#9ff822547e2893213cf1c30efa51ac5fd1ba8281"
|
||||
integrity sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==
|
||||
|
||||
postcss-value-parser@^4.2.0:
|
||||
version "4.2.0"
|
||||
resolved "https://registry.yarnpkg.com/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz#723c09920836ba6d3e5af019f92bc0971c02e514"
|
||||
|
@ -3595,7 +3693,7 @@ promise-retry@2.0.1, promise-retry@^2.0.1:
|
|||
err-code "^2.0.2"
|
||||
retry "^0.12.0"
|
||||
|
||||
prop-types@^15.8.1:
|
||||
prop-types@^15.6.2, prop-types@^15.8.1:
|
||||
version "15.8.1"
|
||||
resolved "https://registry.yarnpkg.com/prop-types/-/prop-types-15.8.1.tgz#67d87bf1a694f48435cf332c24af10214a3140b5"
|
||||
integrity sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==
|
||||
|
@ -3641,6 +3739,11 @@ randombytes@^2.1.0:
|
|||
dependencies:
|
||||
safe-buffer "^5.1.0"
|
||||
|
||||
react-cool-dimensions@^2.0.7:
|
||||
version "2.0.7"
|
||||
resolved "https://registry.yarnpkg.com/react-cool-dimensions/-/react-cool-dimensions-2.0.7.tgz#2fe6657608f034cd7c89f149ed14e79cf1cb2d50"
|
||||
integrity sha512-z1VwkAAJ5d8QybDRuYIXTE41RxGr5GYsv1bQhbOBE8cMfoZQZpcF0odL64vdgrQVzat2jayedj1GoYi80FWcbA==
|
||||
|
||||
react-dom@18.0.0:
|
||||
version "18.0.0"
|
||||
resolved "https://registry.yarnpkg.com/react-dom/-/react-dom-18.0.0.tgz#26b88534f8f1dbb80853e1eabe752f24100d8023"
|
||||
|
@ -3649,11 +3752,41 @@ react-dom@18.0.0:
|
|||
loose-envify "^1.1.0"
|
||||
scheduler "^0.21.0"
|
||||
|
||||
react-is@^16.13.1:
|
||||
react-is@^16.10.2, react-is@^16.13.1:
|
||||
version "16.13.1"
|
||||
resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.13.1.tgz#789729a4dc36de2999dc156dd6c1d9c18cea56a4"
|
||||
integrity sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==
|
||||
|
||||
react-lifecycles-compat@^3.0.4:
|
||||
version "3.0.4"
|
||||
resolved "https://registry.yarnpkg.com/react-lifecycles-compat/-/react-lifecycles-compat-3.0.4.tgz#4f1a273afdfc8f3488a8c516bfda78f872352362"
|
||||
integrity sha512-fBASbA6LnOU9dOU2eW7aQ8xmYBSXUIWr+UmF9b1efZBazGNO+rcXT/icdKnYm2pTwcRylVUYwW7H1PHfLekVzA==
|
||||
|
||||
react-resize-detector@^7.1.2:
|
||||
version "7.1.2"
|
||||
resolved "https://registry.yarnpkg.com/react-resize-detector/-/react-resize-detector-7.1.2.tgz#8ef975dd8c3d56f9a5160ac382ef7136dcd2d86c"
|
||||
integrity sha512-zXnPJ2m8+6oq9Nn8zsep/orts9vQv3elrpA+R8XTcW7DVVUJ9vwDwMXaBtykAYjMnkCIaOoK9vObyR7ZgFNlOw==
|
||||
dependencies:
|
||||
lodash "^4.17.21"
|
||||
|
||||
react-smooth@^2.0.1:
|
||||
version "2.0.1"
|
||||
resolved "https://registry.yarnpkg.com/react-smooth/-/react-smooth-2.0.1.tgz#74c7309916d6ccca182c4b30c8992f179e6c5a05"
|
||||
integrity sha512-Own9TA0GPPf3as4vSwFhDouVfXP15ie/wIHklhyKBH5AN6NFtdk0UpHBnonV11BtqDkAWlt40MOUc+5srmW7NA==
|
||||
dependencies:
|
||||
fast-equals "^2.0.0"
|
||||
react-transition-group "2.9.0"
|
||||
|
||||
react-transition-group@2.9.0:
|
||||
version "2.9.0"
|
||||
resolved "https://registry.yarnpkg.com/react-transition-group/-/react-transition-group-2.9.0.tgz#df9cdb025796211151a436c69a8f3b97b5b07c8d"
|
||||
integrity sha512-+HzNTCHpeQyl4MJ/bdE0u6XRMe9+XG/+aL4mCxVN4DnPBQ0/5bfHWPDuOZUzYdMj94daZaZdCCc1Dzt9R/xSSg==
|
||||
dependencies:
|
||||
dom-helpers "^3.4.0"
|
||||
loose-envify "^1.4.0"
|
||||
prop-types "^15.6.2"
|
||||
react-lifecycles-compat "^3.0.4"
|
||||
|
||||
react@18.0.0:
|
||||
version "18.0.0"
|
||||
resolved "https://registry.yarnpkg.com/react/-/react-18.0.0.tgz#b468736d1f4a5891f38585ba8e8fb29f91c3cb96"
|
||||
|
@ -3677,6 +3810,38 @@ readdirp@~3.6.0:
|
|||
dependencies:
|
||||
picomatch "^2.2.1"
|
||||
|
||||
recharts-scale@^0.4.4:
|
||||
version "0.4.5"
|
||||
resolved "https://registry.yarnpkg.com/recharts-scale/-/recharts-scale-0.4.5.tgz#0969271f14e732e642fcc5bd4ab270d6e87dd1d9"
|
||||
integrity sha512-kivNFO+0OcUNu7jQquLXAxz1FIwZj8nrj+YkOKc5694NbjCvcT6aSZiIzNzd2Kul4o4rTto8QVR9lMNtxD4G1w==
|
||||
dependencies:
|
||||
decimal.js-light "^2.4.1"
|
||||
|
||||
recharts@^2.1.12:
|
||||
version "2.1.12"
|
||||
resolved "https://registry.yarnpkg.com/recharts/-/recharts-2.1.12.tgz#2cbc87b0ed386a1328e9bab2b808a5fbce22e59f"
|
||||
integrity sha512-dAzEuc9AjM+IF0A33QzEdBEUnyGKJcGUPa0MYm0vd38P3WouQjrj2egBrCNInE7ZcQwN+z3MoT7Rw03u8nP9HA==
|
||||
dependencies:
|
||||
classnames "^2.2.5"
|
||||
d3-interpolate "^2.0.0"
|
||||
d3-scale "^3.0.0"
|
||||
d3-shape "^2.0.0"
|
||||
eventemitter3 "^4.0.1"
|
||||
lodash "^4.17.19"
|
||||
react-is "^16.10.2"
|
||||
react-resize-detector "^7.1.2"
|
||||
react-smooth "^2.0.1"
|
||||
recharts-scale "^0.4.4"
|
||||
reduce-css-calc "^2.1.8"
|
||||
|
||||
reduce-css-calc@^2.1.8:
|
||||
version "2.1.8"
|
||||
resolved "https://registry.yarnpkg.com/reduce-css-calc/-/reduce-css-calc-2.1.8.tgz#7ef8761a28d614980dc0c982f772c93f7a99de03"
|
||||
integrity sha512-8liAVezDmUcH+tdzoEGrhfbGcP7nOV4NkGE3a74+qqvE7nt9i4sKLGBuZNOnpI4WiGksiNPklZxva80061QiPg==
|
||||
dependencies:
|
||||
css-unit-converter "^1.1.1"
|
||||
postcss-value-parser "^3.3.0"
|
||||
|
||||
regenerator-runtime@^0.13.4:
|
||||
version "0.13.9"
|
||||
resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.13.9.tgz#8925742a98ffd90814988d7566ad30ca3b263b52"
|
||||
|
|
Loading…
Reference in New Issue