diff --git a/src/plugins/Trader/UI/TrendingView.tsx b/src/plugins/Trader/UI/TrendingView.tsx index d943419b8e52..0c765dce1604 100644 --- a/src/plugins/Trader/UI/TrendingView.tsx +++ b/src/plugins/Trader/UI/TrendingView.tsx @@ -1,28 +1,47 @@ import React, { useState, useEffect } from 'react' -import { makeStyles, Avatar, Typography, Card, CardHeader, IconButton, CardActions } from '@material-ui/core' +import { + makeStyles, + Avatar, + Typography, + Card, + CardHeader, + IconButton, + CardActions, + Theme, + createStyles, +} from '@material-ui/core' import { useAsync } from 'react-use' import SettingsIcon from '@material-ui/icons/Settings' +import classNames from 'classnames' +import ArrowDropUpIcon from '@material-ui/icons/ArrowDropUp' +import ArrowDropDownIcon from '@material-ui/icons/ArrowDropDown' import { SettingsDialog } from './SettingsDialog' import { Platform, Currency, resolvePlatformName, Settings } from '../type' -import { getCurrenies } from '../apis' import { PortalShadowRoot, portalShadowRoot } from '../../../utils/jss/ShadowRootPortal' import { setStorage, getStorage } from '../../../utils/browser.storage' import { getActivatedUI } from '../../../social-network/ui' import stringify from 'json-stable-stringify' import { currentTrendingViewSettings, currentTrendingViewPlatformSettings } from '../settings' import { useValueRef } from '../../../utils/hooks/useValueRef' +import Services from '../../../extension/service' +import { formatCurrency } from '../../Wallet/formatter' +import { useColorStyles } from '../../../utils/theme' const network = getActivatedUI().networkIdentifier -const useStyles = makeStyles({ - root: {}, - header: { - display: 'flex', - }, - body: {}, - avatar: {}, - amount: {}, -}) +const useStyles = makeStyles((theme: Theme) => + createStyles({ + root: {}, + header: { + display: 'flex', + }, + body: {}, + avatar: {}, + percentage: { + marginLeft: theme.spacing(1), + }, + }), +) export interface TrendingViewProps extends withClasses> { keyword: string @@ -30,6 +49,7 @@ export interface TrendingViewProps extends withClasses(currentTrendingViewPlatformSettings[network]) //#region currency & platform - const { value: currencies = [], loading: loadingCurrencies, error } = useAsync(() => getCurrenies(platform), [ - platform, - ]) + const { value: currencies = [], loading: loadingCurrencies } = useAsync( + () => Services.Plugin.invokePlugin('maskbook.trader', 'getCurrenies', platform), + [platform], + ) // sync platform useEffect(() => { @@ -65,25 +86,52 @@ export function TrendingView(props: TrendingViewProps) { }, [trendingSettings, currencies.length]) //#endregion + //#region coins info + const { value: coinInfo, loading: loadingCoinInfo, error } = useAsync(async () => { + if (!currency) return null + return Services.Plugin.invokePlugin( + 'maskbook.trader', + 'getCoinTrendingByKeyword', + props.keyword, + platform, + currency, + ) + }, [platform, currency, props.keyword]) + //#endregion if (loadingCurrencies || !currency) return null + if (loadingCoinInfo || !coinInfo) return null + return ( <> - } + avatar={} action={ setSettingsDialogOpen(true)}> } - title={{`BTC / ${currency.name}`}} + title={ + {`${coinInfo.coin.symbol.toUpperCase()} / ${ + currency.name + }`} + } subheader={ - {`${currency.name} 12,223`} - (1.2%) + {`${currency.symbol ?? currency.name} ${formatCurrency( + coinInfo.market.current_price, + )}`} + {coinInfo.market.price_change_24h ? ( + 0 ? color.success : color.error, + )}> + {coinInfo.market.price_change_24h > 0 ? '\u25B2 ' : '\u25BC '} + {coinInfo.market.price_change_24h.toFixed(2)}% + + ) : null} } /> diff --git a/src/plugins/Trader/apis/coingecko/index.ts b/src/plugins/Trader/apis/coingecko/index.ts index cf335db12fc7..7c2e74c7240d 100644 --- a/src/plugins/Trader/apis/coingecko/index.ts +++ b/src/plugins/Trader/apis/coingecko/index.ts @@ -1,5 +1,3 @@ -import type { Currency } from '../../type' - const BASE_URL = 'https://api.coingecko.com/api/v3' //#region get currency @@ -54,11 +52,12 @@ export interface CoinInfo { localization: Record market_cap_rank: number market_data: { + current_price: Record high_24h: Record low_24h: Record market_cap: Record market_cap_rank: number - price_change_24h: number + price_change_percentage_24h: number total_supply: number total_volume: Record } diff --git a/src/plugins/Trader/apis/coinmarketcap/index.ts b/src/plugins/Trader/apis/coinmarketcap/index.ts index e01e6e7601e0..8dcc4cfe9a55 100644 --- a/src/plugins/Trader/apis/coinmarketcap/index.ts +++ b/src/plugins/Trader/apis/coinmarketcap/index.ts @@ -3,8 +3,7 @@ import CURRENCY_DATA from './currency.json' // proxy: https://web-api.coinmarketcap.com/v1 const BASE_URL = 'https://coinmarketcap.provide.maskbook.com/v1' -// porxy: https://widgets.coinmarketcap.com/v2 -const WIDGET_BASE_URL = 'https://coinmarketcap.provide.maskbook.com/v2' +const WIDGET_BASE_URL = 'https://widgets.coinmarketcap.com/v2' export interface Status { credit_count: number @@ -73,8 +72,11 @@ export interface CoinInfo { last_updated: number } -export async function getCoinInfo(id: number, currency: string) { +export async function getCoinInfo(id: string, currency: string) { const response = await fetch(`${WIDGET_BASE_URL}/ticker/${id}/?ref=widget&convert=${currency}`) - return response.json() as Promise + return response.json() as Promise<{ + data: CoinInfo + status: Status + }> } //#endregion diff --git a/src/plugins/Trader/apis/index.ts b/src/plugins/Trader/apis/index.ts index a68f9cda46dc..327649f45e14 100644 --- a/src/plugins/Trader/apis/index.ts +++ b/src/plugins/Trader/apis/index.ts @@ -1,4 +1,4 @@ -import { Platform, Currency } from '../type' +import { Platform, Currency, Coin, Trending } from '../type' import * as coinGeckoAPI from './coingecko' import * as coinMarketCapAPI from './coinmarketcap' @@ -17,3 +17,56 @@ export async function getCurrenies(platform: Platform): Promise { description: x.name, })) } + +export async function getCoins(platform: Platform): Promise { + if (platform === Platform.COIN_GECKO) return coinGeckoAPI.getAllCoins() + return (await coinMarketCapAPI.getAllCoins()).data.map((x) => ({ + id: String(x.id), + name: x.name, + symbol: x.symbol, + })) +} + +export async function getCoinInfo(id: string, platform: Platform, currency: Currency): Promise { + if (platform === Platform.COIN_GECKO) { + const info = await coinGeckoAPI.getCoinInfo(id) + return { + coin: { + id, + name: info.name, + symbol: info.symbol, + image_url: info.image.thumb, + }, + currency, + platform, + market: { + current_price: info.market_data.current_price[currency.id], + total_volume: info.market_data.total_volume[currency.id], + price_change_24h: info.market_data.price_change_percentage_24h, + }, + } + } + const info = await coinMarketCapAPI.getCoinInfo(id, currency.name.toUpperCase()) + return { + coin: { + id, + name: info.data.name, + symbol: info.data.symbol, + image_url: `https://s2.coinmarketcap.com/static/img/coins/64x64/${id}.png`, + }, + currency, + platform, + market: { + current_price: info.data.quotes[currency.name.toUpperCase()].price, + total_volume: info.data.quotes[currency.name.toUpperCase()].volume_24h, + price_change_24h: info.data.quotes[currency.name.toUpperCase()].percent_change_24h, + }, + } +} + +export async function getCoinTrendingByKeyword(keyword: string, platform: Platform, currency: Currency) { + const coins = await getCoins(platform) + const coin = coins.find((x) => x.symbol.toLowerCase() === keyword.toLowerCase()) + if (!coin) return null + return getCoinInfo(coin.id, platform, currency) +} diff --git a/src/plugins/Trader/services.ts b/src/plugins/Trader/services.ts index 177804c7aba9..5914b704d67f 100644 --- a/src/plugins/Trader/services.ts +++ b/src/plugins/Trader/services.ts @@ -1 +1 @@ -export function noop() {} +export * from './apis' diff --git a/src/plugins/Trader/type.ts b/src/plugins/Trader/type.ts index 276084d2d1d5..c233d64cbfd1 100644 --- a/src/plugins/Trader/type.ts +++ b/src/plugins/Trader/type.ts @@ -14,6 +14,26 @@ export interface Currency { description?: string } +export interface Coin { + id: string + name: string + symbol: string + image_url?: string +} + +export interface Market { + current_price: number + total_volume?: number + price_change_24h?: number +} + +export interface Trending { + platform: Platform + coin: Coin + currency: Currency + market: Market +} + export function resolveCurrencyName(currency: Currency) { return [ currency.name, diff --git a/src/plugins/Wallet/formatter.ts b/src/plugins/Wallet/formatter.ts index 62550546cf8b..95e6aea26fdd 100644 --- a/src/plugins/Wallet/formatter.ts +++ b/src/plugins/Wallet/formatter.ts @@ -21,3 +21,7 @@ export function formatBalance(balance: BigNumber, decimals: number, precision: n return raw.indexOf('.') > -1 ? raw.replace(/0+$/, '').replace(/\.$/, '') : raw } + +export function formatCurrency(balance: number) { + return balance.toFixed(2).replace(/\d(?=(\d{3})+\.)/g, '$&,') +}