Skip to content
Permalink
Browse files

Finance: use aragonAPI for React (#765)

Only contains the changes needed to support aragonAPI for React: this is not a full conversion to React Hooks.
  • Loading branch information...
bpierre committed Apr 5, 2019
1 parent f7a9538 commit e5078ff51b5c5d0fa2d6bc09a75c4fcef11c96f2
@@ -5,13 +5,14 @@
"license": "AGPL-3.0-or-later",
"dependencies": {
"@aragon/api": "^1.0.0",
"@aragon/api-react": "^1.0.0-beta.2",
"@aragon/templates-tokens": "^1.1.1",
"@aragon/ui": "^0.33.0",
"@babel/polyfill": "^7.0.0",
"bn.js": "^4.11.8",
"date-fns": "2.0.0-alpha.22",
"lodash.throttle": "^4.1.1",
"prop-types": "^15.6.0",
"prop-types": "^15.7.2",
"qrcode.react": "^0.8.0",
"react": "^16.8.4",
"react-display-name": "^0.2.3",
@@ -1,47 +1,31 @@
import React from 'react'
import PropTypes from 'prop-types'
import styled from 'styled-components'
import BN from 'bn.js'
import { map } from 'rxjs/operators'
import { EmptyStateCard, Main, SidePanel, observe } from '@aragon/ui'
import { EmptyStateCard, Main, SidePanel } from '@aragon/ui'
import { useAragonApi } from '@aragon/api-react'
import Balances from './components/Balances'
import NewTransferPanelContent from './components/NewTransfer/PanelContent'
import Transfers from './components/Transfers'
import AppLayout from './components/AppLayout'
import NewTransferIcon from './components/NewTransferIcon'
import { networkContextType } from './lib/provideNetwork'
import { ETHER_TOKEN_FAKE_ADDRESS } from './lib/token-utils'
import { IdentityProvider } from './components/IdentityManager/IdentityManager'

import addFundsIcon from './components/assets/add-funds-icon.svg'

class App extends React.Component {
static propTypes = {
app: PropTypes.object.isRequired,
sendMessageToWrapper: PropTypes.func.isRequired,
proxyAddress: PropTypes.string,
api: PropTypes.object,
appState: PropTypes.object,
}
static defaultProps = {
balances: [],
transactions: [],
tokens: [],
network: {},
userAccount: '',
}
static childContextTypes = {
network: networkContextType,
}
state = {
newTransferOpened: false,
}
getChildContext() {
const { network } = this.props
return {
network: {
type: network.type,
},
}
}
handleNewTransferOpen = () => {
this.setState({ newTransferOpened: true })
}
@@ -50,7 +34,7 @@ class App extends React.Component {
}
handleWithdraw = (tokenAddress, recipient, amount, reference) => {
// Immediate, one-time payment
this.props.app.newPayment(
this.props.api.newPayment(
tokenAddress,
recipient,
amount,
@@ -62,7 +46,7 @@ class App extends React.Component {
this.handleNewTransferClose()
}
handleDeposit = async (tokenAddress, amount, reference) => {
const { app, periodDuration, periods } = this.props
const { api, periodDuration, periods } = this.props

let intentParams
if (tokenAddress === ETHER_TOKEN_FAKE_ADDRESS) {
@@ -90,32 +74,23 @@ class App extends React.Component {
}
}

app.deposit(tokenAddress, amount, reference, intentParams)
api.deposit(tokenAddress, amount, reference, intentParams)
this.handleNewTransferClose()
}

handleMenuPanelOpen = () => {
this.props.sendMessageToWrapper('menuPanel', true)
}
handleResolveLocalIdentity = address => {
return this.props.app.resolveAddressIdentity(address).toPromise()
return this.props.api.resolveAddressIdentity(address).toPromise()
}
handleShowLocalIdentityModal = address => {
return this.props.app
return this.props.api
.requestAddressIdentityModification(address)
.toPromise()
}

render() {
const {
app,
balances,
transactions,
tokens,
proxyAddress,
userAccount,
} = this.props
const { appState } = this.props
const { newTransferOpened } = this.state
const { balances, transactions, tokens, proxyAddress } = appState

return (
<Main assetsUrl="./aragon-ui">
@@ -126,7 +101,6 @@ class App extends React.Component {
>
<AppLayout
title="Finance"
onMenuOpen={this.handleMenuPanelOpen}
mainButton={{
label: 'New transfer',
icon: <NewTransferIcon />,
@@ -162,13 +136,11 @@ class App extends React.Component {
title="New Transfer"
>
<NewTransferPanelContent
app={app}
opened={newTransferOpened}
tokens={tokens}
onWithdraw={this.handleWithdraw}
onDeposit={this.handleDeposit}
proxyAddress={proxyAddress}
userAccount={userAccount}
/>
</SidePanel>
</IdentityProvider>
@@ -192,75 +164,7 @@ const SpacedBlock = styled.div`
}
`

// Use this function to sort by ETH and then token symbol
const compareBalancesByEthAndSymbol = (tokenA, tokenB) => {
if (tokenA.address === ETHER_TOKEN_FAKE_ADDRESS) {
return -1
}
if (tokenB.address === ETHER_TOKEN_FAKE_ADDRESS) {
return 1
}
return tokenA.symbol.localeCompare(tokenB.symbol)
export default () => {
const { api, appState } = useAragonApi()
return <App api={api} appState={appState} />
}

export default observe(
observable =>
observable.pipe(
map(state => {
const { balances, transactions } = state || {}

const balancesBn = balances
? balances
.map(balance => ({
...balance,
amount: new BN(balance.amount),
decimals: new BN(balance.decimals),
// Note that numbers in `numData` are not safe for accurate
// computations (but are useful for making divisions easier).
numData: {
amount: parseInt(balance.amount, 10),
decimals: parseInt(balance.decimals, 10),
},
}))
.sort(compareBalancesByEthAndSymbol)
: []

const transactionsBn = transactions
? transactions.map(transaction => ({
...transaction,
amount: new BN(transaction.amount),
numData: {
amount: parseInt(transaction.amount, 10),
},
}))
: []

return {
...state,

tokens: balancesBn.map(
({
address,
name,
symbol,
numData: { amount, decimals },
verified,
}) => ({
address,
amount,
decimals,
name,
symbol,
verified,
})
),

// Filter out empty balances
balances: balancesBn.filter(balance => !balance.amount.isZero()),

transactions: transactionsBn,
}
})
),
{}
)(App)
@@ -0,0 +1,66 @@
import BN from 'bn.js'
import { ETHER_TOKEN_FAKE_ADDRESS } from './lib/token-utils'

// Use this function to sort by ETH and then token symbol
const compareBalancesByEthAndSymbol = (tokenA, tokenB) => {
if (tokenA.address === ETHER_TOKEN_FAKE_ADDRESS) {
return -1
}
if (tokenB.address === ETHER_TOKEN_FAKE_ADDRESS) {
return 1
}
return tokenA.symbol.localeCompare(tokenB.symbol)
}

function appStateReducer(state) {
const { balances, transactions } = state || {}

const balancesBn = balances
? balances
.map(balance => ({
...balance,
amount: new BN(balance.amount),
decimals: new BN(balance.decimals),

// Note that numbers in `numData` are not safe for accurate
// computations (but are useful for making divisions easier).
numData: {
amount: parseInt(balance.amount, 10),
decimals: parseInt(balance.decimals, 10),
},
}))
.sort(compareBalancesByEthAndSymbol)
: []

const transactionsBn = transactions
? transactions.map(transaction => ({
...transaction,
amount: new BN(transaction.amount),
numData: {
amount: parseInt(transaction.amount, 10),
},
}))
: []

return {
...state,

tokens: balancesBn.map(
({ address, name, symbol, numData: { amount, decimals }, verified }) => ({
address,
amount,
decimals,
name,
symbol,
verified,
})
),

// Filter out empty balances
balances: balancesBn.filter(balance => !balance.amount.isZero()),

transactions: transactionsBn,
}
}

export default appStateReducer
@@ -2,6 +2,7 @@ import React from 'react'
import PropTypes from 'prop-types'
import styled from 'styled-components'
import { AppBar, AppView, Button, ButtonIcon, Viewport, font } from '@aragon/ui'
import { useAragonApi } from '@aragon/api-react'
import MenuButton from './MenuButton/MenuButton'

const AppLayout = ({
@@ -10,9 +11,9 @@ const AppLayout = ({
afterTitle,
smallViewPadding,
largeViewPadding,
onMenuOpen,
mainButton,
}) => {
const { requestMenu, displayMenuButton } = useAragonApi()
return (
<Viewport>
{({ below }) => (
@@ -21,18 +22,24 @@ const AppLayout = ({
appBar={
<AppBar>
<AppBarContainer
style={{ padding: below('medium') ? '0' : '0 30px' }}
style={{ padding: below('medium') ? '0' : '0 30px 0 10px' }}
>
<Title>
{below('medium') && <MenuButton onClick={onMenuOpen} />}
<TitleLabel>{title}</TitleLabel>
{displayMenuButton && <MenuButton onClick={requestMenu} />}
<TitleLabel
css={`
margin-left: ${displayMenuButton ? '0' : '20px'};
`}
>
{title}
</TitleLabel>
{afterTitle}
</Title>
{mainButton &&
(below('medium') ? (
<ButtonIcon
onClick={mainButton.onClick}
title={mainButton.label}
label={mainButton.label}
css={`
width: auto;
height: 100%;
@@ -67,7 +74,6 @@ AppLayout.propTypes = {
children: PropTypes.node,
title: PropTypes.node.isRequired,
afterTitle: PropTypes.node,
onMenuOpen: PropTypes.func.isRequired,
smallViewPadding: PropTypes.number,
largeViewPadding: PropTypes.number,
mainButton: PropTypes.shape({
@@ -4,13 +4,13 @@ import { ButtonIcon } from '@aragon/ui'
const Download = props => (
<ButtonIcon
{...props}
label="Menu"
css={`
width: auto;
height: 100%;
padding: 0 8px;
margin: 0 8px;
`}
label="Download"
>
<IconDownload />
</ButtonIcon>

This file was deleted.

Oops, something went wrong.
@@ -1,6 +1,5 @@
import React from 'react'
import { ButtonIcon } from '@aragon/ui'
import IconMenu from './IconMenu'
import { ButtonIcon, IconMenu } from '@aragon/ui'

export default props => (
<ButtonIcon
@@ -11,6 +10,7 @@ export default props => (
padding: 0 10px 0 20px;
margin-right: 8px;
`}
label="Open menu"
>
<IconMenu />
</ButtonIcon>
Oops, something went wrong.

0 comments on commit e5078ff

Please sign in to comment.
You can’t perform that action at this time.