diff --git a/js/src/ui/AccountCard/accountCard.css b/js/src/ui/AccountCard/accountCard.css
index c3cd17e7d..fcf1522f5 100644
--- a/js/src/ui/AccountCard/accountCard.css
+++ b/js/src/ui/AccountCard/accountCard.css
@@ -20,8 +20,8 @@
margin: 0.5em 0;
display: flex;
- flex-direction: row;
- align-items: center;
+ flex-direction: column;
+ align-items: flex-start;
background-color: rgba(0, 0, 0, 0.8);
@@ -53,6 +53,13 @@
}
}
+.infoContainer {
+ display: flex;
+ flex-direction: row;
+ margin-bottom: 0.5em;
+ width: 100%;
+}
+
.description {
font-size: 0.75em;
color: rgba(255, 255, 255, 0.5);
@@ -86,14 +93,10 @@
.accountName {
font-weight: 700 !important;
}
-
}
.balance {
- .tag {
- margin-left: 0.5em;
- font-size: 0.85em;
- }
+ margin-top: 0;
}
@keyframes copied {
diff --git a/js/src/ui/AccountCard/accountCard.js b/js/src/ui/AccountCard/accountCard.js
index 716440568..61d88a37f 100644
--- a/js/src/ui/AccountCard/accountCard.js
+++ b/js/src/ui/AccountCard/accountCard.js
@@ -18,21 +18,20 @@ import React, { Component, PropTypes } from 'react';
import ReactDOM from 'react-dom';
import keycode from 'keycode';
+import Balance from '~/ui/Balance';
import IdentityIcon from '~/ui/IdentityIcon';
import IdentityName from '~/ui/IdentityName';
import Tags from '~/ui/Tags';
-import { fromWei } from '~/api/util/wei';
-
import styles from './accountCard.css';
export default class AccountCard extends Component {
static propTypes = {
account: PropTypes.object.isRequired,
- onClick: PropTypes.func.isRequired,
- onFocus: PropTypes.func.isRequired,
-
- balance: PropTypes.object
+ balance: PropTypes.object,
+ className: PropTypes.string,
+ onClick: PropTypes.func,
+ onFocus: PropTypes.func
};
state = {
@@ -40,11 +39,11 @@ export default class AccountCard extends Component {
};
render () {
- const { account } = this.props;
+ const { account, balance, className } = this.props;
const { copied } = this.state;
const { address, description, meta = {}, name } = account;
const { tags = [] } = meta;
- const classes = [ styles.account ];
+ const classes = [ styles.account, className ];
if (copied) {
classes.push(styles.copied);
@@ -59,21 +58,28 @@ export default class AccountCard extends Component {
onFocus={ this.onFocus }
onKeyDown={ this.handleKeyDown }
>
-
-
-
-
+
+
+
+
+
+
+ { this.renderDescription(description) }
+ { this.renderAddress(address) }
-
- { this.renderTags(tags, address) }
- { this.renderDescription(description) }
- { this.renderAddress(address) }
- { this.renderBalance(address) }
+
+
+
);
}
@@ -105,40 +111,6 @@ export default class AccountCard extends Component {
);
}
- renderTags (tags = [], address) {
- if (tags.length === 0) {
- return null;
- }
-
- return (
-
- );
- }
-
- renderBalance (address) {
- const { balance = {} } = this.props;
-
- if (!balance.tokens) {
- return null;
- }
-
- const ethToken = balance.tokens
- .find((tok) => tok.token && (tok.token.tag || '').toLowerCase() === 'eth');
-
- if (!ethToken) {
- return null;
- }
-
- const value = fromWei(ethToken.value).toFormat(3);
-
- return (
-
- { value }
- ETH
-
- );
- }
-
handleKeyDown = (event) => {
const codeName = keycode(event);
@@ -182,13 +154,13 @@ export default class AccountCard extends Component {
onClick = () => {
const { account, onClick } = this.props;
- onClick(account.address);
+ onClick && onClick(account.address);
}
onFocus = () => {
const { account, onFocus } = this.props;
- onFocus(account.index);
+ onFocus && onFocus(account.index);
}
preventEvent = (e) => {
diff --git a/js/src/ui/AccountCard/accountCard.spec.js b/js/src/ui/AccountCard/accountCard.spec.js
index b94aca325..ba4791778 100644
--- a/js/src/ui/AccountCard/accountCard.spec.js
+++ b/js/src/ui/AccountCard/accountCard.spec.js
@@ -61,6 +61,23 @@ describe('ui/AccountCard', () => {
});
describe('components', () => {
+ describe('Balance', () => {
+ let balance;
+
+ beforeEach(() => {
+ balance = component.find('Connect(Balance)');
+ });
+
+ it('renders the balance', () => {
+ expect(balance.length).to.equal(1);
+ });
+
+ it('sets showOnlyEth & showZeroValues', () => {
+ expect(balance.props().showOnlyEth).to.be.true;
+ expect(balance.props().showZeroValues).to.be.true;
+ });
+ });
+
describe('IdentityIcon', () => {
let icon;
@@ -100,5 +117,17 @@ describe('ui/AccountCard', () => {
expect(name.props().unknown).to.be.true;
});
});
+
+ describe('Tags', () => {
+ let tags;
+
+ beforeEach(() => {
+ tags = component.find('Tags');
+ });
+
+ it('renders the tags', () => {
+ expect(tags.length).to.equal(1);
+ });
+ });
});
});
diff --git a/js/src/ui/Balance/balance.js b/js/src/ui/Balance/balance.js
index e667cf67c..c024b1d06 100644
--- a/js/src/ui/Balance/balance.js
+++ b/js/src/ui/Balance/balance.js
@@ -16,31 +16,46 @@
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 unknownImage from '~/../assets/images/contracts/unknown-64x64.png';
+
import styles from './balance.css';
class Balance extends Component {
static contextTypes = {
api: PropTypes.object
- }
+ };
static propTypes = {
balance: PropTypes.object,
- images: PropTypes.object.isRequired
- }
+ className: PropTypes.string,
+ images: PropTypes.object.isRequired,
+ showOnlyEth: PropTypes.bool,
+ showZeroValues: PropTypes.bool
+ };
+
+ static defaultProps = {
+ showOnlyEth: false,
+ showZeroValues: false
+ };
render () {
const { api } = this.context;
- const { balance, images } = this.props;
+ const { balance, className, images, showZeroValues, showOnlyEth } = this.props;
- if (!balance) {
+ if (!balance || !balance.tokens) {
return null;
}
- let body = (balance.tokens || [])
- .filter((balance) => new BigNumber(balance.value).gt(0))
+ let body = balance.tokens
+ .filter((balance) => {
+ const hasBalance = showZeroValues || new BigNumber(balance.value).gt(0);
+ const isValidToken = !showOnlyEth || (balance.token.tag || '').toLowerCase() === 'eth';
+
+ return hasBalance && isValidToken;
+ })
.map((balance, index) => {
const token = balance.token;
@@ -95,13 +110,16 @@ class Balance extends Component {
if (!body.length) {
body = (
- There are no balances associated with this account
+
);
}
return (
-
+
{ body }
);
diff --git a/js/src/ui/Balance/balance.spec.js b/js/src/ui/Balance/balance.spec.js
new file mode 100644
index 000000000..f12e84851
--- /dev/null
+++ b/js/src/ui/Balance/balance.spec.js
@@ -0,0 +1,122 @@
+// 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 { shallow } from 'enzyme';
+import React from 'react';
+import sinon from 'sinon';
+
+import apiutil from '~/api/util';
+
+import Balance from './';
+
+const BALANCE = {
+ tokens: [
+ { value: '122', token: { tag: 'ETH' } },
+ { value: '345', token: { tag: 'GAV', format: 1 } },
+ { value: '0', token: { tag: 'TST', format: 1 } }
+ ]
+};
+
+let api;
+let component;
+let store;
+
+function createApi () {
+ api = {
+ dappsUrl: 'http://testDapps:1234/',
+ util: apiutil
+ };
+
+ 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;
+ }
+
+ component = shallow(
+
,
+ {
+ context: {
+ store: createStore()
+ }
+ }
+ ).find('Balance').shallow({ context: { api: createApi() } });
+
+ return component;
+}
+
+describe('ui/Balance', () => {
+ beforeEach(() => {
+ render();
+ });
+
+ it('renders defaults', () => {
+ expect(component).to.be.ok;
+ });
+
+ it('passes the specified className', () => {
+ expect(component.hasClass('testClass')).to.be.true;
+ });
+
+ it('renders all the non-zero balances', () => {
+ expect(component.find('img')).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);
+ });
+
+ it('renders all the tokens with showZeroValues', () => {
+ render({ showZeroValues: true });
+ expect(component.find('img')).to.have.length(3);
+ });
+
+ it('shows ETH with zero value with showOnlyEth & showZeroValues', () => {
+ render({
+ showOnlyEth: true,
+ showZeroValues: true,
+ balance: {
+ tokens: [
+ { value: '0', token: { tag: 'ETH' } },
+ { value: '345', token: { tag: 'GAV', format: 1 } }
+ ]
+ }
+ });
+ expect(component.find('img')).to.have.length(1);
+ });
+ });
+});
diff --git a/js/src/ui/Tags/tags.js b/js/src/ui/Tags/tags.js
index 3ea705e0b..5c44127c4 100644
--- a/js/src/ui/Tags/tags.js
+++ b/js/src/ui/Tags/tags.js
@@ -28,14 +28,21 @@ export default class Tags extends Component {
}
render () {
- return (
- { this.renderTags() }
-
);
+ const { tags } = this.props;
+
+ if (!tags || tags.length === 0) {
+ return null;
+ }
+
+ return (
+
+ { this.renderTags() }
+
+ );
}
renderTags () {
- const { handleAddSearchToken, setRefs } = this.props;
- const tags = this.props.tags || [];
+ const { handleAddSearchToken, setRefs, tags } = this.props;
const tagClasses = handleAddSearchToken
? [ styles.tag, styles.tagClickable ]
@@ -47,14 +54,14 @@ export default class Tags extends Component {
return tags
.sort()
- .map((tag, idx) => {
+ .map((tag, index) => {
const onClick = handleAddSearchToken
? () => handleAddSearchToken(tag)
: null;
return (
.
+import AccountCard from './AccountCard';
import Actionbar from './Actionbar';
import ActionbarExport from './Actionbar/Export';
import ActionbarImport from './Actionbar/Import';
@@ -59,6 +60,7 @@ import TxList from './TxList';
import Warning from './Warning';
export {
+ AccountCard,
Actionbar,
ActionbarExport,
ActionbarImport,