import { FunctionComponent, useCallback, useEffect, useState } from 'react' import dayjs from 'dayjs' import relativeTime from 'dayjs/plugin/relativeTime' import { AreaChart, Area, XAxis, YAxis, Tooltip, ResponsiveContainer, } from 'recharts' 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' dayjs.extend(relativeTime) interface SwapTokenChartProps { inputTokenId?: string outputTokenId?: string } const fetchChartData = async ( baseTokenId: string, quoteTokenId: string, daysToShow: number ) => { 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() return formattedData.filter((d: any) => d.price) } const fetchTokenInfo = async (tokenId: string) => { const response = await fetch( `https://api.coingecko.com/api/v3/coins/${tokenId}?localization=false&tickers=false&developer_data=false&sparkline=false ` ) const data = await response.json() return data } const SwapTokenChart: FunctionComponent = ({ inputTokenId, outputTokenId, }) => { const [chartData, setChartData] = useState([]) const [loadChartData, setLoadChartData] = useState(true) const [baseTokenId, setBaseTokenId] = useState('') const [quoteTokenId, setQuoteTokenId] = useState('') const [inputTokenInfo, setInputTokenInfo] = useState(null) const [outputTokenInfo, setOutputTokenInfo] = useState(null) const [mouseData, setMouseData] = useState(null) const [daysToShow, setDaysToShow] = useState(1) 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 = useCallback(async () => { if (!baseTokenId || !quoteTokenId) return const chartData = await fetchChartData( baseTokenId, quoteTokenId, daysToShow ) setChartData(chartData) setTimeout(() => setLoadChartData(false), 1500) }, [baseTokenId, quoteTokenId, daysToShow]) const getInputTokenInfo = useCallback(async () => { if (!inputTokenId) return const response = await fetchTokenInfo(inputTokenId) setInputTokenInfo(response) }, [inputTokenId]) const getOutputTokenInfo = useCallback(async () => { if (!outputTokenId) return const response = await fetchTokenInfo(outputTokenId) setOutputTokenInfo(response) }, [outputTokenId]) useEffect(() => { getChartData() }, [getChartData]) useEffect(() => { getInputTokenInfo() getOutputTokenInfo() }, [getInputTokenInfo, getOutputTokenInfo]) const calculateChartChange = () => { if (chartData.length) { if (mouseData) { const index = chartData.findIndex((d: any) => d.time === mouseData.time) return ( ((chartData[index]['price'] - chartData[0]['price']) / chartData[0]['price']) * 100 ) } else return ( ((chartData[chartData.length - 1]['price'] - chartData[0]['price']) / chartData[0]['price']) * 100 ) } return 0 } return ( {loadChartData ? (
) : chartData.length && baseTokenId && quoteTokenId ? (
{inputTokenInfo && outputTokenInfo ? (

{['usd-coin', 'tether'].includes(inputTokenId || '') ? `${outputTokenInfo?.symbol?.toUpperCase()}/${inputTokenInfo?.symbol?.toUpperCase()}` : `${inputTokenInfo?.symbol?.toUpperCase()}/${outputTokenInfo?.symbol?.toUpperCase()}`}

) : null} {mouseData ? ( <>
= 0 ? 'text-th-green' : 'text-th-red' }`} > {calculateChartChange() >= 0 ? ( ) : ( )} {calculateChartChange().toFixed(2)}%

{dayjs(mouseData['time']).format('DD MMM YY, h:mma')}

) : ( <>
= 0 ? 'text-th-green' : 'text-th-red' }`} > {calculateChartChange() >= 0 ? ( ) : ( )} {calculateChartChange().toFixed(2)}%

{dayjs(chartData[chartData.length - 1]['time']).format( 'DD MMM YY, h:mma' )}

)}
} /> = 0 ? GREEN : RED} stopOpacity={0.15} /> = 0 ? GREEN : RED} stopOpacity={0} /> = 0 ? GREEN : RED} strokeWidth={1.5} fill="url(#gradientArea)" />
) : (

Chart not available

)} ) } export default SwapTokenChart