Skip to content

Commit

Permalink
chore(ui): add TrendingView
Browse files Browse the repository at this point in the history
  • Loading branch information
guanbinrui committed Aug 25, 2020
1 parent 2b0a9a6 commit 870f477
Show file tree
Hide file tree
Showing 14 changed files with 376 additions and 9 deletions.
7 changes: 2 additions & 5 deletions src/components/shared-settings/useSettingsUI.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import {
} from '@material-ui/core'
import ArrowForwardIosIcon from '@material-ui/icons/ArrowForwardIos'
import { useStylesExtends } from '../custom-ui-helper'
import { getEnumAsArray } from '../../utils/enum'

const useStyles = makeStyles((theme) =>
createStyles({
Expand Down Expand Up @@ -153,16 +154,12 @@ export function useSettingsUI(ref: ValueRef<boolean>) {
function useEnumSettings<Q extends object>(
...[ref, enumObject, getText, selectProps]: useEnumSettingsParams<Q>
): HookedUI<Q[keyof Q]> {
const enum_ = Object.keys(enumObject)
// Leave only key of enum
.filter((x) => Number.isNaN(parseInt(x)))
.map((key) => ({ key, value: enumObject[key as keyof Q] }))
const enum_ = getEnumAsArray(enumObject)
const change = (value: any) => {
if (!Number.isNaN(parseInt(value))) {
value = parseInt(value)
}
if (!enum_.some((x) => x.value === value)) {
console.log(value)
throw new Error('Invalid state')
}
ref.value = value
Expand Down
2 changes: 1 addition & 1 deletion src/extension/background-script/PluginService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import * as RedPacket from '../../plugins/Wallet/red-packet-fsm'
import * as Wallet from '../../plugins/Wallet/wallet'
import * as Gitcoin from '../../plugins/Gitcoin/Services'
import * as FileService from '../../plugins/FileService/service'
import * as Trader from '../../plugins/Trader/service'
import * as Trader from '../../plugins/Trader/services'
import type { ERC20TokenRecord, ManagedWalletRecord, ExoticWalletRecord } from '../../plugins/Wallet/database/types'

const Plugins = {
Expand Down
6 changes: 5 additions & 1 deletion src/plugins/Gitcoin/DonateDialog.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,11 @@ import type { ERC20TokenDetails, WalletDetails } from '../../extension/backgroun

const useStyles = makeStyles((theme: Theme) =>
createStyles({
form: { '& > *': { margin: theme.spacing(1, 0) } },
form: {
'& > *': {
margin: theme.spacing(1, 0),
},
},
title: {
marginLeft: 6,
},
Expand Down
174 changes: 174 additions & 0 deletions src/plugins/Trader/UI/SettingsDialog.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,174 @@
import React, { useState } from 'react'
import { useI18N } from '../../../utils/i18n-next-ui'
import {
makeStyles,
DialogTitle,
IconButton,
Typography,
DialogContent,
Theme,
DialogProps,
FormControl,
Select,
MenuItem,
InputLabel,
createStyles,
DialogActions,
Button,
Divider,
} from '@material-ui/core'
import ShadowRootDialog from '../../../utils/jss/ShadowRootDialog'
import { DialogDismissIconUI } from '../../../components/InjectedComponents/DialogDismissIcon'
import { Currency, Platform, resolveCurrencyName, resolvePlatformName } from '../type'
import { useStylesExtends } from '../../../components/custom-ui-helper'
import { getActivatedUI } from '../../../social-network/ui'
import {
useTwitterDialog,
useTwitterButton,
useTwitterCloseButton,
} from '../../../social-network-provider/twitter.com/utils/theme'
import { PortalShadowRoot } from '../../../utils/jss/ShadowRootPortal'
import { getEnumAsArray } from '../../../utils/enum'

const useStyles = makeStyles((theme: Theme) =>
createStyles({
title: {
marginLeft: 6,
},
form: {
'& > *': {
margin: theme.spacing(1, 0),
},
},
menuPaper: {
maxHeight: 300,
},
}),
)

interface SettingsDialogUIProps
extends withClasses<
| KeysInferFromUseStyles<typeof useStyles>
| 'root'
| 'dialog'
| 'backdrop'
| 'container'
| 'paper'
| 'header'
| 'content'
| 'actions'
| 'close'
| 'button'
> {
open: boolean
theme?: Theme
currencies: Currency[]
currency: Currency
platform: Platform
onCurrencyChange?: (currency: Currency) => void
onPlatformChange?: (platform: Platform) => void
onClose?: () => void
DialogProps?: Partial<DialogProps>
}

function SettingsDialogUI(props: SettingsDialogUIProps) {
const { t } = useI18N()
const { currency, platform, currencies } = props
const classes = useStylesExtends(useStyles(), props)
return (
<div className={classes.root}>
<ShadowRootDialog
className={classes.dialog}
classes={{
container: classes.container,
paper: classes.paper,
}}
open={props.open}
scroll="body"
fullWidth
maxWidth="sm"
disableAutoFocus
disableEnforceFocus
onEscapeKeyDown={props.onClose}
onExit={props.onClose}
BackdropProps={{
className: classes.backdrop,
}}
{...props.DialogProps}>
<DialogTitle className={classes.header}>
<IconButton classes={{ root: classes.close }} onClick={props.onClose}>
<DialogDismissIconUI />
</IconButton>
<Typography className={classes.title} display="inline" variant="inherit">
{t('post_dialog__title')}
</Typography>
</DialogTitle>
<Divider />
<DialogContent className={classes.content}>
<form className={classes.form}>
<FormControl variant="filled" fullWidth>
<InputLabel>Data Source</InputLabel>
<Select
fullWidth
value={platform}
onChange={(e) => props.onPlatformChange?.(e.target.value as Platform)}
MenuProps={{ container: props.DialogProps?.container ?? PortalShadowRoot }}>
{getEnumAsArray(Platform).map(({ key, value }) => (
<MenuItem key={key} value={value}>
{resolvePlatformName(value)}
</MenuItem>
))}
</Select>
</FormControl>
<FormControl variant="filled" fullWidth>
<InputLabel>Currency</InputLabel>
<Select
fullWidth
value={currency.id}
onChange={(e) => {
const target = currencies.find((x) => x.id === (e.target.value as string))
if (target) props.onCurrencyChange?.(target)
}}
MenuProps={{
container: props.DialogProps?.container ?? PortalShadowRoot,
classes: { paper: classes.menuPaper },
}}>
{currencies.map((x) => (
<MenuItem key={x.id} value={x.id}>
{resolveCurrencyName(x)}
</MenuItem>
))}
</Select>
</FormControl>
</form>
</DialogContent>
<DialogActions className={classes.actions}>
<Button
className={classes.button}
style={{ marginLeft: 'auto' }}
color="primary"
variant="contained"
onClick={props.onClose}>
{t('confirm')}
</Button>
</DialogActions>
</ShadowRootDialog>
</div>
)
}

export interface SettingsDialogProps extends SettingsDialogUIProps {}

export function SettingsDialog(props: SettingsDialogProps) {
const ui = getActivatedUI()
const twitterClasses = {
...useTwitterDialog(),
...useTwitterButton(),
...useTwitterCloseButton(),
}
return ui.internalName === 'twitter' ? (
<SettingsDialogUI classes={twitterClasses} {...props} />
) : (
<SettingsDialogUI {...props} />
)
}
Empty file.
113 changes: 113 additions & 0 deletions src/plugins/Trader/UI/TrendingView.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
import React, { useState, useEffect } from 'react'
import { makeStyles, Avatar, Typography, Card, CardHeader, IconButton, CardActions } from '@material-ui/core'
import { useAsync } from 'react-use'
import SettingsIcon from '@material-ui/icons/Settings'
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'

const network = getActivatedUI().networkIdentifier

const useStyles = makeStyles({
root: {},
header: {
display: 'flex',
},
body: {},
avatar: {},
amount: {},
})

export interface TrendingViewProps extends withClasses<KeysInferFromUseStyles<typeof useStyles>> {
keyword: string
}

export function TrendingView(props: TrendingViewProps) {
const classes = useStyles()
const [settingsDialogOpen, setSettingsDialogOpen] = useState(false)

const [platform, setPlatform] = useState(Platform.COIN_GECKO)
const [currency, setCurrency] = useState<Currency | null>(null)

const networkKey = `${network}-${platform}`
const trendingSettings = useValueRef<string>(currentTrendingViewSettings[networkKey])
const trendingPlatformSettings = useValueRef<string>(currentTrendingViewPlatformSettings[network])

//#region currency & platform
const { value: currencies = [], loading: loadingCurrencies, error } = useAsync(() => getCurrenies(platform), [
platform,
])

// sync platform
useEffect(() => {
if (String(platform) !== trendingPlatformSettings) {
if (trendingPlatformSettings === String(Platform.COIN_GECKO)) setPlatform(Platform.COIN_GECKO)
if (trendingPlatformSettings === String(Platform.COIN_MARKET_CAP)) setPlatform(Platform.COIN_MARKET_CAP)
}
}, [platform, trendingPlatformSettings])

// sync currency
useEffect(() => {
if (!currencies.length) return
try {
const parsed = JSON.parse(trendingSettings || '{}') as Settings
if (parsed.currency && currencies.some((x) => x.id === parsed.currency.id)) setCurrency(parsed.currency)
else setCurrency(currencies[0])
} catch (e) {
setCurrency(null)
}
}, [trendingSettings, currencies.length])
//#endregion

if (loadingCurrencies || !currency) return null
return (
<>
<Card className={classes.root} elevation={0} component="article">
<CardHeader
className={classes.header}
avatar={
<Avatar src="https://cdn4.iconfinder.com/data/icons/logos-and-brands/512/45_Bitcoin_logo_logos-512.png" />
}
action={
<IconButton size="small" onClick={() => setSettingsDialogOpen(true)}>
<SettingsIcon />
</IconButton>
}
title={<Typography variant="h6">{`BTC / ${currency.name}`}</Typography>}
subheader={
<Typography variant="body1">
<span>{`${currency.name} 12,223`}</span>
<span>(1.2%)</span>
</Typography>
}
/>
<CardActions>
<Typography color="textSecondary" variant="body2">
Powered by {resolvePlatformName(platform)}
</Typography>
</CardActions>
</Card>
<SettingsDialog
open={settingsDialogOpen}
currencies={currencies}
currency={currency}
platform={platform}
onCurrencyChange={(currency) => {
currentTrendingViewSettings[networkKey].value = stringify({
currency,
})
}}
onPlatformChange={(platform) => {
currentTrendingViewPlatformSettings[network].value = String(platform)
}}
onClose={() => setSettingsDialogOpen(false)}
/>
</>
)
}
4 changes: 3 additions & 1 deletion src/plugins/Trader/apis/coingecko/index.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
const BASE_URL = 'https://coingecko.com/api/documentations/v3'
import type { Currency } from '../../type'

const BASE_URL = 'https://api.coingecko.com/api/v3'

//#region get currency
export async function getAllCurrenies() {
Expand Down
19 changes: 19 additions & 0 deletions src/plugins/Trader/apis/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import { Platform, Currency } from '../type'
import * as coinGeckoAPI from './coingecko'
import * as coinMarketCapAPI from './coinmarketcap'

export async function getCurrenies(platform: Platform): Promise<Currency[]> {
if (platform === Platform.COIN_GECKO) {
const currencies = await coinGeckoAPI.getAllCurrenies()
return currencies.map((x) => ({
id: x,
name: x.toUpperCase(),
}))
}
return Object.values(coinMarketCapAPI.getAllCurrenies()).map((x) => ({
id: String(x.id),
name: x.symbol.toUpperCase(),
symbol: x.token,
description: x.name,
}))
}
13 changes: 12 additions & 1 deletion src/plugins/Trader/define.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import React from 'react'
import React, { Suspense } from 'react'
import type { PluginConfig } from '../plugin'
import {
TypedMessage,
Expand All @@ -7,6 +7,8 @@ import {
TypedMessageCompound,
} from '../../protocols/typed-message'
import { makeTypedMessageCashTrending } from './messages/TypedMessageCashTrending'
import { TrendingView } from './UI/TrendingView'
import MaskbookPluginWrapper from '../MaskbookPluginWrapper'

const isCashTagMessage = (m: TypedMessage): m is TypedMessageAnchor => isTypedMessgaeAnchor(m) && m.category === 'cash'

Expand All @@ -20,4 +22,13 @@ export const TraderPluginDefine: PluginConfig = {
items: message.items.map((m: TypedMessage) => (isCashTagMessage(m) ? makeTypedMessageCashTrending(m) : m)),
}
},
postInspector() {
return (
<MaskbookPluginWrapper pluginName="Trader">
<Suspense fallback={null}>
<TrendingView keyword="BTC"></TrendingView>
</Suspense>
</MaskbookPluginWrapper>
)
},
}
File renamed without changes.
4 changes: 4 additions & 0 deletions src/plugins/Trader/settings.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
import { createNetworkSettings } from '../../settings/createSettings'

export const currentTrendingViewSettings = createNetworkSettings('currentTrendingViewSettings')
export const currentTrendingViewPlatformSettings = createNetworkSettings('currentTrendingViewPlatformSettings')
Loading

0 comments on commit 870f477

Please sign in to comment.