Skip to content
This repository has been archived by the owner on Oct 6, 2023. It is now read-only.

Commit

Permalink
provider splitup and refactor
Browse files Browse the repository at this point in the history
  • Loading branch information
kremalicious committed Feb 25, 2020
1 parent c3edae6 commit 2efee0e
Show file tree
Hide file tree
Showing 16 changed files with 213 additions and 144 deletions.
16 changes: 9 additions & 7 deletions package.json
Expand Up @@ -30,11 +30,13 @@
"license": "MIT",
"dependencies": {
"@coingecko/cryptoformat": "^0.3.4",
"axios": "^0.19.2",
"electron-is-dev": "^1.1.0",
"electron-next": "^3.1.5",
"electron-store": "^5.1.0",
"electron-store": "^5.1.1",
"ethereum-address": "^0.0.4",
"ethereum-blockies": "github:MyEtherWallet/blockies",
"ethjs-unit": "^0.1.6",
"ms": "^2.1.2",
"shortid": "^2.2.15"
},
Expand All @@ -43,30 +45,30 @@
"@babel/preset-env": "^7.8.4",
"@jest-runner/electron": "^2.0.3",
"@react-mock/state": "^0.1.8",
"@svgr/webpack": "^5.1.0",
"@svgr/webpack": "^5.2.0",
"@testing-library/jest-dom": "^5.1.1",
"@testing-library/react": "^9.4.0",
"@testing-library/react": "^9.4.1",
"auto-changelog": "^1.16.2",
"babel-eslint": "^10.0.3",
"babel-jest": "^25.1.0",
"copy": "^0.3.2",
"cross-env": "^7.0.0",
"electron": "^8.0.0",
"electron": "^8.0.1",
"electron-builder": "^22.3.2",
"electron-devtools-installer": "^2.2.4",
"eslint": "^6.8.0",
"eslint-config-prettier": "^6.10.0",
"eslint-plugin-react": "^7.18.3",
"identity-obj-proxy": "^3.0.0",
"jest": "^25.1.0",
"next": "^9.2.1",
"next": "^9.2.2",
"prettier": "^1.19.1",
"prettier-stylelint": "^0.4.2",
"react": "^16.12.0",
"react-dom": "^16.12.0",
"react-pose": "^4.0.10",
"release-it": "^12.4.3",
"stylelint": "^13.1.0",
"release-it": "^12.6.1",
"stylelint": "^13.2.0",
"stylelint-config-css-modules": "^2.2.0",
"stylelint-config-standard": "^20.0.0"
},
Expand Down
19 changes: 11 additions & 8 deletions src/renderer/Layout.jsx
Expand Up @@ -3,6 +3,7 @@ import PropTypes from 'prop-types'
import posed, { PoseGroup } from 'react-pose'
import shortid from 'shortid'
import AppProvider from './store/AppProvider'
import PriceProvider from './store/PriceProvider'
import { defaultAnimation } from './components/Animations'
import Titlebar from './components/Titlebar'
import styles from './Layout.module.css'
Expand All @@ -11,14 +12,16 @@ const Animation = posed.div(defaultAnimation)

export default function Layout({ children }) {
return (
<AppProvider>
{process.platform === 'darwin' && <Titlebar />}
<div className={styles.app}>
<PoseGroup animateOnMount>
<Animation key={shortid.generate()}>{children}</Animation>
</PoseGroup>
</div>
</AppProvider>
<PriceProvider>
<AppProvider>
{process.platform === 'darwin' && <Titlebar />}
<div className={styles.app}>
<PoseGroup animateOnMount>
<Animation key={shortid.generate()}>{children}</Animation>
</PoseGroup>
</div>
</AppProvider>
</PriceProvider>
)
}

