diff --git a/components/MarketsTable.tsx b/components/MarketsTable.tsx index 635b2874..a3a7ade2 100644 --- a/components/MarketsTable.tsx +++ b/components/MarketsTable.tsx @@ -12,17 +12,23 @@ import { LinkButton } from './Button' import { ArrowSmDownIcon } from '@heroicons/react/solid' import { useRouter } from 'next/router' import { AreaChart, Area, XAxis, YAxis } from 'recharts' -import { InformationCircleIcon } from '@heroicons/react/outline' -import Tooltip from './Tooltip' +import { useTheme } from 'next-themes' -const MarketsTable = ({ isPerpMarket }) => { +const MarketsTable = ({ + isPerpMarket, + markets, +}: { + isPerpMarket?: boolean + markets: any[] +}) => { const { t } = useTranslation('common') const { width } = useViewport() const isMobile = width ? width < breakpoints.md : false - const marketsInfo = useMangoStore((s) => s.marketsInfo) const actions = useMangoStore((s) => s.actions) - const coingeckoPrices = useMangoStore((s) => s.coingeckoPrices) + const coingeckoPrices = useMangoStore((s) => s.coingeckoPrices.data) + const loadingCoingeckoPrices = useMangoStore((s) => s.coingeckoPrices.loading) const router = useRouter() + const { theme } = useTheme() useEffect(() => { if (coingeckoPrices.length === 0) { @@ -30,13 +36,383 @@ const MarketsTable = ({ isPerpMarket }) => { } }, [coingeckoPrices]) - const perpMarketsInfo = useMemo( - () => - marketsInfo - .filter((mkt) => mkt?.name.includes('PERP')) - .sort((a, b) => b.volumeUsd24h - a.volumeUsd24h), - [marketsInfo] + const { items, requestSort, sortConfig } = useSortableData(markets) + + return !isMobile ? ( + + + + + + + + {isPerpMarket ? ( + <> + + + + ) : null} + + + + + {items.map((market) => { + const { + baseSymbol, + change24h, + funding1h, + last, + name, + openInterest, + openInterestUsd, + volumeUsd24h, + } = market + const fundingApr = funding1h ? (funding1h * 24 * 365).toFixed(2) : '-' + const coingeckoData = coingeckoPrices.find( + (asset) => asset.symbol === baseSymbol + ) + const chartData = coingeckoData ? coingeckoData.prices : undefined + const chartColor = + change24h >= 0 + ? theme === 'Mango' + ? '#AFD803' + : '#5EBF4D' + : theme === 'Mango' + ? '#F84638' + : '#CC2929' + return ( + + + + + + {isPerpMarket ? ( + <> + + + + ) : null} + + + ) + })} + +
+ requestSort('name')} + > + + {t('market')} + + + + + requestSort('last')} + > + + {t('price')} + + + + + requestSort('change24h')} + > + + {t('rolling-change')} + + + + + requestSort('volumeUsd24h')} + > + + {t('daily-volume')} + + + + + requestSort('funding1h')} + > + + {t('average-funding')} + + + + + requestSort('openInterestUsd')} + > + + {t('open-interest')} + + + + + {t('favorite')} +
+ + +
+ + {name} +
+
+ +
+
+ {last ? ( + formatUsdValue(last) + ) : ( + {t('unavailable')} + )} +
+
+ {!loadingCoingeckoPrices ? ( + chartData !== undefined ? ( + + ) : ( + t('unavailable') + ) + ) : ( +
+ )} +
+
+ = 0 ? 'text-th-green' : 'text-th-red'} + > + {change24h || change24h === 0 ? ( + `${(change24h * 100).toFixed(2)}%` + ) : ( + {t('unavailable')} + )} + + + {volumeUsd24h ? ( + usdFormatter(volumeUsd24h, 0) + ) : ( + {t('unavailable')} + )} + + {funding1h ? ( + <> + {`${funding1h.toFixed(4)}%`}{' '} + {`(${fundingApr}% APR)`} + + ) : ( + {t('unavailable')} + )} + + {openInterestUsd ? ( + <> + {usdFormatter(openInterestUsd, 0)}{' '} + {openInterest ? ( +
+ {openInterest.toLocaleString(undefined, { + maximumFractionDigits: + perpContractPrecision[baseSymbol], + })}{' '} + {baseSymbol} +
+ ) : null} + + ) : ( + {t('unavailable')} + )} +
+
+ +
+
+ ) : ( + <> + {items.map((market) => { + const { baseSymbol, change24h, funding1h, last, name } = market + const fundingApr = funding1h ? (funding1h * 24 * 365).toFixed(2) : '-' + const coingeckoData = coingeckoPrices.find( + (asset) => asset.symbol === baseSymbol + ) + const chartData = coingeckoData ? coingeckoData.prices : undefined + const chartColor = + change24h >= 0 + ? theme === 'Mango' + ? '#AFD803' + : '#5EBF4D' + : theme === 'Mango' + ? '#F84638' + : '#CC2929' + return ( + + + router.push(`/?name=${name}`, undefined, { + shallow: true, + }) + } + > +
+
+
+ + + {name} +
= 0 ? 'text-th-green' : 'text-th-red' + }`} + > + {change24h || change24h === 0 ? ( + `${(change24h * 100).toFixed(2)}%` + ) : ( + + {t('unavailable')} + + )} +
+
+ {!loadingCoingeckoPrices ? ( + chartData !== undefined ? ( + + ) : ( + t('unavailable') + ) + ) : ( +
+ )} +
+
+

+ {last ? ( + formatUsdValue(last) + ) : ( + {t('unavailable')} + )} +

+ {isPerpMarket ? ( + funding1h ? ( +
+
+ {t('average-funding')} +
+ {`${fundingApr}% APR`} +
+ ) : ( + {t('unavailable')} + ) + ) : null} +
+
+
+ + ) + })} + ) +} + +const PriceChart = ({ data, width, height, color }) => ( + + + + + + + + + + + +) + +export const SpotMarketsTable = () => { + const marketsInfo = useMangoStore((s) => s.marketsInfo) const spotMarketsInfo = useMemo( () => @@ -45,355 +421,18 @@ const MarketsTable = ({ isPerpMarket }) => { .sort((a, b) => b.volumeUsd24h - a.volumeUsd24h), [marketsInfo] ) - - const { items, requestSort, sortConfig } = useSortableData( - isPerpMarket ? perpMarketsInfo : spotMarketsInfo - ) - - return items.length > 0 ? ( - !isMobile ? ( - - - - - - - - {isPerpMarket ? ( - <> - - - - ) : null} - - - - - {items.map((market) => { - const { - baseSymbol, - change24h, - funding1h, - last, - name, - openInterest, - openInterestUsd, - volumeUsd24h, - } = market - const fundingApr = funding1h - ? (funding1h * 24 * 365).toFixed(2) - : '-' - const coingeckoData = coingeckoPrices.find( - (asset) => asset.symbol === baseSymbol - ) - const chartData = coingeckoData ? coingeckoData.prices : undefined - return ( - - - - - - {isPerpMarket ? ( - <> - - - - ) : null} - - - ) - })} - -
- requestSort('name')} - > - - {t('market')} - - - - - requestSort('last')} - > - - {t('price')} - - - - - requestSort('change24h')} - > - - {t('rolling-change')} - - - - - requestSort('volumeUsd24h')} - > - - {t('daily-volume')} - - - - - requestSort('funding1h')} - > - - {t('average-funding')} - - - - - requestSort('openInterestUsd')} - > - - {t('open-interest')} - - - - - {t('favorite')} -
- - -
- - {name} -
-
- -
-
- {last ? ( - formatUsdValue(last) - ) : ( - {t('unavailable')} - )} -
-
- {chartData !== undefined ? ( - - - - - - ) : ( - t('unavailable') - )} -
-
- = 0 ? 'text-th-green' : 'text-th-red'} - > - {change24h || change24h === 0 ? ( - `${(change24h * 100).toFixed(2)}%` - ) : ( - {t('unavailable')} - )} - - - {volumeUsd24h ? ( - usdFormatter(volumeUsd24h, 0) - ) : ( - {t('unavailable')} - )} - - {funding1h ? ( - <> - {`${funding1h.toFixed(4)}%`}{' '} - {`(${fundingApr}% APR)`} - - ) : ( - - {t('unavailable')} - - )} - - {openInterestUsd ? ( - <> - {usdFormatter(openInterestUsd, 0)}{' '} - {openInterest ? ( -
- {openInterest.toLocaleString(undefined, { - maximumFractionDigits: - perpContractPrecision[baseSymbol], - })}{' '} - {baseSymbol} -
- ) : null} - - ) : ( - - {t('unavailable')} - - )} -
-
- -
-
- ) : ( - items.map((market) => { - const { baseSymbol, change24h, funding1h, last, name } = market - const fundingApr = funding1h ? (funding1h * 24 * 365).toFixed(2) : '-' - const coingeckoData = coingeckoPrices.find( - (asset) => asset.symbol === baseSymbol - ) - const chartData = coingeckoData ? coingeckoData.prices : undefined - return ( - - ) - }) - ) - ) : null + return } -export default MarketsTable as any +export const PerpMarketsTable = () => { + const marketsInfo = useMangoStore((s) => s.marketsInfo) + const perpMarketsInfo = useMemo( + () => + marketsInfo + .filter((mkt) => mkt?.name.includes('PERP')) + .sort((a, b) => b.volumeUsd24h - a.volumeUsd24h), + [marketsInfo] + ) + + return +} diff --git a/components/mobile/BottomBar.tsx b/components/mobile/BottomBar.tsx index 3feb8dfd..6c60b147 100644 --- a/components/mobile/BottomBar.tsx +++ b/components/mobile/BottomBar.tsx @@ -33,7 +33,7 @@ const BottomBar = () => { return ( <> -
+
{ setActiveTab(tabName) } + const handleChangeViewIndex = (index) => { + setViewIndex(index) + } + return (
@@ -34,13 +45,36 @@ export default function Markets() {
- + {!isMobile ? ( + + ) : ( + + )}
- + {!isMobile ? ( + activeTab === 'futures' ? ( + + ) : ( + + ) + ) : ( + +
+ +
+
+ +
+
+ )}
diff --git a/stores/useMangoStore.tsx b/stores/useMangoStore.tsx index b1d2082e..36b3376a 100644 --- a/stores/useMangoStore.tsx +++ b/stores/useMangoStore.tsx @@ -279,7 +279,7 @@ export type MangoStore = { tradingView: { orderLines: Map } - coingeckoPrices: any[] + coingeckoPrices: { data: any[]; loading: boolean } } const useMangoStore = create< @@ -411,7 +411,7 @@ const useMangoStore = create< tradingView: { orderLines: new Map(), }, - coingeckoPrices: [], + coingeckoPrices: { data: [], loading: false }, set: (fn) => set(produce(fn)), actions: { async fetchWalletTokens(wallet: Wallet) { @@ -1131,12 +1131,15 @@ const useMangoStore = create< }, async fetchCoingeckoPrices() { const set = get().set + set((state) => { + state.coingeckoPrices.loading = true + }) try { const promises: any = [] for (const asset of coingeckoIds) { promises.push( fetch( - `https://api.coingecko.com/api/v3/coins/${asset.id}/market_chart?vs_currency=usd&days=2` + `https://api.coingecko.com/api/v3/coins/${asset.id}/market_chart?vs_currency=usd&days=1` ).then((res) => res.json()) ) } @@ -1146,10 +1149,14 @@ const useMangoStore = create< data[i].symbol = coingeckoIds[i].symbol } set((state) => { - state.coingeckoPrices = data + state.coingeckoPrices.data = data + state.coingeckoPrices.loading = false }) } catch (e) { console.log('ERORR: Unable to load Coingecko prices') + set((state) => { + state.coingeckoPrices.loading = false + }) } }, }, diff --git a/tailwind.config.js b/tailwind.config.js index 8b9275db..be5f1972 100644 --- a/tailwind.config.js +++ b/tailwind.config.js @@ -1,6 +1,3 @@ -// const colors = require('tailwindcss/colors') -// const defaultTheme = require('tailwindcss/defaultTheme') - module.exports = { content: [ './pages/**/*.{js,ts,jsx,tsx}',