Sort by ETH balance and contract by date (#3107)

* Added timestamps to contract creation // Sort by date (#3070)

* Added sort by ETH balance (#3070)

* Added timestamp meta to accounts / addresses entry creations (#3107)
This commit is contained in:
Nicolas Gotchac 2016-11-02 23:09:00 +01:00 committed by Jaco Greeff
parent 6098f008ce
commit 391f408653
8 changed files with 147 additions and 26 deletions

View File

@ -136,6 +136,7 @@ export default class AddAddress extends Component {
api.personal.setAccountName(address, name), api.personal.setAccountName(address, name),
api.personal.setAccountMeta(address, { api.personal.setAccountMeta(address, {
description, description,
timestamp: Date.now(),
deleted: false deleted: false
}) })
]).catch((error) => { ]).catch((error) => {

View File

@ -145,6 +145,7 @@ export default class AddContract extends Component {
api.personal.setAccountMeta(address, { api.personal.setAccountMeta(address, {
contract: true, contract: true,
deleted: false, deleted: false,
timestamp: Date.now(),
abi: abiParsed, abi: abiParsed,
description description
}) })

View File

@ -214,7 +214,10 @@ export default class CreateAccount extends Component {
this.setState({ address }); this.setState({ address });
return api.personal return api.personal
.setAccountName(address, this.state.name) .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(() => { .then(() => {
this.onNext(); this.onNext();
@ -236,7 +239,10 @@ export default class CreateAccount extends Component {
this.setState({ address }); this.setState({ address });
return api.personal return api.personal
.setAccountName(address, this.state.name) .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(() => { .then(() => {
this.onNext(); this.onNext();
@ -285,7 +291,10 @@ export default class CreateAccount extends Component {
return api.personal return api.personal
.setAccountName(address, this.state.name) .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(() => { .then(() => {
this.onNext(); this.onNext();

View File

@ -216,6 +216,7 @@ export default class DeployContract extends Component {
api.personal.setAccountMeta(address, { api.personal.setAccountMeta(address, {
abi: abiParsed, abi: abiParsed,
contract: true, contract: true,
timestamp: Date.now(),
deleted: false, deleted: false,
description description
}) })

View File

@ -27,14 +27,23 @@ import styles from './sort.css';
export default class ActionbarSort extends Component { export default class ActionbarSort extends Component {
static propTypes = { static propTypes = {
onChange: PropTypes.func.isRequired, onChange: PropTypes.func.isRequired,
order: PropTypes.string order: PropTypes.string,
showDefault: PropTypes.bool,
metas: PropTypes.array
}; };
static defaultProps = {
metas: [],
showDefault: true
}
state = { state = {
menuOpen: false menuOpen: false
} }
render () { render () {
const { showDefault } = this.props;
return ( return (
<IconMenu <IconMenu
iconButtonElement={ iconButtonElement={
@ -50,14 +59,56 @@ export default class ActionbarSort extends Component {
onItemTouchTap={ this.handleSortChange } onItemTouchTap={ this.handleSortChange }
targetOrigin={ { horizontal: 'right', vertical: 'top' } } targetOrigin={ { horizontal: 'right', vertical: 'top' } }
anchorOrigin={ { horizontal: 'right', vertical: 'top' } } anchorOrigin={ { horizontal: 'right', vertical: 'top' } }
> touchTapCloseDelay={ 0 }
<MenuItem value='' primaryText='Default' /> >
<MenuItem value='tags' primaryText='Sort by tags' /> {
<MenuItem value='name' primaryText='Sort by name' /> 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() }
</IconMenu> </IconMenu>
); );
} }
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 (
<MenuItem
checked={ checked }
value={ value }
primaryText={ label }
innerDivStyle={ {
paddingLeft: checked ? 50 : 16
} }
{ ...props }
/>
);
}
handleSortChange = (event, child) => { handleSortChange = (event, child) => {
const order = child.props.value; const order = child.props.value;
this.props.onChange(order); this.props.onChange(order);

View File

@ -18,6 +18,7 @@
flex: 1; flex: 1;
padding: 0em; padding: 0em;
background: rgba(0, 0, 0, 0.8); background: rgba(0, 0, 0, 0.8);
height: 100%;
} }
.compact, .compact,

View File

@ -29,6 +29,7 @@ export default class List extends Component {
search: PropTypes.array, search: PropTypes.array,
empty: PropTypes.bool, empty: PropTypes.bool,
order: PropTypes.string, order: PropTypes.string,
orderFallback: PropTypes.string,
handleAddSearchToken: PropTypes.func handleAddSearchToken: PropTypes.func
}; };
@ -79,9 +80,9 @@ export default class List extends Component {
} }
sortAddresses (addresses) { sortAddresses (addresses) {
const { order } = this.props; const { order, orderFallback } = this.props;
if (!order || ['tags', 'name'].indexOf(order) === -1) { if (!order) {
return addresses; return addresses;
} }
@ -91,26 +92,77 @@ export default class List extends Component {
const accountA = accounts[addressA]; const accountA = accounts[addressA];
const accountB = accounts[addressB]; const accountB = accounts[addressB];
if (order === 'name') { const sort = this.compareAccounts(accountA, accountB, order);
return accountA.name.localeCompare(accountB.name);
if (sort === 0 && orderFallback) {
return this.compareAccounts(accountA, accountB, orderFallback);
} }
if (order === 'tags') { return sort;
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(''));
}
}); });
} }
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 () { getFilteredAddresses () {
const { accounts, search } = this.props; const { accounts, search } = this.props;
const searchValues = (search || []).map(v => v.toLowerCase()); const searchValues = (search || []).map(v => v.toLowerCase());

View File

@ -42,7 +42,7 @@ class Contracts extends Component {
state = { state = {
addContract: false, addContract: false,
deployContract: false, deployContract: false,
sortOrder: '', sortOrder: 'timestamp',
searchValues: [], searchValues: [],
searchTokens: [] searchTokens: []
} }
@ -65,6 +65,7 @@ class Contracts extends Component {
balances={ balances } balances={ balances }
empty={ !hasContracts } empty={ !hasContracts }
order={ sortOrder } order={ sortOrder }
orderFallback='name'
handleAddSearchToken={ this.onAddSearchToken } /> handleAddSearchToken={ this.onAddSearchToken } />
</Page> </Page>
</div> </div>
@ -80,6 +81,10 @@ class Contracts extends Component {
<ActionbarSort <ActionbarSort
key='sortAccounts' key='sortAccounts'
order={ this.state.sortOrder } order={ this.state.sortOrder }
metas={ [
{ key: 'timestamp', label: 'date' }
] }
showDefault={ false }
onChange={ onChange } /> onChange={ onChange } />
); );
} }