Expand Down
15 changes: 6 additions & 9 deletions src/renderer/components/Home/Ticker.jsx
@@ -1,7 +1,7 @@
import React, { useContext } from 'react'
import PropTypes from 'prop-types'
import posed, { PoseGroup } from 'react-pose'
import { AppContext } from '../../store/createContext'
import { AppContext, PriceContext } from '../../store/createContext'
import { cryptoFormatter } from '../../../utils'
import stylesIndex from '../../pages/index.module.css'
import styles from './Ticker.module.css'
Expand All @@ -10,7 +10,7 @@ import { fadeIn } from '../Animations'
const Item = posed.div(fadeIn)

const Change = ({ currency }) => {
const { priceChanges } = useContext(AppContext)
const { priceChanges } = useContext(PriceContext)
const isNegative = JSON.stringify(priceChanges[currency]).startsWith('-')
let classes = isNegative ? styles.negative : styles.positive

Expand All @@ -27,13 +27,10 @@ Change.propTypes = {
}

const Items = () => {
const {
prices,
needsConfig,
currency,
toggleCurrencies,
accentColor
} = useContext(AppContext)
const { prices } = useContext(PriceContext)
const { needsConfig, currency, toggleCurrencies, accentColor } = useContext(
AppContext
)

const activeStyle = {
backgroundColor: accentColor,
Expand Down
2 changes: 1 addition & 1 deletion src/renderer/pages/_app.jsx
Expand Up @@ -2,9 +2,9 @@ import React, { useEffect } from 'react'
import PropTypes from 'prop-types'
import Router from 'next/router'
// import { ipcRenderer } from 'electron'
import Layout from '../Layout'

import '../global.css'
import Layout from '../Layout'

export default function App({ Component, pageProps }) {
useEffect(() => {
Expand Down
159 changes: 64 additions & 95 deletions src/renderer/store/AppProvider.jsx
@@ -1,120 +1,81 @@
import React, { PureComponent } from 'react'
import React, { useContext, useState, useEffect } from 'react'
import PropTypes from 'prop-types'
import ms from 'ms'
// import { ipcRenderer } from 'electron'
import Store from 'electron-store'
import { AppContext } from './createContext'
import unit from 'ethjs-unit'
import { AppContext, PriceContext } from './createContext'
import { fetchData } from '../../utils'
import { refreshInterval, conversions, oceanTokenContract } from '../../config'

// construct initial prices Map to get consistent
// order for Ticker and Touchbar
let pricesMap = new Map()
pricesMap.set('ocean', 1)
conversions.map(key => pricesMap.set(key, 0))
async function getBalance(account) {
const json = await fetchData(
`https://api.etherscan.io/api?module=account&action=tokenbalance&contractaddress=${oceanTokenContract}&address=${account}&tag=latest`
)

export default class AppProvider extends PureComponent {
static propTypes = {
children: PropTypes.any.isRequired
}
const balance = unit.fromWei(`${json.result}`, 'ether')
return balance
}

store = process.env.NODE_ENV === 'test' ? new Store() : global.store

state = {
isLoading: true,
accounts: [],
currency: 'ocean',
needsConfig: false,
prices: pricesMap,
priceChanges: Object.assign(
...conversions.map(key => ({
[key]: 0
}))
),
toggleCurrencies: currency => this.toggleCurrencies(currency),
setBalances: () => this.setBalances(),
accentColor: '#f6388a'
}
export default function AppProvider({ children }) {
const { prices } = useContext(PriceContext)
const [isLoading, setIsLoading] = useState(true)
const [accounts, setAccounts] = useState([])
const [needsConfig, setNeedsConfig] = useState(false)
const [currency, setCurrency] = useState('ocean')
const [accentColor, setAccentColor] = useState('#f6388a')

async componentDidMount() {
useEffect(() => {
// listener for accent color
global.ipcRenderer.on('accent-color', (evt, accentColor) => {
this.setState({ accentColor })
setAccentColor(accentColor)
})
}, [])

// listener for touchbar
global.ipcRenderer.on('setCurrency', (evt, currency) =>
this.state.toggleCurrencies(currency)
)
useEffect(() => {
async function init() {
await setBalances()
setIsLoading(false)

const newPrizes = await this.fetchAndSetPrices()
this.setState({ prices: newPrizes })

await this.setBalances()
// listener for touchbar
global.ipcRenderer.on('setCurrency', (evt, currency) =>
toggleCurrencies(currency)
)
}

setInterval(this.fetchAndSetPrices, ms(refreshInterval))
setInterval(this.setBalances, ms(refreshInterval))
init()
setInterval(init, ms(refreshInterval))

this.setState({ isLoading: false })
}
return () => {
clearInterval(init)
}
}, [prices])

getAccounts() {
function getAccounts() {
let accountsPref
const store = process.env.NODE_ENV === 'test' ? new Store() : global.store

if (this.store.has('accounts')) {
accountsPref = this.store.get('accounts')

!accountsPref.length
? this.setState({ needsConfig: true })
: this.setState({ needsConfig: false })
if (store.has('accounts')) {
accountsPref = store.get('accounts')
!accountsPref.length ? setNeedsConfig(true) : setNeedsConfig(false)
} else {
accountsPref = []
this.setState({ needsConfig: true })
setNeedsConfig(true)
}

return accountsPref
}

async getBalance(account) {
const json = await fetchData(
`https://api.etherscan.io/api?module=account&action=tokenbalance&contractaddress=${oceanTokenContract}&address=${account}&tag=latest`
)

const balance = json.result / 1e18 // Convert from vodka 10^18
return balance
}

fetchAndSetPrices = async () => {
const currencies = conversions.join(',')
const json = await fetchData(
`https://api.coingecko.com/api/v3/simple/price?ids=ocean-protocol&vs_currencies=${currencies}&include_24hr_change=true`
)

let newPrices = new Map(this.state.prices) // make a shallow copy of the Map
conversions.map(key => newPrices.set(key, json['ocean-protocol'][key])) // modify the copy

const newPriceChanges = await Object.assign(
...conversions.map(key => ({
[key]: json['ocean-protocol'][key + '_24h_change']
}))
)

global.ipcRenderer.send('prices-updated', Array.from(newPrices)) // convert Map to array, ipc messages seem to kill it
this.setState({ prices: newPrices, priceChanges: newPriceChanges })
return newPrices
}

setBalances = async () => {
const accountsPref = await this.getAccounts()

async function setBalances() {
let newAccounts = []
const accountsPref = await getAccounts()

for (const account of accountsPref) {
const oceanBalance = await this.getBalance(account)
const oceanBalance = await getBalance(account)

const conversionsBalance = Object.assign(
...conversions.map(key => ({
[key]: oceanBalance * this.state.prices.get(key) || 0
[key]: oceanBalance * prices.get(key) || 0
}))
)

Expand All @@ -129,22 +90,30 @@ export default class AppProvider extends PureComponent {
newAccounts.push(newAccount)
}

if (newAccounts !== this.state.accounts) {
this.setState({ accounts: newAccounts })
if (newAccounts !== accounts) {
setAccounts(newAccounts)
}
}

toggleCurrencies(currency) {
const pricesNew = Array.from(this.state.prices)
function toggleCurrencies(currency) {
const pricesNew = Array.from(prices)
global.ipcRenderer.send('currency-updated', pricesNew, currency)
this.setState({ currency })
setCurrency(currency)
}

render() {
return (
<AppContext.Provider value={this.state}>
{this.props.children}
</AppContext.Provider>
)
const context = {
isLoading,
accounts,
currency,
needsConfig,
accentColor,
toggleCurrencies: currency => toggleCurrencies(currency),
setBalances: () => setBalances()
}

return <AppContext.Provider value={context}>{children}</AppContext.Provider>
}

AppProvider.propTypes = {
children: PropTypes.any.isRequired
}

0 comments on commit 2efee0e

Please sign in to comment.