From db4317400ded74966311b634e274560b092ac4ee Mon Sep 17 00:00:00 2001 From: saml33 Date: Tue, 11 Oct 2022 22:59:01 +1100 Subject: [PATCH 1/9] add token details page --- components/TokenList.tsx | 29 +- components/shared/DailyRange.tsx | 37 +++ components/stats/TokenStats.tsx | 34 ++- package.json | 1 + pages/stats.tsx | 2 +- pages/token/[token].tsx | 455 +++++++++++++++++++++++++++++++ public/locales/en/token.json | 16 ++ public/locales/es/token.json | 16 ++ public/locales/ru/token.json | 16 ++ public/locales/zh/token.json | 16 ++ public/locales/zh_tw/token.json | 16 ++ utils/constants.ts | 3 +- yarn.lock | 87 ++++++ 13 files changed, 717 insertions(+), 11 deletions(-) create mode 100644 components/shared/DailyRange.tsx create mode 100644 pages/token/[token].tsx create mode 100644 public/locales/en/token.json create mode 100644 public/locales/es/token.json create mode 100644 public/locales/ru/token.json create mode 100644 public/locales/zh/token.json create mode 100644 public/locales/zh_tw/token.json diff --git a/components/TokenList.tsx b/components/TokenList.tsx index c2d41d56..e5ff8576 100644 --- a/components/TokenList.tsx +++ b/components/TokenList.tsx @@ -2,6 +2,7 @@ import { Bank, MangoAccount } from '@blockworks-foundation/mango-v4' import { Transition } from '@headlessui/react' import { ChevronDownIcon, + ChevronRightIcon, EllipsisHorizontalIcon, QuestionMarkCircleIcon, } from '@heroicons/react/20/solid' @@ -12,7 +13,6 @@ import { useRouter } from 'next/router' import { Fragment, useCallback, useEffect, useMemo, useState } from 'react' // import useLocalStorageState from '../hooks/useLocalStorageState' import { useViewport } from '../hooks/useViewport' - import mangoStore from '@store/mangoStore' import { formatDecimal, formatFixedDecimals } from '../utils/numbers' import { breakpoints } from '../utils/theme' @@ -23,7 +23,6 @@ import WithdrawModal from './modals/WithdrawModal' import { IconButton, LinkButton } from './shared/Button' import ContentBox from './shared/ContentBox' import IconDropMenu from './shared/IconDropMenu' -import Change from './shared/Change' import Tooltip from './shared/Tooltip' import { formatTokenSymbol } from 'utils/tokens' @@ -40,6 +39,7 @@ const TokenList = () => { ) const { width } = useViewport() const showTableView = width ? width > breakpoints.md : false + const router = useRouter() const banks = useMemo(() => { if (group) { @@ -76,6 +76,10 @@ const TokenList = () => { } }, [connected]) + const goToTokenPage = (bank: Bank) => { + router.push(`/token/${bank.name}`, undefined, { shallow: true }) + } + return (
@@ -225,6 +229,9 @@ const TokenList = () => { id={i === 0 ? 'account-step-ten' : ''} > + goToTokenPage(bank)}> + +
@@ -246,7 +253,7 @@ const TokenList = () => { export default TokenList const MobileTokenListItem = ({ bank }: { bank: Bank }) => { - const { t } = useTranslation('common') + const { t } = useTranslation(['common', 'token']) const [showTokenDetails, setShowTokenDetails] = useState(false) const jupiterTokens = mangoStore((s) => s.jupiterTokens) const spotBalances = mangoStore((s) => s.mangoAccount.spotBalances) @@ -256,6 +263,7 @@ const MobileTokenListItem = ({ bank }: { bank: Bank }) => { ) const symbol = bank.name const oraclePrice = bank.uiPrice + const router = useRouter() let logoURI if (jupiterTokens.length) { @@ -281,6 +289,10 @@ const MobileTokenListItem = ({ bank }: { bank: Bank }) => { const unsettled = spotBalances[bank.mint.toString()]?.unsettled || 0.0 + const goToTokenPage = (bank: Bank) => { + router.push(`/token/${bank.name}`, undefined, { shallow: true }) + } + return (
@@ -366,6 +378,15 @@ const MobileTokenListItem = ({ bank }: { bank: Bank }) => {

+
+ goToTokenPage(bank)} + > + {t('token:token-details')} + + +
@@ -385,7 +406,7 @@ const ActionsMenu = ({ const [showBorrowModal, setShowBorrowModal] = useState(false) const [selectedToken, setSelectedToken] = useState('') // const set = mangoStore.getState().set - const router = useRouter() + // const router = useRouter() // const { asPath } = router const jupiterTokens = mangoStore((s) => s.jupiterTokens) diff --git a/components/shared/DailyRange.tsx b/components/shared/DailyRange.tsx new file mode 100644 index 00000000..a0ddc164 --- /dev/null +++ b/components/shared/DailyRange.tsx @@ -0,0 +1,37 @@ +import { useMemo } from 'react' +import { formatFixedDecimals } from 'utils/numbers' + +interface DailyRangeProps { + high: number + low: number + price: number +} + +const DailyRange = ({ high, low, price }: DailyRangeProps) => { + const rangePercent = useMemo(() => { + return ((price - low) * 100) / (high - low) + }, [high, low, price]) + + return ( +
+
+ + {formatFixedDecimals(low, true)} + +
+
+
+ + {formatFixedDecimals(high, true)} + +
+
+ ) +} + +export default DailyRange diff --git a/components/stats/TokenStats.tsx b/components/stats/TokenStats.tsx index f67f54ec..50200718 100644 --- a/components/stats/TokenStats.tsx +++ b/components/stats/TokenStats.tsx @@ -1,6 +1,7 @@ import { Transition } from '@headlessui/react' import { ChevronDownIcon, + ChevronRightIcon, QuestionMarkCircleIcon, } from '@heroicons/react/20/solid' import { useTranslation } from 'next-i18next' @@ -11,18 +12,21 @@ import { useViewport } from '../../hooks/useViewport' import mangoStore from '@store/mangoStore' import { formatDecimal, formatFixedDecimals } from '../../utils/numbers' import { breakpoints } from '../../utils/theme' -import { IconButton } from '../shared/Button' +import { IconButton, LinkButton } from '../shared/Button' import ContentBox from '../shared/ContentBox' import FlipNumbers from 'react-flip-numbers' import Tooltip from '@components/shared/Tooltip' +import { Bank } from '@blockworks-foundation/mango-v4' +import { useRouter } from 'next/router' -const TokenList = () => { - const { t } = useTranslation('common') +const TokenStats = () => { + const { t } = useTranslation(['common', 'token']) const [showTokenDetails, setShowTokenDetails] = useState('') const group = mangoStore((s) => s.group) const jupiterTokens = mangoStore((s) => s.jupiterTokens) const { width } = useViewport() const showTableView = width ? width > breakpoints.md : false + const router = useRouter() const banks = useMemo(() => { if (group) { @@ -55,6 +59,10 @@ const TokenList = () => { return [] }, [banks]) + const goToTokenPage = (bank: Bank) => { + router.push(`/token/${bank.name}`, undefined, { shallow: true }) + } + return (
@@ -113,7 +121,7 @@ const TokenList = () => {
-
+
{t('asset-weight')} @@ -204,6 +212,13 @@ const TokenList = () => {

{bank.initLiabWeight.toFixed(2)}

+ +
+ goToTokenPage(bank)}> + + +
+ ) })} @@ -315,6 +330,15 @@ const TokenList = () => { {bank.initLiabWeight.toFixed(2)}

+
+ goToTokenPage(bank)} + > + {t('token:token-details')} + + +
@@ -326,4 +350,4 @@ const TokenList = () => { ) } -export default TokenList +export default TokenStats diff --git a/package.json b/package.json index f0ab4cda..a437300b 100644 --- a/package.json +++ b/package.json @@ -29,6 +29,7 @@ "date-fns": "^2.29.3", "dayjs": "^1.11.3", "decimal.js": "^10.4.0", + "html-react-parser": "^3.0.4", "immer": "^9.0.12", "jsbi": "^4.3.0", "lodash": "^4.17.21", diff --git a/pages/stats.tsx b/pages/stats.tsx index 6087f11d..0a52dde4 100644 --- a/pages/stats.tsx +++ b/pages/stats.tsx @@ -5,7 +5,7 @@ import { serverSideTranslations } from 'next-i18next/serverSideTranslations' export async function getStaticProps({ locale }: { locale: string }) { return { props: { - ...(await serverSideTranslations(locale, ['common', 'profile'])), + ...(await serverSideTranslations(locale, ['common', 'profile', 'token'])), }, } } diff --git a/pages/token/[token].tsx b/pages/token/[token].tsx new file mode 100644 index 00000000..d77be96d --- /dev/null +++ b/pages/token/[token].tsx @@ -0,0 +1,455 @@ +import Change from '@components/shared/Change' +import DailyRange from '@components/shared/DailyRange' +import mangoStore from '@store/mangoStore' +import { fetchTokenInfo } from 'apis/coingecko' +import type { GetStaticPaths, NextPage } from 'next' +import { useTranslation } from 'next-i18next' +import { serverSideTranslations } from 'next-i18next/serverSideTranslations' +import Image from 'next/image' +import { useRouter } from 'next/router' +import { useEffect, useMemo, useState } from 'react' +import FlipNumbers from 'react-flip-numbers' +import { formatDecimal, formatFixedDecimals } from 'utils/numbers' +import dayjs from 'dayjs' +import relativeTime from 'dayjs/plugin/relativeTime' +import Button, { IconButton, LinkButton } from '@components/shared/Button' +import { ArrowLeftIcon } from '@heroicons/react/20/solid' +import DepositModal from '@components/modals/DepositModal' +import BorrowModal from '@components/modals/BorrowModal' +import parse from 'html-react-parser' +import Link from 'next/link' +import SheenLoader from '@components/shared/SheenLoader' +dayjs.extend(relativeTime) + +export async function getStaticProps({ locale }: { locale: string }) { + return { + props: { + ...(await serverSideTranslations(locale, ['common', 'token'])), + }, + } +} + +export const getStaticPaths: GetStaticPaths<{ slug: string }> = async () => { + return { + paths: [], + fallback: 'blocking', + } +} + +const DEFAULT_COINGECKO_VALUES = { + ath: 0, + atl: 0, + ath_change_percentage: 0, + atl_change_percentage: 0, + ath_date: 0, + atl_date: 0, + high_24h: 0, + circulating_supply: 0, + fully_diluted_valuation: 0, + low_24h: 0, + market_cap: 0, + max_supply: 0, + price_change_percentage_24h: 0, + total_supply: 0, + total_volume: 0, +} + +const Token: NextPage = () => { + const { t } = useTranslation(['common', 'token']) + const [showFullDesc, setShowFullDesc] = useState(false) + const [showDepositModal, setShowDepositModal] = useState(false) + const [showBorrowModal, setShowBorrowModal] = useState(false) + const [coingeckoData, setCoingeckoData] = useState(null) + const [loading, setLoading] = useState(true) + const router = useRouter() + const { token } = router.query + const group = mangoStore((s) => s.group) + const mangoAccount = mangoStore((s) => s.mangoAccount.current) + const jupiterTokens = mangoStore((s) => s.jupiterTokens) + + const bank = useMemo(() => { + if (group && token) { + const bank = group.banksMapByName.get(token.toString()) + if (bank) { + return bank[0] + } else { + setLoading(false) + } + } + }, [group, token]) + + const logoURI = useMemo(() => { + if (bank && jupiterTokens.length) { + return jupiterTokens.find((t) => t.address === bank.mint.toString()) + ?.logoURI + } + }, [bank, jupiterTokens]) + + const coingeckoId = useMemo(() => { + if (bank && jupiterTokens.length) { + return jupiterTokens.find((t) => t.address === bank.mint.toString()) + ?.extensions?.coingeckoId + } + }, [bank, jupiterTokens]) + + const serumMarkets = useMemo(() => { + if (group) { + return Array.from(group.serum3MarketsMapByExternal.values()) + } + return [] + }, [group]) + + const handleTrade = () => { + const set = mangoStore.getState().set + const market = serumMarkets.find( + (m) => m.baseTokenIndex === bank?.tokenIndex + ) + if (market) { + set((state) => { + state.selectedMarket.current = market + }) + router.push('/trade') + } + } + + const getCoingeckoData = async (id: string) => { + const response = await fetchTokenInfo(id) + setCoingeckoData(response) + setLoading(false) + } + + useEffect(() => { + if (coingeckoId) { + getCoingeckoData(coingeckoId) + } + }, [coingeckoId]) + + const { + ath, + atl, + ath_change_percentage, + atl_change_percentage, + ath_date, + atl_date, + high_24h, + circulating_supply, + fully_diluted_valuation, + low_24h, + market_cap, + max_supply, + price_change_percentage_24h, + total_supply, + total_volume, + } = coingeckoData ? coingeckoData.market_data : DEFAULT_COINGECKO_VALUES + + return ( +
+ {coingeckoData && bank ? ( + <> +
+
+ router.back()} + hideBg + size="small" + > + + +
+ +

+ {coingeckoData.name}{' '} + + ({bank!.name}) + +

+
+
+ $ + + +
+ +
+
+
+

{t('balance')}

+

+ {mangoAccount + ? formatDecimal( + mangoAccount.getTokenBalanceUi(bank!), + bank!.mintDecimals + ) + : 0} +

+
+
+ + + +
+
+
+
+
+

{t('token:lending')}

+
+

{t('total-deposits')}

+

+ {formatFixedDecimals(bank!.uiDeposits())} +

+
+
+

{t('value')}

+

+ {formatFixedDecimals( + bank!.uiDeposits() * bank!.uiPrice, + true + )} +

+
+
+

{t('deposit-rate')}

+

+ {formatDecimal(bank!.getDepositRateUi(), 2, { + fixed: true, + })} + % +

+
+
+
+

{t('token:borrowing')}

+
+

{t('total-borrows')}

+

+ {formatFixedDecimals(bank!.uiBorrows())} +

+
+
+

{t('value')}

+

+ {formatFixedDecimals(bank!.uiBorrows() * bank!.uiPrice, true)} +

+
+
+

{t('borrow-rate')}

+

+ {formatDecimal(bank!.getBorrowRateUi(), 2, { + fixed: true, + })} + % +

+
+
+
+
+

+ Utilization:{' '} + {bank!.uiDeposits() > 0 + ? formatDecimal( + (bank!.uiBorrows() / bank!.uiDeposits()) * 100, + 1, + { fixed: true } + ) + : '0.0'} + % of deposits have been lent out +

+
+
+

About {bank!.name}

+
+

+ {parse(coingeckoData.description.en)} + {/* {showFullDesc + ? parse(coingeckoData.description.en) + : `${coingeckoData.description.en.substr( + 0, + 100 + )}...`} */}{' '} +

+ setShowFullDesc(!showFullDesc)} + > + {showFullDesc ? 'Less' : 'More'} + +
+
+
+
+

{bank!.name} Stats

+
+
+
+

{t('token:market-cap')}

+

+ {formatFixedDecimals(market_cap.usd, true)}{' '} + + #{coingeckoData.market_cap_rank} + +

+
+
+

{t('token:volume')}

+

+ {formatFixedDecimals(total_volume.usd, true)} +

+
+
+

{t('token:all-time-high')}

+
+
+ + {formatFixedDecimals(ath.usd, true)} + + +
+

+ {dayjs(ath_date.usd).format('MMM, D, YYYY')} ( + {dayjs(ath_date.usd).fromNow()}) +

+
+
+
+

{t('token:all-time-low')}

+
+
+ + {formatFixedDecimals(atl.usd, true)} + + +
+

+ {dayjs(atl_date.usd).format('MMM, D, YYYY')} ( + {dayjs(atl_date.usd).fromNow()}) +

+
+
+
+
+ {fully_diluted_valuation.usd ? ( +
+

{t('token:fdv')}

+

+ {formatFixedDecimals(fully_diluted_valuation.usd, true)} +

+
+ ) : null} +
+

{t('token:circulating-supply')}

+

+ {formatFixedDecimals(circulating_supply)} +

+
+
+

{t('token:total-supply')}

+

+ {formatFixedDecimals(total_supply)} +

+
+ {max_supply ? ( +
+

{t('token:max-supply')}

+

+ {formatFixedDecimals(max_supply)} +

+
+ ) : null} +
+
+ + ) : loading ? ( +
+ +
+ + +
+ +
+ ) : ( +
+

😔

+

{t('token:token-not-found')}

+

+ {t('token:token-not-found-desc', { token: token })} +

+ + {t('token:go-to-account')} + +
+ )} + {showDepositModal ? ( + setShowDepositModal(false)} + token={bank!.name} + /> + ) : null} + {showBorrowModal ? ( + setShowBorrowModal(false)} + token={bank!.name} + /> + ) : null} +
+ ) +} + +export default Token diff --git a/public/locales/en/token.json b/public/locales/en/token.json new file mode 100644 index 00000000..0cc3e739 --- /dev/null +++ b/public/locales/en/token.json @@ -0,0 +1,16 @@ +{ + "all-time-high": "All-time High", + "all-time-low": "All-time Low", + "borrowing": "Borrowing", + "circulating-supply": "Circulating Supply", + "fdv": "Fully Diluted Value", + "go-to-account": "Go To Account", + "lending": "Lending", + "market-cap": "Market Cap", + "max-supply": "Max Supply", + "token-details": "Token Details", + "token-not-found": "Token Not Found", + "token-not-found-desc": "'{{token}}' is either not listed or we're having issues loading the data.", + "total-supply": "Total Supply", + "volume": "24h Volume" +} \ No newline at end of file diff --git a/public/locales/es/token.json b/public/locales/es/token.json new file mode 100644 index 00000000..0cc3e739 --- /dev/null +++ b/public/locales/es/token.json @@ -0,0 +1,16 @@ +{ + "all-time-high": "All-time High", + "all-time-low": "All-time Low", + "borrowing": "Borrowing", + "circulating-supply": "Circulating Supply", + "fdv": "Fully Diluted Value", + "go-to-account": "Go To Account", + "lending": "Lending", + "market-cap": "Market Cap", + "max-supply": "Max Supply", + "token-details": "Token Details", + "token-not-found": "Token Not Found", + "token-not-found-desc": "'{{token}}' is either not listed or we're having issues loading the data.", + "total-supply": "Total Supply", + "volume": "24h Volume" +} \ No newline at end of file diff --git a/public/locales/ru/token.json b/public/locales/ru/token.json new file mode 100644 index 00000000..0cc3e739 --- /dev/null +++ b/public/locales/ru/token.json @@ -0,0 +1,16 @@ +{ + "all-time-high": "All-time High", + "all-time-low": "All-time Low", + "borrowing": "Borrowing", + "circulating-supply": "Circulating Supply", + "fdv": "Fully Diluted Value", + "go-to-account": "Go To Account", + "lending": "Lending", + "market-cap": "Market Cap", + "max-supply": "Max Supply", + "token-details": "Token Details", + "token-not-found": "Token Not Found", + "token-not-found-desc": "'{{token}}' is either not listed or we're having issues loading the data.", + "total-supply": "Total Supply", + "volume": "24h Volume" +} \ No newline at end of file diff --git a/public/locales/zh/token.json b/public/locales/zh/token.json new file mode 100644 index 00000000..0cc3e739 --- /dev/null +++ b/public/locales/zh/token.json @@ -0,0 +1,16 @@ +{ + "all-time-high": "All-time High", + "all-time-low": "All-time Low", + "borrowing": "Borrowing", + "circulating-supply": "Circulating Supply", + "fdv": "Fully Diluted Value", + "go-to-account": "Go To Account", + "lending": "Lending", + "market-cap": "Market Cap", + "max-supply": "Max Supply", + "token-details": "Token Details", + "token-not-found": "Token Not Found", + "token-not-found-desc": "'{{token}}' is either not listed or we're having issues loading the data.", + "total-supply": "Total Supply", + "volume": "24h Volume" +} \ No newline at end of file diff --git a/public/locales/zh_tw/token.json b/public/locales/zh_tw/token.json new file mode 100644 index 00000000..0cc3e739 --- /dev/null +++ b/public/locales/zh_tw/token.json @@ -0,0 +1,16 @@ +{ + "all-time-high": "All-time High", + "all-time-low": "All-time Low", + "borrowing": "Borrowing", + "circulating-supply": "Circulating Supply", + "fdv": "Fully Diluted Value", + "go-to-account": "Go To Account", + "lending": "Lending", + "market-cap": "Market Cap", + "max-supply": "Max Supply", + "token-details": "Token Details", + "token-not-found": "Token Not Found", + "token-not-found-desc": "'{{token}}' is either not listed or we're having issues loading the data.", + "total-supply": "Total Supply", + "volume": "24h Volume" +} \ No newline at end of file diff --git a/utils/constants.ts b/utils/constants.ts index ffe01e6e..86319344 100644 --- a/utils/constants.ts +++ b/utils/constants.ts @@ -44,7 +44,8 @@ export const COINGECKO_IDS = [ // { id: 'cope', symbol: 'COPE' }, // { id: 'cardano', symbol: 'ADA' }, { id: 'msol', symbol: 'MSOL' }, - // { id: 'tether', symbol: 'USDT' }, + { id: 'usd-coin', symbol: 'USDC' }, + { id: 'tether', symbol: 'USDT' }, // { id: 'stepn', symbol: 'GMT' }, ] diff --git a/yarn.lock b/yarn.lock index 38d65f09..98a0e503 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3200,6 +3200,36 @@ dom-helpers@^3.4.0: dependencies: "@babel/runtime" "^7.1.2" +dom-serializer@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/dom-serializer/-/dom-serializer-2.0.0.tgz#e41b802e1eedf9f6cae183ce5e622d789d7d8e53" + integrity sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg== + dependencies: + domelementtype "^2.3.0" + domhandler "^5.0.2" + entities "^4.2.0" + +domelementtype@^2.3.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/domelementtype/-/domelementtype-2.3.0.tgz#5c45e8e869952626331d7aab326d01daf65d589d" + integrity sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw== + +domhandler@5.0.3, domhandler@^5.0.1, domhandler@^5.0.2: + version "5.0.3" + resolved "https://registry.yarnpkg.com/domhandler/-/domhandler-5.0.3.tgz#cc385f7f751f1d1fc650c21374804254538c7d31" + integrity sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w== + dependencies: + domelementtype "^2.3.0" + +domutils@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/domutils/-/domutils-3.0.1.tgz#696b3875238338cb186b6c0612bd4901c89a4f1c" + integrity sha512-z08c1l761iKhDFtfXO04C7kTdPBLi41zwOZl00WS8b5eiaebNpY00HKbztwBq+e3vyqWNwWF3mP9YLUeqIrF+Q== + dependencies: + dom-serializer "^2.0.0" + domelementtype "^2.3.0" + domhandler "^5.0.1" + dot-case@^3.0.4: version "3.0.4" resolved "https://registry.yarnpkg.com/dot-case/-/dot-case-3.0.4.tgz#9b2b670d00a431667a8a75ba29cd1b98809ce751" @@ -3290,6 +3320,11 @@ engine.io-parser@~5.0.3: resolved "https://registry.yarnpkg.com/engine.io-parser/-/engine.io-parser-5.0.4.tgz#0b13f704fa9271b3ec4f33112410d8f3f41d0fc0" integrity sha512-+nVFp+5z1E3HcToEnO7ZIj3g+3k9389DvWtvJZz0T6/eOCPIyyxehFcedoYrZQrp0LgQbD9pPXhpMBKMd5QURg== +entities@^4.2.0, entities@^4.3.0: + version "4.4.0" + resolved "https://registry.yarnpkg.com/entities/-/entities-4.4.0.tgz#97bdaba170339446495e653cfd2db78962900174" + integrity sha512-oYp7156SP8LkeGD0GF85ad1X9Ai79WtRsZ2gxJqtBuzH+98YUV6jkHEKlZkMbcrjJjIVJNIDP/3WL9wQkoPbWA== + err-code@^2.0.2: version "2.0.3" resolved "https://registry.yarnpkg.com/err-code/-/err-code-2.0.3.tgz#23c2f3b756ffdfc608d30e27c9a941024807e7f9" @@ -4128,6 +4163,14 @@ hoist-non-react-statics@^3.3.0, hoist-non-react-statics@^3.3.2: dependencies: react-is "^16.7.0" +html-dom-parser@3.1.2: + version "3.1.2" + resolved "https://registry.yarnpkg.com/html-dom-parser/-/html-dom-parser-3.1.2.tgz#c137c42df80e17d185ff35a806925d96cc73f408" + integrity sha512-mLTtl3pVn3HnqZSZzW3xVs/mJAKrG1yIw3wlp+9bdoZHHLaBRvELdpfShiPVLyjPypq1Fugv2KMDoGHW4lVXnw== + dependencies: + domhandler "5.0.3" + htmlparser2 "8.0.1" + html-parse-stringify@^3.0.1: version "3.0.1" resolved "https://registry.yarnpkg.com/html-parse-stringify/-/html-parse-stringify-3.0.1.tgz#dfc1017347ce9f77c8141a507f233040c59c55d2" @@ -4135,6 +4178,26 @@ html-parse-stringify@^3.0.1: dependencies: void-elements "3.1.0" +html-react-parser@^3.0.4: + version "3.0.4" + resolved "https://registry.yarnpkg.com/html-react-parser/-/html-react-parser-3.0.4.tgz#6a6a115a011dfdadd901ca9d2ed80fa5390647e5" + integrity sha512-va68PSmC7uA6PbOEc9yuw5Mu3OHPXmFKUpkLGvUPdTuNrZ0CJZk1s/8X/FaHjswK/6uZghu2U02tJjussT8+uw== + dependencies: + domhandler "5.0.3" + html-dom-parser "3.1.2" + react-property "2.0.0" + style-to-js "1.1.1" + +htmlparser2@8.0.1: + version "8.0.1" + resolved "https://registry.yarnpkg.com/htmlparser2/-/htmlparser2-8.0.1.tgz#abaa985474fcefe269bc761a779b544d7196d010" + integrity sha512-4lVbmc1diZC7GUJQtRQ5yBAeUCL1exyMwmForWkRLnwyzWBFxN633SALPMGYaWZvKe9j1pRZJpauvmxENSp/EA== + dependencies: + domelementtype "^2.3.0" + domhandler "^5.0.2" + domutils "^3.0.1" + entities "^4.3.0" + human-signals@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/human-signals/-/human-signals-2.1.0.tgz#dc91fcba42e4d06e4abaed33b3e7a3c02f514ea0" @@ -4198,6 +4261,11 @@ inherits@2, inherits@^2.0.1, inherits@^2.0.3, inherits@^2.0.4, inherits@~2.0.4: resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c" integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== +inline-style-parser@0.1.1: + version "0.1.1" + resolved "https://registry.yarnpkg.com/inline-style-parser/-/inline-style-parser-0.1.1.tgz#ec8a3b429274e9c0a1f1c4ffa9453a7fef72cea1" + integrity sha512-7NXolsK4CAS5+xvdj5OMMbI962hU/wvwoxk+LWR9Ek9bVtyuuYScDN6eS0rUm6TxApFpw7CX1o4uJzcd4AyD3Q== + internal-slot@^1.0.3: version "1.0.3" resolved "https://registry.yarnpkg.com/internal-slot/-/internal-slot-1.0.3.tgz#7347e307deeea2faac2ac6205d4bc7d34967f59c" @@ -5605,6 +5673,11 @@ react-number-format@^4.9.2: dependencies: prop-types "^15.7.2" +react-property@2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/react-property/-/react-property-2.0.0.tgz#2156ba9d85fa4741faf1918b38efc1eae3c6a136" + integrity sha512-kzmNjIgU32mO4mmH5+iUyrqlpFQhF8K2k7eZ4fdLSOPFrD1XgEuSBv9LDEgxRXTMBqMd8ppT0x6TIzqE5pdGdw== + react-qr-reader@^2.2.1: version "2.2.1" resolved "https://registry.yarnpkg.com/react-qr-reader/-/react-qr-reader-2.2.1.tgz#dc89046d1c1a1da837a683dd970de5926817d55b" @@ -6201,6 +6274,20 @@ strip-json-comments@3.1.1, strip-json-comments@^3.1.0, strip-json-comments@^3.1. resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-3.1.1.tgz#31f1281b3832630434831c310c01cccda8cbe006" integrity sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig== +style-to-js@1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/style-to-js/-/style-to-js-1.1.1.tgz#417786986cda61d4525c80aed9d1123a6a7af9b8" + integrity sha512-RJ18Z9t2B02sYhZtfWKQq5uplVctgvjTfLWT7+Eb1zjUjIrWzX5SdlkwLGQozrqarTmEzJJ/YmdNJCUNI47elg== + dependencies: + style-to-object "0.3.0" + +style-to-object@0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/style-to-object/-/style-to-object-0.3.0.tgz#b1b790d205991cc783801967214979ee19a76e46" + integrity sha512-CzFnRRXhzWIdItT3OmF8SQfWyahHhjq3HwcMNCNLn+N7klOOqPjMeG/4JSu77D7ypZdGvSzvkrbyeTMizz2VrA== + dependencies: + inline-style-parser "0.1.1" + styled-jsx@5.0.2: version "5.0.2" resolved "https://registry.yarnpkg.com/styled-jsx/-/styled-jsx-5.0.2.tgz#ff230fd593b737e9e68b630a694d460425478729" From 292ba79b3c6305ae497fc7e68fbb67c54356744c Mon Sep 17 00:00:00 2001 From: saml33 Date: Tue, 11 Oct 2022 23:02:42 +1100 Subject: [PATCH 2/9] add token symbol to balance panel --- pages/token/[token].tsx | 37 ++++++++++++++++++------------------- 1 file changed, 18 insertions(+), 19 deletions(-) diff --git a/pages/token/[token].tsx b/pages/token/[token].tsx index d77be96d..6917ab92 100644 --- a/pages/token/[token].tsx +++ b/pages/token/[token].tsx @@ -161,7 +161,7 @@ const Token: NextPage = () => {

{coingeckoData.name}{' '} - ({bank!.name}) + ({bank.name})

@@ -173,24 +173,26 @@ const Token: NextPage = () => { play delay={0.05} duration={1} - numbers={formatDecimal(bank!.uiPrice, 2)} + numbers={formatDecimal(bank.uiPrice, 2)} />
-

{t('balance')}

+

+ {bank.name} {t('balance')} +

{mangoAccount ? formatDecimal( - mangoAccount.getTokenBalanceUi(bank!), - bank!.mintDecimals + mangoAccount.getTokenBalanceUi(bank), + bank.mintDecimals ) : 0}

@@ -236,22 +238,19 @@ const Token: NextPage = () => {

{t('total-deposits')}

- {formatFixedDecimals(bank!.uiDeposits())} + {formatFixedDecimals(bank.uiDeposits())}

{t('value')}

- {formatFixedDecimals( - bank!.uiDeposits() * bank!.uiPrice, - true - )} + {formatFixedDecimals(bank.uiDeposits() * bank.uiPrice, true)}

{t('deposit-rate')}

- {formatDecimal(bank!.getDepositRateUi(), 2, { + {formatDecimal(bank.getDepositRateUi(), 2, { fixed: true, })} % @@ -263,19 +262,19 @@ const Token: NextPage = () => {

{t('total-borrows')}

- {formatFixedDecimals(bank!.uiBorrows())} + {formatFixedDecimals(bank.uiBorrows())}

{t('value')}

- {formatFixedDecimals(bank!.uiBorrows() * bank!.uiPrice, true)} + {formatFixedDecimals(bank.uiBorrows() * bank.uiPrice, true)}

{t('borrow-rate')}

- {formatDecimal(bank!.getBorrowRateUi(), 2, { + {formatDecimal(bank.getBorrowRateUi(), 2, { fixed: true, })} % @@ -286,9 +285,9 @@ const Token: NextPage = () => {

Utilization:{' '} - {bank!.uiDeposits() > 0 + {bank.uiDeposits() > 0 ? formatDecimal( - (bank!.uiBorrows() / bank!.uiDeposits()) * 100, + (bank.uiBorrows() / bank.uiDeposits()) * 100, 1, { fixed: true } ) @@ -297,7 +296,7 @@ const Token: NextPage = () => {

-

About {bank!.name}

+

About {bank.name}

{

-

{bank!.name} Stats

+

{bank.name} Stats

From b9c0d967059314663660b8ff8f82a1af270d7ec4 Mon Sep 17 00:00:00 2001 From: saml33 Date: Fri, 21 Oct 2022 21:16:35 +1100 Subject: [PATCH 3/9] styling updates --- pages/token/[token].tsx | 54 +++++++++++++++------------------ public/locales/en/token.json | 1 + public/locales/es/token.json | 1 + public/locales/ru/token.json | 1 + public/locales/zh/token.json | 1 + public/locales/zh_tw/token.json | 1 + 6 files changed, 29 insertions(+), 30 deletions(-) diff --git a/pages/token/[token].tsx b/pages/token/[token].tsx index 6917ab92..2abf37dc 100644 --- a/pages/token/[token].tsx +++ b/pages/token/[token].tsx @@ -13,12 +13,13 @@ import { formatDecimal, formatFixedDecimals } from 'utils/numbers' import dayjs from 'dayjs' import relativeTime from 'dayjs/plugin/relativeTime' import Button, { IconButton, LinkButton } from '@components/shared/Button' -import { ArrowLeftIcon } from '@heroicons/react/20/solid' +import { ArrowSmallUpIcon } from '@heroicons/react/20/solid' import DepositModal from '@components/modals/DepositModal' import BorrowModal from '@components/modals/BorrowModal' import parse from 'html-react-parser' import Link from 'next/link' import SheenLoader from '@components/shared/SheenLoader' +import Tooltip from '@components/shared/Tooltip' dayjs.extend(relativeTime) export async function getStaticProps({ locale }: { locale: string }) { @@ -147,22 +148,12 @@ const Token: NextPage = () => { {coingeckoData && bank ? ( <>
-
- router.back()} - hideBg - size="small" - > - - +
- -

+ +

{coingeckoData.name}{' '} - - ({bank.name}) - + ({bank.name})

@@ -186,7 +177,7 @@ const Token: NextPage = () => {

- {bank.name} {t('balance')} + {bank.name} {t('balance')}:

{mangoAccount @@ -242,7 +233,7 @@ const Token: NextPage = () => {

-

{t('value')}

+

{t('token:total-value')}

{formatFixedDecimals(bank.uiDeposits() * bank.uiPrice, true)}

@@ -266,7 +257,7 @@ const Token: NextPage = () => {

-

{t('value')}

+

{t('token:total-value')}

{formatFixedDecimals(bank.uiBorrows() * bank.uiPrice, true)}

@@ -282,9 +273,13 @@ const Token: NextPage = () => {
-
-

- Utilization:{' '} +

+ +

{t('utilization')}:

+
+ {bank.uiDeposits() > 0 ? formatDecimal( (bank.uiBorrows() / bank.uiDeposits()) * 100, @@ -292,8 +287,8 @@ const Token: NextPage = () => { { fixed: true } ) : '0.0'} - % of deposits have been lent out -

+ % +

About {bank.name}

@@ -304,18 +299,17 @@ const Token: NextPage = () => { } max-w-[720px] overflow-hidden`} > {parse(coingeckoData.description.en)} - {/* {showFullDesc - ? parse(coingeckoData.description.en) - : `${coingeckoData.description.en.substr( - 0, - 100 - )}...`} */}{' '}

setShowFullDesc(!showFullDesc)} > {showFullDesc ? 'Less' : 'More'} +
diff --git a/public/locales/en/token.json b/public/locales/en/token.json index 0cc3e739..a3a4f7ae 100644 --- a/public/locales/en/token.json +++ b/public/locales/en/token.json @@ -12,5 +12,6 @@ "token-not-found": "Token Not Found", "token-not-found-desc": "'{{token}}' is either not listed or we're having issues loading the data.", "total-supply": "Total Supply", + "total-value": "Total Value", "volume": "24h Volume" } \ No newline at end of file diff --git a/public/locales/es/token.json b/public/locales/es/token.json index 0cc3e739..a3a4f7ae 100644 --- a/public/locales/es/token.json +++ b/public/locales/es/token.json @@ -12,5 +12,6 @@ "token-not-found": "Token Not Found", "token-not-found-desc": "'{{token}}' is either not listed or we're having issues loading the data.", "total-supply": "Total Supply", + "total-value": "Total Value", "volume": "24h Volume" } \ No newline at end of file diff --git a/public/locales/ru/token.json b/public/locales/ru/token.json index 0cc3e739..a3a4f7ae 100644 --- a/public/locales/ru/token.json +++ b/public/locales/ru/token.json @@ -12,5 +12,6 @@ "token-not-found": "Token Not Found", "token-not-found-desc": "'{{token}}' is either not listed or we're having issues loading the data.", "total-supply": "Total Supply", + "total-value": "Total Value", "volume": "24h Volume" } \ No newline at end of file diff --git a/public/locales/zh/token.json b/public/locales/zh/token.json index 0cc3e739..a3a4f7ae 100644 --- a/public/locales/zh/token.json +++ b/public/locales/zh/token.json @@ -12,5 +12,6 @@ "token-not-found": "Token Not Found", "token-not-found-desc": "'{{token}}' is either not listed or we're having issues loading the data.", "total-supply": "Total Supply", + "total-value": "Total Value", "volume": "24h Volume" } \ No newline at end of file diff --git a/public/locales/zh_tw/token.json b/public/locales/zh_tw/token.json index 0cc3e739..a3a4f7ae 100644 --- a/public/locales/zh_tw/token.json +++ b/public/locales/zh_tw/token.json @@ -12,5 +12,6 @@ "token-not-found": "Token Not Found", "token-not-found-desc": "'{{token}}' is either not listed or we're having issues loading the data.", "total-supply": "Total Supply", + "total-value": "Total Value", "volume": "24h Volume" } \ No newline at end of file From d942a990fb14d1a0d4059dcbeede37352a113aa8 Mon Sep 17 00:00:00 2001 From: saml33 Date: Fri, 21 Oct 2022 23:54:18 +1100 Subject: [PATCH 4/9] add price chart --- components/shared/DetailedAreaChart.tsx | 18 +-- pages/token/[token].tsx | 161 +++++++++++++++++++++++- 2 files changed, 168 insertions(+), 11 deletions(-) diff --git a/components/shared/DetailedAreaChart.tsx b/components/shared/DetailedAreaChart.tsx index 533e056b..8020bbb6 100644 --- a/components/shared/DetailedAreaChart.tsx +++ b/components/shared/DetailedAreaChart.tsx @@ -38,6 +38,14 @@ interface DetailedAreaChartProps { yKey: string } +export const formatDateAxis = (date: string, days: number) => { + if (days === 1) { + return dayjs(date).format('h:mma') + } else { + return dayjs(date).format('D MMM') + } +} + const DetailedAreaChart: FunctionComponent = ({ data, daysToShow = 1, @@ -80,14 +88,6 @@ const DetailedAreaChart: FunctionComponent = ({ return 0 } - const formatDateAxis = (date: string) => { - if (daysToShow === 1) { - return dayjs(date).format('h:mma') - } else { - return dayjs(date).format('D MMM') - } - } - const flipGradientCoords = useMemo( () => data[0][yKey] <= 0 && data[data.length - 1][yKey] < data[0][yKey], [data] @@ -229,7 +229,7 @@ const DetailedAreaChart: FunctionComponent = ({ fontSize: 10, }} tickLine={false} - tickFormatter={(d) => formatDateAxis(d)} + tickFormatter={(d) => formatDateAxis(d, daysToShow)} /> { const group = mangoStore((s) => s.group) const mangoAccount = mangoStore((s) => s.mangoAccount.current) const jupiterTokens = mangoStore((s) => s.jupiterTokens) + const { theme } = useTheme() + const coingeckoPrices = mangoStore((s) => s.coingeckoPrices.data) + const [chartData, setChartData] = useState<{ prices: any[] } | null>(null) + const [loadChartData, setLoadChartData] = useState(true) + const loadingCoingeckoPrices = mangoStore((s) => s.coingeckoPrices.loading) + const [daysToShow, setDaysToShow] = useState(1) const bank = useMemo(() => { if (group && token) { @@ -143,6 +156,53 @@ const Token: NextPage = () => { total_volume, } = coingeckoData ? coingeckoData.market_data : DEFAULT_COINGECKO_VALUES + const loadingChart = useMemo(() => { + return daysToShow == 1 ? loadingCoingeckoPrices : loadChartData + }, [loadChartData, loadingCoingeckoPrices]) + + const coingeckoTokenPrices = useMemo(() => { + if (daysToShow === 1 && coingeckoPrices.length && bank) { + const tokenPriceData = coingeckoPrices.find((asset) => + bank?.name === 'soETH' + ? asset.symbol === 'ETH' + : asset.symbol === bank.name + ) + if (tokenPriceData) { + return tokenPriceData.prices + } + } else { + if (chartData && !loadingChart) { + return chartData.prices + } + } + return [] + }, [coingeckoPrices, bank, daysToShow, chartData, loadingChart]) + + const change = useMemo(() => { + return coingeckoTokenPrices.length + ? ((coingeckoTokenPrices[coingeckoTokenPrices.length - 1][1] - + coingeckoTokenPrices[0][1]) / + coingeckoTokenPrices[0][1]) * + 100 + : 0 + }, [coingeckoTokenPrices]) + + const handleDaysToShow = async (days: number) => { + if (days !== 1) { + try { + const response = await fetch( + `https://api.coingecko.com/api/v3/coins/${coingeckoId}/market_chart?vs_currency=usd&days=${days}` + ) + const data = await response.json() + setLoadChartData(false) + setChartData(data) + } catch { + setLoadChartData(false) + } + } + setDaysToShow(days) + } + return (
{coingeckoData && bank ? ( @@ -313,8 +373,105 @@ const Token: NextPage = () => {
+ {!loadingChart ? ( + coingeckoTokenPrices.length ? ( + <> +
+

{bank.name} Price Chart

+ handleDaysToShow(v)} + /> +
+
+
+ + + + + = 0 + ? COLORS.GREEN[theme] + : COLORS.RED[theme] + } + stopOpacity={0.15} + /> + = 0 + ? COLORS.GREEN[theme] + : COLORS.RED[theme] + } + stopOpacity={0} + /> + + + = 0 + ? COLORS.GREEN[theme] + : COLORS.RED[theme] + } + strokeWidth={1.5} + fill="url(#gradientArea)" + /> + formatDateAxis(d, daysToShow)} + /> + `$${x.toFixed(2)}`} + tickLine={false} + /> + + +
+
+ + ) : bank?.name === 'USDC' || bank?.name === 'USDT' ? null : ( +

{t('unavailable')}

+ ) + ) : ( +
+ )}
-
+

{bank.name} Stats

From 871f3e82d1bacf295fd9c48eb7052f86e9d24d40 Mon Sep 17 00:00:00 2001 From: saml33 Date: Sat, 22 Oct 2022 20:21:14 +1100 Subject: [PATCH 5/9] price chart component --- pages/token/[token].tsx | 177 +++++++++++++++++++--------------------- 1 file changed, 86 insertions(+), 91 deletions(-) diff --git a/pages/token/[token].tsx b/pages/token/[token].tsx index dfc04701..b3f4809a 100644 --- a/pages/token/[token].tsx +++ b/pages/token/[token].tsx @@ -21,9 +21,7 @@ import Link from 'next/link' import SheenLoader from '@components/shared/SheenLoader' import Tooltip from '@components/shared/Tooltip' import { COLORS } from 'styles/colors' -import DetailedAreaChart, { - formatDateAxis, -} from '@components/shared/DetailedAreaChart' +import { formatDateAxis } from '@components/shared/DetailedAreaChart' import { Area, AreaChart, ResponsiveContainer, XAxis, YAxis } from 'recharts' import { useTheme } from 'next-themes' import ChartRangeButtons from '@components/shared/ChartRangeButtons' @@ -74,7 +72,6 @@ const Token: NextPage = () => { const group = mangoStore((s) => s.group) const mangoAccount = mangoStore((s) => s.mangoAccount.current) const jupiterTokens = mangoStore((s) => s.jupiterTokens) - const { theme } = useTheme() const coingeckoPrices = mangoStore((s) => s.coingeckoPrices.data) const [chartData, setChartData] = useState<{ prices: any[] } | null>(null) const [loadChartData, setLoadChartData] = useState(true) @@ -178,15 +175,6 @@ const Token: NextPage = () => { return [] }, [coingeckoPrices, bank, daysToShow, chartData, loadingChart]) - const change = useMemo(() => { - return coingeckoTokenPrices.length - ? ((coingeckoTokenPrices[coingeckoTokenPrices.length - 1][1] - - coingeckoTokenPrices[0][1]) / - coingeckoTokenPrices[0][1]) * - 100 - : 0 - }, [coingeckoTokenPrices]) - const handleDaysToShow = async (days: number) => { if (days !== 1) { try { @@ -385,84 +373,10 @@ const Token: NextPage = () => { onChange={(v) => handleDaysToShow(v)} />
-
-
- - - - - = 0 - ? COLORS.GREEN[theme] - : COLORS.RED[theme] - } - stopOpacity={0.15} - /> - = 0 - ? COLORS.GREEN[theme] - : COLORS.RED[theme] - } - stopOpacity={0} - /> - - - = 0 - ? COLORS.GREEN[theme] - : COLORS.RED[theme] - } - strokeWidth={1.5} - fill="url(#gradientArea)" - /> - formatDateAxis(d, daysToShow)} - /> - `$${x.toFixed(2)}`} - tickLine={false} - /> - - -
-
+ ) : bank?.name === 'USDC' || bank?.name === 'USDT' ? null : (

{t('unavailable')}

@@ -603,3 +517,84 @@ const Token: NextPage = () => { } export default Token + +const PriceChart = ({ + prices, + daysToShow, +}: { + prices: number[][] + daysToShow: number +}) => { + const { theme } = useTheme() + + const change = useMemo(() => { + return prices[prices.length - 1][1] - prices[0][1] + }, [prices]) + + return ( +
+
+ + + + + = 0 ? COLORS.GREEN[theme] : COLORS.RED[theme] + } + stopOpacity={0.15} + /> + = 0 ? COLORS.GREEN[theme] : COLORS.RED[theme] + } + stopOpacity={0} + /> + + + = 0 ? COLORS.GREEN[theme] : COLORS.RED[theme]} + strokeWidth={1.5} + fill="url(#gradientArea)" + /> + formatDateAxis(d, daysToShow)} + /> + `$${x.toFixed(2)}`} + tickLine={false} + /> + + +
+
+ ) +} From e15305aae660ab05a33fe4a236eddbc3b0fbb86e Mon Sep 17 00:00:00 2001 From: saml33 Date: Mon, 24 Oct 2022 12:43:07 +1100 Subject: [PATCH 6/9] fix errors --- components/shared/DetailedAreaChart.tsx | 3 +- components/token/PriceChart.tsx | 88 ++++++++++++++++++++++ pages/token/[token].tsx | 99 ++++--------------------- 3 files changed, 102 insertions(+), 88 deletions(-) create mode 100644 components/token/PriceChart.tsx diff --git a/components/shared/DetailedAreaChart.tsx b/components/shared/DetailedAreaChart.tsx index 8020bbb6..ca575cbd 100644 --- a/components/shared/DetailedAreaChart.tsx +++ b/components/shared/DetailedAreaChart.tsx @@ -1,4 +1,4 @@ -import { FunctionComponent, ReactNode, useMemo, useState } from 'react' +import { FunctionComponent, useMemo, useState } from 'react' import dayjs from 'dayjs' import relativeTime from 'dayjs/plugin/relativeTime' import { @@ -13,7 +13,6 @@ import FlipNumbers from 'react-flip-numbers' import LineChartIcon from '../icons/LineChartIcon' import ContentBox from '../shared/ContentBox' -import { DownTriangle, UpTriangle } from '../shared/DirectionTriangles' import SheenLoader from '../shared/SheenLoader' import { COLORS } from '../../styles/colors' import { useTheme } from 'next-themes' diff --git a/components/token/PriceChart.tsx b/components/token/PriceChart.tsx new file mode 100644 index 00000000..e3105d4e --- /dev/null +++ b/components/token/PriceChart.tsx @@ -0,0 +1,88 @@ +import { formatDateAxis } from '@components/shared/DetailedAreaChart' +import { useTheme } from 'next-themes' +import { useMemo } from 'react' +import { Area, AreaChart, ResponsiveContainer, XAxis, YAxis } from 'recharts' +import { COLORS } from 'styles/colors' + +const PriceChart = ({ + prices, + daysToShow, +}: { + prices: number[][] + daysToShow: number +}) => { + const { theme } = useTheme() + + const change = useMemo(() => { + return prices[prices.length - 1][1] - prices[0][1] + }, [prices]) + + return ( +
+
+ + + + + = 0 ? COLORS.GREEN[theme] : COLORS.RED[theme] + } + stopOpacity={0.15} + /> + = 0 ? COLORS.GREEN[theme] : COLORS.RED[theme] + } + stopOpacity={0} + /> + + + = 0 ? COLORS.GREEN[theme] : COLORS.RED[theme]} + strokeWidth={1.5} + fill="url(#gradientArea)" + /> + formatDateAxis(d, daysToShow)} + /> + `$${x.toFixed(2)}`} + tickLine={false} + /> + + +
+
+ ) +} + +export default PriceChart diff --git a/pages/token/[token].tsx b/pages/token/[token].tsx index b3f4809a..726c5529 100644 --- a/pages/token/[token].tsx +++ b/pages/token/[token].tsx @@ -1,7 +1,6 @@ import Change from '@components/shared/Change' import DailyRange from '@components/shared/DailyRange' import mangoStore from '@store/mangoStore' -import { fetchTokenInfo } from 'apis/coingecko' import type { GetStaticPaths, NextPage } from 'next' import { useTranslation } from 'next-i18next' import { serverSideTranslations } from 'next-i18next/serverSideTranslations' @@ -20,11 +19,11 @@ import parse from 'html-react-parser' import Link from 'next/link' import SheenLoader from '@components/shared/SheenLoader' import Tooltip from '@components/shared/Tooltip' -import { COLORS } from 'styles/colors' -import { formatDateAxis } from '@components/shared/DetailedAreaChart' -import { Area, AreaChart, ResponsiveContainer, XAxis, YAxis } from 'recharts' -import { useTheme } from 'next-themes' import ChartRangeButtons from '@components/shared/ChartRangeButtons' +import dynamic from 'next/dynamic' +const PriceChart = dynamic(() => import('@components/token/PriceChart'), { + ssr: false, +}) dayjs.extend(relativeTime) export async function getStaticProps({ locale }: { locale: string }) { @@ -123,6 +122,15 @@ const Token: NextPage = () => { } } + 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 getCoingeckoData = async (id: string) => { const response = await fetchTokenInfo(id) setCoingeckoData(response) @@ -517,84 +525,3 @@ const Token: NextPage = () => { } export default Token - -const PriceChart = ({ - prices, - daysToShow, -}: { - prices: number[][] - daysToShow: number -}) => { - const { theme } = useTheme() - - const change = useMemo(() => { - return prices[prices.length - 1][1] - prices[0][1] - }, [prices]) - - return ( -
-
- - - - - = 0 ? COLORS.GREEN[theme] : COLORS.RED[theme] - } - stopOpacity={0.15} - /> - = 0 ? COLORS.GREEN[theme] : COLORS.RED[theme] - } - stopOpacity={0} - /> - - - = 0 ? COLORS.GREEN[theme] : COLORS.RED[theme]} - strokeWidth={1.5} - fill="url(#gradientArea)" - /> - formatDateAxis(d, daysToShow)} - /> - `$${x.toFixed(2)}`} - tickLine={false} - /> - - -
-
- ) -} From bb8b7a35bbc3e1032eeefba2f1b7aef811c724bb Mon Sep 17 00:00:00 2001 From: saml33 Date: Mon, 24 Oct 2022 14:34:47 +1100 Subject: [PATCH 7/9] update static paths --- pages/token/[token].tsx | 14 ++++++++------ utils/tokens.ts | 10 ++++++++++ 2 files changed, 18 insertions(+), 6 deletions(-) diff --git a/pages/token/[token].tsx b/pages/token/[token].tsx index 726c5529..d441d7ea 100644 --- a/pages/token/[token].tsx +++ b/pages/token/[token].tsx @@ -1,7 +1,7 @@ import Change from '@components/shared/Change' import DailyRange from '@components/shared/DailyRange' import mangoStore from '@store/mangoStore' -import type { GetStaticPaths, NextPage } from 'next' +import type { NextPage } from 'next' import { useTranslation } from 'next-i18next' import { serverSideTranslations } from 'next-i18next/serverSideTranslations' import Image from 'next/image' @@ -21,6 +21,7 @@ import SheenLoader from '@components/shared/SheenLoader' import Tooltip from '@components/shared/Tooltip' import ChartRangeButtons from '@components/shared/ChartRangeButtons' import dynamic from 'next/dynamic' +import { LISTED_TOKENS } from 'utils/tokens' const PriceChart = dynamic(() => import('@components/token/PriceChart'), { ssr: false, }) @@ -34,11 +35,12 @@ export async function getStaticProps({ locale }: { locale: string }) { } } -export const getStaticPaths: GetStaticPaths<{ slug: string }> = async () => { - return { - paths: [], - fallback: 'blocking', - } +export const getStaticPaths = async () => { + const paths = LISTED_TOKENS.map((token) => ({ + params: { token: token }, + })) + + return { paths, fallback: false } } const DEFAULT_COINGECKO_VALUES = { diff --git a/utils/tokens.ts b/utils/tokens.ts index 24205483..11c75be8 100644 --- a/utils/tokens.ts +++ b/utils/tokens.ts @@ -105,3 +105,13 @@ export const fetchNftsFromHolaplexIndexer = async (owner: PublicKey) => { export const formatTokenSymbol = (symbol: string) => symbol === 'MSOL' ? 'mSOL' : symbol === 'SOETH' ? 'soETH' : symbol + +export const LISTED_TOKENS: string[] = [ + 'BTC', + 'ETH', + 'soETH', + 'SOL', + 'mSOL', + 'USDC', + 'USDT', +] From bfb5453b347f0b6f978e856094175bc10c634a0d Mon Sep 17 00:00:00 2001 From: saml33 Date: Mon, 24 Oct 2022 14:39:29 +1100 Subject: [PATCH 8/9] update mSOL symbol --- utils/tokens.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/utils/tokens.ts b/utils/tokens.ts index 11c75be8..fbaa2bb0 100644 --- a/utils/tokens.ts +++ b/utils/tokens.ts @@ -111,7 +111,7 @@ export const LISTED_TOKENS: string[] = [ 'ETH', 'soETH', 'SOL', - 'mSOL', + 'MSOL', 'USDC', 'USDT', ] From 08505b09bce3c7f664f333041968bb7c584c8c26 Mon Sep 17 00:00:00 2001 From: saml33 Date: Tue, 25 Oct 2022 20:42:51 +1100 Subject: [PATCH 9/9] add back arrow --- components/TopBar.tsx | 21 ++++++++++++++++---- components/modals/MangoAccountsListModal.tsx | 13 ++++++------ pages/token/[token].tsx | 8 ++++---- 3 files changed, 28 insertions(+), 14 deletions(-) diff --git a/components/TopBar.tsx b/components/TopBar.tsx index 1d4369b3..ab37c7f5 100644 --- a/components/TopBar.tsx +++ b/components/TopBar.tsx @@ -1,11 +1,10 @@ import { useCallback, useState } from 'react' -import { ArrowRightIcon } from '@heroicons/react/20/solid' +import { ArrowLeftIcon, ArrowRightIcon } from '@heroicons/react/20/solid' import { useTranslation } from 'next-i18next' import mangoStore from '@store/mangoStore' import WalletIcon from './icons/WalletIcon' -import MangoAccountsList from './MangoAccountsList' -import { LinkButton } from './shared/Button' +import { IconButton, LinkButton } from './shared/Button' import ConnectedMenu from './wallet/ConnectedMenu' import { ConnectWalletButton } from './wallet/ConnectWalletButton' import { IS_ONBOARDED_KEY } from '../utils/constants' @@ -13,6 +12,7 @@ import useLocalStorageState from '../hooks/useLocalStorageState' import UserSetupModal from './modals/UserSetupModal' import CreateAccountModal from './modals/CreateAccountModal' import MangoAccountsListModal from './modals/MangoAccountsListModal' +import { useRouter } from 'next/router' const TopBar = () => { const { t } = useTranslation('common') @@ -22,6 +22,8 @@ const TopBar = () => { const [showUserSetupModal, setShowUserSetupModal] = useState(false) const [showCreateAccountModal, setShowCreateAccountModal] = useState(false) const [showMangoAccountsModal, setShowMangoAccountsModal] = useState(false) + const router = useRouter() + const { query } = router const handleCloseModal = useCallback(() => { setShowUserSetupModal(false) @@ -34,7 +36,18 @@ const TopBar = () => { return ( <>
- + + {query.token ? ( + + ) : null} {!connected ? ( diff --git a/components/modals/MangoAccountsListModal.tsx b/components/modals/MangoAccountsListModal.tsx index ab4da349..faaa6527 100644 --- a/components/modals/MangoAccountsListModal.tsx +++ b/components/modals/MangoAccountsListModal.tsx @@ -29,6 +29,7 @@ const MangoAccountsListModal = ({ const { t } = useTranslation('common') const mangoAccounts = mangoStore((s) => s.mangoAccounts) const actions = mangoStore((s) => s.actions) + const group = mangoStore((s) => s.group) const loading = mangoStore((s) => s.mangoAccount.initialLoad) const [showNewAccountForm, setShowNewAccountForm] = useState(false) const [, setLastAccountViewed] = useLocalStorageStringState(LAST_ACCOUNT_KEY) @@ -36,16 +37,13 @@ const MangoAccountsListModal = ({ const handleSelectMangoAccount = async (acc: MangoAccount) => { const set = mangoStore.getState().set const client = mangoStore.getState().client - const group = mangoStore.getState().group if (!group) return set((s) => { s.activityFeed.feed = [] s.activityFeed.loading = true }) try { - const reloadedMangoAccount = await retryFn(() => - acc.reload(client, group) - ) + const reloadedMangoAccount = await retryFn(() => acc.reload(client)) set((s) => { s.mangoAccount.current = reloadedMangoAccount s.mangoAccount.lastUpdatedAt = new Date().toISOString() @@ -70,10 +68,13 @@ const MangoAccountsListModal = ({
{mangoAccounts.map((acc) => { const accountValue = formatFixedDecimals( - toUiDecimalsForQuote(Number(acc.getEquity())), + toUiDecimalsForQuote(Number(acc.getEquity(group!))), true ) - const maintHealth = acc.getHealthRatioUi(HealthType.maint) + const maintHealth = acc.getHealthRatioUi( + group!, + HealthType.maint + ) return (