SMS Faucet (#4774)
* Faucet * Remove flakey button-index testing * Only display faucet when sms verified (mainnet) * simplify availability checks * WIP * Resuest from verified -> verified * Update endpoint, display response text * Error icon on errors * Parse hash text response * Use /api/:address endpoint * hash -> data * Adjust sms-certified message
This commit is contained in:
parent
4d08e7b0ae
commit
c3c83086bc
162
js/src/modals/Faucet/faucet.js
Normal file
162
js/src/modals/Faucet/faucet.js
Normal file
@ -0,0 +1,162 @@
|
|||||||
|
// 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 { observer } from 'mobx-react';
|
||||||
|
import React, { Component, PropTypes } from 'react';
|
||||||
|
import { FormattedMessage } from 'react-intl';
|
||||||
|
|
||||||
|
import { txLink } from '~/3rdparty/etherscan/links';
|
||||||
|
import { Button, ModalBox, Portal, ShortenedHash } from '~/ui';
|
||||||
|
import { CloseIcon, DialIcon, DoneIcon, ErrorIcon, SendIcon } from '~/ui/Icons';
|
||||||
|
|
||||||
|
import Store from './store';
|
||||||
|
|
||||||
|
@observer
|
||||||
|
export default class Faucet extends Component {
|
||||||
|
static propTypes = {
|
||||||
|
address: PropTypes.string.isRequired,
|
||||||
|
netVersion: PropTypes.string.isRequired,
|
||||||
|
onClose: PropTypes.func.isRequired
|
||||||
|
}
|
||||||
|
|
||||||
|
store = new Store(this.props.netVersion, this.props.address);
|
||||||
|
|
||||||
|
render () {
|
||||||
|
const { error, isBusy, isCompleted } = this.store;
|
||||||
|
|
||||||
|
let icon = <DialIcon />;
|
||||||
|
|
||||||
|
if (isCompleted) {
|
||||||
|
icon = error
|
||||||
|
? <ErrorIcon />
|
||||||
|
: <DoneIcon />;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Portal
|
||||||
|
buttons={ this.renderActions() }
|
||||||
|
busy={ isBusy }
|
||||||
|
isSmallModal
|
||||||
|
onClose={ this.onClose }
|
||||||
|
open
|
||||||
|
title={
|
||||||
|
<FormattedMessage
|
||||||
|
id='faucet.title'
|
||||||
|
defaultMessage='Kovan ETH Faucet'
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<ModalBox
|
||||||
|
icon={ icon }
|
||||||
|
summary={
|
||||||
|
isCompleted
|
||||||
|
? this.renderSummaryDone()
|
||||||
|
: this.renderSummaryRequest()
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
</Portal>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
renderActions = () => {
|
||||||
|
const { canTransact, isBusy, isCompleted } = this.store;
|
||||||
|
|
||||||
|
return isCompleted || isBusy
|
||||||
|
? (
|
||||||
|
<Button
|
||||||
|
disabled={ isBusy }
|
||||||
|
icon={ <DoneIcon /> }
|
||||||
|
key='done'
|
||||||
|
label={
|
||||||
|
<FormattedMessage
|
||||||
|
id='faucet.buttons.done'
|
||||||
|
defaultMessage='close'
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
onClick={ this.onClose }
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
: [
|
||||||
|
<Button
|
||||||
|
icon={ <CloseIcon /> }
|
||||||
|
key='close'
|
||||||
|
label={
|
||||||
|
<FormattedMessage
|
||||||
|
id='faucet.buttons.close'
|
||||||
|
defaultMessage='close'
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
onClick={ this.onClose }
|
||||||
|
/>,
|
||||||
|
<Button
|
||||||
|
disabled={ !canTransact }
|
||||||
|
icon={ <SendIcon /> }
|
||||||
|
key='request'
|
||||||
|
label={
|
||||||
|
<FormattedMessage
|
||||||
|
id='faucet.buttons.request'
|
||||||
|
defaultMessage='request'
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
onClick={ this.onExecute }
|
||||||
|
/>
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
renderSummaryDone () {
|
||||||
|
const { error, responseText, responseTxHash } = this.store;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<FormattedMessage
|
||||||
|
id='faucet.summary.done'
|
||||||
|
defaultMessage='Your Kovan ETH has been requested from the faucet which responded with -'
|
||||||
|
/>
|
||||||
|
{
|
||||||
|
error
|
||||||
|
? (
|
||||||
|
<p>{ error }</p>
|
||||||
|
)
|
||||||
|
: (
|
||||||
|
<p>
|
||||||
|
<span>{ responseText } </span>
|
||||||
|
<a href={ txLink(responseTxHash, false, '42') } target='_blank'>
|
||||||
|
<ShortenedHash data={ responseTxHash } />
|
||||||
|
</a>
|
||||||
|
</p>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
renderSummaryRequest () {
|
||||||
|
return (
|
||||||
|
<FormattedMessage
|
||||||
|
id='faucet.summary.info'
|
||||||
|
defaultMessage='To request a deposit of Kovan ETH to this address, you need to ensure that the address is sms-verified on the mainnet. Once executed the faucet will deposit Kovan ETH into the current account.'
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
onClose = () => {
|
||||||
|
this.props.onClose();
|
||||||
|
}
|
||||||
|
|
||||||
|
onExecute = () => {
|
||||||
|
return this.store.makeItRain();
|
||||||
|
}
|
||||||
|
}
|
17
js/src/modals/Faucet/index.js
Normal file
17
js/src/modals/Faucet/index.js
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
// 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/>.
|
||||||
|
|
||||||
|
export default from './faucet';
|
126
js/src/modals/Faucet/store.js
Normal file
126
js/src/modals/Faucet/store.js
Normal file
@ -0,0 +1,126 @@
|
|||||||
|
// 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 { action, computed, observable, transaction } from 'mobx';
|
||||||
|
import apiutil from '~/api/util';
|
||||||
|
|
||||||
|
const ENDPOINT = 'http://faucet.kovan.network/api/';
|
||||||
|
|
||||||
|
export default class Store {
|
||||||
|
@observable addressReceive = null;
|
||||||
|
@observable addressVerified = null;
|
||||||
|
@observable error = null;
|
||||||
|
@observable responseText = null;
|
||||||
|
@observable responseTxHash = null;
|
||||||
|
@observable isBusy = false;
|
||||||
|
@observable isCompleted = false;
|
||||||
|
@observable isDestination = false;
|
||||||
|
@observable isDone = false;
|
||||||
|
|
||||||
|
constructor (netVersion, address) {
|
||||||
|
transaction(() => {
|
||||||
|
this.setDestination(netVersion === '42');
|
||||||
|
|
||||||
|
this.setAddressReceive(address);
|
||||||
|
this.setAddressVerified(address);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@computed get canTransact () {
|
||||||
|
return !this.isBusy && this.addressReceiveValid && this.addressVerifiedValid;
|
||||||
|
}
|
||||||
|
|
||||||
|
@computed get addressReceiveValid () {
|
||||||
|
return apiutil.isAddressValid(this.addressReceive);
|
||||||
|
}
|
||||||
|
|
||||||
|
@computed get addressVerifiedValid () {
|
||||||
|
return apiutil.isAddressValid(this.addressVerified);
|
||||||
|
}
|
||||||
|
|
||||||
|
@action setAddressReceive = (address) => {
|
||||||
|
this.addressReceive = address;
|
||||||
|
}
|
||||||
|
|
||||||
|
@action setAddressVerified = (address) => {
|
||||||
|
this.addressVerified = address;
|
||||||
|
}
|
||||||
|
|
||||||
|
@action setBusy = (isBusy) => {
|
||||||
|
this.isBusy = isBusy;
|
||||||
|
}
|
||||||
|
|
||||||
|
@action setCompleted = (isCompleted) => {
|
||||||
|
transaction(() => {
|
||||||
|
this.setBusy(false);
|
||||||
|
this.isCompleted = isCompleted;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@action setDestination = (isDestination) => {
|
||||||
|
this.isDestination = isDestination;
|
||||||
|
}
|
||||||
|
|
||||||
|
@action setError = (error) => {
|
||||||
|
if (error.indexOf('not certified') !== -1) {
|
||||||
|
this.error = `${error}. Please ensure that this account is sms certified on the mainnet.`;
|
||||||
|
} else {
|
||||||
|
this.error = error;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@action setResponse = (response) => {
|
||||||
|
this.responseText = response.result;
|
||||||
|
this.responseTxHash = response.tx;
|
||||||
|
}
|
||||||
|
|
||||||
|
makeItRain = () => {
|
||||||
|
this.setBusy(true);
|
||||||
|
|
||||||
|
const options = {
|
||||||
|
method: 'GET',
|
||||||
|
mode: 'cors'
|
||||||
|
};
|
||||||
|
const url = `${ENDPOINT}${this.addressVerified}`;
|
||||||
|
|
||||||
|
return fetch(url, options)
|
||||||
|
.then((response) => {
|
||||||
|
if (!response.ok) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return response.json();
|
||||||
|
})
|
||||||
|
.catch(() => {
|
||||||
|
return null;
|
||||||
|
})
|
||||||
|
.then((response) => {
|
||||||
|
transaction(() => {
|
||||||
|
if (!response || response.error) {
|
||||||
|
this.setError(
|
||||||
|
response
|
||||||
|
? response.error
|
||||||
|
: 'Unable to complete request to the faucet, the server may be unavailable. Please try again later.'
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
this.setResponse(response);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.setCompleted(true);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
@ -24,6 +24,7 @@ export DeleteAccount from './DeleteAccount';
|
|||||||
export DeployContract from './DeployContract';
|
export DeployContract from './DeployContract';
|
||||||
export EditMeta from './EditMeta';
|
export EditMeta from './EditMeta';
|
||||||
export ExecuteContract from './ExecuteContract';
|
export ExecuteContract from './ExecuteContract';
|
||||||
|
export Faucet from './Faucet';
|
||||||
export FirstRun from './FirstRun';
|
export FirstRun from './FirstRun';
|
||||||
export LoadContract from './LoadContract';
|
export LoadContract from './LoadContract';
|
||||||
export PasswordManager from './PasswordManager';
|
export PasswordManager from './PasswordManager';
|
||||||
|
@ -31,6 +31,7 @@ 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 DevelopIcon from 'material-ui/svg-icons/action/description';
|
export DevelopIcon from 'material-ui/svg-icons/action/description';
|
||||||
export DoneIcon from 'material-ui/svg-icons/action/done-all';
|
export DoneIcon from 'material-ui/svg-icons/action/done-all';
|
||||||
|
export DialIcon from 'material-ui/svg-icons/communication/dialpad';
|
||||||
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 ErrorIcon from 'material-ui/svg-icons/alert/error';
|
||||||
export FileUploadIcon from 'material-ui/svg-icons/file/file-upload';
|
export FileUploadIcon from 'material-ui/svg-icons/file/file-upload';
|
||||||
|
@ -22,13 +22,13 @@ import styles from './modalBox.css';
|
|||||||
|
|
||||||
export default class ModalBox extends Component {
|
export default class ModalBox extends Component {
|
||||||
static propTypes = {
|
static propTypes = {
|
||||||
children: PropTypes.node.isRequired,
|
children: PropTypes.node,
|
||||||
icon: PropTypes.node.isRequired,
|
icon: PropTypes.node.isRequired,
|
||||||
summary: nodeOrStringProptype()
|
summary: nodeOrStringProptype()
|
||||||
}
|
}
|
||||||
|
|
||||||
render () {
|
render () {
|
||||||
const { children, icon } = this.props;
|
const { icon } = this.props;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={ styles.body }>
|
<div className={ styles.body }>
|
||||||
@ -37,11 +37,23 @@ export default class ModalBox extends Component {
|
|||||||
</div>
|
</div>
|
||||||
<div className={ styles.content }>
|
<div className={ styles.content }>
|
||||||
{ this.renderSummary() }
|
{ this.renderSummary() }
|
||||||
|
{ this.renderBody() }
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
renderBody () {
|
||||||
|
const { children } = this.props;
|
||||||
|
|
||||||
|
if (!children) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
<div className={ styles.body }>
|
<div className={ styles.body }>
|
||||||
{ children }
|
{ children }
|
||||||
</div>
|
</div>
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -22,11 +22,11 @@ import { bindActionCreators } from 'redux';
|
|||||||
|
|
||||||
import shapeshiftBtn from '~/../assets/images/shapeshift-btn.png';
|
import shapeshiftBtn from '~/../assets/images/shapeshift-btn.png';
|
||||||
import HardwareStore from '~/mobx/hardwareStore';
|
import HardwareStore from '~/mobx/hardwareStore';
|
||||||
import { EditMeta, DeleteAccount, Shapeshift, Verification, Transfer, PasswordManager } from '~/modals';
|
import { DeleteAccount, EditMeta, Faucet, PasswordManager, Shapeshift, Transfer, Verification } from '~/modals';
|
||||||
import { setVisibleAccounts } from '~/redux/providers/personalActions';
|
import { setVisibleAccounts } from '~/redux/providers/personalActions';
|
||||||
import { fetchCertifiers, fetchCertifications } from '~/redux/providers/certifications/actions';
|
import { fetchCertifiers, fetchCertifications } from '~/redux/providers/certifications/actions';
|
||||||
import { Actionbar, Button, Page } from '~/ui';
|
import { Actionbar, Button, Page } from '~/ui';
|
||||||
import { DeleteIcon, EditIcon, LockedIcon, SendIcon, VerifyIcon } from '~/ui/Icons';
|
import { DeleteIcon, DialIcon, EditIcon, LockedIcon, SendIcon, VerifyIcon } from '~/ui/Icons';
|
||||||
|
|
||||||
import DeleteAddress from '../Address/Delete';
|
import DeleteAddress from '../Address/Delete';
|
||||||
|
|
||||||
@ -48,6 +48,8 @@ class Account extends Component {
|
|||||||
|
|
||||||
accounts: PropTypes.object,
|
accounts: PropTypes.object,
|
||||||
balances: PropTypes.object,
|
balances: PropTypes.object,
|
||||||
|
certifications: PropTypes.object,
|
||||||
|
netVersion: PropTypes.string.isRequired,
|
||||||
params: PropTypes.object
|
params: PropTypes.object
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -97,6 +99,7 @@ class Account extends Component {
|
|||||||
<div>
|
<div>
|
||||||
{ this.renderDeleteDialog(account) }
|
{ this.renderDeleteDialog(account) }
|
||||||
{ this.renderEditDialog(account) }
|
{ this.renderEditDialog(account) }
|
||||||
|
{ this.renderFaucetDialog() }
|
||||||
{ this.renderFundDialog() }
|
{ this.renderFundDialog() }
|
||||||
{ this.renderPasswordDialog(account) }
|
{ this.renderPasswordDialog(account) }
|
||||||
{ this.renderTransferDialog(account, balance) }
|
{ this.renderTransferDialog(account, balance) }
|
||||||
@ -117,8 +120,35 @@ class Account extends Component {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
isKovan = (netVersion) => {
|
||||||
|
return netVersion === '42';
|
||||||
|
}
|
||||||
|
|
||||||
|
isMainnet = (netVersion) => {
|
||||||
|
return netVersion === '1';
|
||||||
|
}
|
||||||
|
|
||||||
|
isFaucettable = (netVersion, certifications, address) => {
|
||||||
|
return this.isKovan(netVersion) || (
|
||||||
|
this.isMainnet(netVersion) &&
|
||||||
|
this.isSmsCertified(certifications, address)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
isSmsCertified = (_certifications, address) => {
|
||||||
|
const certifications = _certifications && _certifications[address]
|
||||||
|
? _certifications[address].filter((cert) => cert.name.indexOf('smsverification') === 0)
|
||||||
|
: [];
|
||||||
|
|
||||||
|
return certifications.length !== 0;
|
||||||
|
}
|
||||||
|
|
||||||
renderActionbar (account, balance) {
|
renderActionbar (account, balance) {
|
||||||
|
const { certifications, netVersion } = this.props;
|
||||||
|
const { address } = this.props.params;
|
||||||
const showTransferButton = !!(balance && balance.tokens);
|
const showTransferButton = !!(balance && balance.tokens);
|
||||||
|
const isVerifiable = this.isMainnet(netVersion);
|
||||||
|
const isFaucettable = this.isFaucettable(netVersion, certifications, address);
|
||||||
|
|
||||||
const buttons = [
|
const buttons = [
|
||||||
<Button
|
<Button
|
||||||
@ -149,9 +179,11 @@ class Account extends Component {
|
|||||||
}
|
}
|
||||||
onClick={ this.store.toggleFundDialog }
|
onClick={ this.store.toggleFundDialog }
|
||||||
/>,
|
/>,
|
||||||
|
isVerifiable
|
||||||
|
? (
|
||||||
<Button
|
<Button
|
||||||
icon={ <VerifyIcon /> }
|
icon={ <VerifyIcon /> }
|
||||||
key='sms-verification'
|
key='verification'
|
||||||
label={
|
label={
|
||||||
<FormattedMessage
|
<FormattedMessage
|
||||||
id='account.button.verify'
|
id='account.button.verify'
|
||||||
@ -159,7 +191,24 @@ class Account extends Component {
|
|||||||
/>
|
/>
|
||||||
}
|
}
|
||||||
onClick={ this.store.toggleVerificationDialog }
|
onClick={ this.store.toggleVerificationDialog }
|
||||||
/>,
|
/>
|
||||||
|
)
|
||||||
|
: null,
|
||||||
|
isFaucettable
|
||||||
|
? (
|
||||||
|
<Button
|
||||||
|
icon={ <DialIcon /> }
|
||||||
|
key='faucet'
|
||||||
|
label={
|
||||||
|
<FormattedMessage
|
||||||
|
id='account.button.faucet'
|
||||||
|
defaultMessage='Kovan ETH'
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
onClick={ this.store.toggleFaucetDialog }
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
: null,
|
||||||
<Button
|
<Button
|
||||||
icon={ <EditIcon /> }
|
icon={ <EditIcon /> }
|
||||||
key='editmeta'
|
key='editmeta'
|
||||||
@ -253,6 +302,24 @@ class Account extends Component {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
renderFaucetDialog () {
|
||||||
|
const { netVersion } = this.props;
|
||||||
|
|
||||||
|
if (!this.store.isFaucetVisible) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
const { address } = this.props.params;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Faucet
|
||||||
|
address={ address }
|
||||||
|
netVersion={ netVersion }
|
||||||
|
onClose={ this.store.toggleFaucetDialog }
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
renderFundDialog () {
|
renderFundDialog () {
|
||||||
if (!this.store.isFundVisible) {
|
if (!this.store.isFundVisible) {
|
||||||
return null;
|
return null;
|
||||||
@ -317,10 +384,14 @@ class Account extends Component {
|
|||||||
function mapStateToProps (state) {
|
function mapStateToProps (state) {
|
||||||
const { accounts } = state.personal;
|
const { accounts } = state.personal;
|
||||||
const { balances } = state.balances;
|
const { balances } = state.balances;
|
||||||
|
const certifications = state.certifications;
|
||||||
|
const { netVersion } = state.nodeStatus;
|
||||||
|
|
||||||
return {
|
return {
|
||||||
accounts,
|
accounts,
|
||||||
balances
|
balances,
|
||||||
|
certifications,
|
||||||
|
netVersion
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -80,57 +80,16 @@ describe('views/Account', () => {
|
|||||||
describe('sub-renderers', () => {
|
describe('sub-renderers', () => {
|
||||||
describe('renderActionBar', () => {
|
describe('renderActionBar', () => {
|
||||||
let bar;
|
let bar;
|
||||||
let barShallow;
|
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
render();
|
render();
|
||||||
|
|
||||||
bar = instance.renderActionbar({ tokens: {} });
|
bar = instance.renderActionbar({ tokens: {} });
|
||||||
barShallow = shallow(bar);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
it('renders the bar', () => {
|
it('renders the bar', () => {
|
||||||
expect(bar.type).to.match(/Actionbar/);
|
expect(bar.type).to.match(/Actionbar/);
|
||||||
});
|
});
|
||||||
|
|
||||||
// TODO: Finding by index is not optimal, however couldn't find a better method atm
|
|
||||||
// since we cannot find by key (prop not visible in shallow debug())
|
|
||||||
describe('clicks', () => {
|
|
||||||
it('toggles transfer on click', () => {
|
|
||||||
barShallow.find('Button').at(0).simulate('click');
|
|
||||||
expect(store.isTransferVisible).to.be.true;
|
|
||||||
});
|
|
||||||
|
|
||||||
it('toggles fund on click', () => {
|
|
||||||
barShallow.find('Button').at(1).simulate('click');
|
|
||||||
expect(store.isFundVisible).to.be.true;
|
|
||||||
});
|
|
||||||
|
|
||||||
it('toggles fund on click', () => {
|
|
||||||
barShallow.find('Button').at(1).simulate('click');
|
|
||||||
expect(store.isFundVisible).to.be.true;
|
|
||||||
});
|
|
||||||
|
|
||||||
it('toggles verify on click', () => {
|
|
||||||
barShallow.find('Button').at(2).simulate('click');
|
|
||||||
expect(store.isVerificationVisible).to.be.true;
|
|
||||||
});
|
|
||||||
|
|
||||||
it('toggles edit on click', () => {
|
|
||||||
barShallow.find('Button').at(3).simulate('click');
|
|
||||||
expect(store.isEditVisible).to.be.true;
|
|
||||||
});
|
|
||||||
|
|
||||||
it('toggles password on click', () => {
|
|
||||||
barShallow.find('Button').at(4).simulate('click');
|
|
||||||
expect(store.isPasswordVisible).to.be.true;
|
|
||||||
});
|
|
||||||
|
|
||||||
it('toggles delete on click', () => {
|
|
||||||
barShallow.find('Button').at(5).simulate('click');
|
|
||||||
expect(store.isDeleteVisible).to.be.true;
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('renderDeleteDialog', () => {
|
describe('renderDeleteDialog', () => {
|
||||||
|
@ -19,6 +19,7 @@ import { action, observable } from 'mobx';
|
|||||||
export default class Store {
|
export default class Store {
|
||||||
@observable isDeleteVisible = false;
|
@observable isDeleteVisible = false;
|
||||||
@observable isEditVisible = false;
|
@observable isEditVisible = false;
|
||||||
|
@observable isFaucetVisible = false;
|
||||||
@observable isFundVisible = false;
|
@observable isFundVisible = false;
|
||||||
@observable isPasswordVisible = false;
|
@observable isPasswordVisible = false;
|
||||||
@observable isTransferVisible = false;
|
@observable isTransferVisible = false;
|
||||||
@ -32,6 +33,10 @@ export default class Store {
|
|||||||
this.isEditVisible = !this.isEditVisible;
|
this.isEditVisible = !this.isEditVisible;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@action toggleFaucetDialog = () => {
|
||||||
|
this.isFaucetVisible = !this.isFaucetVisible;
|
||||||
|
}
|
||||||
|
|
||||||
@action toggleFundDialog = () => {
|
@action toggleFundDialog = () => {
|
||||||
this.isFundVisible = !this.isFundVisible;
|
this.isFundVisible = !this.isFundVisible;
|
||||||
}
|
}
|
||||||
|
@ -31,6 +31,7 @@ describe('views/Account/Store', () => {
|
|||||||
it('sets all modal visibility to false', () => {
|
it('sets all modal visibility to false', () => {
|
||||||
expect(store.isDeleteVisible).to.be.false;
|
expect(store.isDeleteVisible).to.be.false;
|
||||||
expect(store.isEditVisible).to.be.false;
|
expect(store.isEditVisible).to.be.false;
|
||||||
|
expect(store.isFaucetVisible).to.be.false;
|
||||||
expect(store.isFundVisible).to.be.false;
|
expect(store.isFundVisible).to.be.false;
|
||||||
expect(store.isPasswordVisible).to.be.false;
|
expect(store.isPasswordVisible).to.be.false;
|
||||||
expect(store.isTransferVisible).to.be.false;
|
expect(store.isTransferVisible).to.be.false;
|
||||||
@ -53,6 +54,13 @@ describe('views/Account/Store', () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('toggleFaucetDialog', () => {
|
||||||
|
it('toggles the visibility', () => {
|
||||||
|
store.toggleFaucetDialog();
|
||||||
|
expect(store.isFaucetVisible).to.be.true;
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
describe('toggleFundDialog', () => {
|
describe('toggleFundDialog', () => {
|
||||||
it('toggles the visibility', () => {
|
it('toggles the visibility', () => {
|
||||||
store.toggleFundDialog();
|
store.toggleFundDialog();
|
||||||
|
Loading…
Reference in New Issue
Block a user