Convert all remaining Modals to use Portal (UI consistency) (#4625)

* FirstRun dialog -> Portal

* CreateAccount Modal -> Portal

* CreateWallet dialog -> Portal

* Transfer dialog -> Portal

* Fix failing tests

* ShapeShift dialog -> Portal

* Verification dialog -> Portal

* EditMeta dialog -> Portal

* PasswordManager dialog -> Portal

* WalletSettings dialog -> Portal

* AddAddress dialog -> Portal

* s/delete address/forget address/

* AddContract dialog -> Portal

* DeployContract dialog -> Portal

* ExceuteContract dialog -> Portal

* LoadContract dialog -> Portal

* SaveContract dialog -> Portal

* UpgradeParity dialog -> Portal

* Convert inline modals (tsk, tsk)

* Remove ui/Modal

* Import dialog i18n

* Button array returns (thanks @derhuerst)

* Unneeded debug

* Typo

* Readability formatting
This commit is contained in:
Jaco Greeff 2017-02-22 15:26:58 +01:00 committed by GitHub
parent 49675483c3
commit 6938a7a202
45 changed files with 1009 additions and 666 deletions

View File

@ -14,13 +14,12 @@
// You should have received a copy of the GNU General Public License // You should have received a copy of the GNU General Public License
// along with Parity. If not, see <http://www.gnu.org/licenses/>. // along with Parity. If not, see <http://www.gnu.org/licenses/>.
import ContentAdd from 'material-ui/svg-icons/content/add';
import ContentClear from 'material-ui/svg-icons/content/clear';
import { observer } from 'mobx-react'; import { observer } from 'mobx-react';
import React, { Component, PropTypes } from 'react'; import React, { Component, PropTypes } from 'react';
import { FormattedMessage } from 'react-intl'; import { FormattedMessage } from 'react-intl';
import { Button, Form, Input, InputAddress, Modal } from '~/ui'; import { Button, Form, Input, InputAddress, Portal } from '~/ui';
import { AddIcon, CancelIcon } from '~/ui/Icons';
import Store from './store'; import Store from './store';
@ -46,8 +45,10 @@ export default class AddAddress extends Component {
render () { render () {
return ( return (
<Modal <Portal
actions={ this.renderDialogActions() } buttons={ this.renderDialogActions() }
onClose={ this.onClose }
open
title={ title={
<FormattedMessage <FormattedMessage
id='addAddress.label' id='addAddress.label'
@ -57,7 +58,7 @@ export default class AddAddress extends Component {
visible visible
> >
{ this.renderFields() } { this.renderFields() }
</Modal> </Portal>
); );
} }
@ -66,7 +67,7 @@ export default class AddAddress extends Component {
return ([ return ([
<Button <Button
icon={ <ContentClear /> } icon={ <CancelIcon /> }
label={ label={
<FormattedMessage <FormattedMessage
id='addAddress.button.close' id='addAddress.button.close'
@ -78,7 +79,7 @@ export default class AddAddress extends Component {
/>, />,
<Button <Button
disabled={ hasError } disabled={ hasError }
icon={ <ContentAdd /> } icon={ <AddIcon /> }
label={ label={
<FormattedMessage <FormattedMessage
id='addAddress.button.add' id='addAddress.button.add'
@ -169,7 +170,7 @@ export default class AddAddress extends Component {
onAdd = () => { onAdd = () => {
this.store.add(); this.store.add();
this.props.onClose(); this.onClose();
} }
onClose = () => { onClose = () => {

View File

@ -21,7 +21,7 @@ import { connect } from 'react-redux';
import { bindActionCreators } from 'redux'; import { bindActionCreators } from 'redux';
import { newError } from '~/redux/actions'; import { newError } from '~/redux/actions';
import { Button, Modal, Form, Input, InputAddress, RadioButtons } from '~/ui'; import { Button, Form, Input, InputAddress, Portal, RadioButtons } from '~/ui';
import { AddIcon, CancelIcon, NextIcon, PrevIcon } from '~/ui/Icons'; import { AddIcon, CancelIcon, NextIcon, PrevIcon } from '~/ui/Icons';
import Store from './store'; import Store from './store';
@ -44,9 +44,11 @@ class AddContract extends Component {
const { step } = this.store; const { step } = this.store;
return ( return (
<Modal <Portal
actions={ this.renderDialogActions() } activeStep={ step }
current={ step } buttons={ this.renderDialogActions() }
onClose={ this.onClose }
open
steps={ [ steps={ [
<FormattedMessage <FormattedMessage
id='addContract.title.type' id='addContract.title.type'
@ -59,10 +61,9 @@ class AddContract extends Component {
key='details' key='details'
/> />
] } ] }
visible
> >
{ this.renderStep() } { this.renderStep() }
</Modal> </Portal>
); );
} }

View File

@ -18,7 +18,9 @@ import { observer } from 'mobx-react';
import React, { Component, PropTypes } from 'react'; import React, { Component, PropTypes } from 'react';
import { FormattedMessage } from 'react-intl'; import { FormattedMessage } from 'react-intl';
import { Form, Input, InputAddress } from '~/ui'; import { Form, Input, InputAddress, QrCode } from '~/ui';
import styles from '../createAccount.css';
@observer @observer
export default class AccountDetails extends Component { export default class AccountDetails extends Component {
@ -30,42 +32,54 @@ export default class AccountDetails extends Component {
const { address, name } = this.props.store; const { address, name } = this.props.store;
return ( return (
<Form> <div className={ styles.details }>
<Input <p>
allowCopy <FormattedMessage
hint={ id='createAccount.accountDetails.intro'
<FormattedMessage defaultMessage='Your account has been created with the following details:'
id='createAccount.accountDetails.name.hint' />
defaultMessage='a descriptive name for the account' </p>
/> <Form className={ styles.infoForm }>
} <Input
label={ allowCopy
<FormattedMessage hint={
id='createAccount.accountDetails.name.label' <FormattedMessage
defaultMessage='account name' id='createAccount.accountDetails.name.hint'
/> defaultMessage='a descriptive name for the account'
} />
readOnly }
value={ name } label={
/> <FormattedMessage
<InputAddress id='createAccount.accountDetails.name.label'
disabled defaultMessage='account name'
hint={ />
<FormattedMessage }
id='createAccount.accountDetails.address.hint' readOnly
defaultMessage='the network address for the account' value={ name }
/> />
} <InputAddress
label={ disabled
<FormattedMessage hint={
id='createAccount.accountDetails.address.label' <FormattedMessage
defaultMessage='address' id='createAccount.accountDetails.address.hint'
/> defaultMessage='the network address for the account'
} />
}
label={
<FormattedMessage
id='createAccount.accountDetails.address.label'
defaultMessage='address'
/>
}
value={ address }
/>
{ this.renderPhrase() }
</Form>
<QrCode
className={ styles.qr }
value={ address } value={ address }
/> />
{ this.renderPhrase() } </div>
</Form>
); );
} }

View File

@ -17,10 +17,104 @@
import { observer } from 'mobx-react'; import { observer } from 'mobx-react';
import React, { Component, PropTypes } from 'react'; import React, { Component, PropTypes } from 'react';
import { FormattedMessage } from 'react-intl'; import { FormattedMessage } from 'react-intl';
import { RadioButton, RadioButtonGroup } from 'material-ui/RadioButton';
import { RadioButtons } from '~/ui';
import styles from '../createAccount.css'; import styles from '../createAccount.css';
const TYPES = [
{
description: (
<FormattedMessage
id='createAccount.creationType.fromNew.description'
defaultMessage='Create an account by selecting your identity icon and specifying the password'
/>
),
label: (
<FormattedMessage
id='createAccount.creationType.fromNew.label'
defaultMessage='Create new account manually'
/>
),
key: 'fromNew'
},
{
description: (
<FormattedMessage
id='createAccount.creationType.fromPhrase.description'
defaultMessage='Recover an account by entering a previously stored recovery phrase and new password'
/>
),
label: (
<FormattedMessage
id='createAccount.creationType.fromPhrase.label'
defaultMessage='Recover account from recovery phrase'
/>
),
key: 'fromPhrase'
},
{
description: (
<FormattedMessage
id='createAccount.creationType.fromGeth.description'
defaultMessage='Import an accounts from the Geth keystore with the original password'
/>
),
label: (
<FormattedMessage
id='createAccount.creationType.fromGeth.label'
defaultMessage='Import accounts from Geth keystore'
/>
),
key: 'fromGeth'
},
{
description: (
<FormattedMessage
id='createAccount.creationType.fromJSON.description'
defaultMessage='Create an account by importing an industry-standard JSON keyfile'
/>
),
label: (
<FormattedMessage
id='createAccount.creationType.fromJSON.label'
defaultMessage='Import account from a backup JSON file'
/>
),
key: 'fromJSON'
},
{
description: (
<FormattedMessage
id='createAccount.creationType.fromPresale.description'
defaultMessage='Create an account by importing an Ethereum presale wallet file'
/>
),
label: (
<FormattedMessage
id='createAccount.creationType.fromPresale.label'
defaultMessage='Import account from an Ethereum pre-sale wallet'
/>
),
key: 'fromPresale'
},
{
description: (
<FormattedMessage
id='createAccount.creationType.fromRaw.description'
defaultMessage='Create an account by entering a previously backed-up raw private key'
/>
),
label: (
<FormattedMessage
id='createAccount.creationType.fromRaw.label'
defaultMessage='Import raw private key'
/>
),
key: 'fromRaw'
}
];
@observer @observer
export default class CreationType extends Component { export default class CreationType extends Component {
static propTypes = { static propTypes = {
@ -32,66 +126,12 @@ export default class CreationType extends Component {
return ( return (
<div className={ styles.spaced }> <div className={ styles.spaced }>
<RadioButtonGroup <RadioButtons
defaultSelected={ createType }
name='creationType' name='creationType'
onChange={ this.onChange } onChange={ this.onChange }
> value={ createType }
<RadioButton values={ TYPES }
label={ />
<FormattedMessage
id='createAccount.creationType.fromNew.label'
defaultMessage='Create new account manually'
/>
}
value='fromNew'
/>
<RadioButton
label={
<FormattedMessage
id='createAccount.creationType.fromPhrase.label'
defaultMessage='Recover account from recovery phrase'
/>
}
value='fromPhrase'
/>
<RadioButton
label={
<FormattedMessage
id='createAccount.creationType.fromGeth.label'
defaultMessage='Import accounts from Geth keystore'
/>
}
value='fromGeth'
/>
<RadioButton
label={
<FormattedMessage
id='createAccount.creationType.fromJSON.label'
defaultMessage='Import account from a backup JSON file'
/>
}
value='fromJSON'
/>
<RadioButton
label={
<FormattedMessage
id='createAccount.creationType.fromPresale.label'
defaultMessage='Import account from an Ethereum pre-sale wallet'
/>
}
value='fromPresale'
/>
<RadioButton
label={
<FormattedMessage
id='createAccount.creationType.fromRaw.label'
defaultMessage='Import raw private key'
/>
}
value='fromRaw'
/>
</RadioButtonGroup>
</div> </div>
); );
} }

View File

@ -50,7 +50,7 @@ describe('modals/CreateAccount/CreationType', () => {
beforeEach(() => { beforeEach(() => {
store.setCreateType(SELECT_TYPE); store.setCreateType(SELECT_TYPE);
selector = component.find('RadioButtonGroup'); selector = component.find('RadioButtons');
}); });
it('renders the selector', () => { it('renders the selector', () => {
@ -58,7 +58,7 @@ describe('modals/CreateAccount/CreationType', () => {
}); });
it('passes the store type to defaultSelected', () => { it('passes the store type to defaultSelected', () => {
expect(selector.props().defaultSelected).to.equal(SELECT_TYPE); expect(selector.props().value).to.equal(SELECT_TYPE);
}); });
}); });

View File

@ -59,7 +59,7 @@ describe('modals/CreateAccount/NewAccount', () => {
}); });
it('creates initial accounts', () => { it('creates initial accounts', () => {
expect(Object.keys(instance.state.accounts).length).to.equal(5); expect(Object.keys(instance.state.accounts).length).to.equal(7);
}); });
it('sets the initial selected value', () => { it('sets the initial selected value', () => {

View File

@ -15,6 +15,19 @@
/* along with Parity. If not, see <http://www.gnu.org/licenses/>. /* along with Parity. If not, see <http://www.gnu.org/licenses/>.
*/ */
.details {
text-align: center;
.infoForm {
background: rgba(0, 0, 0, 0.1);
padding: 1.5em;
}
.qr {
margin: 1.5em auto 0 auto;
}
}
.spaced { .spaced {
line-height: 1.618em; line-height: 1.618em;
} }
@ -39,7 +52,8 @@
} }
} }
.identities, .selector { .identities,
.selector {
display: flex; display: flex;
} }
@ -47,9 +61,10 @@
margin-top: 1.5em; margin-top: 1.5em;
} }
.identities .identity, .selector .button { .identities .identity,
flex: 0 1 18%; .selector .button {
width: 18% !important; flex: 0 1 12.5%;
width: 12.5% !important;
text-align: center; text-align: center;
cursor: pointer; cursor: pointer;
} }

View File

@ -22,7 +22,7 @@ import { bindActionCreators } from 'redux';
import { createIdentityImg } from '~/api/util/identity'; import { createIdentityImg } from '~/api/util/identity';
import { newError } from '~/redux/actions'; import { newError } from '~/redux/actions';
import { Button, Modal } from '~/ui'; import { Button, Portal } from '~/ui';
import { CancelIcon, CheckIcon, DoneIcon, NextIcon, PrevIcon, PrintIcon } from '~/ui/Icons'; import { CancelIcon, CheckIcon, DoneIcon, NextIcon, PrevIcon, PrintIcon } from '~/ui/Icons';
import ParityLogo from '~/../assets/images/parity-logo-black-no-text.svg'; import ParityLogo from '~/../assets/images/parity-logo-black-no-text.svg';
@ -86,10 +86,11 @@ class CreateAccount extends Component {
const { createType, stage } = this.store; const { createType, stage } = this.store;
return ( return (
<Modal <Portal
visible buttons={ this.renderDialogActions() }
actions={ this.renderDialogActions() } activeStep={ stage }
current={ stage } onClose={ this.onClose }
open
steps={ steps={
createType === 'fromNew' createType === 'fromNew'
? STAGE_NAMES ? STAGE_NAMES
@ -97,7 +98,7 @@ class CreateAccount extends Component {
} }
> >
{ this.renderPage() } { this.renderPage() }
</Modal> </Portal>
); );
} }

View File

@ -325,6 +325,8 @@ export default class Store {
this._api.parity.generateSecretPhrase(), this._api.parity.generateSecretPhrase(),
this._api.parity.generateSecretPhrase(), this._api.parity.generateSecretPhrase(),
this._api.parity.generateSecretPhrase(), this._api.parity.generateSecretPhrase(),
this._api.parity.generateSecretPhrase(),
this._api.parity.generateSecretPhrase(),
this._api.parity.generateSecretPhrase() this._api.parity.generateSecretPhrase()
]) ])
.then((phrases) => { .then((phrases) => {

View File

@ -580,9 +580,9 @@ describe('modals/CreateAccount/Store', () => {
}); });
}); });
it('returns a map of 5 accounts', () => { it('returns a map of 7 accounts', () => {
return store.createIdentities().then((accounts) => { return store.createIdentities().then((accounts) => {
expect(Object.keys(accounts).length).to.equal(5); expect(Object.keys(accounts).length).to.equal(7);
}); });
}); });

View File

@ -18,7 +18,7 @@ import { observer } from 'mobx-react';
import React, { Component, PropTypes } from 'react'; import React, { Component, PropTypes } from 'react';
import { FormattedMessage } from 'react-intl'; import { FormattedMessage } from 'react-intl';
import { Button, Modal, TxHash, BusyStep } from '~/ui'; import { BusyStep, Button, Portal, TxHash } from '~/ui';
import { CancelIcon, DoneIcon, NextIcon } from '~/ui/Icons'; import { CancelIcon, DoneIcon, NextIcon } from '~/ui/Icons';
import WalletType from './WalletType'; import WalletType from './WalletType';
@ -44,15 +44,16 @@ export default class CreateWallet extends Component {
if (rejected) { if (rejected) {
return ( return (
<Modal <Portal
visible buttons={ this.renderDialogActions() }
onClose={ this.onClose }
open
title={ title={
<FormattedMessage <FormattedMessage
id='createWallet.rejected.title' id='createWallet.rejected.title'
defaultMessage='rejected' defaultMessage='rejected'
/> />
} }
actions={ this.renderDialogActions() }
> >
<BusyStep <BusyStep
title={ title={
@ -68,20 +69,21 @@ export default class CreateWallet extends Component {
/> />
} }
/> />
</Modal> </Portal>
); );
} }
return ( return (
<Modal <Portal
visible activeStep={ stage }
actions={ this.renderDialogActions() } busySteps={ waiting }
current={ stage } buttons={ this.renderDialogActions() }
onClose={ this.onClose }
open
steps={ steps.map((step) => step.title) } steps={ steps.map((step) => step.title) }
waiting={ waiting }
> >
{ this.renderPage() } { this.renderPage() }
</Modal> </Portal>
); );
} }
@ -151,6 +153,7 @@ export default class CreateWallet extends Component {
const cancelBtn = ( const cancelBtn = (
<Button <Button
icon={ <CancelIcon /> } icon={ <CancelIcon /> }
key='cancel'
label={ label={
<FormattedMessage <FormattedMessage
id='createWallet.button.cancel' id='createWallet.button.cancel'
@ -164,6 +167,7 @@ export default class CreateWallet extends Component {
const closeBtn = ( const closeBtn = (
<Button <Button
icon={ <CancelIcon /> } icon={ <CancelIcon /> }
key='close'
label={ label={
<FormattedMessage <FormattedMessage
id='createWallet.button.close' id='createWallet.button.close'
@ -177,6 +181,7 @@ export default class CreateWallet extends Component {
const doneBtn = ( const doneBtn = (
<Button <Button
icon={ <DoneIcon /> } icon={ <DoneIcon /> }
key='done'
label={ label={
<FormattedMessage <FormattedMessage
id='createWallet.button.done' id='createWallet.button.done'
@ -190,6 +195,7 @@ export default class CreateWallet extends Component {
const sendingBtn = ( const sendingBtn = (
<Button <Button
icon={ <DoneIcon /> } icon={ <DoneIcon /> }
key='sending'
label={ label={
<FormattedMessage <FormattedMessage
id='createWallet.button.sending' id='createWallet.button.sending'
@ -203,6 +209,7 @@ export default class CreateWallet extends Component {
const nextBtn = ( const nextBtn = (
<Button <Button
icon={ <NextIcon /> } icon={ <NextIcon /> }
key='next'
label={ label={
<FormattedMessage <FormattedMessage
id='createWallet.button.next' id='createWallet.button.next'
@ -230,6 +237,7 @@ export default class CreateWallet extends Component {
<Button <Button
disabled={ hasErrors } disabled={ hasErrors }
icon={ <NextIcon /> } icon={ <NextIcon /> }
key='add'
label={ label={
<FormattedMessage <FormattedMessage
id='createWallet.button.add' id='createWallet.button.add'
@ -245,6 +253,7 @@ export default class CreateWallet extends Component {
<Button <Button
disabled={ hasErrors } disabled={ hasErrors }
icon={ <NextIcon /> } icon={ <NextIcon /> }
key='create'
label={ label={
<FormattedMessage <FormattedMessage
id='createWallet.button.create' id='createWallet.button.create'

View File

@ -41,7 +41,7 @@ function create () {
store = new Store(api); store = new Store(api);
} }
describe.only('modals/DappPermissions/store', () => { describe('modals/DappPermissions/store', () => {
beforeEach(() => { beforeEach(() => {
create(); create();
}); });

View File

@ -20,7 +20,7 @@ import React, { Component, PropTypes } from 'react';
import { FormattedMessage } from 'react-intl'; import { FormattedMessage } from 'react-intl';
import { connect } from 'react-redux'; import { connect } from 'react-redux';
import { BusyStep, Button, CompletedStep, CopyToClipboard, GasPriceEditor, IdentityIcon, Modal, TxHash, Warning } from '~/ui'; import { BusyStep, Button, CompletedStep, CopyToClipboard, GasPriceEditor, IdentityIcon, Portal, TxHash, Warning } from '~/ui';
import { CancelIcon, DoneIcon } from '~/ui/Icons'; import { CancelIcon, DoneIcon } from '~/ui/Icons';
import { ERRORS, validateAbi, validateCode, validateName } from '~/util/validation'; import { ERRORS, validateAbi, validateCode, validateName } from '~/util/validation';
@ -166,21 +166,22 @@ class DeployContract extends Component {
: null; : null;
return ( return (
<Modal <Portal
actions={ this.renderDialogActions() } buttons={ this.renderDialogActions() }
current={ realStep } activeStep={ realStep }
busySteps={ waiting }
onClose={ this.onClose }
open
steps={ steps={
realSteps realSteps
? realSteps.map((s) => s.title) ? realSteps.map((s) => s.title)
: null : null
} }
title={ title } title={ title }
visible
waiting={ waiting }
> >
{ this.renderExceptionWarning() } { this.renderExceptionWarning() }
{ this.renderStep() } { this.renderStep() }
</Modal> </Portal>
); );
} }
@ -207,6 +208,7 @@ class DeployContract extends Component {
const cancelBtn = ( const cancelBtn = (
<Button <Button
icon={ <CancelIcon /> } icon={ <CancelIcon /> }
key='cancel'
label={ label={
<FormattedMessage <FormattedMessage
id='deployContract.button.cancel' id='deployContract.button.cancel'
@ -220,6 +222,7 @@ class DeployContract extends Component {
const closeBtn = ( const closeBtn = (
<Button <Button
icon={ <CancelIcon /> } icon={ <CancelIcon /> }
key='close'
label={ label={
<FormattedMessage <FormattedMessage
id='deployContract.button.close' id='deployContract.button.close'
@ -233,6 +236,7 @@ class DeployContract extends Component {
const closeBtnOk = ( const closeBtnOk = (
<Button <Button
icon={ <DoneIcon /> } icon={ <DoneIcon /> }
key='done'
label={ label={
<FormattedMessage <FormattedMessage
id='deployContract.button.done' id='deployContract.button.done'
@ -253,6 +257,7 @@ class DeployContract extends Component {
cancelBtn, cancelBtn,
<Button <Button
disabled={ !isValid } disabled={ !isValid }
key='next'
icon={ icon={
<IdentityIcon <IdentityIcon
address={ fromAddress } address={ fromAddress }
@ -279,6 +284,7 @@ class DeployContract extends Component {
button button
/> />
} }
key='create'
label={ label={
<FormattedMessage <FormattedMessage
id='deployContract.button.create' id='deployContract.button.create'

View File

@ -21,7 +21,7 @@ import { connect } from 'react-redux';
import { bindActionCreators } from 'redux'; import { bindActionCreators } from 'redux';
import { newError } from '~/redux/actions'; import { newError } from '~/redux/actions';
import { Button, Form, Input, InputChip, Modal } from '~/ui'; import { Button, Form, Input, InputChip, Portal } from '~/ui';
import { CancelIcon, SaveIcon } from '~/ui/Icons'; import { CancelIcon, SaveIcon } from '~/ui/Icons';
import Store from './store'; import Store from './store';
@ -44,15 +44,16 @@ class EditMeta extends Component {
const { description, name, nameError, tags } = this.store; const { description, name, nameError, tags } = this.store;
return ( return (
<Modal <Portal
actions={ this.renderActions() } buttons={ this.renderActions() }
onClose={ this.onClose }
open
title={ title={
<FormattedMessage <FormattedMessage
id='editMeta.title' id='editMeta.title'
defaultMessage='edit metadata' defaultMessage='edit metadata'
/> />
} }
visible
> >
<Form> <Form>
<Input <Input
@ -101,7 +102,7 @@ class EditMeta extends Component {
tokens={ tags.slice() } tokens={ tags.slice() }
/> />
</Form> </Form>
</Modal> </Portal>
); );
} }
@ -112,12 +113,14 @@ class EditMeta extends Component {
<Button <Button
label='Cancel' label='Cancel'
icon={ <CancelIcon /> } icon={ <CancelIcon /> }
onClick={ this.props.onClose } key='cancel'
onClick={ this.onClose }
/>, />,
<Button <Button
disabled={ hasError } disabled={ hasError }
label='Save' label='Save'
icon={ <SaveIcon /> } icon={ <SaveIcon /> }
key='save'
onClick={ this.onSave } onClick={ this.onSave }
/> />
]; ];
@ -150,6 +153,10 @@ class EditMeta extends Component {
); );
} }
onClose = () => {
this.props.onClose();
}
onSave = () => { onSave = () => {
if (this.store.hasError) { if (this.store.hasError) {
return; return;
@ -157,7 +164,7 @@ class EditMeta extends Component {
return this.store return this.store
.save() .save()
.then(() => this.props.onClose()) .then(this.onClose)
.catch((error) => { .catch((error) => {
this.props.newError(error); this.props.newError(error);
}); });

View File

@ -21,7 +21,7 @@ import { FormattedMessage } from 'react-intl';
import { connect } from 'react-redux'; import { connect } from 'react-redux';
import { toWei } from '~/api/util/wei'; import { toWei } from '~/api/util/wei';
import { BusyStep, Button, CompletedStep, GasPriceEditor, IdentityIcon, Modal, TxHash, Warning } from '~/ui'; import { BusyStep, Button, CompletedStep, GasPriceEditor, IdentityIcon, Portal, TxHash, Warning } from '~/ui';
import { CancelIcon, DoneIcon, NextIcon, PrevIcon } from '~/ui/Icons'; import { CancelIcon, DoneIcon, NextIcon, PrevIcon } from '~/ui/Icons';
import { MAX_GAS_ESTIMATION } from '~/util/constants'; import { MAX_GAS_ESTIMATION } from '~/util/constants';
import { validateAddress, validateUint } from '~/util/validation'; import { validateAddress, validateUint } from '~/util/validation';
@ -131,21 +131,22 @@ class ExecuteContract extends Component {
} }
return ( return (
<Modal <Portal
actions={ this.renderDialogActions() } activeStep={ step }
busy={ sending } buttons={ this.renderDialogActions() }
current={ step } busySteps={
steps={ steps }
visible
waiting={
advancedOptions advancedOptions
? [STEP_BUSY] ? [STEP_BUSY]
: [STEP_BUSY_OR_ADVANCED] : [STEP_BUSY_OR_ADVANCED]
} }
busy={ sending }
onClose={ this.onClose }
open
steps={ steps }
> >
{ this.renderExceptionWarning() } { this.renderExceptionWarning() }
{ this.renderStep() } { this.renderStep() }
</Modal> </Portal>
); );
} }
@ -163,7 +164,7 @@ class ExecuteContract extends Component {
} }
renderDialogActions () { renderDialogActions () {
const { onClose, fromAddress } = this.props; const { fromAddress } = this.props;
const { advancedOptions, sending, step, fromAddressError, valuesError } = this.state; const { advancedOptions, sending, step, fromAddressError, valuesError } = this.state;
const hasError = fromAddressError || valuesError.find((error) => error); const hasError = fromAddressError || valuesError.find((error) => error);
@ -177,7 +178,7 @@ class ExecuteContract extends Component {
/> />
} }
icon={ <CancelIcon /> } icon={ <CancelIcon /> }
onClick={ onClose } onClick={ this.onClose }
/> />
); );
const postBtn = ( const postBtn = (
@ -248,7 +249,7 @@ class ExecuteContract extends Component {
/> />
} }
icon={ <DoneIcon /> } icon={ <DoneIcon /> }
onClick={ onClose } onClick={ this.onClose }
/> />
]; ];
} }
@ -462,6 +463,10 @@ class ExecuteContract extends Component {
step: this.state.step - 1 step: this.state.step - 1
}); });
} }
onClose = () => {
this.props.onClose();
}
} }
function mapStateToProps (initState, initProps) { function mapStateToProps (initState, initProps) {

View File

@ -15,12 +15,26 @@
// along with Parity. If not, see <http://www.gnu.org/licenses/>. // along with Parity. If not, see <http://www.gnu.org/licenses/>.
import React, { Component } from 'react'; import React, { Component } from 'react';
import { FormattedMessage } from 'react-intl';
import styles from '../firstRun.css';
export default class Completed extends Component { export default class Completed extends Component {
render () { render () {
return ( return (
<div> <div className={ styles.completed }>
<p>Your node setup has been completed successfully and you are ready to use the application. Next you will receive a walk-through of the available functions and the general application interface to get you up and running in record time.</p> <p>
<FormattedMessage
id='firstRun.completed.congrats'
defaultMessage='Congratulations! Your node setup has been completed successfully and you are ready to use the application.'
/>
</p>
<p>
<FormattedMessage
id='firstRun.completed.next'
defaultMessage='Next you will receive a walk-through of the available functions and the general application interface to get you up and running in record time.'
/>
</p>
</div> </div>
); );
} }

View File

@ -15,9 +15,10 @@
// along with Parity. If not, see <http://www.gnu.org/licenses/>. // along with Parity. If not, see <http://www.gnu.org/licenses/>.
import React, { Component, PropTypes } from 'react'; import React, { Component, PropTypes } from 'react';
import { FormattedMessage } from 'react-intl';
import { Checkbox } from 'material-ui'; import { Checkbox } from 'material-ui';
import styles from './tnc.css'; import styles from '../firstRun.css';
export default class TnC extends Component { export default class TnC extends Component {
static propTypes = { static propTypes = {
@ -29,7 +30,7 @@ export default class TnC extends Component {
const { hasAccepted, onAccept } = this.props; const { hasAccepted, onAccept } = this.props;
return ( return (
<div className={ styles.body }> <div className={ styles.tnc }>
<h1>SECURITY WARNINGS</h1> <h1>SECURITY WARNINGS</h1>
<ul> <ul>
<li>You are responsible for your own computer security. If your machine is compromised you will lose your ether, access to any contracts and maybe more.</li> <li>You are responsible for your own computer security. If your machine is compromised you will lose your ether, access to any contracts and maybe more.</li>
@ -165,7 +166,12 @@ export default class TnC extends Component {
<Checkbox <Checkbox
className={ styles.accept } className={ styles.accept }
label='I accept these terms and conditions' label={
<FormattedMessage
id='firstRun.tnc.accept'
defaultMessage='I accept these terms and conditions'
/>
}
checked={ hasAccepted } checked={ hasAccepted }
onCheck={ onAccept } onCheck={ onAccept }
/> />

View File

@ -15,12 +15,15 @@
// along with Parity. If not, see <http://www.gnu.org/licenses/>. // along with Parity. If not, see <http://www.gnu.org/licenses/>.
import React, { Component } from 'react'; import React, { Component } from 'react';
import { FormattedMessage } from 'react-intl';
import imagesEthcore from '../../../../assets/images/parity-logo-white.svg'; import imagesEthcore from '~/../assets/images/parity-logo-white.svg';
import styles from '../firstRun.css';
const LOGO_STYLE = { const LOGO_STYLE = {
float: 'right', float: 'right',
width: '25%', maxWidth: '10em',
height: 'auto', height: 'auto',
margin: '0 1.5em' margin: '0 1.5em'
}; };
@ -28,15 +31,52 @@ const LOGO_STYLE = {
export default class FirstRun extends Component { export default class FirstRun extends Component {
render () { render () {
return ( return (
<div> <div className={ styles.welcome }>
<img <img
src={ imagesEthcore } src={ imagesEthcore }
alt='Ethcore Ltd.' alt='Ethcore Ltd.'
style={ LOGO_STYLE } style={ LOGO_STYLE }
/> />
<p>Welcome to <strong>Parity</strong>, the fastest and simplest way to run your node.</p> <p>
<p>The next few steps will guide you through the process of setting up you Parity instance and the associated account.</p> <FormattedMessage
<p>Click <strong>Next</strong> to continue your journey.</p> id='firstRun.welcome.greeting'
defaultMessage='Welcome to Parity, the fastest and simplest way to run your node.'
/>
</p>
<p>
<FormattedMessage
id='firstRun.welcome.description'
defaultMessage='As part of a new installation, the next few steps will guide you through the process of setting up you Parity instance and your associated accounts. Our aim is to make it as simple as possible and to get you up and running in record-time, so please bear with us. Once completed you will have -'
/>
</p>
<p>
<ul>
<li>
<FormattedMessage
id='firstRun.welcome.step.privacy'
defaultMessage='Understood our privacy policy & terms of operation'
/>
</li>
<li>
<FormattedMessage
id='firstRun.welcome.step.account'
defaultMessage='Created your first Parity account'
/>
</li>
<li>
<FormattedMessage
id='firstRun.welcome.step.recovery'
defaultMessage='Have the ability to recover your account'
/>
</li>
</ul>
</p>
<p>
<FormattedMessage
id='firstRun.welcome.next'
defaultMessage='Click Next to continue your journey.'
/>
</p>
</div> </div>
); );
} }

View File

@ -15,15 +15,33 @@
/* along with Parity. If not, see <http://www.gnu.org/licenses/>. /* along with Parity. If not, see <http://www.gnu.org/licenses/>.
*/ */
.body { .completed,
.welcome {
p {
line-height: 1.5em;
}
ul {
background: rgba(0, 0, 0, 0.1);
margin-right: 12em;
padding: 1em 3em;
li {
line-height: 2em;
}
}
}
.tnc {
overflow-y: auto; overflow-y: auto;
}
.body p, .body li { p,
opacity: 0.8; li {
line-height: 1.5em; opacity: 0.8;
} line-height: 1.5em;
}
.accept { .accept {
margin: 1.5em 0; margin: 1.5em 0;
}
} }

View File

@ -23,7 +23,7 @@ import { bindActionCreators } from 'redux';
import ParityLogo from '~/../assets/images/parity-logo-black-no-text.svg'; import ParityLogo from '~/../assets/images/parity-logo-black-no-text.svg';
import { createIdentityImg } from '~/api/util/identity'; import { createIdentityImg } from '~/api/util/identity';
import { newError } from '~/redux/actions'; import { newError } from '~/redux/actions';
import { Button, Modal } from '~/ui'; import { Button, Portal } from '~/ui';
import { CheckIcon, DoneIcon, NextIcon, PrintIcon } from '~/ui/Icons'; import { CheckIcon, DoneIcon, NextIcon, PrintIcon } from '~/ui/Icons';
import { NewAccount, AccountDetails } from '../CreateAccount'; import { NewAccount, AccountDetails } from '../CreateAccount';
@ -93,14 +93,15 @@ class FirstRun extends Component {
} }
return ( return (
<Modal <Portal
actions={ this.renderDialogActions() } buttons={ this.renderDialogActions() }
current={ stage } activeStep={ stage }
hideClose
steps={ STAGE_NAMES } steps={ STAGE_NAMES }
visible open
> >
{ this.renderStage() } { this.renderStage() }
</Modal> </Portal>
); );
} }

View File

@ -20,7 +20,7 @@ import moment from 'moment';
import React, { Component, PropTypes } from 'react'; import React, { Component, PropTypes } from 'react';
import { FormattedMessage } from 'react-intl'; import { FormattedMessage } from 'react-intl';
import { Button, Modal } from '~/ui'; import { Button, Portal } from '~/ui';
import Editor from '~/ui/Editor'; import Editor from '~/ui/Editor';
import { CancelIcon, CheckIcon, DeleteIcon } from '~/ui/Icons'; import { CancelIcon, CheckIcon, DeleteIcon } from '~/ui/Icons';
@ -55,8 +55,10 @@ export default class LoadContract extends Component {
const { deleteRequest } = this.state; const { deleteRequest } = this.state;
return ( return (
<Modal <Portal
actions={ this.renderDialogActions() } buttons={ this.renderDialogActions() }
onClose={ this.onClose }
open
title={ title={
deleteRequest deleteRequest
? ( ? (
@ -72,10 +74,9 @@ export default class LoadContract extends Component {
/> />
) )
} }
visible
> >
{ this.renderBody() } { this.renderBody() }
</Modal> </Portal>
); );
} }

View File

@ -78,6 +78,6 @@
.form { .form {
margin-top: 0; margin-top: 0;
padding: 0 0.5rem 1rem; padding: 0.75rem 1.5rem 1.5rem 1.5rem;
background-color: rgba(255, 255, 255, 0.05); background-color: rgba(255, 255, 255, 0.05);
} }

View File

@ -23,7 +23,7 @@ import { connect } from 'react-redux';
import { bindActionCreators } from 'redux'; import { bindActionCreators } from 'redux';
import { newError, openSnackbar } from '~/redux/actions'; import { newError, openSnackbar } from '~/redux/actions';
import { Button, Modal, IdentityName, IdentityIcon } from '~/ui'; import { Button, IdentityName, IdentityIcon, Portal } from '~/ui';
import PasswordStrength from '~/ui/Form/PasswordStrength'; import PasswordStrength from '~/ui/Form/PasswordStrength';
import Form, { Input } from '~/ui/Form'; import Form, { Input } from '~/ui/Form';
import { CancelIcon, CheckIcon, SendIcon } from '~/ui/Icons'; import { CancelIcon, CheckIcon, SendIcon } from '~/ui/Icons';
@ -38,7 +38,7 @@ const MSG_FAILURE_STYLE = {
backgroundColor: 'rgba(229, 115, 115, 0.75)' backgroundColor: 'rgba(229, 115, 115, 0.75)'
}; };
const TABS_INKBAR_STYLE = { const TABS_INKBAR_STYLE = {
backgroundColor: 'rgba(255, 255, 255, 0.55)' backgroundColor: 'rgb(0, 151, 167)' // 'rgba(255, 255, 255, 0.55)'
}; };
const TABS_ITEM_STYLE = { const TABS_ITEM_STYLE = {
backgroundColor: 'rgba(255, 255, 255, 0.05)' backgroundColor: 'rgba(255, 255, 255, 0.05)'
@ -61,20 +61,21 @@ class PasswordManager extends Component {
render () { render () {
return ( return (
<Modal <Portal
actions={ this.renderDialogActions() } buttons={ this.renderDialogActions() }
onClose={ this.onClose }
open
title={ title={
<FormattedMessage <FormattedMessage
id='passwordChange.title' id='passwordChange.title'
defaultMessage='Password Manager' defaultMessage='Password Manager'
/> />
} }
visible
> >
{ this.renderAccount() } { this.renderAccount() }
{ this.renderPage() } { this.renderPage() }
{ this.renderMessage() } { this.renderMessage() }
</Modal> </Portal>
); );
} }
@ -273,7 +274,6 @@ class PasswordManager extends Component {
renderDialogActions () { renderDialogActions () {
const { actionTab, busy, isRepeatValid } = this.store; const { actionTab, busy, isRepeatValid } = this.store;
const { onClose } = this.props;
const cancelBtn = ( const cancelBtn = (
<Button <Button
@ -285,7 +285,7 @@ class PasswordManager extends Component {
defaultMessage='Cancel' defaultMessage='Cancel'
/> />
} }
onClick={ onClose } onClick={ this.onClose }
/> />
); );
@ -367,6 +367,10 @@ class PasswordManager extends Component {
this.store.setValidatePassword(password); this.store.setValidatePassword(password);
} }
onClose = () => {
this.props.onClose();
}
changePassword = () => { changePassword = () => {
return this.store return this.store
.changePassword() .changePassword()
@ -380,7 +384,7 @@ class PasswordManager extends Component {
/> />
</div> </div>
); );
this.props.onClose(); this.onClose();
} }
}) })
.catch((error) => { .catch((error) => {

View File

@ -19,7 +19,7 @@ import React, { Component, PropTypes } from 'react';
import SaveIcon from 'material-ui/svg-icons/content/save'; import SaveIcon from 'material-ui/svg-icons/content/save';
import ContentClear from 'material-ui/svg-icons/content/clear'; import ContentClear from 'material-ui/svg-icons/content/clear';
import { Button, Modal, Form, Input } from '~/ui'; import { Button, Form, Input, Portal } from '~/ui';
import Editor from '~/ui/Editor'; import Editor from '~/ui/Editor';
import { ERRORS, validateName } from '~/util/validation'; import { ERRORS, validateName } from '~/util/validation';
@ -42,10 +42,11 @@ export default class SaveContract extends Component {
const { name, nameError } = this.state; const { name, nameError } = this.state;
return ( return (
<Modal <Portal
buttons={ this.renderDialogActions() }
onClose={ this.onClose }
open
title='save contract' title='save contract'
actions={ this.renderDialogActions() }
visible
> >
<div> <div>
<Form> <Form>
@ -60,11 +61,11 @@ export default class SaveContract extends Component {
<Editor <Editor
className={ styles.source } className={ styles.source }
value={ sourcecode } value={ sourcecode }
maxLines={ 20 } maxLines={ 25 }
readOnly readOnly
/> />
</div> </div>
</Modal> </Portal>
); );
} }
@ -72,6 +73,7 @@ export default class SaveContract extends Component {
const cancelBtn = ( const cancelBtn = (
<Button <Button
icon={ <ContentClear /> } icon={ <ContentClear /> }
key='cancel'
label='Cancel' label='Cancel'
onClick={ this.onClose } onClick={ this.onClose }
/> />
@ -80,6 +82,7 @@ export default class SaveContract extends Component {
const confirmBtn = ( const confirmBtn = (
<Button <Button
icon={ <SaveIcon /> } icon={ <SaveIcon /> }
key='save'
label='Save' label='Save'
disabled={ !!this.state.nameError } disabled={ !!this.state.nameError }
onClick={ this.onSave } onClick={ this.onSave }

View File

@ -37,25 +37,23 @@
} }
.shapeshift { .shapeshift {
position: absolute;
bottom: 0.5em;
left: 1em;
cursor: pointer; cursor: pointer;
left: 1.5em;
outline: none; outline: none;
} position: absolute;
.shapeshift img { img {
height: 28px; height: 28px;
}
} }
.info, .busy { .info, .busy {
} }
.center { .center {
} div {
text-align: center;
.center div { }
text-align: center;
} }
.error { .error {
@ -74,9 +72,11 @@
color: #aaa; color: #aaa;
} }
.price div { .price {
text-align: center; div {
font-size: small; text-align: center;
font-size: small;
}
} }
.empty { .empty {

View File

@ -19,7 +19,7 @@ import React, { Component, PropTypes } from 'react';
import { FormattedMessage } from 'react-intl'; import { FormattedMessage } from 'react-intl';
import shapeshiftLogo from '~/../assets/images/shapeshift-logo.png'; import shapeshiftLogo from '~/../assets/images/shapeshift-logo.png';
import { Button, IdentityIcon, Modal } from '~/ui'; import { Button, IdentityIcon, Portal } from '~/ui';
import { CancelIcon, DoneIcon } from '~/ui/Icons'; import { CancelIcon, DoneIcon } from '~/ui/Icons';
import AwaitingDepositStep from './AwaitingDepositStep'; import AwaitingDepositStep from './AwaitingDepositStep';
@ -81,9 +81,15 @@ export default class Shapeshift extends Component {
const { error, stage } = this.store; const { error, stage } = this.store;
return ( return (
<Modal <Portal
actions={ this.renderDialogActions() } activeStep={ stage }
current={ stage } busySteps={ [
STAGE_WAIT_DEPOSIT,
STAGE_WAIT_EXCHANGE
] }
buttons={ this.renderDialogActions() }
onClose={ this.onClose }
open
steps={ steps={
error error
? null ? null
@ -94,14 +100,9 @@ export default class Shapeshift extends Component {
? ERROR_TITLE ? ERROR_TITLE
: null : null
} }
visible
waiting={ [
STAGE_WAIT_DEPOSIT,
STAGE_WAIT_EXCHANGE
] }
> >
{ this.renderPage() } { this.renderPage() }
</Modal> </Portal>
); );
} }
@ -110,13 +111,19 @@ export default class Shapeshift extends Component {
const { coins, error, hasAcceptedTerms, stage } = this.store; const { coins, error, hasAcceptedTerms, stage } = this.store;
const logo = ( const logo = (
<a href='http://shapeshift.io' target='_blank' className={ styles.shapeshift }> <a
className={ styles.shapeshift }
href='http://shapeshift.io'
key='logo'
target='_blank'
>
<img src={ shapeshiftLogo } /> <img src={ shapeshiftLogo } />
</a> </a>
); );
const cancelBtn = ( const cancelBtn = (
<Button <Button
icon={ <CancelIcon /> } icon={ <CancelIcon /> }
key='cancel'
label={ label={
<FormattedMessage <FormattedMessage
id='shapeshift.button.cancel' id='shapeshift.button.cancel'
@ -147,6 +154,7 @@ export default class Shapeshift extends Component {
button button
/> />
} }
key='shift'
label={ label={
<FormattedMessage <FormattedMessage
id='shapeshift.button.shift' id='shapeshift.button.shift'
@ -169,6 +177,7 @@ export default class Shapeshift extends Component {
logo, logo,
<Button <Button
icon={ <DoneIcon /> } icon={ <DoneIcon /> }
key='done'
label={ label={
<FormattedMessage <FormattedMessage
id='shapeshift.button.done' id='shapeshift.button.done'

View File

@ -21,7 +21,7 @@ import { bindActionCreators } from 'redux';
import { observer } from 'mobx-react'; import { observer } from 'mobx-react';
import { pick } from 'lodash'; import { pick } from 'lodash';
import { BusyStep, CompletedStep, Button, IdentityIcon, Input, Modal, TxHash, Warning } from '~/ui'; import { BusyStep, CompletedStep, Button, IdentityIcon, Input, Portal, TxHash, Warning } from '~/ui';
import { newError } from '~/ui/Errors/actions'; import { newError } from '~/ui/Errors/actions';
import { CancelIcon, DoneIcon, NextIcon, PrevIcon } from '~/ui/Icons'; import { CancelIcon, DoneIcon, NextIcon, PrevIcon } from '~/ui/Icons';
import { nullableProptype } from '~/util/proptypes'; import { nullableProptype } from '~/util/proptypes';
@ -60,21 +60,22 @@ class Transfer extends Component {
const { stage, extras, steps } = this.store; const { stage, extras, steps } = this.store;
return ( return (
<Modal <Portal
actions={ this.renderDialogActions() } activeStep={ stage }
current={ stage } busySteps={
steps={ steps }
waiting={
extras extras
? [STEP_BUSY] ? [STEP_BUSY]
: [STEP_ADVANCED_OR_BUSY] : [STEP_ADVANCED_OR_BUSY]
} }
visible buttons={ this.renderDialogActions() }
onClose={ this.handleClose }
open
steps={ steps }
> >
{ this.renderExceptionWarning() } { this.renderExceptionWarning() }
{ this.renderWalletWarning() } { this.renderWalletWarning() }
{ this.renderPage() } { this.renderPage() }
</Modal> </Portal>
); );
} }
@ -252,6 +253,7 @@ class Transfer extends Component {
const cancelBtn = ( const cancelBtn = (
<Button <Button
icon={ <CancelIcon /> } icon={ <CancelIcon /> }
key='cancel'
label='Cancel' label='Cancel'
onClick={ this.handleClose } onClick={ this.handleClose }
/> />
@ -260,6 +262,7 @@ class Transfer extends Component {
<Button <Button
disabled={ !this.store.isValid } disabled={ !this.store.isValid }
icon={ <NextIcon /> } icon={ <NextIcon /> }
key='next'
label='Next' label='Next'
onClick={ this.store.onNext } onClick={ this.store.onNext }
/> />
@ -267,6 +270,7 @@ class Transfer extends Component {
const prevBtn = ( const prevBtn = (
<Button <Button
icon={ <PrevIcon /> } icon={ <PrevIcon /> }
key='back'
label='Back' label='Back'
onClick={ this.store.onPrev } onClick={ this.store.onPrev }
/> />
@ -275,6 +279,7 @@ class Transfer extends Component {
<Button <Button
disabled={ !this.store.isValid || sending } disabled={ !this.store.isValid || sending }
icon={ <IdentityIcon address={ account.address } button /> } icon={ <IdentityIcon address={ account.address } button /> }
key='send'
label='Send' label='Send'
onClick={ this.store.onSend } onClick={ this.store.onSend }
/> />
@ -282,6 +287,7 @@ class Transfer extends Component {
const doneBtn = ( const doneBtn = (
<Button <Button
icon={ <DoneIcon /> } icon={ <DoneIcon /> }
key='close'
label='Close' label='Close'
onClick={ this.handleClose } onClick={ this.handleClose }
/> />

View File

@ -19,9 +19,23 @@
padding-top: 1.25em; padding-top: 1.25em;
} }
.infoStep { .step {
div+div { display: flex;
padding-top: 1.25em; flex-direction: row;
justify-content: flex-start;
.icon {
height: 10em !important;
opacity: 0.5;
width: 10em !important;
}
.text {
background: rgba(0, 0, 0, 0.25);
line-height: 1.5em;
margin-left: 3em;
padding: 2em;
width: 100%;
} }
} }

View File

@ -18,9 +18,8 @@ import { observer } from 'mobx-react';
import React, { Component, PropTypes } from 'react'; import React, { Component, PropTypes } from 'react';
import { FormattedMessage } from 'react-intl'; import { FormattedMessage } from 'react-intl';
import { Button } from '~/ui'; import { Button, Portal } from '~/ui';
import { CancelIcon, DoneIcon, NextIcon } from '~/ui/Icons'; import { CancelIcon, DoneIcon, ErrorIcon, NextIcon, UpdateIcon, UpdateWaitIcon } from '~/ui/Icons';
import Modal, { Busy, Completed } from '~/ui/Modal';
import { STEP_COMPLETED, STEP_ERROR, STEP_INFO, STEP_UPDATING } from './store'; import { STEP_COMPLETED, STEP_ERROR, STEP_INFO, STEP_UPDATING } from './store';
import styles from './upgradeParity.css'; import styles from './upgradeParity.css';
@ -43,9 +42,12 @@ export default class UpgradeParity extends Component {
} }
return ( return (
<Modal <Portal
actions={ this.renderActions() } activeStep={ store.step }
current={ store.step } busySteps={ [ 1 ] }
buttons={ this.renderActions() }
onClose={ this.onClose }
open
steps={ [ steps={ [
<FormattedMessage <FormattedMessage
id='upgradeParity.step.info' id='upgradeParity.step.info'
@ -57,7 +59,7 @@ export default class UpgradeParity extends Component {
id='upgradeParity.step.updating' id='upgradeParity.step.updating'
defaultMessage='upgrading parity' defaultMessage='upgrading parity'
/>, />,
store.step === STEP_ERROR store.error
? <FormattedMessage ? <FormattedMessage
id='upgradeParity.step.error' id='upgradeParity.step.error'
key='error' key='error'
@ -69,10 +71,9 @@ export default class UpgradeParity extends Component {
defaultMessage='upgrade completed' defaultMessage='upgrade completed'
/> />
] } ] }
visible
> >
{ this.renderStep() } { this.renderStep() }
</Modal> </Portal>
); );
} }
@ -89,7 +90,7 @@ export default class UpgradeParity extends Component {
defaultMessage='close' defaultMessage='close'
/> />
} }
onClick={ store.closeModal } onClick={ this.onClose }
/>; />;
const doneButton = const doneButton =
<Button <Button
@ -101,7 +102,7 @@ export default class UpgradeParity extends Component {
defaultMessage='done' defaultMessage='done'
/> />
} }
onClick={ store.closeModal } onClick={ this.onDone }
/>; />;
switch (store.step) { switch (store.step) {
@ -116,7 +117,7 @@ export default class UpgradeParity extends Component {
defaultMessage='upgrade now' defaultMessage='upgrade now'
/> />
} }
onClick={ store.upgradeNow } onClick={ this.onUpgrade }
/>, />,
closeButton closeButton
]; ];
@ -136,7 +137,6 @@ export default class UpgradeParity extends Component {
renderStep () { renderStep () {
const { store } = this.props; const { store } = this.props;
const currentversion = this.formatVersion(store); const currentversion = this.formatVersion(store);
const newversion = store.upgrading const newversion = store.upgrading
? this.formatVersion(store.upgrading) ? this.formatVersion(store.upgrading)
@ -144,70 +144,121 @@ export default class UpgradeParity extends Component {
switch (store.step) { switch (store.step) {
case STEP_INFO: case STEP_INFO:
return ( return this.renderStepInfo(newversion, currentversion);
<div className={ styles.infoStep }>
<div>
<FormattedMessage
id='upgradeParity.info.upgrade'
defaultMessage='A new version of Parity, version {newversion} is available as an upgrade from your current version {currentversion}'
values={ {
currentversion: <div className={ styles.version }>{ currentversion }</div>,
newversion: <div className={ styles.version }>{ newversion }</div>
} }
/>
</div>
{ this.renderConsensusInfo() }
</div>
);
case STEP_UPDATING: case STEP_UPDATING:
return ( return this.renderStepBusy(newversion);
<Busy
title={
<FormattedMessage
id='upgradeParity.busy'
defaultMessage='Your upgrade to Parity {newversion} is currently in progress'
values={ {
newversion: <div className={ styles.version }>{ newversion }</div>
} }
/>
}
/>
);
case STEP_COMPLETED: case STEP_COMPLETED:
case STEP_ERROR: case STEP_ERROR:
if (store.error) { return store.error
return ( ? this.renderStepError(newversion)
<Completed> : this.renderStepCompleted(newversion);
<div> }
}
renderStepBusy (newversion) {
return (
<div className={ styles.step }>
<UpdateWaitIcon className={ styles.icon } />
<div className={ styles.text }>
<FormattedMessage
id='upgradeParity.busy'
defaultMessage='Your upgrade to Parity {newversion} is currently in progress. Please wait until the process completes.'
values={ {
newversion: <div className={ styles.version }>{ newversion }</div>
} }
/>
</div>
</div>
);
}
renderStepCompleted (newversion) {
return (
<div className={ styles.step }>
<DoneIcon className={ styles.icon } />
<div className={ styles.text }>
<FormattedMessage
id='upgradeParity.completed'
defaultMessage='Your upgrade to Parity {newversion} has been successfully completed. Click "done" to automatically reload the application.'
values={ {
newversion: <div className={ styles.version }>{ newversion }</div>
} }
/>
</div>
</div>
);
}
renderStepError (newversion) {
const { store } = this.props;
return (
<div className={ styles.step }>
<ErrorIcon className={ styles.icon } />
<div className={ styles.text }>
<FormattedMessage
id='upgradeParity.failed'
defaultMessage='Your upgrade to Parity {newversion} has failed with an error.'
values={ {
newversion: <div className={ styles.version }>{ newversion }</div>
} }
/>
<div className={ styles.error }>
{ store.error.message }
</div>
</div>
</div>
);
}
renderStepInfo (newversion, currentversion) {
return (
<div className={ styles.step }>
<UpdateIcon className={ styles.icon } />
<div className={ styles.text }>
<div>
<FormattedMessage
id='upgradeParity.info.welcome'
defaultMessage='Welcome to the Parity upgrade wizard, allowing you a completely seamless upgrade experience to the next version of Parity.'
/>
</div>
<div>
<ul>
<li>
<FormattedMessage <FormattedMessage
id='upgradeParity.failed' id='upgradeParity.info.currentVersion'
defaultMessage='Your upgrade to Parity {newversion} has failed with an error.' defaultMessage='You are currently running {currentversion}'
values={ { values={ {
currentversion: <div className={ styles.version }>{ currentversion }</div>
} }
/>
</li>
<li>
<FormattedMessage
id='upgradeParity.info.upgrade'
defaultMessage='An upgrade to version {newversion} is available'
values={ {
currentversion: <div className={ styles.version }>{ currentversion }</div>,
newversion: <div className={ styles.version }>{ newversion }</div> newversion: <div className={ styles.version }>{ newversion }</div>
} } } }
/> />
</div> </li>
<div className={ styles.error }> <li>
{ store.error.message } { this.renderConsensusInfo() }
</div> </li>
</Completed> </ul>
); </div>
} <div>
return (
<Completed>
<FormattedMessage <FormattedMessage
id='upgradeParity.completed' id='upgradeParity.info.next'
defaultMessage='Your upgrade to Parity {newversion} has been successfully completed.' defaultMessage='Proceed with "upgrade now" to start your Parity upgrade.'
values={ {
newversion: <div className={ styles.version }>{ newversion }</div>
} }
/> />
</Completed> </div>
); </div>
} </div>
);
} }
renderConsensusInfo () { renderConsensusInfo () {
@ -217,47 +268,39 @@ export default class UpgradeParity extends Component {
if (consensusCapability) { if (consensusCapability) {
if (consensusCapability === 'capable') { if (consensusCapability === 'capable') {
return ( return (
<div> <FormattedMessage
<FormattedMessage id='upgradeParity.consensus.capable'
id='upgradeParity.consensus.capable' defaultMessage='Your current Parity version is capable of handling the network requirements.'
defaultMessage='Your current Parity version is capable of handling the network requirements.' />
/>
</div>
); );
} else if (consensusCapability.capableUntil) { } else if (consensusCapability.capableUntil) {
return ( return (
<div> <FormattedMessage
<FormattedMessage id='upgradeParity.consensus.capableUntil'
id='upgradeParity.consensus.capableUntil' defaultMessage='Your current Parity version is capable of handling the network requirements until block {blockNumber}'
defaultMessage='Your current Parity version is capable of handling the network requirements until block {blockNumber}' values={ {
values={ { blockNumber: consensusCapability.capableUntil
blockNumber: consensusCapability.capableUntil } }
} } />
/>
</div>
); );
} else if (consensusCapability.incapableSince) { } else if (consensusCapability.incapableSince) {
return ( return (
<div> <FormattedMessage
<FormattedMessage id='upgradeParity.consensus.incapableSince'
id='upgradeParity.consensus.incapableSince' defaultMessage='Your current Parity version is incapable of handling the network requirements since block {blockNumber}'
defaultMessage='Your current Parity version is incapable of handling the network requirements since block {blockNumber}' values={ {
values={ { blockNumber: consensusCapability.incapableSince
blockNumber: consensusCapability.incapableSince } }
} } />
/>
</div>
); );
} }
} }
return ( return (
<div> <FormattedMessage
<FormattedMessage id='upgradeParity.consensus.unknown'
id='upgradeParity.consensus.unknown' defaultMessage='Your current Parity version is capable of handling the network requirements.'
defaultMessage='Your current Parity version is capable of handling the network requirements.' />
/>
</div>
); );
} }
@ -275,4 +318,20 @@ export default class UpgradeParity extends Component {
return `${version.major}.${version.minor}.${version.patch}-${track}`; return `${version.major}.${version.minor}.${version.patch}-${track}`;
} }
onClose = () => {
this.props.store.closeModal();
}
onDone = () => {
if (this.props.store.error) {
this.onClose();
} else {
window.location.reload();
}
}
onUpgrade = () => {
this.props.store.upgradeNow();
}
} }

View File

@ -15,19 +15,26 @@
// along with Parity. If not, see <http://www.gnu.org/licenses/>. // along with Parity. If not, see <http://www.gnu.org/licenses/>.
import React, { Component, PropTypes } from 'react'; import React, { Component, PropTypes } from 'react';
import { FormattedMessage } from 'react-intl';
import { Form, Input } from '~/ui'; import { Form, Input } from '~/ui';
import { nodeOrStringProptype } from '~/util/proptypes';
export default class QueryCode extends Component { export default class QueryCode extends Component {
static propTypes = { static propTypes = {
receiver: PropTypes.string.isRequired, receiver: PropTypes.string.isRequired,
hint: PropTypes.string, hint: nodeOrStringProptype(),
isCodeValid: PropTypes.bool.isRequired, isCodeValid: PropTypes.bool.isRequired,
setCode: PropTypes.func.isRequired setCode: PropTypes.func.isRequired
} }
static defaultProps = { static defaultProps = {
hint: 'Enter the code you received.' hint: (
<FormattedMessage
id='verification.code.hint'
defaultMessage='Enter the code you received.'
/>
)
} }
render () { render () {
@ -37,9 +44,23 @@ export default class QueryCode extends Component {
<Form> <Form>
<p>The verification code has been sent to { receiver }.</p> <p>The verification code has been sent to { receiver }.</p>
<Input <Input
label={ 'verification code' } label={
<FormattedMessage
id='verification.code.label'
defaultMessage='verification code'
/>
}
hint={ hint } hint={ hint }
error={ isCodeValid ? null : 'invalid code' } error={
isCodeValid
? null
: (
<FormattedMessage
id='verification.code.error'
defaultMessage='invalid code'
/>
)
}
onChange={ this.onChange } onChange={ this.onChange }
onSubmit={ this.onSubmit } onSubmit={ this.onSubmit }
/> />

View File

@ -22,7 +22,7 @@ import { observable } from 'mobx';
import DoneIcon from 'material-ui/svg-icons/action/done-all'; import DoneIcon from 'material-ui/svg-icons/action/done-all';
import CancelIcon from 'material-ui/svg-icons/content/clear'; import CancelIcon from 'material-ui/svg-icons/content/clear';
import { Button, IdentityIcon, Modal } from '~/ui'; import { Button, IdentityIcon, Portal } from '~/ui';
import RadioButtons from '~/ui/Form/RadioButtons'; import RadioButtons from '~/ui/Form/RadioButtons';
import SMSVerificationStore from './sms-store'; import SMSVerificationStore from './sms-store';
@ -30,17 +30,72 @@ import EmailVerificationStore from './email-store';
import styles from './verification.css'; import styles from './verification.css';
const methods = { const METHODS = {
sms: { sms: {
label: 'SMS Verification', key: 0, value: 'sms', label: (
description: (<p className={ styles.noSpacing }>It will be stored on the blockchain that you control a phone number (not <em>which</em>).</p>) <FormattedMessage
id='verification.types.sms.label'
defaultMessage='SMS Verification'
/>
),
key: 0,
value: 'sms',
description: (
<p className={ styles.noSpacing }>
<FormattedMessage
id='verification.types.sms.description'
defaultMessage='It will be stored on the blockchain that you control a phone number (not <em>which</em>).'
/>
</p>
)
}, },
email: { email: {
label: 'E-mail Verification', key: 1, value: 'email', label: (
description: (<p className={ styles.noSpacing }>The hash of the e-mail address you prove control over will be stored on the blockchain.</p>) <FormattedMessage
id='verification.types.email.label'
defaultMessage='E-mail Verification'
/>
),
key: 1,
value: 'email',
description: (
<p className={ styles.noSpacing }>
<FormattedMessage
id='verification.types.email.description'
defaultMessage='The hash of the e-mail address you prove control over will be stored on the blockchain.'
/>
</p>
)
} }
}; };
const STEPS = [
<FormattedMessage
id='verification.steps.method'
defaultMessage='Method'
/>,
<FormattedMessage
id='verification.steps.data'
defaultMessage='Enter Data'
/>,
<FormattedMessage
id='verification.steps.request'
defaultMessage='Request'
/>,
<FormattedMessage
id='verification.steps.code'
defaultMessage='Enter Code'
/>,
<FormattedMessage
id='verification.steps.confirm'
defaultMessage='Confirm'
/>,
<FormattedMessage
id='verification.steps.completed'
defaultMessage='Completed'
/>
];
import { import {
LOADING, LOADING,
QUERY_DATA, QUERY_DATA,
@ -83,6 +138,7 @@ class Verification extends Component {
@observable store = null; @observable store = null;
render () { render () {
const { onClose } = this.props;
const store = this.store; const store = this.store;
let phase = 0; let phase = 0;
let error = false; let error = false;
@ -95,16 +151,26 @@ class Verification extends Component {
} }
return ( return (
<Modal <Portal
actions={ this.renderDialogActions(phase, error, isStepValid) } activeStep={ phase }
current={ phase } busySteps={
steps={ ['Method', 'Enter Data', 'Request', 'Enter Code', 'Confirm', 'Done!'] } error
title='verify your account' ? []
visible : [ 2, 4 ]
waiting={ error ? [] : [ 2, 4 ] } }
buttons={ this.renderDialogActions(phase, error, isStepValid) }
onClose={ onClose }
open
steps={ STEPS }
title={
<FormattedMessage
id='verification.title'
defaultMessage='verify your account'
/>
}
> >
{ this.renderStep(phase, error) } { this.renderStep(phase, error) }
</Modal> </Portal>
); );
} }
@ -112,32 +178,40 @@ class Verification extends Component {
const { account, onClose } = this.props; const { account, onClose } = this.props;
const store = this.store; const store = this.store;
const cancel = ( const cancelButton = (
<Button <Button
icon={ <CancelIcon /> } icon={ <CancelIcon /> }
key='cancel' key='cancel'
label='Cancel' label={
<FormattedMessage
id='verification.button.cancel'
defaultMessage='Cancel'
/>
}
onClick={ onClose } onClick={ onClose }
/> />
); );
if (error) { if (error) {
return (<div>{ cancel }</div>); return cancelButton;
} }
if (phase === 5) { if (phase === 5) {
return ( return [
<div> cancelButton,
{ cancel } <Button
<Button disabled={ !isStepValid }
disabled={ !isStepValid } icon={ <DoneIcon /> }
icon={ <DoneIcon /> } key='done'
key='done' label={
label='Done' <FormattedMessage
onClick={ onClose } id='verification.button.done'
/> defaultMessage='Done'
</div> />
); }
onClick={ onClose }
/>
];
} }
let action = () => {}; let action = () => {};
@ -164,23 +238,26 @@ class Verification extends Component {
break; break;
} }
return ( return [
<div> cancelButton,
{ cancel } <Button
<Button disabled={ !isStepValid }
disabled={ !isStepValid } icon={
icon={ <IdentityIcon
<IdentityIcon address={ account }
address={ account } button
button />
/> }
} key='next'
key='next' label={
label='Next' <FormattedMessage
onClick={ action } id='verification.button.next'
/> defaultMessage='Next'
</div> />
); }
onClick={ action }
/>
];
} }
renderStep (phase, error) { renderStep (phase, error) {
@ -193,7 +270,7 @@ class Verification extends Component {
const { method } = this.state; const { method } = this.state;
if (phase === 0) { if (phase === 0) {
const values = Object.values(methods); const values = Object.values(METHODS);
const value = values.findIndex((v) => v.value === method); const value = values.findIndex((v) => v.value === method);
return ( return (
@ -215,7 +292,14 @@ class Verification extends Component {
switch (phase) { switch (phase) {
case 1: case 1:
if (step === LOADING) { if (step === LOADING) {
return (<p>Loading verification data.</p>); return (
<p>
<FormattedMessage
id='verification.loading'
defaultMessage='Loading verification data.'
/>
</p>
);
} }
const { setConsentGiven } = this.store; const { setConsentGiven } = this.store;
@ -226,17 +310,24 @@ class Verification extends Component {
key: 'number', key: 'number',
label: ( label: (
<FormattedMessage <FormattedMessage
id='ui.verification.gatherData.phoneNumber.label' id='verification.gatherData.phoneNumber.label'
defaultMessage='phone number in international format' defaultMessage='phone number in international format'
/> />
), ),
hint: ( hint: (
<FormattedMessage <FormattedMessage
id='ui.verification.gatherData.phoneNumber.hint' id='verification.gatherData.phoneNumber.hint'
defaultMessage='the SMS will be sent to this number' defaultMessage='the SMS will be sent to this number'
/> />
), ),
error: this.store.isNumberValid ? null : 'invalid number', error: this.store.isNumberValid
? null
: (
<FormattedMessage
id='verification.gatherDate.phoneNumber.error'
defaultMessage='invalid number'
/>
),
onChange: this.store.setNumber onChange: this.store.setNumber
}); });
} else if (method === 'email') { } else if (method === 'email') {
@ -244,17 +335,24 @@ class Verification extends Component {
key: 'email', key: 'email',
label: ( label: (
<FormattedMessage <FormattedMessage
id='ui.verification.gatherData.email.label' id='verification.gatherData.email.label'
defaultMessage='e-mail address' defaultMessage='e-mail address'
/> />
), ),
hint: ( hint: (
<FormattedMessage <FormattedMessage
id='ui.verification.gatherData.email.hint' id='verification.gatherData.email.hint'
defaultMessage='the code will be sent to this address' defaultMessage='the code will be sent to this address'
/> />
), ),
error: this.store.isEmailValid ? null : 'invalid e-mail', error: this.store.isEmailValid
? null
: (
<FormattedMessage
id='verification.gatherDate.email.error'
defaultMessage='invalid e-mail'
/>
),
onChange: this.store.setEmail onChange: this.store.setEmail
}); });
} }
@ -286,10 +384,20 @@ class Verification extends Component {
if (method === 'sms') { if (method === 'sms') {
receiver = this.store.number; receiver = this.store.number;
hint = 'Enter the code you received via SMS.'; hint = (
<FormattedMessage
id='verification.sms.enterCode'
defaultMessage='Enter the code you received via SMS.'
/>
);
} else if (method === 'email') { } else if (method === 'email') {
receiver = this.store.email; receiver = this.store.email;
hint = 'Enter the code you received via e-mail.'; hint = (
<FormattedMessage
id='verification.email.enterCode'
defaultMessage='Enter the code you received via e-mail.'
/>
);
} }
return ( return (
<QueryCode <QueryCode

View File

@ -20,11 +20,8 @@ import { connect } from 'react-redux';
import { observer } from 'mobx-react'; import { observer } from 'mobx-react';
import { pick } from 'lodash'; import { pick } from 'lodash';
import ActionDone from 'material-ui/svg-icons/action/done'; import { BusyStep, AddressSelect, Button, Form, TypedInput, Input, InputAddress, Portal, TxHash } from '~/ui';
import ContentClear from 'material-ui/svg-icons/content/clear'; import { CancelIcon, DoneIcon, NextIcon } from '~/ui/Icons';
import NavigationArrowForward from 'material-ui/svg-icons/navigation/arrow-forward';
import { Button, Modal, TxHash, BusyStep, Form, TypedInput, Input, InputAddress, AddressSelect } from '~/ui';
import { fromWei } from '~/api/util/wei'; import { fromWei } from '~/api/util/wei';
import WalletSettingsStore from './walletSettingsStore.js'; import WalletSettingsStore from './walletSettingsStore.js';
@ -50,8 +47,9 @@ class WalletSettings extends Component {
if (rejected) { if (rejected) {
return ( return (
<Modal <Portal
visible onClose={ this.onClose }
open
title={ title={
<FormattedMessage <FormattedMessage
id='walletSettings.rejected.title' id='walletSettings.rejected.title'
@ -74,20 +72,21 @@ class WalletSettings extends Component {
/> />
} }
/> />
</Modal> </Portal>
); );
} }
return ( return (
<Modal <Portal
visible activeStep={ stage }
actions={ this.renderDialogActions() } busySteps={ waiting }
current={ stage } buttons={ this.renderDialogActions() }
steps={ steps.map((s) => s.title) } onClose={ this.onClose }
waiting={ waiting } open
steps={ steps.map((step) => step.title) }
> >
{ this.renderPage() } { this.renderPage() }
</Modal> </Portal>
); );
} }
@ -106,11 +105,26 @@ class WalletSettings extends Component {
const key = req.id; const key = req.id;
if (req.txhash) { if (req.txhash) {
return (<TxHash key={ key } hash={ req.txhash } />); return (
<TxHash
key={ key }
hash={ req.txhash }
/>
);
} }
if (req.rejected) { if (req.rejected) {
return (<p key={ key }>The transaction #{parseInt(key, 16)} has been rejected</p>); return (
<p key={ key }>
<FormattedMessage
id='walletSettings.rejected'
defaultMessage='The transaction #{txid} has been rejected'
values={ {
txid: parseInt(key, 16)
} }
/>
</p>
);
} }
}) })
} }
@ -291,9 +305,7 @@ class WalletSettings extends Component {
<p> <p>
<FormattedMessage <FormattedMessage
id='walletSettings.changes.overview' id='walletSettings.changes.overview'
defaultMessage={ defaultMessage='You are about to make the following modifications'
`You are about to make the following modifications`
}
/> />
</p> </p>
{ modifications } { modifications }
@ -323,12 +335,21 @@ class WalletSettings extends Component {
case 'require': case 'require':
return ( return (
<div className={ styles.change }> <div className={ styles.change }>
<div className={ styles.label }>Change Required Owners</div> <div className={ styles.label }>
<FormattedMessage
id='walletSettings.ownersChange.title'
defaultMessage='Change Required Owners'
/>
</div>
<div> <div>
<span> from </span> <FormattedMessage
<code> { change.initial.toNumber() }</code> id='walletSettings.ownersChange.details'
<span> to </span> defaultMessage=' from {from} to {to} '
<code> { change.value.toNumber() }</code> values={ {
from: <code>change.initial.toNumber()</code>,
to: <code>change.value.toNumber()</code>
} }
/>
</div> </div>
</div> </div>
); );
@ -336,7 +357,12 @@ class WalletSettings extends Component {
case 'add_owner': case 'add_owner':
return ( return (
<div className={ [ styles.change, styles.add ].join(' ') }> <div className={ [ styles.change, styles.add ].join(' ') }>
<div className={ styles.label }>Add Owner</div> <div className={ styles.label }>
<FormattedMessage
id='walletSettings.addOwner.title'
defaultMessage='Add Owner'
/>
</div>
<div> <div>
<InputAddress <InputAddress
disabled disabled
@ -350,7 +376,12 @@ class WalletSettings extends Component {
case 'remove_owner': case 'remove_owner':
return ( return (
<div className={ [ styles.change, styles.remove ].join(' ') }> <div className={ [ styles.change, styles.remove ].join(' ') }>
<div className={ styles.label }>Remove Owner</div> <div className={ styles.label }>
<FormattedMessage
id='walletSettings.removeOwner.title'
defaultMessage='Remove Owner'
/>
</div>
<div> <div>
<InputAddress <InputAddress
disabled disabled
@ -364,37 +395,56 @@ class WalletSettings extends Component {
} }
renderDialogActions () { renderDialogActions () {
const { onClose } = this.props;
const { step, hasErrors, rejected, onNext, send, done } = this.store; const { step, hasErrors, rejected, onNext, send, done } = this.store;
const cancelBtn = ( const cancelBtn = (
<Button <Button
icon={ <ContentClear /> } icon={ <CancelIcon /> }
label='Cancel' label={
onClick={ onClose } <FormattedMessage
id='walletSettings.buttons.cancel'
defaultMessage='Cancel'
/>
}
onClick={ this.onClose }
/> />
); );
const closeBtn = ( const closeBtn = (
<Button <Button
icon={ <ContentClear /> } icon={ <CancelIcon /> }
label='Close' label={
onClick={ onClose } <FormattedMessage
id='walletSettings.buttons.close'
defaultMessage='Close'
/>
}
onClick={ this.onClose }
/> />
); );
const sendingBtn = ( const sendingBtn = (
<Button <Button
icon={ <ActionDone /> } icon={ <DoneIcon /> }
label='Sending...' label={
<FormattedMessage
id='walletSettings.buttons.sending'
defaultMessage='Sending...'
/>
}
disabled disabled
/> />
); );
const nextBtn = ( const nextBtn = (
<Button <Button
icon={ <NavigationArrowForward /> } icon={ <NextIcon /> }
label='Next' label={
<FormattedMessage
id='walletSettings.buttons.next'
defaultMessage='Next'
/>
}
onClick={ onNext } onClick={ onNext }
disabled={ hasErrors } disabled={ hasErrors }
/> />
@ -402,8 +452,13 @@ class WalletSettings extends Component {
const sendBtn = ( const sendBtn = (
<Button <Button
icon={ <NavigationArrowForward /> } icon={ <NextIcon /> }
label='Send' label={
<FormattedMessage
id='walletSettings.buttons.send'
defaultMessage='Send'
/>
}
onClick={ send } onClick={ send }
disabled={ hasErrors } disabled={ hasErrors }
/> />
@ -415,7 +470,9 @@ class WalletSettings extends Component {
switch (step) { switch (step) {
case 'SENDING': case 'SENDING':
return done ? [ closeBtn ] : [ closeBtn, sendingBtn ]; return done
? [ closeBtn ]
: [ closeBtn, sendingBtn ];
case 'CONFIRMATION': case 'CONFIRMATION':
const { changes } = this.store; const { changes } = this.store;
@ -431,6 +488,10 @@ class WalletSettings extends Component {
return [ cancelBtn, nextBtn ]; return [ cancelBtn, nextBtn ];
} }
} }
onClose = () => {
this.props.onClose();
}
} }
function mapStateToProps (initState, initProps) { function mapStateToProps (initState, initProps) {

View File

@ -16,12 +16,13 @@
import React, { Component, PropTypes } from 'react'; import React, { Component, PropTypes } from 'react';
import Dropzone from 'react-dropzone'; import Dropzone from 'react-dropzone';
import FileUploadIcon from 'material-ui/svg-icons/file/file-upload'; import { FormattedMessage } from 'react-intl';
import ContentClear from 'material-ui/svg-icons/content/clear';
import ActionDoneAll from 'material-ui/svg-icons/action/done-all'; import { nodeOrStringProptype } from '~/util/proptypes';
import Button from '../../Button'; import Button from '../../Button';
import Modal from '../../Modal'; import { CancelIcon, DoneIcon, FileUploadIcon } from '../../Icons';
import Portal from '../../Portal';
import styles from './import.css'; import styles from './import.css';
@ -37,14 +38,19 @@ const initialState = {
export default class ActionbarImport extends Component { export default class ActionbarImport extends Component {
static propTypes = { static propTypes = {
className: PropTypes.string,
onConfirm: PropTypes.func.isRequired, onConfirm: PropTypes.func.isRequired,
renderValidation: PropTypes.func, renderValidation: PropTypes.func,
className: PropTypes.string, title: nodeOrStringProptype()
title: PropTypes.string
}; };
static defaultProps = { static defaultProps = {
title: 'Import from a file' title: (
<FormattedMessage
id='ui.actionbar.import.title'
defaultMessage='Import from a file'
/>
)
}; };
state = Object.assign({}, initialState); state = Object.assign({}, initialState);
@ -57,7 +63,12 @@ export default class ActionbarImport extends Component {
<Button <Button
className={ className } className={ className }
icon={ <FileUploadIcon /> } icon={ <FileUploadIcon /> }
label='import' label={
<FormattedMessage
id='ui.actiobar.import.button.import'
defaultMessage='import'
/>
}
onClick={ this.onOpenModal } onClick={ this.onOpenModal }
/> />
{ this.renderModal() } { this.renderModal() }
@ -73,20 +84,38 @@ export default class ActionbarImport extends Component {
return null; return null;
} }
const hasSteps = typeof renderValidation === 'function'; const steps = typeof renderValidation === 'function'
? [
const steps = hasSteps ? [ 'select a file', error ? 'error' : 'validate' ] : null; <FormattedMessage
id='ui.actiobar.import.step.select'
defaultMessage='select a file'
/>,
error
? (
<FormattedMessage
id='ui.actiobar.import.step.error'
defaultMessage='error'
/>
)
: (
<FormattedMessage
id='ui.actiobar.import.step.validate'
defaultMessage='validate'
/>)
]
: null;
return ( return (
<Modal <Portal
actions={ this.renderActions() } activeStep={ step }
title={ title } buttons={ this.renderActions() }
onClose={ this.onCloseModal }
open
steps={ steps } steps={ steps }
current={ step } title={ title }
visible
> >
{ this.renderBody() } { this.renderBody() }
</Modal> </Portal>
); );
} }
@ -95,9 +124,14 @@ export default class ActionbarImport extends Component {
const cancelBtn = ( const cancelBtn = (
<Button <Button
icon={ <CancelIcon /> }
key='cancel' key='cancel'
label='Cancel' label={
icon={ <ContentClear /> } <FormattedMessage
id='ui.actiobar.import.button.cancel'
defaultMessage='Cancel'
/>
}
onClick={ this.onCloseModal } onClick={ this.onCloseModal }
/> />
); );
@ -109,9 +143,14 @@ export default class ActionbarImport extends Component {
if (validate) { if (validate) {
const confirmBtn = ( const confirmBtn = (
<Button <Button
icon={ <DoneIcon /> }
key='confirm' key='confirm'
label='Confirm' label={
icon={ <ActionDoneAll /> } <FormattedMessage
id='ui.actiobar.import.button.confirm'
defaultMessage='Confirm'
/>
}
onClick={ this.onConfirm } onClick={ this.onConfirm }
/> />
); );
@ -128,7 +167,15 @@ export default class ActionbarImport extends Component {
if (error) { if (error) {
return ( return (
<div> <div>
<p>An error occured: { errorText }</p> <p>
<FormattedMessage
id='ui.actiobar.import.error'
defaultMessage='An error occured: {errorText}'
values={ {
errorText
} }
/>
</p>
</div> </div>
); );
} }
@ -148,7 +195,12 @@ export default class ActionbarImport extends Component {
multiple={ false } multiple={ false }
className={ styles.importZone } className={ styles.importZone }
> >
<div>Drop a file here, or click to select a file to upload.</div> <div>
<FormattedMessage
id='ui.actiobar.import.dropzone'
defaultMessage='Drop a file here, or click to select a file to upload.'
/>
</div>
</Dropzone> </Dropzone>
</div> </div>
); );
@ -160,7 +212,10 @@ export default class ActionbarImport extends Component {
return ( return (
<div> <div>
<p className={ styles.desc }> <p className={ styles.desc }>
Confirm that this is what was intended to import. <FormattedMessage
id='ui.actiobar.import.confirm'
defaultMessage='Confirm that this is what was intended to import.'
/>
</p> </p>
<div> <div>
{ validationBody } { validationBody }

View File

@ -28,6 +28,8 @@ export DashboardIcon from 'material-ui/svg-icons/action/dashboard';
export DeleteIcon from 'material-ui/svg-icons/action/delete'; export DeleteIcon from 'material-ui/svg-icons/action/delete';
export DoneIcon from 'material-ui/svg-icons/action/done-all'; export DoneIcon from 'material-ui/svg-icons/action/done-all';
export EditIcon from 'material-ui/svg-icons/content/create'; export EditIcon from 'material-ui/svg-icons/content/create';
export ErrorIcon from 'material-ui/svg-icons/alert/error';
export FileUploadIcon from 'material-ui/svg-icons/file/file-upload';
export FingerprintIcon from 'material-ui/svg-icons/action/fingerprint'; export FingerprintIcon from 'material-ui/svg-icons/action/fingerprint';
export KeyIcon from 'material-ui/svg-icons/communication/vpn-key'; export KeyIcon from 'material-ui/svg-icons/communication/vpn-key';
export LinkIcon from 'material-ui/svg-icons/content/link'; export LinkIcon from 'material-ui/svg-icons/content/link';
@ -44,6 +46,8 @@ export StarCircleIcon from 'material-ui/svg-icons/action/stars';
export StarIcon from 'material-ui/svg-icons/toggle/star'; export StarIcon from 'material-ui/svg-icons/toggle/star';
export StarOutlineIcon from 'material-ui/svg-icons/toggle/star-border'; export StarOutlineIcon from 'material-ui/svg-icons/toggle/star-border';
export UnlockedIcon from 'material-ui/svg-icons/action/lock-open'; export UnlockedIcon from 'material-ui/svg-icons/action/lock-open';
export UpdateIcon from 'material-ui/svg-icons/action/system-update-alt';
export UpdateWaitIcon from 'material-ui/svg-icons/action/update';
export VerifyIcon from 'material-ui/svg-icons/action/verified-user'; export VerifyIcon from 'material-ui/svg-icons/action/verified-user';
export VisibleIcon from 'material-ui/svg-icons/image/remove-red-eye'; export VisibleIcon from 'material-ui/svg-icons/image/remove-red-eye';
export VpnIcon from 'material-ui/svg-icons/notification/vpn-lock'; export VpnIcon from 'material-ui/svg-icons/notification/vpn-lock';

View File

@ -17,8 +17,6 @@
import Busy from './Busy'; import Busy from './Busy';
import Completed from './Completed'; import Completed from './Completed';
export default from './modal';
export { export {
Busy, Busy,
Completed Completed

View File

@ -1,55 +0,0 @@
/* 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 <http://www.gnu.org/licenses/>.
*/
.actions {
background: rgba(0, 0, 0, 0.25) !important;
button:not([disabled]) {
color: white !important;
svg {
fill: white !important;
}
}
}
.body {
padding: 0 !important;
}
.dialog {
}
.content {
transform: translate(0px, 0px) !important;
transition: none !important;
&>div {
background: rgba(0, 0, 0, 0.5) !important;
transition: none !important;
}
}
.title {
background: rgba(0, 0, 0, 0.25) !important;
padding: 1em;
}
.overlay {
background: rgba(255, 255, 255, 0.5) !important;
transition: none !important;
}

View File

@ -1,121 +0,0 @@
// 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 <http://www.gnu.org/licenses/>.
import { Dialog } from 'material-ui';
import React, { Component, PropTypes } from 'react';
import ReactDOM from 'react-dom';
import { connect } from 'react-redux';
import { nodeOrStringProptype } from '~/util/proptypes';
import Container from '../Container';
import Title from '../Title';
const ACTIONS_STYLE = { borderStyle: 'none' };
const TITLE_STYLE = { borderStyle: 'none' };
const DIALOG_STYLE = { paddingTop: '1px' };
import styles from './modal.css';
class Modal extends Component {
static contextTypes = {
muiTheme: PropTypes.object.isRequired
}
static propTypes = {
actions: PropTypes.node,
busy: PropTypes.bool,
children: PropTypes.node,
className: PropTypes.string,
compact: PropTypes.bool,
current: PropTypes.number,
settings: PropTypes.object.isRequired,
steps: PropTypes.array,
title: nodeOrStringProptype(),
visible: PropTypes.bool.isRequired,
waiting: PropTypes.array
}
componentDidMount () {
const element = ReactDOM.findDOMNode(this.refs.dialog);
if (element) {
element.focus();
}
}
render () {
const { muiTheme } = this.context;
const { actions, busy, children, className, current, compact, settings, steps, title, visible, waiting } = this.props;
const contentStyle = muiTheme.parity.getBackgroundStyle(null, settings.backgroundSeed);
const header = (
<Title
activeStep={ current }
busy={ busy }
busySteps={ waiting }
className={ styles.title }
steps={ steps }
title={ title }
/>
);
const classes = `${styles.dialog} ${className}`;
return (
<Dialog
actions={ actions }
actionsContainerClassName={ styles.actions }
actionsContainerStyle={ ACTIONS_STYLE }
autoDetectWindowHeight={ false }
autoScrollBodyContent
bodyClassName={ styles.body }
className={ classes }
contentClassName={ styles.content }
contentStyle={ contentStyle }
modal
open={ visible }
overlayClassName={ styles.overlay }
overlayStyle={ { transition: 'none' } }
repositionOnUpdate={ false }
style={ DIALOG_STYLE }
title={ header }
titleStyle={ TITLE_STYLE }
>
<Container
compact={ compact }
light
ref='dialog'
style={
{ transition: 'none' }
}
tabIndex={ 0 }
>
{ children }
</Container>
</Dialog>
);
}
}
function mapStateToProps (state) {
const { settings } = state;
return { settings };
}
export default connect(
mapStateToProps,
null
)(Modal);

View File

@ -19,7 +19,6 @@ import React, { Component } from 'react';
import { Button } from '~/ui'; import { Button } from '~/ui';
import PlaygroundExample from '~/playground/playgroundExample'; import PlaygroundExample from '~/playground/playgroundExample';
import Modal from '../Modal';
import Portal from './portal'; import Portal from './portal';
export default class PortalExample extends Component { export default class PortalExample extends Component {
@ -61,14 +60,6 @@ export default class PortalExample extends Component {
<div> <div>
<button onClick={ this.handleOpen(2) }>Open</button> <button onClick={ this.handleOpen(2) }>Open</button>
<Modal
title='Modal'
visible={ open[2] || false }
>
<button onClick={ this.handleOpen(3) }>Open</button>
<button onClick={ this.handleClose }>Close</button>
</Modal>
<Portal <Portal
isChildModal isChildModal
open={ open[3] || false } open={ open[3] || false }

View File

@ -71,10 +71,7 @@ export default class Portal extends Component {
} }
return ( return (
<ReactPortal <ReactPortal isOpened>
isOpened
onClose={ this.handleClose }
>
<div <div
className={ styles.backOverlay } className={ styles.backOverlay }
onClick={ this.handleClose } onClick={ this.handleClose }
@ -159,6 +156,8 @@ export default class Portal extends Component {
if (!hideClose) { if (!hideClose) {
onClose(); onClose();
} }
this.stopEvent(event);
} }
handleKeyDown = (event) => { handleKeyDown = (event) => {

View File

@ -38,6 +38,8 @@ muiTheme.textField.hintColor = 'rgba(255, 255, 255, 0.5)';
muiTheme.textField.disabledTextColor = muiTheme.textField.textColor; muiTheme.textField.disabledTextColor = muiTheme.textField.textColor;
muiTheme.toolbar = lightTheme.toolbar; muiTheme.toolbar = lightTheme.toolbar;
muiTheme.toolbar.backgroundColor = 'transparent'; muiTheme.toolbar.backgroundColor = 'transparent';
muiTheme.zIndex.layer = 4000;
muiTheme.zIndex.popover = 4100;
const imageCache = {}; const imageCache = {};

View File

@ -93,7 +93,6 @@ export default class VaultCard extends Component {
address={ address } address={ address }
center center
className={ styles.account } className={ styles.account }
key={ address }
/> />
</Link> </Link>
); );

View File

@ -39,7 +39,7 @@ export IdentityName from './IdentityName';
export LanguageSelector from './LanguageSelector'; export LanguageSelector from './LanguageSelector';
export Loading from './Loading'; export Loading from './Loading';
export MethodDecoding from './MethodDecoding'; export MethodDecoding from './MethodDecoding';
export Modal, { Busy as BusyStep, Completed as CompletedStep } from './Modal'; export { Busy as BusyStep, Completed as CompletedStep } from './Modal';
export muiTheme from './Theme'; export muiTheme from './Theme';
export Page from './Page'; export Page from './Page';
export ParityBackground from './ParityBackground'; export ParityBackground from './ParityBackground';

View File

@ -318,22 +318,26 @@ class Accounts extends Component {
onNewAccountClick = () => { onNewAccountClick = () => {
this.setState({ this.setState({
newDialog: !this.state.newDialog newDialog: true
}); });
} }
onNewWalletClick = () => { onNewWalletClick = () => {
this.setState({ this.setState({
newWalletDialog: !this.state.newWalletDialog newWalletDialog: true
}); });
} }
onNewAccountClose = () => { onNewAccountClose = () => {
this.onNewAccountClick(); this.setState({
newDialog: false
});
} }
onNewWalletClose = () => { onNewWalletClose = () => {
this.onNewWalletClick(); this.setState({
newWalletDialog: false
});
} }
onNewAccountUpdate = () => { onNewAccountUpdate = () => {

View File

@ -153,7 +153,7 @@ class Address extends Component {
<Button <Button
key='delete' key='delete'
icon={ <ActionDelete /> } icon={ <ActionDelete /> }
label='delete address' label='forget address'
onClick={ this.showDeleteDialog } onClick={ this.showDeleteDialog }
/> />
]; ];

View File

@ -30,7 +30,7 @@ import { newError } from '~/redux/actions';
import { setVisibleAccounts } from '~/redux/providers/personalActions'; import { setVisibleAccounts } from '~/redux/providers/personalActions';
import { EditMeta, ExecuteContract } from '~/modals'; import { EditMeta, ExecuteContract } from '~/modals';
import { Actionbar, Button, Page, Modal } from '~/ui'; import { Actionbar, Button, Page, Portal } from '~/ui';
import Editor from '~/ui/Editor'; import Editor from '~/ui/Editor';
import Header from '../Account/Header'; import Header from '../Account/Header';
@ -198,10 +198,11 @@ class Contract extends Component {
); );
return ( return (
<Modal <Portal
actions={ [ cancelBtn ] } buttons={ [ cancelBtn ] }
onClose={ this.closeDetailsDialog }
open
title={ 'contract details' } title={ 'contract details' }
visible
> >
<div className={ styles.details }> <div className={ styles.details }>
{ this.renderSource(contract) } { this.renderSource(contract) }
@ -216,7 +217,7 @@ class Contract extends Component {
/> />
</div> </div>
</div> </div>
</Modal> </Portal>
); );
} }