diff --git a/js/src/modals/AddAddress/addAddress.js b/js/src/modals/AddAddress/addAddress.js
index 5ab8bbe80..ebcf78815 100644
--- a/js/src/modals/AddAddress/addAddress.js
+++ b/js/src/modals/AddAddress/addAddress.js
@@ -136,6 +136,7 @@ export default class AddAddress extends Component {
api.personal.setAccountName(address, name),
api.personal.setAccountMeta(address, {
description,
+ timestamp: Date.now(),
deleted: false
})
]).catch((error) => {
diff --git a/js/src/modals/AddContract/addContract.js b/js/src/modals/AddContract/addContract.js
index ebad86807..ad7345430 100644
--- a/js/src/modals/AddContract/addContract.js
+++ b/js/src/modals/AddContract/addContract.js
@@ -145,6 +145,7 @@ export default class AddContract extends Component {
api.personal.setAccountMeta(address, {
contract: true,
deleted: false,
+ timestamp: Date.now(),
abi: abiParsed,
description
})
diff --git a/js/src/modals/CreateAccount/createAccount.js b/js/src/modals/CreateAccount/createAccount.js
index e0808b47b..aacc91d5e 100644
--- a/js/src/modals/CreateAccount/createAccount.js
+++ b/js/src/modals/CreateAccount/createAccount.js
@@ -214,7 +214,10 @@ export default class CreateAccount extends Component {
this.setState({ address });
return api.personal
.setAccountName(address, this.state.name)
- .then(() => api.personal.setAccountMeta(address, { passwordHint: this.state.passwordHint }));
+ .then(() => api.personal.setAccountMeta(address, {
+ timestamp: Date.now(),
+ passwordHint: this.state.passwordHint
+ }));
})
.then(() => {
this.onNext();
@@ -236,7 +239,10 @@ export default class CreateAccount extends Component {
this.setState({ address });
return api.personal
.setAccountName(address, this.state.name)
- .then(() => api.personal.setAccountMeta(address, { passwordHint: this.state.passwordHint }));
+ .then(() => api.personal.setAccountMeta(address, {
+ timestamp: Date.now(),
+ passwordHint: this.state.passwordHint
+ }));
})
.then(() => {
this.onNext();
@@ -285,7 +291,10 @@ export default class CreateAccount extends Component {
return api.personal
.setAccountName(address, this.state.name)
- .then(() => api.personal.setAccountMeta(address, { passwordHint: this.state.passwordHint }));
+ .then(() => api.personal.setAccountMeta(address, {
+ timestamp: Date.now(),
+ passwordHint: this.state.passwordHint
+ }));
})
.then(() => {
this.onNext();
diff --git a/js/src/modals/DeployContract/deployContract.js b/js/src/modals/DeployContract/deployContract.js
index 3e1b10599..c62b968b5 100644
--- a/js/src/modals/DeployContract/deployContract.js
+++ b/js/src/modals/DeployContract/deployContract.js
@@ -216,6 +216,7 @@ export default class DeployContract extends Component {
api.personal.setAccountMeta(address, {
abi: abiParsed,
contract: true,
+ timestamp: Date.now(),
deleted: false,
description
})
diff --git a/js/src/ui/Actionbar/Sort/sort.js b/js/src/ui/Actionbar/Sort/sort.js
index 35c51e5a1..474ef465b 100644
--- a/js/src/ui/Actionbar/Sort/sort.js
+++ b/js/src/ui/Actionbar/Sort/sort.js
@@ -27,14 +27,23 @@ import styles from './sort.css';
export default class ActionbarSort extends Component {
static propTypes = {
onChange: PropTypes.func.isRequired,
- order: PropTypes.string
+ order: PropTypes.string,
+ showDefault: PropTypes.bool,
+ metas: PropTypes.array
};
+ static defaultProps = {
+ metas: [],
+ showDefault: true
+ }
+
state = {
menuOpen: false
}
render () {
+ const { showDefault } = this.props;
+
return (
-
-
-
+ touchTapCloseDelay={ 0 }
+ >
+ {
+ showDefault
+ ? this.renderMenuItem('', 'Default')
+ : null
+ }
+ { this.renderMenuItem('tags', 'Sort by tags') }
+ { this.renderMenuItem('name', 'Sort by name') }
+ { this.renderMenuItem('eth', 'Sort by ETH') }
+
+ { this.renderSortByMetas() }
);
}
+ renderSortByMetas () {
+ const { metas } = this.props;
+
+ return metas
+ .map((meta, index) => {
+ return this
+ .renderMenuItem(meta.key, `Sort by ${meta.label}`, index);
+ });
+ }
+
+ renderMenuItem (value, label, key = null) {
+ const { order } = this.props;
+
+ const props = {};
+
+ if (key !== null) {
+ props.key = key;
+ }
+
+ const checked = order === value;
+
+ return (
+
+ );
+ }
+
handleSortChange = (event, child) => {
const order = child.props.value;
this.props.onChange(order);
diff --git a/js/src/ui/Container/container.css b/js/src/ui/Container/container.css
index 1071125bd..d5c2ef336 100644
--- a/js/src/ui/Container/container.css
+++ b/js/src/ui/Container/container.css
@@ -18,6 +18,7 @@
flex: 1;
padding: 0em;
background: rgba(0, 0, 0, 0.8);
+ height: 100%;
}
.compact,
diff --git a/js/src/views/Accounts/List/list.js b/js/src/views/Accounts/List/list.js
index bcdf7b072..ab231a53a 100644
--- a/js/src/views/Accounts/List/list.js
+++ b/js/src/views/Accounts/List/list.js
@@ -29,6 +29,7 @@ export default class List extends Component {
search: PropTypes.array,
empty: PropTypes.bool,
order: PropTypes.string,
+ orderFallback: PropTypes.string,
handleAddSearchToken: PropTypes.func
};
@@ -79,9 +80,9 @@ export default class List extends Component {
}
sortAddresses (addresses) {
- const { order } = this.props;
+ const { order, orderFallback } = this.props;
- if (!order || ['tags', 'name'].indexOf(order) === -1) {
+ if (!order) {
return addresses;
}
@@ -91,26 +92,77 @@ export default class List extends Component {
const accountA = accounts[addressA];
const accountB = accounts[addressB];
- if (order === 'name') {
- return accountA.name.localeCompare(accountB.name);
+ const sort = this.compareAccounts(accountA, accountB, order);
+
+ if (sort === 0 && orderFallback) {
+ return this.compareAccounts(accountA, accountB, orderFallback);
}
- if (order === 'tags') {
- const tagsA = [].concat(accountA.meta.tags)
- .filter(t => t)
- .sort();
- const tagsB = [].concat(accountB.meta.tags)
- .filter(t => t)
- .sort();
-
- if (tagsA.length === 0) return 1;
- if (tagsB.length === 0) return -1;
-
- return tagsA.join('').localeCompare(tagsB.join(''));
- }
+ return sort;
});
}
+ compareAccounts (accountA, accountB, key) {
+ if (key === 'name') {
+ return accountA.name.localeCompare(accountB.name);
+ }
+
+ if (key === 'eth') {
+ const { balances } = this.props;
+
+ const balanceA = balances[accountA.address];
+ const balanceB = balances[accountB.address];
+
+ if (!balanceA && !balanceB) return 0;
+ if (balanceA && !balanceB) return -1;
+ if (!balanceA && balanceB) return 1;
+
+ const ethA = balanceA.tokens
+ .find(token => token.token.tag.toLowerCase() === 'eth')
+ .value;
+ const ethB = balanceB.tokens
+ .find(token => token.token.tag.toLowerCase() === 'eth')
+ .value;
+
+ return -1 * ethA.comparedTo(ethB);
+ }
+
+ if (key === 'tags') {
+ const tagsA = [].concat(accountA.meta.tags)
+ .filter(t => t)
+ .sort()
+ .join('');
+
+ const tagsB = [].concat(accountB.meta.tags)
+ .filter(t => t)
+ .sort()
+ .join('');
+
+ if (!tagsA && !tagsB) return 0;
+ if (tagsA && !tagsB) return -1;
+ if (!tagsA && tagsB) return 1;
+
+ return tagsA.localeCompare(tagsB);
+ }
+
+ const metaA = accountA.meta[key];
+ const metaB = accountB.meta[key];
+
+ if (!metaA && !metaB) {
+ return 0;
+ }
+
+ if ((metaA && !metaB) || (metaA < metaB)) {
+ return -1;
+ }
+
+ if ((!metaA && metaB) || (metaA > metaB)) {
+ return 1;
+ }
+
+ return 0;
+ }
+
getFilteredAddresses () {
const { accounts, search } = this.props;
const searchValues = (search || []).map(v => v.toLowerCase());
diff --git a/js/src/views/Contracts/contracts.js b/js/src/views/Contracts/contracts.js
index f4cbc6dcc..ef408cae2 100644
--- a/js/src/views/Contracts/contracts.js
+++ b/js/src/views/Contracts/contracts.js
@@ -42,7 +42,7 @@ class Contracts extends Component {
state = {
addContract: false,
deployContract: false,
- sortOrder: '',
+ sortOrder: 'timestamp',
searchValues: [],
searchTokens: []
}
@@ -65,6 +65,7 @@ class Contracts extends Component {
balances={ balances }
empty={ !hasContracts }
order={ sortOrder }
+ orderFallback='name'
handleAddSearchToken={ this.onAddSearchToken } />
@@ -80,6 +81,10 @@ class Contracts extends Component {
);
}