diff --git a/src/components/GlobalChart/index.js b/src/components/GlobalChart/index.js index 8668180..402347e 100644 --- a/src/components/GlobalChart/index.js +++ b/src/components/GlobalChart/index.js @@ -1,6 +1,6 @@ import React, { useState, useMemo, useEffect, useRef } from "react"; import { ResponsiveContainer } from "recharts"; -import { timeframeOptions } from "../../constants"; +import { timeframeOptions, WETH_ADDRESS } from "../../constants"; import { useGlobalChartData, useGlobalData } from "../../contexts/GlobalData"; import { useMedia } from "react-use"; import DropdownSelect from "../DropdownSelect"; @@ -9,6 +9,8 @@ import { RowFixed } from "../Row"; import { OptionButton } from "../ButtonStyled"; import { getTimeframe } from "../../utils"; import { TYPE } from "../../Theme"; +import { useAllTokenData } from "../../contexts/TokenData"; +import { useSelectedNetwork } from "../../contexts/Network"; const CHART_VIEW = { VOLUME: "Volume", @@ -19,7 +21,7 @@ const VOLUME_WINDOW = { WEEKLY: "WEEKLY", DAYS: "DAYS", }; -const GlobalChart = ({ display }) => { +const GlobalChart = ({ display, unit }) => { // chart options const [chartView, setChartView] = useState( display === "volume" ? CHART_VIEW.VOLUME : CHART_VIEW.LIQUIDITY @@ -40,6 +42,12 @@ const GlobalChart = ({ display }) => { weeklyVolumeChange, } = useGlobalData(); + const allTokens = useAllTokenData(); + const network = useSelectedNetwork(); + const wethNativeCurrency = Number( + allTokens[WETH_ADDRESS[network].toLowerCase()].derivedNativeCurrency + ); + // based on window, get starttim let utcStartTime = getTimeframe(timeWindow); @@ -96,6 +104,8 @@ const GlobalChart = ({ display }) => { data={dailyData} base={totalLiquidityUSD} baseChange={liquidityChangeUSD} + unit={unit} + wethCurrency={wethNativeCurrency} title="Liquidity" field="totalLiquidityUSD" width={width} @@ -120,6 +130,8 @@ const GlobalChart = ({ display }) => { title={ volumeWindow === VOLUME_WINDOW.WEEKLY ? "Volume (7d)" : "Volume" } + unit={unit} + wethCurrency={wethNativeCurrency} field={ volumeWindow === VOLUME_WINDOW.WEEKLY ? "weeklyVolumeUSD" diff --git a/src/components/TradingviewChart/index.js b/src/components/TradingviewChart/index.js index 7f9dae8..f0b8cf6 100644 --- a/src/components/TradingviewChart/index.js +++ b/src/components/TradingviewChart/index.js @@ -1,30 +1,30 @@ -import React, { useState, useEffect, useRef } from 'react' -import { createChart } from 'lightweight-charts' -import dayjs from 'dayjs' -import utc from 'dayjs/plugin/utc' -import { formattedNum } from '../../utils' -import styled from 'styled-components' -import { usePrevious } from 'react-use' -import { Play } from 'react-feather' -import { useDarkModeManager } from '../../contexts/LocalStorage' -import { IconWrapper } from '..' +import React, { useState, useEffect, useRef } from "react"; +import { createChart } from "lightweight-charts"; +import dayjs from "dayjs"; +import utc from "dayjs/plugin/utc"; +import { formattedEthUsdNum } from "../../utils"; +import styled from "styled-components"; +import { usePrevious } from "react-use"; +import { Play } from "react-feather"; +import { useDarkModeManager } from "../../contexts/LocalStorage"; +import { IconWrapper } from ".."; -import { useSelectedNetwork } from '../../contexts/Network' -import { NETWORK_COLORS } from '../../constants' +import { useSelectedNetwork } from "../../contexts/Network"; +import { NETWORK_COLORS } from "../../constants"; -dayjs.extend(utc) +dayjs.extend(utc); export const CHART_TYPES = { - BAR: 'BAR', - AREA: 'AREA', -} + BAR: "BAR", + AREA: "AREA", +}; const Wrapper = styled.div` position: relative; -` +`; // constant height for charts -const HEIGHT = 300 +const HEIGHT = 300; const TradingViewChart = ({ type = CHART_TYPES.BAR, @@ -35,188 +35,204 @@ const TradingViewChart = ({ title, width, useWeekly = false, + unit, + wethCurrency, }) => { // reference for DOM element to create with chart - const ref = useRef() - const network = useSelectedNetwork() + const ref = useRef(); + const network = useSelectedNetwork(); // pointer to the chart object - const [chartCreated, setChartCreated] = useState(false) - const dataPrev = usePrevious(data) + const [chartCreated, setChartCreated] = useState(false); + const dataPrev = usePrevious(data); useEffect(() => { if (data !== dataPrev && chartCreated && type === CHART_TYPES.BAR) { // remove the tooltip element - let tooltip = document.getElementById('tooltip-id' + type) - let node = document.getElementById('test-id' + type) - node.removeChild(tooltip) - chartCreated.resize(0, 0) - setChartCreated() + let tooltip = document.getElementById("tooltip-id" + type); + let node = document.getElementById("test-id" + type); + node.removeChild(tooltip); + chartCreated.resize(0, 0); + setChartCreated(); } - }, [chartCreated, data, dataPrev, type]) + }, [chartCreated, data, dataPrev, type]); // parese the data and format for tardingview consumption const formattedData = data?.map((entry) => { return { - time: dayjs.unix(entry.date).utc().format('YYYY-MM-DD'), + time: dayjs.unix(entry.date).utc().format("YYYY-MM-DD"), value: parseFloat(entry[field]), - } - }) + }; + }); // adjust the scale based on the type of chart - const topScale = type === CHART_TYPES.AREA ? 0.32 : 0.2 + const topScale = type === CHART_TYPES.AREA ? 0.32 : 0.2; - const [darkMode] = useDarkModeManager() - const textColor = darkMode ? 'white' : 'black' - const previousTheme = usePrevious(darkMode) + const [darkMode] = useDarkModeManager(); + const textColor = darkMode ? "white" : "black"; + const previousTheme = usePrevious(darkMode); // reset the chart if them switches useEffect(() => { if (chartCreated && previousTheme !== darkMode) { // remove the tooltip element - let tooltip = document.getElementById('tooltip-id' + type) - let node = document.getElementById('test-id' + type) - node.removeChild(tooltip) - chartCreated.resize(0, 0) - setChartCreated() + let tooltip = document.getElementById("tooltip-id" + type); + let node = document.getElementById("test-id" + type); + node.removeChild(tooltip); + chartCreated.resize(0, 0); + setChartCreated(); } - }, [chartCreated, darkMode, previousTheme, type]) + }, [chartCreated, darkMode, previousTheme, type]); - // if no chart created yet, create one with options and add to DOM manually - useEffect(() => { - if (!chartCreated && formattedData) { - var chart = createChart(ref.current, { - width: width, - height: HEIGHT, - layout: { - backgroundColor: 'transparent', - textColor: textColor, + const setupChart = () => { + var chart = createChart(ref.current, { + width: width, + height: HEIGHT, + layout: { + backgroundColor: "transparent", + textColor: textColor, + }, + rightPriceScale: { + scaleMargins: { + top: topScale, + bottom: 0, }, - rightPriceScale: { - scaleMargins: { - top: topScale, - bottom: 0, - }, - borderVisible: false, + borderVisible: false, + }, + timeScale: { + borderVisible: false, + }, + grid: { + horzLines: { + color: "rgba(197, 203, 206, 0.5)", + visible: false, }, - timeScale: { - borderVisible: false, + vertLines: { + color: "rgba(197, 203, 206, 0.5)", + visible: false, }, - grid: { - horzLines: { - color: 'rgba(197, 203, 206, 0.5)', - visible: false, - }, - vertLines: { - color: 'rgba(197, 203, 206, 0.5)', - visible: false, - }, + }, + crosshair: { + horzLine: { + visible: false, + labelVisible: false, }, - crosshair: { - horzLine: { - visible: false, - labelVisible: false, - }, - vertLine: { - visible: true, - style: 0, - width: 2, - color: 'rgba(32, 38, 46, 0.1)', - labelVisible: false, - }, + vertLine: { + visible: true, + style: 0, + width: 2, + color: "rgba(32, 38, 46, 0.1)", + labelVisible: false, }, - localization: { - priceFormatter: (val) => formattedNum(val, true), - }, - }) + }, + localization: { + priceFormatter: (val) => formattedEthUsdNum(wethCurrency, val, unit), + }, + }); + + var series = + type === CHART_TYPES.BAR + ? chart.addHistogramSeries({ + color: NETWORK_COLORS[network].hex, + priceFormat: { + type: "volume", + }, + scaleMargins: { + top: 0.32, + bottom: 0, + }, + lineColor: NETWORK_COLORS[network].hex, + lineWidth: 3, + }) + : chart.addAreaSeries({ + topColor: NETWORK_COLORS[network].hex, + bottomColor: NETWORK_COLORS[network].rgba, + lineColor: NETWORK_COLORS[network].hex, + lineWidth: 3, + }); - var series = - type === CHART_TYPES.BAR - ? chart.addHistogramSeries({ - color: NETWORK_COLORS[network].hex, - priceFormat: { - type: 'volume', - }, - scaleMargins: { - top: 0.32, - bottom: 0, - }, - lineColor: NETWORK_COLORS[network].hex, - lineWidth: 3, - }) - : chart.addAreaSeries({ - topColor: NETWORK_COLORS[network].hex, - bottomColor: NETWORK_COLORS[network].rgba, - lineColor: NETWORK_COLORS[network].hex, - lineWidth: 3, - }) + series.setData(formattedData); + var toolTip = document.createElement("div"); + toolTip.setAttribute("id", "tooltip-id" + type); + toolTip.className = darkMode + ? "three-line-legend-dark" + : "three-line-legend"; + ref.current.appendChild(toolTip); + toolTip.style.display = "block"; + toolTip.style.fontWeight = "500"; + toolTip.style.left = -4 + "px"; + toolTip.style.top = "-" + 8 + "px"; + toolTip.style.backgroundColor = "transparent"; - series.setData(formattedData) - var toolTip = document.createElement('div') - toolTip.setAttribute('id', 'tooltip-id' + type) - toolTip.className = darkMode ? 'three-line-legend-dark' : 'three-line-legend' - ref.current.appendChild(toolTip) - toolTip.style.display = 'block' - toolTip.style.fontWeight = '500' - toolTip.style.left = -4 + 'px' - toolTip.style.top = '-' + 8 + 'px' - toolTip.style.backgroundColor = 'transparent' + // format numbers + let percentChange = baseChange?.toFixed(2); + let formattedPercentChange = percentChange + ? (percentChange > 0 ? "+" : "") + percentChange + "%" + : "0%"; + let color = percentChange >= 0 ? "green" : "red"; + + // get the title of the chart + function setLastBarText() { + toolTip.innerHTML = + `
${title} ${ + type === CHART_TYPES.BAR && !useWeekly ? "(24hr)" : "" + }
` + + `
` + + formattedEthUsdNum(wethCurrency, base ?? 0, unit) + + `${formattedPercentChange}` + + "
"; + } + setLastBarText(); - // format numbers - let percentChange = baseChange?.toFixed(2) - let formattedPercentChange = percentChange ? (percentChange > 0 ? '+' : '') + percentChange + '%' : '0%' - let color = percentChange >= 0 ? 'green' : 'red' + // update the title when hovering on the chart + chart.subscribeCrosshairMove(function (param) { + if ( + param === undefined || + param.time === undefined || + param.point.x < 0 || + param.point.x > width || + param.point.y < 0 || + param.point.y > HEIGHT + ) { + setLastBarText(); + } else { + let dateStr = useWeekly + ? dayjs( + param.time.year + "-" + param.time.month + "-" + param.time.day + ) + .startOf("week") + .format("MMMM D, YYYY") + + "-" + + dayjs( + param.time.year + "-" + param.time.month + "-" + param.time.day + ) + .endOf("week") + .format("MMMM D, YYYY") + : dayjs( + param.time.year + "-" + param.time.month + "-" + param.time.day + ).format("MMMM D, YYYY"); + var price = param.seriesPrices.get(series); - // get the title of the chart - function setLastBarText() { toolTip.innerHTML = - `
${title} ${ - type === CHART_TYPES.BAR && !useWeekly ? '(24hr)' : '' - }
` + - `
` + - formattedNum(base ?? 0, true) + - `${formattedPercentChange}` + - '
' + `
${title}
` + + `
` + + formattedEthUsdNum(wethCurrency, price, unit) + + "
" + + "
" + + dateStr + + "
"; } - setLastBarText() + }); - // update the title when hovering on the chart - chart.subscribeCrosshairMove(function (param) { - if ( - param === undefined || - param.time === undefined || - param.point.x < 0 || - param.point.x > width || - param.point.y < 0 || - param.point.y > HEIGHT - ) { - setLastBarText() - } else { - let dateStr = useWeekly - ? dayjs(param.time.year + '-' + param.time.month + '-' + param.time.day) - .startOf('week') - .format('MMMM D, YYYY') + - '-' + - dayjs(param.time.year + '-' + param.time.month + '-' + param.time.day) - .endOf('week') - .format('MMMM D, YYYY') - : dayjs(param.time.year + '-' + param.time.month + '-' + param.time.day).format('MMMM D, YYYY') - var price = param.seriesPrices.get(series) + chart.timeScale().fitContent(); - toolTip.innerHTML = - `
${title}
` + - `
` + - formattedNum(price, true) + - '
' + - '
' + - dateStr + - '
' - } - }) + setChartCreated(chart); + }; - chart.timeScale().fitContent() - - setChartCreated(chart) + // if no chart created yet, create one with options and add to DOM manually + useEffect(() => { + if (!chartCreated && formattedData) { + setupChart(); } }, [ base, @@ -232,28 +248,35 @@ const TradingViewChart = ({ useWeekly, width, network, - ]) + ]); + + useEffect(() => { + if (chartCreated && formattedData) { + ref.current.innerHTML = ""; + setupChart(); + } + }, [unit]); // responsiveness useEffect(() => { if (width) { - chartCreated && chartCreated.resize(width, HEIGHT) - chartCreated && chartCreated.timeScale().scrollToPosition(0) + chartCreated && chartCreated.resize(width, HEIGHT); + chartCreated && chartCreated.timeScale().scrollToPosition(0); } - }, [chartCreated, width]) + }, [chartCreated, width]); return ( -
+
{ - chartCreated && chartCreated.timeScale().fitContent() + chartCreated && chartCreated.timeScale().fitContent(); }} /> - ) -} + ); +}; -export default TradingViewChart +export default TradingViewChart; diff --git a/src/components/UnitOptions/index.js b/src/components/UnitOptions/index.js new file mode 100644 index 0000000..79b8220 --- /dev/null +++ b/src/components/UnitOptions/index.js @@ -0,0 +1,45 @@ +import React from "react"; +import styled from "styled-components"; + +const Options = styled.div` + display: flex; + align-items: center; +`; + +const Option = styled.span` + padding: 0.5rem; + font-size: 14px; + font-weight: 500; + color: white; + cursor: pointer; + opacity: ${(props) => (props.selected ? 1 : 0.6)}; + + &:hover { + opacity: 1; + } +`; + +const Devider = styled.span` + margin: 0; + color: white; +`; + +const UnitOptions = ({ selected, setSelected }) => { + return ( + <> + + + / + + + + ); +}; + +export default UnitOptions; diff --git a/src/constants/index.js b/src/constants/index.js index a4dfbca..6fdd4d5 100644 --- a/src/constants/index.js +++ b/src/constants/index.js @@ -49,6 +49,10 @@ export const HNY_ADDRESS = { [SupportedNetwork.MATIC]: "0xb371248Dd0f9E4061ccf8850E9223Ca48Aa7CA4b", }; +export const WETH_ADDRESS = { + [SupportedNetwork.XDAI]: "0x6A023CCd1ff6F2045C3309768eAd9E68F978f6e1", +}; + export const ETHERSCAN_PREFIXES = { // [SupportedNetwork.MAINNET]: "", }; diff --git a/src/pages/GlobalPage.js b/src/pages/GlobalPage.js index 62a5510..5ba0ca4 100644 --- a/src/pages/GlobalPage.js +++ b/src/pages/GlobalPage.js @@ -1,31 +1,32 @@ -import React, { useEffect } from 'react' -import { withRouter } from 'react-router-dom' -import { Box } from 'rebass' -import styled from 'styled-components' +import React, { useEffect, useState } from "react"; +import { withRouter } from "react-router-dom"; +import { Box } from "rebass"; +import styled from "styled-components"; -import { AutoRow, RowBetween } from '../components/Row' -import { AutoColumn } from '../components/Column' -import PairList from '../components/PairList' -import TopTokenList from '../components/TokenList' -import TxnList from '../components/TxnList' -import GlobalChart from '../components/GlobalChart' -import Search from '../components/Search' -import GlobalStats from '../components/GlobalStats' +import { AutoRow, RowBetween } from "../components/Row"; +import { AutoColumn } from "../components/Column"; +import PairList from "../components/PairList"; +import TopTokenList from "../components/TokenList"; +import TxnList from "../components/TxnList"; +import GlobalChart from "../components/GlobalChart"; +import Search from "../components/Search"; +import GlobalStats from "../components/GlobalStats"; -import { useGlobalData, useGlobalTransactions } from '../contexts/GlobalData' -import { useAllPairData } from '../contexts/PairData' -import { useMedia } from 'react-use' -import Panel from '../components/Panel' -import { useAllTokenData } from '../contexts/TokenData' -import { formattedNum, formattedPercent } from '../utils' -import { TYPE, ThemedBackground } from '../Theme' -import { transparentize } from 'polished' -import { CustomLink } from '../components/Link' +import { useGlobalData, useGlobalTransactions } from "../contexts/GlobalData"; +import { useAllPairData } from "../contexts/PairData"; +import { useMedia } from "react-use"; +import Panel from "../components/Panel"; +import { useAllTokenData } from "../contexts/TokenData"; +import { formattedEthUsdNum, formattedNum, formattedPercent } from "../utils"; +import { TYPE, ThemedBackground } from "../Theme"; +import { transparentize } from "polished"; +import { CustomLink } from "../components/Link"; -import { PageWrapper, ContentWrapper } from '../components' +import { PageWrapper, ContentWrapper } from "../components"; -import { useSelectedNetwork } from '../contexts/Network' -import { NETWORK_COLORS } from '../constants' +import { useSelectedNetwork } from "../contexts/Network"; +import { NETWORK_COLORS, WETH_ADDRESS } from "../constants"; +import UnitOptions from "../components/UnitOptions"; const ListOptions = styled(AutoRow)` height: 40px; @@ -36,7 +37,7 @@ const ListOptions = styled(AutoRow)` @media screen and (max-width: 640px) { font-size: 1rem; } -` +`; const GridRow = styled.div` display: grid; @@ -45,27 +46,43 @@ const GridRow = styled.div` column-gap: 6px; align-items: start; justify-content: space-between; -` +`; function GlobalPage() { // get data for lists and totals - const allPairs = useAllPairData() - const allTokens = useAllTokenData() - const transactions = useGlobalTransactions() - const { totalLiquidityUSD, oneDayVolumeUSD, volumeChangeUSD, liquidityChangeUSD } = useGlobalData() - const network = useSelectedNetwork() + const allPairs = useAllPairData(); + const allTokens = useAllTokenData(); + const transactions = useGlobalTransactions(); + const { + totalLiquidityUSD, + oneDayVolumeUSD, + volumeChangeUSD, + liquidityChangeUSD, + } = useGlobalData(); + const [selected, setSelected] = useState(0); + const network = useSelectedNetwork(); + const wethNativeCurrency = Number( + allTokens[WETH_ADDRESS[network].toLowerCase()].derivedNativeCurrency + ); // breakpoints - const below800 = useMedia('(max-width: 800px)') + const below800 = useMedia("(max-width: 800px)"); + + useEffect(() => { + const fetchNativeCurrencyWethValue = async () => {}; + if (selected === 0) { + fetchNativeCurrencyWethValue(); + } + }, [selected]); // scrolling refs useEffect(() => { - document.querySelector('body').scrollTo({ - behavior: 'smooth', + document.querySelector("body").scrollTo({ + behavior: "smooth", top: 0, - }) - }, []) + }); + }, []); return ( @@ -74,11 +91,17 @@ function GlobalPage() { />
- - {below800 ? 'Protocol Analytics' : 'Honeyswap Protocol Analytics'} + + + {below800 ? "Protocol Analytics" : "Honeyswap Protocol Analytics"} + + {below800 && ( // mobile card @@ -90,10 +113,20 @@ function GlobalPage() {
- - {formattedNum(oneDayVolumeUSD, true)} + + {formattedEthUsdNum( + wethNativeCurrency, + oneDayVolumeUSD, + selected + )} + + + {formattedPercent(volumeChangeUSD)} - {formattedPercent(volumeChangeUSD)} @@ -102,10 +135,20 @@ function GlobalPage() {
- - {formattedNum(totalLiquidityUSD, true)} + + {formattedEthUsdNum( + wethNativeCurrency, + totalLiquidityUSD, + selected + )} + + + {formattedPercent(liquidityChangeUSD)} - {formattedPercent(liquidityChangeUSD)} @@ -115,52 +158,58 @@ function GlobalPage() { )} {!below800 && ( - - + + - - + + )} {below800 && ( - - - + + + )} - + - Top Tokens - See All + Top Tokens + See All - + - + - Top Pairs - See All + Top Pairs + See All - + - + Transactions - +
- ) + ); } -export default withRouter(GlobalPage) +export default withRouter(GlobalPage); diff --git a/src/utils/index.js b/src/utils/index.js index e56aeee..5291801 100644 --- a/src/utils/index.js +++ b/src/utils/index.js @@ -7,11 +7,7 @@ import { GET_BLOCK, GET_BLOCKS, SHARE_VALUE } from "../apollo/queries"; import { Text } from "rebass"; import _Decimal from "decimal.js-light"; import toFormat from "toformat"; -import { - SupportedNetwork, - timeframeOptions, - ChainId, -} from "../constants"; +import { SupportedNetwork, timeframeOptions, ChainId } from "../constants"; import Numeral from "numeral"; import { getAddress } from "ethers/utils"; @@ -452,6 +448,10 @@ export const toSignificant = (number, significantDigits) => { return updated.toFormat(updated.decimalPlaces(), { groupSeparator: "" }); }; +export const formattedEthUsdNum = (weth, number, unit) => { + return formattedNum(!unit ? number : number / weth, !unit); +}; + export const formattedNum = (number, usd = false, acceptNegatives = false) => { if (isNaN(number) || number === "" || number === undefined) { return usd ? "$0" : 0; @@ -605,19 +605,26 @@ export function getFeeRate({ token0, token1 }, selectedNetwork) { let feeRate = 0.0025; if (!token0 || !token1) return feeRate; if (selectedNetwork !== "MATIC") return feeRate; - if(getAddress(token0.id) === wethAddress || getAddress(token1.id) === wethAddress) { - feeRate = 0.00125; + if ( + getAddress(token0.id) === wethAddress || + getAddress(token1.id) === wethAddress + ) { + feeRate = 0.00125; } - + return feeRate; } -export function getPaidFeeRateByTokenSymbols(token0Symbol, token1Symbol, selectedNetwork) { +export function getPaidFeeRateByTokenSymbols( + token0Symbol, + token1Symbol, + selectedNetwork +) { let feeRate = 0.003; if (selectedNetwork !== "MATIC") return feeRate; if (token0Symbol === "WETH" || token1Symbol === "WETH") { - feeRate = 0.0015; - } - + feeRate = 0.0015; + } + return feeRate; }