add simple area chart
This commit is contained in:
parent
ba39db5b9f
commit
0f46288df6
|
@ -3,12 +3,14 @@ import { Transition } from '@headlessui/react'
|
|||
import { ChevronDownIcon, DotsHorizontalIcon } from '@heroicons/react/solid'
|
||||
import { useWallet } from '@solana/wallet-adapter-react'
|
||||
import { useTranslation } from 'next-i18next'
|
||||
import { useTheme } from 'next-themes'
|
||||
import Image from 'next/image'
|
||||
import { useRouter } from 'next/router'
|
||||
import { Fragment, useEffect, useMemo, useState } from 'react'
|
||||
import { useViewport } from '../hooks/useViewport'
|
||||
|
||||
import mangoStore from '../store/state'
|
||||
import { COLORS } from '../styles/colors'
|
||||
import { formatDecimal, numberFormat } from '../utils/numbers'
|
||||
import { breakpoints } from '../utils/theme'
|
||||
import Switch from './forms/Switch'
|
||||
|
@ -19,6 +21,7 @@ import { IconButton, LinkButton } from './shared/Button'
|
|||
import ContentBox from './shared/ContentBox'
|
||||
import { UpTriangle } from './shared/DirectionTriangles'
|
||||
import IconDropMenu from './shared/IconDropMenu'
|
||||
import SimpleAreaChart from './shared/SimpleAreaChart'
|
||||
import { FadeInList } from './shared/Transitions'
|
||||
|
||||
const TokenList = () => {
|
||||
|
@ -27,10 +30,20 @@ const TokenList = () => {
|
|||
const [showTokenDetails, setShowTokenDetails] = useState('')
|
||||
const [showZeroBalances, setShowZeroBalances] = useState(true)
|
||||
const mangoAccount = mangoStore((s) => s.mangoAccount.current)
|
||||
const coingeckoPrices = mangoStore((s) => s.coingeckoPrices.data)
|
||||
const loadingCoingeckoPrices = mangoStore((s) => s.coingeckoPrices.loading)
|
||||
const actions = mangoStore((s) => s.actions)
|
||||
const group = mangoStore((s) => s.group)
|
||||
const { theme } = useTheme()
|
||||
const { width } = useViewport()
|
||||
const showTableView = width ? width > breakpoints.md : false
|
||||
|
||||
useEffect(() => {
|
||||
if (coingeckoPrices.length === 0) {
|
||||
actions.fetchCoingeckoPrices()
|
||||
}
|
||||
}, [coingeckoPrices])
|
||||
|
||||
const banks = useMemo(() => {
|
||||
if (group?.banksMap) {
|
||||
const rawBanks = Array.from(group?.banksMap, ([key, value]) => ({
|
||||
|
@ -85,21 +98,27 @@ const TokenList = () => {
|
|||
<table className="min-w-full">
|
||||
<thead>
|
||||
<tr>
|
||||
<th className="w-[12.5%] text-left">{t('token')}</th>
|
||||
<th className="w-[12.5%] text-right">{t('price')}</th>
|
||||
{/* <th className="w-[12.5%] text-right">{t('rolling-change')}</th>
|
||||
<th className="w-[12.5%] text-right">{t('daily-volume')}</th> */}
|
||||
<th className="w-[12.5%] text-right">{t('rates')}</th>
|
||||
<th className="w-[12.5%] text-right">{t('liquidity')}</th>
|
||||
<th className="w-[12.5%] text-right">{t('available-balance')}</th>
|
||||
<th className="w-[16.67%] text-left">{t('token')}</th>
|
||||
<th className="w-[16.67%] text-right">{t('price')}</th>
|
||||
<th className="className='hidden lg:block' w-[16.67%] text-right"></th>
|
||||
<th className="w-[16.67%] text-right">{t('rates')}</th>
|
||||
<th className="w-[16.67%] text-right">{t('liquidity')}</th>
|
||||
<th className="w-[16.67%] text-right">
|
||||
{t('available-balance')}
|
||||
</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{banks.map((bank, index) => {
|
||||
const oraclePrice = bank.value.price
|
||||
|
||||
const coingeckoData = coingeckoPrices.find(
|
||||
(asset) => asset.symbol === bank.key
|
||||
)
|
||||
const chartData = coingeckoData ? coingeckoData.prices : undefined
|
||||
return (
|
||||
<FadeInList as="tr" index={index} key={bank.key}>
|
||||
<td className="w-[12.5%]">
|
||||
<td className="w-[16.67%]">
|
||||
<div className="flex items-center">
|
||||
<div className="mr-2.5 flex flex-shrink-0 items-center">
|
||||
<Image
|
||||
|
@ -112,7 +131,7 @@ const TokenList = () => {
|
|||
<p>{bank.value.name}</p>
|
||||
</div>
|
||||
</td>
|
||||
<td className="w-[12.5%]">
|
||||
<td className="w-[16.67%]">
|
||||
<div className="flex flex-col text-right">
|
||||
<p>${formatDecimal(oraclePrice.toNumber(), 2)}</p>
|
||||
{/* <div className="flex items-center justify-end">
|
||||
|
@ -121,17 +140,37 @@ const TokenList = () => {
|
|||
</div> */}
|
||||
</div>
|
||||
</td>
|
||||
{/* <td className="w-[12.5%]">
|
||||
<td className="hidden lg:block">
|
||||
<div>
|
||||
{!loadingCoingeckoPrices ? (
|
||||
chartData !== undefined ? (
|
||||
<SimpleAreaChart
|
||||
// update color when we have 24h change
|
||||
color={COLORS.GREEN[theme]}
|
||||
data={chartData}
|
||||
height={40}
|
||||
name={bank.key}
|
||||
width={104}
|
||||
/>
|
||||
) : bank.key === 'USDC' ? null : (
|
||||
t('unavailable')
|
||||
)
|
||||
) : (
|
||||
<div className="h-10 w-[104px] animate-pulse rounded bg-th-bkg-3" />
|
||||
)}
|
||||
</div>
|
||||
</td>
|
||||
{/* <td className="w-[16.67%]">
|
||||
<div className="flex flex-col text-right">
|
||||
<p className="text-th-green">0%</p>
|
||||
</div>
|
||||
</td> */}
|
||||
{/* <td className="w-[12.5%]">
|
||||
{/* <td className="w-[16.67%]">
|
||||
<div className="flex flex-col text-right">
|
||||
<p>1000</p>
|
||||
</div>
|
||||
</td> */}
|
||||
<td className="w-[12.5%]">
|
||||
<td className="w-[16.67%]">
|
||||
<div className="flex justify-end space-x-2 text-right">
|
||||
<p className="text-th-green">
|
||||
{formatDecimal(
|
||||
|
@ -150,7 +189,7 @@ const TokenList = () => {
|
|||
</p>
|
||||
</div>
|
||||
</td>
|
||||
<td className="w-[12.5%]">
|
||||
<td className="w-[16.67%]">
|
||||
<div className="flex flex-col text-right">
|
||||
<p>
|
||||
{formatDecimal(
|
||||
|
@ -160,7 +199,7 @@ const TokenList = () => {
|
|||
</p>
|
||||
</div>
|
||||
</td>
|
||||
<td className="w-[12.5%] pt-4 text-right">
|
||||
<td className="w-[16.67%] pt-4 text-right">
|
||||
<p className="px-2">
|
||||
{mangoAccount
|
||||
? formatDecimal(mangoAccount.getUi(bank.value))
|
||||
|
@ -176,7 +215,7 @@ const TokenList = () => {
|
|||
: '$0'}
|
||||
</p>
|
||||
</td>
|
||||
<td className="w-[12.5%]">
|
||||
<td className="w-[16.67%]">
|
||||
<div className="flex justify-end space-x-2">
|
||||
<ActionsMenu
|
||||
bank={bank.value}
|
||||
|
|
|
@ -0,0 +1,37 @@
|
|||
import { Area, AreaChart, XAxis, YAxis } from 'recharts'
|
||||
|
||||
const SimpleAreaChart = ({
|
||||
color,
|
||||
data,
|
||||
height,
|
||||
name,
|
||||
width,
|
||||
}: {
|
||||
color: string
|
||||
data: any[]
|
||||
height: number
|
||||
name: string
|
||||
width: number
|
||||
}) => {
|
||||
return (
|
||||
<AreaChart width={width} height={height} data={data}>
|
||||
<defs>
|
||||
<linearGradient id={`gradientArea-${name}`} x1="0" y1="0" x2="0" y2="1">
|
||||
<stop offset="0%" stopColor={color} stopOpacity={0.6} />
|
||||
<stop offset="100%" stopColor={color} stopOpacity={0} />
|
||||
</linearGradient>
|
||||
</defs>
|
||||
<Area
|
||||
isAnimationActive={false}
|
||||
type="monotone"
|
||||
dataKey="1"
|
||||
stroke={color}
|
||||
fill={`url(#gradientArea-${name})`}
|
||||
/>
|
||||
<XAxis dataKey="0" hide />
|
||||
<YAxis domain={['dataMin', 'dataMax']} dataKey="1" hide />
|
||||
</AreaChart>
|
||||
)
|
||||
}
|
||||
|
||||
export default SimpleAreaChart
|
|
@ -13,10 +13,11 @@ import FlipNumbers from 'react-flip-numbers'
|
|||
|
||||
import LineChartIcon from '../icons/LineChartIcon'
|
||||
import ContentBox from '../shared/ContentBox'
|
||||
import { GREEN, RED } from '../../styles/colors'
|
||||
import { DownTriangle, UpTriangle } from '../shared/DirectionTriangles'
|
||||
import { formatFixedDecimals } from '../../utils/numbers'
|
||||
import SheenLoader from '../shared/SheenLoader'
|
||||
import { COLORS } from '../../styles/colors'
|
||||
import { useTheme } from 'next-themes'
|
||||
|
||||
dayjs.extend(relativeTime)
|
||||
|
||||
|
@ -85,6 +86,7 @@ const SwapTokenChart: FunctionComponent<SwapTokenChartProps> = ({
|
|||
const [outputTokenInfo, setOutputTokenInfo] = useState<any>(null)
|
||||
const [mouseData, setMouseData] = useState<any>(null)
|
||||
const [daysToShow, setDaysToShow] = useState(1)
|
||||
const { theme } = useTheme()
|
||||
|
||||
const handleMouseMove = (coords: any) => {
|
||||
if (coords.activePayload) {
|
||||
|
@ -295,12 +297,20 @@ const SwapTokenChart: FunctionComponent<SwapTokenChartProps> = ({
|
|||
>
|
||||
<stop
|
||||
offset="0%"
|
||||
stopColor={calculateChartChange() >= 0 ? GREEN : RED}
|
||||
stopColor={
|
||||
calculateChartChange() >= 0
|
||||
? COLORS.GREEN[theme]
|
||||
: COLORS.RED[theme]
|
||||
}
|
||||
stopOpacity={0.15}
|
||||
/>
|
||||
<stop
|
||||
offset="99%"
|
||||
stopColor={calculateChartChange() >= 0 ? GREEN : RED}
|
||||
stopColor={
|
||||
calculateChartChange() >= 0
|
||||
? COLORS.GREEN[theme]
|
||||
: COLORS.RED[theme]
|
||||
}
|
||||
stopOpacity={0}
|
||||
/>
|
||||
</linearGradient>
|
||||
|
@ -309,7 +319,11 @@ const SwapTokenChart: FunctionComponent<SwapTokenChartProps> = ({
|
|||
isAnimationActive={false}
|
||||
type="monotone"
|
||||
dataKey="price"
|
||||
stroke={calculateChartChange() >= 0 ? GREEN : RED}
|
||||
stroke={
|
||||
calculateChartChange() >= 0
|
||||
? COLORS.GREEN[theme]
|
||||
: COLORS.RED[theme]
|
||||
}
|
||||
strokeWidth={1.5}
|
||||
fill="url(#gradientArea)"
|
||||
/>
|
||||
|
|
|
@ -14,6 +14,7 @@ import EmptyWallet from '../utils/wallet'
|
|||
import { Order } from '@project-serum/serum/lib/market'
|
||||
import { Notification, notify } from '../utils/notifications'
|
||||
import {
|
||||
COINGECKO_IDS,
|
||||
fetchNftsFromHolaplexIndexer,
|
||||
getTokenAccountsByOwnerWithWrappedSol,
|
||||
TokenAccount,
|
||||
|
@ -51,6 +52,10 @@ interface NFT {
|
|||
}
|
||||
|
||||
export type MangoStore = {
|
||||
coingeckoPrices: {
|
||||
data: any[]
|
||||
loading: boolean
|
||||
}
|
||||
connected: boolean
|
||||
connection: Connection
|
||||
group: Group | undefined
|
||||
|
@ -82,6 +87,7 @@ export type MangoStore = {
|
|||
}
|
||||
}
|
||||
actions: {
|
||||
fetchCoingeckoPrices: () => Promise<void>
|
||||
fetchGroup: () => Promise<void>
|
||||
fetchMangoAccount: (wallet: Wallet) => Promise<void>
|
||||
fetchMangoAccounts: (wallet: Wallet) => Promise<void>
|
||||
|
@ -98,6 +104,10 @@ export type MangoStore = {
|
|||
const mangoStore = create<MangoStore>(
|
||||
subscribeWithSelector((set, get) => {
|
||||
return {
|
||||
coingeckoPrices: {
|
||||
data: [],
|
||||
loading: false,
|
||||
},
|
||||
connected: false,
|
||||
connection,
|
||||
group: undefined,
|
||||
|
@ -129,6 +139,36 @@ const mangoStore = create<MangoStore>(
|
|||
},
|
||||
},
|
||||
actions: {
|
||||
fetchCoingeckoPrices: async () => {
|
||||
const set = get().set
|
||||
set((state) => {
|
||||
state.coingeckoPrices.loading = true
|
||||
})
|
||||
try {
|
||||
const promises: any = []
|
||||
for (const asset of COINGECKO_IDS) {
|
||||
promises.push(
|
||||
fetch(
|
||||
`https://api.coingecko.com/api/v3/coins/${asset.id}/market_chart?vs_currency=usd&days=1`
|
||||
).then((res) => res.json())
|
||||
)
|
||||
}
|
||||
|
||||
const data = await Promise.all(promises)
|
||||
for (let i = 0; i < data.length; i++) {
|
||||
data[i].symbol = COINGECKO_IDS[i].symbol
|
||||
}
|
||||
set((state) => {
|
||||
state.coingeckoPrices.data = data
|
||||
state.coingeckoPrices.loading = false
|
||||
})
|
||||
} catch (e) {
|
||||
console.log('ERORR: Unable to load Coingecko prices')
|
||||
set((state) => {
|
||||
state.coingeckoPrices.loading = false
|
||||
})
|
||||
}
|
||||
},
|
||||
fetchGroup: async () => {
|
||||
try {
|
||||
const set = get().set
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
export const PRIMARY = '#F2C94C'
|
||||
export const GREEN = '#AFD803'
|
||||
export const RED = '#F84638'
|
||||
export const COLORS: any = {
|
||||
GREEN: { Mango: '#AFD803', Dark: '#5EBF4d', Light: '#5EBF4d' },
|
||||
PRIMARY: { Mango: '#F2C94C', Dark: '#F2C94C', Light: '#FF9C24' },
|
||||
RED: { Mango: '#F84638', Dark: '#CC2929', Light: '#CC2929' },
|
||||
}
|
||||
|
|
|
@ -97,3 +97,21 @@ export const fetchNftsFromHolaplexIndexer = async (owner: PublicKey) => {
|
|||
const body = await result.json()
|
||||
return body.data
|
||||
}
|
||||
|
||||
export const COINGECKO_IDS = [
|
||||
{ id: 'bitcoin', symbol: 'BTC' },
|
||||
// { id: 'ethereum', symbol: 'ETH' },
|
||||
{ id: 'solana', symbol: 'SOL' },
|
||||
// { id: 'mango-markets', symbol: 'MNGO' },
|
||||
// { id: 'binancecoin', symbol: 'BNB' },
|
||||
// { id: 'serum', symbol: 'SRM' },
|
||||
// { id: 'raydium', symbol: 'RAY' },
|
||||
// { id: 'ftx-token', symbol: 'FTT' },
|
||||
// { id: 'avalanche-2', symbol: 'AVAX' },
|
||||
// { id: 'terra-luna', symbol: 'LUNA' },
|
||||
// { id: 'cope', symbol: 'COPE' },
|
||||
// { id: 'cardano', symbol: 'ADA' },
|
||||
// { id: 'msol', symbol: 'MSOL' },
|
||||
// { id: 'tether', symbol: 'USDT' },
|
||||
// { id: 'stepn', symbol: 'GMT' },
|
||||
]
|
||||
|
|
Loading…
Reference in New Issue