diff --git a/js/src/modals/Transfer/Details/details.js b/js/src/modals/Transfer/Details/details.js index 97d42ffefd4..a1d0cc637c7 100644 --- a/js/src/modals/Transfer/Details/details.js +++ b/js/src/modals/Transfer/Details/details.js @@ -14,15 +14,13 @@ // You should have received a copy of the GNU General Public License // along with Parity. If not, see . -import BigNumber from 'bignumber.js'; import React, { Component, PropTypes } from 'react'; -import { Checkbox, MenuItem } from 'material-ui'; -import { isEqual } from 'lodash'; +import { Checkbox } from 'material-ui'; -import Form, { Input, InputAddressSelect, AddressSelect, Select } from '~/ui/Form'; +import Form, { Input, InputAddressSelect, AddressSelect } from '~/ui/Form'; import { nullableProptype } from '~/util/proptypes'; -import imageUnknown from '../../../../assets/images/contracts/unknown-64x64.png'; +import TokenSelect from './tokenSelect'; import styles from '../transfer.css'; const CHECK_STYLE = { @@ -31,110 +29,12 @@ const CHECK_STYLE = { left: '1em' }; -class TokenSelect extends Component { - static contextTypes = { - api: PropTypes.object - } - - static propTypes = { - onChange: PropTypes.func.isRequired, - balance: PropTypes.object.isRequired, - images: PropTypes.object.isRequired, - tag: PropTypes.string.isRequired - }; - - componentWillMount () { - this.computeTokens(); - } - - componentWillReceiveProps (nextProps) { - const prevTokens = this.props.balance.tokens.map((t) => `${t.token.tag}_${t.value.toNumber()}`); - const nextTokens = nextProps.balance.tokens.map((t) => `${t.token.tag}_${t.value.toNumber()}`); - - if (!isEqual(prevTokens, nextTokens)) { - this.computeTokens(nextProps); - } - } - - computeTokens (props = this.props) { - const { api } = this.context; - const { balance, images } = this.props; - - const items = balance.tokens - .filter((token, index) => !index || token.value.gt(0)) - .map((balance, index) => { - const token = balance.token; - const isEth = index === 0; - let imagesrc = token.image; - - if (!imagesrc) { - imagesrc = - images[token.address] - ? `${api.dappsUrl}${images[token.address]}` - : imageUnknown; - } - let value = 0; - - if (isEth) { - value = api.util.fromWei(balance.value).toFormat(3); - } else { - const format = balance.token.format || 1; - const decimals = format === 1 ? 0 : Math.min(3, Math.floor(format / 10)); - - value = new BigNumber(balance.value).div(format).toFormat(decimals); - } - - const label = ( -
- -
- { token.name } -
-
- { value } { token.tag } -
-
- ); - - return ( - - { label } - - ); - }); - - this.setState({ items }); - } - - render () { - const { tag, onChange } = this.props; - const { items } = this.state; - - return ( - - ); - } -} - export default class Details extends Component { static propTypes = { address: PropTypes.string, balance: PropTypes.object, all: PropTypes.bool, extras: PropTypes.bool, - images: PropTypes.object.isRequired, sender: PropTypes.string, senderError: PropTypes.string, sendersBalances: PropTypes.object, @@ -249,12 +149,11 @@ export default class Details extends Component { } renderTokenSelect () { - const { balance, images, tag } = this.props; + const { balance, tag } = this.props; return ( diff --git a/js/src/modals/Transfer/Details/tokenSelect.js b/js/src/modals/Transfer/Details/tokenSelect.js new file mode 100644 index 00000000000..47f42edaaf2 --- /dev/null +++ b/js/src/modals/Transfer/Details/tokenSelect.js @@ -0,0 +1,114 @@ +// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// This file is part of Parity. + +// Parity is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Parity is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Parity. If not, see . + +import BigNumber from 'bignumber.js'; +import React, { Component, PropTypes } from 'react'; +import { MenuItem } from 'material-ui'; +import { isEqual } from 'lodash'; + +import { Select } from '~/ui/Form'; +import TokenImage from '~/ui/TokenImage'; + +import styles from '../transfer.css'; + +export default class TokenSelect extends Component { + static contextTypes = { + api: PropTypes.object + }; + + static propTypes = { + onChange: PropTypes.func.isRequired, + balance: PropTypes.object.isRequired, + tag: PropTypes.string.isRequired + }; + + componentWillMount () { + this.computeTokens(); + } + + componentWillReceiveProps (nextProps) { + const prevTokens = this.props.balance.tokens.map((t) => `${t.token.tag}_${t.value.toNumber()}`); + const nextTokens = nextProps.balance.tokens.map((t) => `${t.token.tag}_${t.value.toNumber()}`); + + if (!isEqual(prevTokens, nextTokens)) { + this.computeTokens(nextProps); + } + } + + computeTokens (props = this.props) { + const { api } = this.context; + const { balance } = this.props; + + const items = balance.tokens + .filter((token, index) => !index || token.value.gt(0)) + .map((balance, index) => { + const token = balance.token; + const isEth = index === 0; + + let value = 0; + + if (isEth) { + value = api.util.fromWei(balance.value).toFormat(3); + } else { + const format = balance.token.format || 1; + const decimals = format === 1 ? 0 : Math.min(3, Math.floor(format / 10)); + + value = new BigNumber(balance.value).div(format).toFormat(decimals); + } + + const label = ( +
+ +
+ { token.name } +
+
+ { value } { token.tag } +
+
+ ); + + return ( + + { label } + + ); + }); + + this.setState({ items }); + } + + render () { + const { tag, onChange } = this.props; + const { items } = this.state; + + return ( + + ); + } +} diff --git a/js/src/modals/Transfer/transfer.js b/js/src/modals/Transfer/transfer.js index d636b52ae32..8751a1cd18d 100644 --- a/js/src/modals/Transfer/transfer.js +++ b/js/src/modals/Transfer/transfer.js @@ -44,7 +44,6 @@ class Transfer extends Component { static propTypes = { newError: PropTypes.func.isRequired, gasLimit: PropTypes.object.isRequired, - images: PropTypes.object.isRequired, senders: nullableProptype(PropTypes.object), sendersBalances: nullableProptype(PropTypes.object), @@ -174,7 +173,7 @@ class Transfer extends Component { } renderDetailsPage () { - const { account, balance, images, senders } = this.props; + const { account, balance, senders } = this.props; const { recipient, recipientError, sender, senderError, sendersBalances } = this.store; const { valueAll, extras, tag, total, totalError, value, valueError } = this.store; @@ -184,7 +183,6 @@ class Transfer extends Component { all={ valueAll } balance={ balance } extras={ extras } - images={ images } onChange={ this.store.onUpdateDetails } recipient={ recipient } recipientError={ recipientError } diff --git a/js/src/ui/AccountCard/accountCard.spec.js b/js/src/ui/AccountCard/accountCard.spec.js index ba47917783b..7a5b6842851 100644 --- a/js/src/ui/AccountCard/accountCard.spec.js +++ b/js/src/ui/AccountCard/accountCard.spec.js @@ -65,7 +65,7 @@ describe('ui/AccountCard', () => { let balance; beforeEach(() => { - balance = component.find('Connect(Balance)'); + balance = component.find('Balance'); }); it('renders the balance', () => { diff --git a/js/src/ui/Balance/balance.js b/js/src/ui/Balance/balance.js index c024b1d069d..04fed6942f0 100644 --- a/js/src/ui/Balance/balance.js +++ b/js/src/ui/Balance/balance.js @@ -17,13 +17,12 @@ import BigNumber from 'bignumber.js'; import React, { Component, PropTypes } from 'react'; import { FormattedMessage } from 'react-intl'; -import { connect } from 'react-redux'; -import unknownImage from '~/../assets/images/contracts/unknown-64x64.png'; +import TokenImage from '~/ui/TokenImage'; import styles from './balance.css'; -class Balance extends Component { +export default class Balance extends Component { static contextTypes = { api: PropTypes.object }; @@ -31,7 +30,6 @@ class Balance extends Component { static propTypes = { balance: PropTypes.object, className: PropTypes.string, - images: PropTypes.object.isRequired, showOnlyEth: PropTypes.bool, showZeroValues: PropTypes.bool }; @@ -43,7 +41,7 @@ class Balance extends Component { render () { const { api } = this.context; - const { balance, className, images, showZeroValues, showOnlyEth } = this.props; + const { balance, className, showZeroValues, showOnlyEth } = this.props; if (!balance || !balance.tokens) { return null; @@ -79,26 +77,12 @@ class Balance extends Component { value = api.util.fromWei(balance.value).toFormat(3); } - const imageurl = token.image || images[token.address]; - let imagesrc = unknownImage; - - if (imageurl) { - const host = /^(\/)?api/.test(imageurl) - ? api.dappsUrl - : ''; - - imagesrc = `${host}${imageurl}`; - } - return (
- { +
{ value }
@@ -125,14 +109,3 @@ class Balance extends Component { ); } } - -function mapStateToProps (state) { - const { images } = state; - - return { images }; -} - -export default connect( - mapStateToProps, - null -)(Balance); diff --git a/js/src/ui/Balance/balance.spec.js b/js/src/ui/Balance/balance.spec.js index f12e8485118..8a886b39b77 100644 --- a/js/src/ui/Balance/balance.spec.js +++ b/js/src/ui/Balance/balance.spec.js @@ -16,7 +16,6 @@ import { shallow } from 'enzyme'; import React from 'react'; -import sinon from 'sinon'; import apiutil from '~/api/util'; @@ -32,7 +31,6 @@ const BALANCE = { let api; let component; -let store; function createApi () { api = { @@ -43,36 +41,22 @@ function createApi () { return api; } -function createStore () { - store = { - dispatch: sinon.stub(), - subscribe: sinon.stub(), - getState: () => { - return { - images: {} - }; - } - }; - - return store; -} - function render (props = {}) { if (!props.balance) { props.balance = BALANCE; } + const api = createApi(); + component = shallow( , { - context: { - store: createStore() - } + context: { api } } - ).find('Balance').shallow({ context: { api: createApi() } }); + ); return component; } @@ -91,18 +75,18 @@ describe('ui/Balance', () => { }); it('renders all the non-zero balances', () => { - expect(component.find('img')).to.have.length(2); + expect(component.find('Connect(TokenImage)')).to.have.length(2); }); describe('render specifiers', () => { it('renders only the single token with showOnlyEth', () => { render({ showOnlyEth: true }); - expect(component.find('img')).to.have.length(1); + expect(component.find('Connect(TokenImage)')).to.have.length(1); }); it('renders all the tokens with showZeroValues', () => { render({ showZeroValues: true }); - expect(component.find('img')).to.have.length(3); + expect(component.find('Connect(TokenImage)')).to.have.length(3); }); it('shows ETH with zero value with showOnlyEth & showZeroValues', () => { @@ -116,7 +100,7 @@ describe('ui/Balance', () => { ] } }); - expect(component.find('img')).to.have.length(1); + expect(component.find('Connect(TokenImage)')).to.have.length(1); }); }); }); diff --git a/js/src/ui/TokenImage/index.js b/js/src/ui/TokenImage/index.js new file mode 100644 index 00000000000..f0b2f9d4965 --- /dev/null +++ b/js/src/ui/TokenImage/index.js @@ -0,0 +1,17 @@ +// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// This file is part of Parity. + +// Parity is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Parity is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Parity. If not, see . + +export default from './tokenImage'; diff --git a/js/src/ui/TokenImage/tokenImage.js b/js/src/ui/TokenImage/tokenImage.js new file mode 100644 index 00000000000..e0e66d22b71 --- /dev/null +++ b/js/src/ui/TokenImage/tokenImage.js @@ -0,0 +1,72 @@ +// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// This file is part of Parity. + +// Parity is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Parity is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Parity. If not, see . + +import React, { Component, PropTypes } from 'react'; +import { connect } from 'react-redux'; + +import unknownImage from '~/../assets/images/contracts/unknown-64x64.png'; + +class TokenImage extends Component { + static contextTypes = { + api: PropTypes.object + }; + + static propTypes = { + image: PropTypes.string, + token: PropTypes.shape({ + image: PropTypes.string, + address: PropTypes.string + }).isRequired + }; + + render () { + const { api } = this.context; + const { image, token } = this.props; + + const imageurl = token.image || image; + let imagesrc = unknownImage; + + if (imageurl) { + const host = /^(\/)?api/.test(imageurl) + ? api.dappsUrl + : ''; + + imagesrc = `${host}${imageurl}`; + } + + return ( + { + ); + } +} + +function mapStateToProps (iniState) { + const { images } = iniState; + + return (_, props) => { + const { token } = props; + + return { image: images[token.address] }; + }; +} + +export default connect( + mapStateToProps, + null +)(TokenImage); diff --git a/js/src/views/Account/Header/header.spec.js b/js/src/views/Account/Header/header.spec.js index 4881edb3724..4f56044f0a7 100644 --- a/js/src/views/Account/Header/header.spec.js +++ b/js/src/views/Account/Header/header.spec.js @@ -73,7 +73,7 @@ describe('views/Account/Header', () => { beforeEach(() => { render({ balance: { balance: 'testing' } }); - balance = component.find('Connect(Balance)'); + balance = component.find('Balance'); }); it('renders', () => { diff --git a/js/src/views/Account/account.js b/js/src/views/Account/account.js index c92ce0c7750..230ee788a0a 100644 --- a/js/src/views/Account/account.js +++ b/js/src/views/Account/account.js @@ -37,7 +37,6 @@ class Account extends Component { static propTypes = { fetchCertifiers: PropTypes.func.isRequired, fetchCertifications: PropTypes.func.isRequired, - images: PropTypes.object.isRequired, setVisibleAccounts: PropTypes.func.isRequired, accounts: PropTypes.object, @@ -257,14 +256,13 @@ class Account extends Component { return null; } - const { balances, images } = this.props; + const { balances } = this.props; return ( ); @@ -289,12 +287,10 @@ class Account extends Component { function mapStateToProps (state) { const { accounts } = state.personal; const { balances } = state.balances; - const { images } = state; return { accounts, - balances, - images + balances }; } diff --git a/js/src/views/Wallet/wallet.js b/js/src/views/Wallet/wallet.js index 33be32c3bc0..317541599f7 100644 --- a/js/src/views/Wallet/wallet.js +++ b/js/src/views/Wallet/wallet.js @@ -66,7 +66,6 @@ class Wallet extends Component { static propTypes = { address: PropTypes.string.isRequired, balance: nullableProptype(PropTypes.object.isRequired), - images: PropTypes.object.isRequired, isTest: PropTypes.bool.isRequired, owned: PropTypes.bool.isRequired, setVisibleAccounts: PropTypes.func.isRequired, @@ -315,13 +314,12 @@ class Wallet extends Component { return null; } - const { walletAccount, balance, images } = this.props; + const { walletAccount, balance } = this.props; return ( ); @@ -365,7 +363,6 @@ function mapStateToProps (_, initProps) { const { isTest } = state.nodeStatus; const { accountsInfo = {}, accounts = {} } = state.personal; const { balances } = state.balances; - const { images } = state; const walletAccount = accounts[address] || accountsInfo[address] || null; if (walletAccount) { @@ -379,7 +376,6 @@ function mapStateToProps (_, initProps) { return { address, balance, - images, isTest, owned, wallet,