openethereum/js/src/modals/WalletSettings/walletSettings.js

337 lines
8.9 KiB
JavaScript
Raw Normal View History

2016-12-11 19:31:31 +01:00
// Copyright 2015, 2016 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 <http://www.gnu.org/licenses/>.
import React, { Component, PropTypes } from 'react';
import { connect } from 'react-redux';
import { observer } from 'mobx-react';
import { pick } from 'lodash';
import ActionDone from 'material-ui/svg-icons/action/done';
import ContentClear from 'material-ui/svg-icons/content/clear';
import NavigationArrowForward from 'material-ui/svg-icons/navigation/arrow-forward';
import { Button, Modal, TxHash, BusyStep, Form, TypedInput, InputAddress, AddressSelect } from '~/ui';
import { fromWei } from '~/api/util/wei';
import WalletSettingsStore from './walletSettingsStore.js';
import styles from './walletSettings.css';
@observer
class WalletSettings extends Component {
static contextTypes = {
api: PropTypes.object.isRequired
};
static propTypes = {
accountsInfo: PropTypes.object.isRequired,
wallet: PropTypes.object.isRequired,
onClose: PropTypes.func.isRequired,
senders: PropTypes.object.isRequired
};
store = new WalletSettingsStore(this.context.api, this.props.wallet);
render () {
const { stage, steps, waiting, rejected } = this.store;
if (rejected) {
return (
<Modal
visible
title='rejected'
actions={ this.renderDialogActions() }
>
<BusyStep
title='The modifications have been rejected'
state='The wallet settings will not be modified. You can safely close this window.'
/>
</Modal>
);
}
return (
<Modal
visible
actions={ this.renderDialogActions() }
current={ stage }
steps={ steps.map((s) => s.title) }
waiting={ waiting }
>
{ this.renderPage() }
</Modal>
);
}
renderPage () {
const { step } = this.store;
switch (step) {
case 'SENDING':
return (
<BusyStep
title='The modifications are currently being sent'
state={ this.store.deployState }
>
{
this.store.requests.map((req) => {
const key = req.id;
if (req.txhash) {
return (<TxHash key={ key } hash={ req.txhash } />);
}
if (req.rejected) {
return (<p key={ key }>The transaction #{parseInt(key, 16)} has been rejected</p>);
}
})
}
</BusyStep>
);
case 'CONFIRMATION':
const { changes } = this.store;
return (
<div>
{ this.renderChanges(changes) }
</div>
);
default:
case 'EDIT':
const { wallet, errors } = this.store;
const { accountsInfo, senders } = this.props;
return (
<Form>
<p>
In order to edit this contract's settings, at
least { this.store.initialWallet.require.toNumber() } owners have to
send the very same modifications.
Otherwise, no modification will be taken into account...
</p>
<AddressSelect
label='from account (wallet owner)'
hint='send modifications as this owner'
value={ wallet.sender }
error={ errors.sender }
onChange={ this.store.onSenderChange }
accounts={ senders }
/>
<TypedInput
label='other wallet owners'
value={ wallet.owners.slice() }
onChange={ this.store.onOwnersChange }
accounts={ accountsInfo }
param='address[]'
/>
<div className={ styles.splitInput }>
<TypedInput
label='required owners'
hint='number of required owners to accept a transaction'
error={ errors.require }
min={ 1 }
onChange={ this.store.onRequireChange }
max={ wallet.owners.length }
param='uint'
value={ wallet.require }
/>
<TypedInput
label='wallet day limit'
hint='amount of ETH spendable without confirmations'
value={ wallet.dailylimit }
error={ errors.dailylimit }
onChange={ this.store.onDailylimitChange }
param='uint'
isEth
/>
</div>
</Form>
);
}
}
renderChanges (changes) {
if (changes.length === 0) {
return (
<p>No modifications have been made to the Wallet settings.</p>
);
}
const modifications = changes.map((change, index) => (
<div key={ `${change.type}_${index}` }>
{ this.renderChange(change) }
</div>
));
return (
<div>
<p>You are about to make the following modifications</p>
{ modifications }
</div>
);
}
renderChange (change) {
const { accountsInfo } = this.props;
switch (change.type) {
case 'dailylimit':
return (
<div className={ styles.change }>
<div className={ styles.label }>Change Daily Limit</div>
<div>
<span> from </span>
<code> { fromWei(change.initial).toFormat() }</code>
<span className={ styles.eth } />
<span> to </span>
<code> { fromWei(change.value).toFormat() }</code>
<span className={ styles.eth } />
</div>
</div>
);
case 'require':
return (
<div className={ styles.change }>
<div className={ styles.label }>Change Required Owners</div>
<div>
<span> from </span>
<code> { change.initial.toNumber() }</code>
<span> to </span>
<code> { change.value.toNumber() }</code>
</div>
</div>
);
case 'add_owner':
return (
<div className={ [ styles.change, styles.add ].join(' ') }>
<div className={ styles.label }>Add Owner</div>
<div>
<InputAddress
disabled
value={ change.value }
accounts={ accountsInfo }
/>
</div>
</div>
);
case 'remove_owner':
return (
<div className={ [ styles.change, styles.remove ].join(' ') }>
<div className={ styles.label }>Remove Owner</div>
<div>
<InputAddress
disabled
value={ change.value }
accounts={ accountsInfo }
/>
</div>
</div>
);
}
}
renderDialogActions () {
const { onClose } = this.props;
const { step, hasErrors, rejected, onNext, send, done } = this.store;
const cancelBtn = (
<Button
icon={ <ContentClear /> }
label='Cancel'
onClick={ onClose }
/>
);
const closeBtn = (
<Button
icon={ <ContentClear /> }
label='Close'
onClick={ onClose }
/>
);
const sendingBtn = (
<Button
icon={ <ActionDone /> }
label='Sending...'
disabled
/>
);
const nextBtn = (
<Button
icon={ <NavigationArrowForward /> }
label='Next'
onClick={ onNext }
disabled={ hasErrors }
/>
);
const sendBtn = (
<Button
icon={ <NavigationArrowForward /> }
label='Send'
onClick={ send }
disabled={ hasErrors }
/>
);
if (rejected) {
return [ closeBtn ];
}
switch (step) {
case 'SENDING':
return done ? [ closeBtn ] : [ closeBtn, sendingBtn ];
case 'CONFIRMATION':
const { changes } = this.store;
if (changes.length === 0) {
return [ closeBtn ];
}
return [ cancelBtn, sendBtn ];
default:
case 'TYPE':
return [ cancelBtn, nextBtn ];
}
}
}
function mapStateToProps (initState, initProps) {
const { accountsInfo, accounts } = initState.personal;
const { owners } = initProps.wallet;
const senders = pick(accounts, owners);
return () => {
return { accountsInfo, senders };
};
}
export default connect(mapStateToProps)(WalletSettings);