* Smarter dApps Manifest fetching... * Fetching only visible accounts (and don't delete other balances) #3590 * Moved balances action into BalancesActions #3590 * Fetch balances for accounts and contracts #3590 * Add balances to contract/address/account views #3590 * Fix transaction not fetching on first load * Remove console.warn * Fix pending tokens not showing #3154 * Fix tokens image update * Remove unused name in Header * Separate Tokens and ETH fetching #3590 * Remove unused isTest * Fetch Tokens Balance via Filter #3590 * Fix linting * Fix updating tokens image (#3590) * Fix contract balances * Improved Status * Fixing secureApi issues... * Fetch all tokens every 2 minutes (for safety) #3590 * PR changes fix * Fix Account error
206 lines
5.1 KiB
JavaScript
206 lines
5.1 KiB
JavaScript
// Copyright 2015, 2016 Ethcore (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 <http://www.gnu.org/licenses/>.
|
|
|
|
import React, { Component, PropTypes } from 'react';
|
|
|
|
import { Container } from '../../../ui';
|
|
|
|
import Summary from '../Summary';
|
|
import styles from './list.css';
|
|
|
|
export default class List extends Component {
|
|
static propTypes = {
|
|
accounts: PropTypes.object,
|
|
balances: PropTypes.object,
|
|
link: PropTypes.string,
|
|
search: PropTypes.array,
|
|
empty: PropTypes.bool,
|
|
order: PropTypes.string,
|
|
orderFallback: PropTypes.string,
|
|
handleAddSearchToken: PropTypes.func
|
|
};
|
|
|
|
render () {
|
|
return (
|
|
<div className={ styles.list }>
|
|
{ this.renderAccounts() }
|
|
</div>
|
|
);
|
|
}
|
|
|
|
renderAccounts () {
|
|
const { accounts, balances, link, empty, handleAddSearchToken } = this.props;
|
|
|
|
if (empty) {
|
|
return (
|
|
<Container className={ styles.empty }>
|
|
<div>
|
|
There are currently no accounts or addresses to display.
|
|
</div>
|
|
</Container>
|
|
);
|
|
}
|
|
|
|
const addresses = this.getAddresses();
|
|
|
|
return addresses.map((address, idx) => {
|
|
const account = accounts[address] || {};
|
|
const balance = balances[address] || {};
|
|
|
|
return (
|
|
<div
|
|
className={ styles.item }
|
|
key={ address }>
|
|
<Summary
|
|
link={ link }
|
|
account={ account }
|
|
balance={ balance }
|
|
handleAddSearchToken={ handleAddSearchToken } />
|
|
</div>
|
|
);
|
|
});
|
|
}
|
|
|
|
getAddresses () {
|
|
const filteredAddresses = this.getFilteredAddresses();
|
|
return this.sortAddresses(filteredAddresses);
|
|
}
|
|
|
|
sortAddresses (addresses) {
|
|
const { order, orderFallback } = this.props;
|
|
|
|
if (!order) {
|
|
return addresses;
|
|
}
|
|
|
|
const { accounts } = this.props;
|
|
|
|
return addresses.sort((addressA, addressB) => {
|
|
const accountA = accounts[addressA];
|
|
const accountB = accounts[addressB];
|
|
|
|
const sort = this.compareAccounts(accountA, accountB, order);
|
|
|
|
if (sort === 0 && orderFallback) {
|
|
return this.compareAccounts(accountA, accountB, orderFallback);
|
|
}
|
|
|
|
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');
|
|
const ethB = balanceB.tokens.find(token => token.token.tag.toLowerCase() === 'eth');
|
|
|
|
if (!ethA && !ethB) return 0;
|
|
if (ethA && !ethB) return -1;
|
|
if (!ethA && ethB) return 1;
|
|
|
|
return -1 * ethA.value.comparedTo(ethB.value);
|
|
}
|
|
|
|
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 reverse = key === 'timestamp' ? -1 : 1;
|
|
|
|
const metaA = accountA.meta[key];
|
|
const metaB = accountB.meta[key];
|
|
|
|
if (!metaA && !metaB) {
|
|
return 0;
|
|
}
|
|
|
|
if (metaA && !metaB) {
|
|
return -1;
|
|
}
|
|
|
|
if (metaA < metaB) {
|
|
return -1 * reverse;
|
|
}
|
|
|
|
if (!metaA && metaB) {
|
|
return 1;
|
|
}
|
|
|
|
if (metaA > metaB) {
|
|
return 1 * reverse;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
getFilteredAddresses () {
|
|
const { accounts, search } = this.props;
|
|
const searchValues = (search || []).map(v => v.toLowerCase());
|
|
|
|
if (searchValues.length === 0) {
|
|
return Object.keys(accounts);
|
|
}
|
|
|
|
return Object.keys(accounts)
|
|
.filter((address) => {
|
|
const account = accounts[address];
|
|
|
|
const tags = account.meta.tags || [];
|
|
const name = account.name || '';
|
|
|
|
const values = []
|
|
.concat(tags, name)
|
|
.map(v => v.toLowerCase());
|
|
|
|
return searchValues
|
|
.map(searchValue => {
|
|
return values
|
|
.some(value => value.indexOf(searchValue) >= 0);
|
|
})
|
|
// `current && truth, true` => use tokens as AND
|
|
// `current || truth, false` => use tokens as OR
|
|
.reduce((current, truth) => current && truth, true);
|
|
});
|
|
}
|
|
}
|