Merge pull request #3766 from ethcore/jr-email-verification
email verification
This commit is contained in:
@@ -15,10 +15,6 @@
|
||||
/* along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
.list li {
|
||||
padding: .1em 0;
|
||||
}
|
||||
|
||||
.spacing {
|
||||
margin-top: 1.5em;
|
||||
}
|
||||
@@ -25,41 +25,33 @@ import { fromWei } from '~/api/util/wei';
|
||||
import { Form, Input } from '~/ui';
|
||||
import { nullableProptype } from '~/util/proptypes';
|
||||
|
||||
import { termsOfService } from '../../../3rdparty/sms-verification';
|
||||
import smsTermsOfService from '~/3rdparty/sms-verification/terms-of-service';
|
||||
import emailTermsOfService from '~/3rdparty/email-verification/terms-of-service';
|
||||
import { howSMSVerificationWorks, howEmailVerificationWorks } from '../how-it-works';
|
||||
import styles from './gatherData.css';
|
||||
|
||||
export default class GatherData extends Component {
|
||||
static propTypes = {
|
||||
fee: React.PropTypes.instanceOf(BigNumber),
|
||||
isNumberValid: PropTypes.bool.isRequired,
|
||||
method: PropTypes.string.isRequired,
|
||||
fields: PropTypes.array.isRequired,
|
||||
isVerified: nullableProptype(PropTypes.bool.isRequired),
|
||||
hasRequested: nullableProptype(PropTypes.bool.isRequired),
|
||||
setNumber: PropTypes.func.isRequired,
|
||||
setConsentGiven: PropTypes.func.isRequired
|
||||
}
|
||||
|
||||
render () {
|
||||
const { isNumberValid, isVerified } = this.props;
|
||||
const { method, isVerified } = this.props;
|
||||
const termsOfService = method === 'email' ? emailTermsOfService : smsTermsOfService;
|
||||
const howItWorks = method === 'email' ? howEmailVerificationWorks : howSMSVerificationWorks;
|
||||
|
||||
return (
|
||||
<Form>
|
||||
<p>The following steps will let you prove that you control both an account and a phone number.</p>
|
||||
<ol className={ styles.list }>
|
||||
<li>You send a verification request to a specific contract.</li>
|
||||
<li>Our server puts a puzzle into this contract.</li>
|
||||
<li>The code you receive via SMS is the solution to this puzzle.</li>
|
||||
</ol>
|
||||
{ howItWorks }
|
||||
{ this.renderFee() }
|
||||
{ this.renderCertified() }
|
||||
{ this.renderRequested() }
|
||||
<Input
|
||||
label={ 'phone number in international format' }
|
||||
hint={ 'the SMS will be sent to this number' }
|
||||
error={ isNumberValid ? null : 'invalid number' }
|
||||
disabled={ isVerified }
|
||||
onChange={ this.numberOnChange }
|
||||
onSubmit={ this.numberOnSubmit }
|
||||
/>
|
||||
{ this.renderFields() }
|
||||
<Checkbox
|
||||
className={ styles.spacing }
|
||||
label={ 'I agree to the terms and conditions below.' }
|
||||
@@ -136,12 +128,28 @@ export default class GatherData extends Component {
|
||||
);
|
||||
}
|
||||
|
||||
numberOnSubmit = (value) => {
|
||||
this.props.setNumber(value);
|
||||
}
|
||||
renderFields () {
|
||||
const { isVerified, fields } = this.props;
|
||||
|
||||
numberOnChange = (_, value) => {
|
||||
this.props.setNumber(value);
|
||||
const rendered = fields.map((field) => {
|
||||
const onChange = (_, v) => {
|
||||
field.onChange(v);
|
||||
};
|
||||
const onSubmit = field.onChange;
|
||||
return (
|
||||
<Input
|
||||
key={ field.key }
|
||||
label={ field.label }
|
||||
hint={ field.hint }
|
||||
error={ field.error }
|
||||
disabled={ isVerified }
|
||||
onChange={ onChange }
|
||||
onSubmit={ onSubmit }
|
||||
/>
|
||||
);
|
||||
});
|
||||
|
||||
return (<div>{rendered}</div>);
|
||||
}
|
||||
|
||||
consentOnChange = (_, consentGiven) => {
|
||||
@@ -20,20 +20,25 @@ import { Form, Input } from '~/ui';
|
||||
|
||||
export default class QueryCode extends Component {
|
||||
static propTypes = {
|
||||
number: PropTypes.string.isRequired,
|
||||
receiver: PropTypes.string.isRequired,
|
||||
hint: PropTypes.string,
|
||||
isCodeValid: PropTypes.bool.isRequired,
|
||||
setCode: PropTypes.func.isRequired
|
||||
}
|
||||
|
||||
static defaultProps = {
|
||||
hint: 'Enter the code you received.'
|
||||
}
|
||||
|
||||
render () {
|
||||
const { number, isCodeValid } = this.props;
|
||||
const { receiver, hint, isCodeValid } = this.props;
|
||||
|
||||
return (
|
||||
<Form>
|
||||
<p>The verification code has been sent to { number }.</p>
|
||||
<p>The verification code has been sent to { receiver }.</p>
|
||||
<Input
|
||||
label={ 'verification code' }
|
||||
hint={ 'Enter the code you received via SMS.' }
|
||||
hint={ hint }
|
||||
error={ isCodeValid ? null : 'invalid code' }
|
||||
onChange={ this.onChange }
|
||||
onSubmit={ this.onSubmit }
|
||||
@@ -19,7 +19,7 @@ import React, { Component, PropTypes } from 'react';
|
||||
import { nullableProptype } from '~/util/proptypes';
|
||||
import TxHash from '~/ui/TxHash';
|
||||
import {
|
||||
POSTING_REQUEST, POSTED_REQUEST, REQUESTING_SMS
|
||||
POSTING_REQUEST, POSTED_REQUEST, REQUESTING_CODE
|
||||
} from '../store';
|
||||
|
||||
import styles from './sendRequest.css';
|
||||
@@ -45,9 +45,9 @@ export default class SendRequest extends Component {
|
||||
</div>
|
||||
);
|
||||
|
||||
case REQUESTING_SMS:
|
||||
case REQUESTING_CODE:
|
||||
return (
|
||||
<p>Requesting an SMS from the Parity server and waiting for the puzzle to be put into the contract.</p>
|
||||
<p>Requesting a code from the Parity server and waiting for the puzzle to be put into the contract.</p>
|
||||
);
|
||||
|
||||
default:
|
||||
70
js/src/modals/Verification/email-store.js
Normal file
70
js/src/modals/Verification/email-store.js
Normal file
@@ -0,0 +1,70 @@
|
||||
// Copyright 2015, 2016 Ethcore (UK) Ltd.
|
||||
// This file is part of Parity.
|
||||
|
||||
// Parity is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
|
||||
// Parity is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import { observable, computed, action } from 'mobx';
|
||||
import { sha3 } from '~/api/util/sha3';
|
||||
|
||||
import EmailVerificationABI from '~/contracts/abi/email-verification.json';
|
||||
import VerificationStore, {
|
||||
LOADING, QUERY_DATA, QUERY_CODE, POSTED_CONFIRMATION, DONE
|
||||
} from './store';
|
||||
import { postToServer } from '../../3rdparty/email-verification';
|
||||
|
||||
export default class EmailVerificationStore extends VerificationStore {
|
||||
@observable email = '';
|
||||
|
||||
@computed get isEmailValid () {
|
||||
// See https://davidcel.is/posts/stop-validating-email-addresses-with-regex/
|
||||
return this.email && this.email.indexOf('@') >= 0;
|
||||
}
|
||||
|
||||
@computed get isStepValid () {
|
||||
if (this.step === DONE) {
|
||||
return true;
|
||||
}
|
||||
if (this.error) {
|
||||
return false;
|
||||
}
|
||||
|
||||
switch (this.step) {
|
||||
case LOADING:
|
||||
return this.contract && this.fee && this.isVerified !== null && this.hasRequested !== null;
|
||||
case QUERY_DATA:
|
||||
return this.isEmailValid && this.consentGiven;
|
||||
case QUERY_CODE:
|
||||
return this.requestTx && this.isCodeValid === true;
|
||||
case POSTED_CONFIRMATION:
|
||||
return !!this.confirmationTx;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
constructor (api, account, isTestnet) {
|
||||
super(api, EmailVerificationABI, 'emailverification3', account, isTestnet);
|
||||
}
|
||||
|
||||
requestValues = () => [ sha3(this.email) ]
|
||||
|
||||
@action setEmail = (email) => {
|
||||
this.email = email;
|
||||
}
|
||||
|
||||
requestCode = () => {
|
||||
const { email, account, isTestnet } = this;
|
||||
return postToServer({ email, address: account }, isTestnet);
|
||||
}
|
||||
}
|
||||
41
js/src/modals/Verification/how-it-works.js
Normal file
41
js/src/modals/Verification/how-it-works.js
Normal file
@@ -0,0 +1,41 @@
|
||||
// Copyright 2015, 2016 Ethcore (UK) Ltd.
|
||||
// This file is part of Parity.
|
||||
|
||||
// Parity is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
|
||||
// Parity is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import React from 'react';
|
||||
|
||||
import styles from './verification.css';
|
||||
|
||||
export const howSMSVerificationWorks = (
|
||||
<div>
|
||||
<p>The following steps will let you prove that you control both an account and a phone number.</p>
|
||||
<ol className={ styles.list }>
|
||||
<li>You send a verification request to a specific contract.</li>
|
||||
<li>Our server puts a puzzle into this contract.</li>
|
||||
<li>The code you receive via SMS is the solution to this puzzle.</li>
|
||||
</ol>
|
||||
</div>
|
||||
);
|
||||
|
||||
export const howEmailVerificationWorks = (
|
||||
<div>
|
||||
<p>The following steps will let you prove that you control both an account and an e-mail address.</p>
|
||||
<ol className={ styles.list }>
|
||||
<li>You send a verification request to a specific contract.</li>
|
||||
<li>Our server puts a puzzle into this contract.</li>
|
||||
<li>The code you receive via e-mail is the solution to this puzzle.</li>
|
||||
</ol>
|
||||
</div>
|
||||
);
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright 2015, 2016 Parity Technologies (UK) Ltd.
|
||||
// Copyright 2015, 2016 Ethcore (UK) Ltd.
|
||||
// This file is part of Parity.
|
||||
|
||||
// Parity is free software: you can redistribute it and/or modify
|
||||
@@ -14,4 +14,4 @@
|
||||
// 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 './SMSVerification';
|
||||
export default from './verification';
|
||||
67
js/src/modals/Verification/sms-store.js
Normal file
67
js/src/modals/Verification/sms-store.js
Normal file
@@ -0,0 +1,67 @@
|
||||
// Copyright 2015, 2016 Ethcore (UK) Ltd.
|
||||
// This file is part of Parity.
|
||||
|
||||
// Parity is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
|
||||
// Parity is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import { observable, computed, action } from 'mobx';
|
||||
import phone from 'phoneformat.js';
|
||||
|
||||
import SMSVerificationABI from '~/contracts/abi/sms-verification.json';
|
||||
import VerificationStore, {
|
||||
LOADING, QUERY_DATA, QUERY_CODE, POSTED_CONFIRMATION, DONE
|
||||
} from './store';
|
||||
import { postToServer } from '../../3rdparty/sms-verification';
|
||||
|
||||
export default class SMSVerificationStore extends VerificationStore {
|
||||
@observable number = '';
|
||||
|
||||
@computed get isNumberValid () {
|
||||
return phone.isValidNumber(this.number);
|
||||
}
|
||||
|
||||
@computed get isStepValid () {
|
||||
if (this.step === DONE) {
|
||||
return true;
|
||||
}
|
||||
if (this.error) {
|
||||
return false;
|
||||
}
|
||||
|
||||
switch (this.step) {
|
||||
case LOADING:
|
||||
return this.contract && this.fee && this.isVerified !== null && this.hasRequested !== null;
|
||||
case QUERY_DATA:
|
||||
return this.isNumberValid && this.consentGiven;
|
||||
case QUERY_CODE:
|
||||
return this.requestTx && this.isCodeValid === true;
|
||||
case POSTED_CONFIRMATION:
|
||||
return !!this.confirmationTx;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
constructor (api, account, isTestnet) {
|
||||
super(api, SMSVerificationABI, 'smsverification', account, isTestnet);
|
||||
}
|
||||
|
||||
@action setNumber = (number) => {
|
||||
this.number = number;
|
||||
}
|
||||
|
||||
requestCode = () => {
|
||||
const { number, account, isTestnet } = this;
|
||||
return postToServer({ number, address: account }, isTestnet);
|
||||
}
|
||||
}
|
||||
@@ -14,21 +14,19 @@
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import { observable, computed, autorun, action } from 'mobx';
|
||||
import phone from 'phoneformat.js';
|
||||
import { observable, autorun, action } from 'mobx';
|
||||
import { sha3 } from '~/api/util/sha3';
|
||||
|
||||
import Contract from '~/api/contract';
|
||||
import Contracts from '~/contracts';
|
||||
|
||||
import { checkIfVerified, checkIfRequested, awaitPuzzle } from '~/contracts/sms-verification';
|
||||
import { postToServer } from '~/3rdparty/sms-verification';
|
||||
import { checkIfVerified, checkIfRequested, awaitPuzzle } from '~/contracts/verification';
|
||||
import { checkIfTxFailed, waitForConfirmations } from '~/util/tx';
|
||||
|
||||
export const LOADING = 'fetching-contract';
|
||||
export const QUERY_DATA = 'query-data';
|
||||
export const POSTING_REQUEST = 'posting-request';
|
||||
export const POSTED_REQUEST = 'posted-request';
|
||||
export const REQUESTING_SMS = 'requesting-sms';
|
||||
export const REQUESTING_CODE = 'requesting-code';
|
||||
export const QUERY_CODE = 'query-code';
|
||||
export const POSTING_CONFIRMATION = 'posting-confirmation';
|
||||
export const POSTED_CONFIRMATION = 'posted-confirmation';
|
||||
@@ -43,56 +41,30 @@ export default class VerificationStore {
|
||||
@observable isVerified = null;
|
||||
@observable hasRequested = null;
|
||||
@observable consentGiven = false;
|
||||
@observable number = '';
|
||||
@observable requestTx = null;
|
||||
@observable code = '';
|
||||
@observable isCodeValid = null;
|
||||
@observable confirmationTx = null;
|
||||
|
||||
@computed get isNumberValid () {
|
||||
return phone.isValidNumber(this.number);
|
||||
}
|
||||
|
||||
@computed get isStepValid () {
|
||||
if (this.step === DONE) {
|
||||
return true;
|
||||
}
|
||||
if (this.error) {
|
||||
return false;
|
||||
}
|
||||
|
||||
switch (this.step) {
|
||||
case LOADING:
|
||||
return this.contract && this.fee && this.isVerified !== null && this.hasRequested !== null;
|
||||
case QUERY_DATA:
|
||||
return this.isNumberValid && this.consentGiven;
|
||||
case QUERY_CODE:
|
||||
return this.requestTx && this.isCodeValid === true;
|
||||
case POSTED_CONFIRMATION:
|
||||
return !!this.confirmationTx;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
constructor (api, account, isTestnet) {
|
||||
constructor (api, abi, name, account, isTestnet) {
|
||||
this.api = api;
|
||||
this.account = account;
|
||||
this.isTestnet = isTestnet;
|
||||
|
||||
this.step = LOADING;
|
||||
Contracts.create(api).registry.getContract('smsverification')
|
||||
.then((contract) => {
|
||||
this.contract = contract;
|
||||
Contracts.get().badgeReg.fetchCertifier(name)
|
||||
.then(({ address }) => {
|
||||
this.contract = new Contract(api, abi).at(address);
|
||||
this.load();
|
||||
})
|
||||
.catch((err) => {
|
||||
console.error('error', err);
|
||||
this.error = 'Failed to fetch the contract: ' + err.message;
|
||||
});
|
||||
|
||||
autorun(() => {
|
||||
if (this.error) {
|
||||
console.error('sms verification: ' + this.error);
|
||||
console.error('verification: ' + this.error);
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -135,10 +107,6 @@ export default class VerificationStore {
|
||||
});
|
||||
}
|
||||
|
||||
@action setNumber = (number) => {
|
||||
this.number = number;
|
||||
}
|
||||
|
||||
@action setConsentGiven = (consentGiven) => {
|
||||
this.consentGiven = consentGiven;
|
||||
}
|
||||
@@ -166,19 +134,22 @@ export default class VerificationStore {
|
||||
});
|
||||
}
|
||||
|
||||
requestValues = () => []
|
||||
|
||||
@action sendRequest = () => {
|
||||
const { api, account, contract, fee, number, hasRequested } = this;
|
||||
const { api, account, contract, fee, hasRequested } = this;
|
||||
|
||||
const request = contract.functions.find((fn) => fn.name === 'request');
|
||||
const options = { from: account, value: fee.toString() };
|
||||
const values = this.requestValues();
|
||||
|
||||
let chain = Promise.resolve();
|
||||
if (!hasRequested) {
|
||||
this.step = POSTING_REQUEST;
|
||||
chain = request.estimateGas(options, [])
|
||||
chain = request.estimateGas(options, values)
|
||||
.then((gas) => {
|
||||
options.gas = gas.mul(1.2).toFixed(0);
|
||||
return request.postTransaction(options, []);
|
||||
return request.postTransaction(options, values);
|
||||
})
|
||||
.then((handle) => {
|
||||
// TODO: The "request rejected" error doesn't have any property to
|
||||
@@ -200,18 +171,15 @@ export default class VerificationStore {
|
||||
|
||||
chain
|
||||
.then(() => {
|
||||
return api.parity.netChain();
|
||||
})
|
||||
.then((chain) => {
|
||||
this.step = REQUESTING_SMS;
|
||||
return postToServer({ number, address: account }, this.isTestnet);
|
||||
this.step = REQUESTING_CODE;
|
||||
return this.requestCode();
|
||||
})
|
||||
.then(() => awaitPuzzle(api, contract, account))
|
||||
.then(() => {
|
||||
this.step = QUERY_CODE;
|
||||
})
|
||||
.catch((err) => {
|
||||
this.error = 'Failed to request a confirmation SMS: ' + err.message;
|
||||
this.error = 'Failed to request a confirmation code: ' + err.message;
|
||||
});
|
||||
}
|
||||
|
||||
25
js/src/modals/Verification/verification.css
Normal file
25
js/src/modals/Verification/verification.css
Normal file
@@ -0,0 +1,25 @@
|
||||
/* Copyright 2015, 2016 Ethcore (UK) Ltd.
|
||||
/* This file is part of Parity.
|
||||
/*
|
||||
/* Parity is free software: you can redistribute it and/or modify
|
||||
/* it under the terms of the GNU General Public License as published by
|
||||
/* the Free Software Foundation, either version 3 of the License, or
|
||||
/* (at your option) any later version.
|
||||
/*
|
||||
/* Parity is distributed in the hope that it will be useful,
|
||||
/* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
/* GNU General Public License for more details.
|
||||
/*
|
||||
/* You should have received a copy of the GNU General Public License
|
||||
/* along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
.noSpacing {
|
||||
margin-top: 0;
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.list li {
|
||||
padding: .1em 0;
|
||||
}
|
||||
@@ -20,12 +20,27 @@ import DoneIcon from 'material-ui/svg-icons/action/done-all';
|
||||
import CancelIcon from 'material-ui/svg-icons/content/clear';
|
||||
|
||||
import { Button, IdentityIcon, Modal } from '~/ui';
|
||||
import RadioButtons from '~/ui/Form/RadioButtons';
|
||||
import { nullableProptype } from '~/util/proptypes';
|
||||
|
||||
import styles from './verification.css';
|
||||
|
||||
const methods = {
|
||||
sms: {
|
||||
label: 'SMS Verification', key: 0, value: 'sms',
|
||||
description: (<p className={ styles.noSpacing }>It will be stored on the blockchain that you control a phone number (not <em>which</em>).</p>)
|
||||
},
|
||||
email: {
|
||||
label: 'E-mail Verification', key: 1, value: 'email',
|
||||
description: (<p className={ styles.noSpacing }>The hash of the e-mail address you prove control over will be stored on the blockchain.</p>)
|
||||
}
|
||||
};
|
||||
|
||||
import {
|
||||
LOADING,
|
||||
QUERY_DATA,
|
||||
POSTING_REQUEST, POSTED_REQUEST,
|
||||
REQUESTING_SMS, QUERY_CODE,
|
||||
REQUESTING_CODE, QUERY_CODE,
|
||||
POSTING_CONFIRMATION, POSTED_CONFIRMATION,
|
||||
DONE
|
||||
} from './store';
|
||||
@@ -37,34 +52,44 @@ import SendConfirmation from './SendConfirmation';
|
||||
import Done from './Done';
|
||||
|
||||
@observer
|
||||
export default class SMSVerification extends Component {
|
||||
export default class Verification extends Component {
|
||||
static propTypes = {
|
||||
store: PropTypes.any.isRequired,
|
||||
store: nullableProptype(PropTypes.object.isRequired),
|
||||
account: PropTypes.string.isRequired,
|
||||
onSelectMethod: PropTypes.func.isRequired,
|
||||
onClose: PropTypes.func.isRequired
|
||||
}
|
||||
|
||||
static phases = { // mapping (store steps -> steps)
|
||||
[LOADING]: 0,
|
||||
[QUERY_DATA]: 1,
|
||||
[POSTING_REQUEST]: 2, [POSTED_REQUEST]: 2, [REQUESTING_SMS]: 2,
|
||||
[LOADING]: 1, [QUERY_DATA]: 1,
|
||||
[POSTING_REQUEST]: 2, [POSTED_REQUEST]: 2, [REQUESTING_CODE]: 2,
|
||||
[QUERY_CODE]: 3,
|
||||
[POSTING_CONFIRMATION]: 4, [POSTED_CONFIRMATION]: 4,
|
||||
[DONE]: 5
|
||||
}
|
||||
|
||||
state = {
|
||||
method: 'sms'
|
||||
};
|
||||
|
||||
render () {
|
||||
const phase = SMSVerification.phases[this.props.store.step];
|
||||
const { error, isStepValid } = this.props.store;
|
||||
const { store } = this.props;
|
||||
let phase = 0; let error = false; let isStepValid = true;
|
||||
|
||||
if (store) {
|
||||
phase = Verification.phases[store.step];
|
||||
error = store.error;
|
||||
isStepValid = store.isStepValid;
|
||||
}
|
||||
|
||||
return (
|
||||
<Modal
|
||||
actions={ this.renderDialogActions(phase, error, isStepValid) }
|
||||
title='verify your account via SMS'
|
||||
title='verify your account'
|
||||
visible
|
||||
current={ phase }
|
||||
steps={ ['Prepare', 'Enter Data', 'Request', 'Enter Code', 'Confirm', 'Done!'] }
|
||||
waiting={ error ? [] : [ 0, 2, 4 ] }
|
||||
steps={ ['Method', 'Enter Data', 'Request', 'Enter Code', 'Confirm', 'Done!'] }
|
||||
waiting={ error ? [] : [ 2, 4 ] }
|
||||
>
|
||||
{ this.renderStep(phase, error) }
|
||||
</Modal>
|
||||
@@ -101,6 +126,13 @@ export default class SMSVerification extends Component {
|
||||
|
||||
let action = () => {};
|
||||
switch (phase) {
|
||||
case 0:
|
||||
action = () => {
|
||||
const { onSelectMethod } = this.props;
|
||||
const { method } = this.state;
|
||||
onSelectMethod(method);
|
||||
};
|
||||
break;
|
||||
case 1:
|
||||
action = store.sendRequest;
|
||||
break;
|
||||
@@ -133,26 +165,58 @@ export default class SMSVerification extends Component {
|
||||
return (<p>{ error }</p>);
|
||||
}
|
||||
|
||||
const { method } = this.state;
|
||||
if (phase === 0) {
|
||||
const values = Object.values(methods);
|
||||
const value = values.findIndex((v) => v.value === method);
|
||||
return (
|
||||
<RadioButtons
|
||||
value={ value < 0 ? 0 : value }
|
||||
values={ values }
|
||||
onChange={ this.selectMethod }
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
const {
|
||||
step,
|
||||
fee, number, isNumberValid, isVerified, hasRequested,
|
||||
fee, isVerified, hasRequested,
|
||||
requestTx, isCodeValid, confirmationTx,
|
||||
setCode
|
||||
} = this.props.store;
|
||||
|
||||
switch (phase) {
|
||||
case 0:
|
||||
return (
|
||||
<p>Loading SMS Verification.</p>
|
||||
);
|
||||
|
||||
case 1:
|
||||
const { setNumber, setConsentGiven } = this.props.store;
|
||||
if (step === LOADING) {
|
||||
return (<p>Loading verification data.</p>);
|
||||
}
|
||||
|
||||
const { setConsentGiven } = this.props.store;
|
||||
|
||||
const fields = [];
|
||||
if (method === 'sms') {
|
||||
fields.push({
|
||||
key: 'number',
|
||||
label: 'phone number in international format',
|
||||
hint: 'the SMS will be sent to this number',
|
||||
error: this.props.store.isNumberValid ? null : 'invalid number',
|
||||
onChange: this.props.store.setNumber
|
||||
});
|
||||
} else if (method === 'email') {
|
||||
fields.push({
|
||||
key: 'email',
|
||||
label: 'email address',
|
||||
hint: 'the code will be sent to this address',
|
||||
error: this.props.store.isEmailValid ? null : 'invalid email',
|
||||
onChange: this.props.store.setEmail
|
||||
});
|
||||
}
|
||||
|
||||
return (
|
||||
<GatherData
|
||||
fee={ fee } isNumberValid={ isNumberValid }
|
||||
isVerified={ isVerified } hasRequested={ hasRequested }
|
||||
setNumber={ setNumber } setConsentGiven={ setConsentGiven }
|
||||
method={ method } fields={ fields }
|
||||
fee={ fee } isVerified={ isVerified } hasRequested={ hasRequested }
|
||||
setConsentGiven={ setConsentGiven }
|
||||
/>
|
||||
);
|
||||
|
||||
@@ -162,9 +226,19 @@ export default class SMSVerification extends Component {
|
||||
);
|
||||
|
||||
case 3:
|
||||
let receiver, hint;
|
||||
if (method === 'sms') {
|
||||
receiver = this.props.store.number;
|
||||
hint = 'Enter the code you received via SMS.';
|
||||
} else if (method === 'email') {
|
||||
receiver = this.props.store.email;
|
||||
hint = 'Enter the code you received via e-mail.';
|
||||
}
|
||||
return (
|
||||
<QueryCode
|
||||
number={ number } fee={ fee } isCodeValid={ isCodeValid }
|
||||
receiver={ receiver }
|
||||
hint={ hint }
|
||||
isCodeValid={ isCodeValid }
|
||||
setCode={ setCode }
|
||||
/>
|
||||
);
|
||||
@@ -183,4 +257,8 @@ export default class SMSVerification extends Component {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
selectMethod = (choice, i) => {
|
||||
this.setState({ method: choice.value });
|
||||
}
|
||||
}
|
||||
@@ -24,7 +24,7 @@ import EditMeta from './EditMeta';
|
||||
import ExecuteContract from './ExecuteContract';
|
||||
import FirstRun from './FirstRun';
|
||||
import Shapeshift from './Shapeshift';
|
||||
import SMSVerification from './SMSVerification';
|
||||
import Verification from './Verification';
|
||||
import Transfer from './Transfer';
|
||||
import PasswordManager from './PasswordManager';
|
||||
import SaveContract from './SaveContract';
|
||||
@@ -42,7 +42,7 @@ export {
|
||||
ExecuteContract,
|
||||
FirstRun,
|
||||
Shapeshift,
|
||||
SMSVerification,
|
||||
Verification,
|
||||
Transfer,
|
||||
PasswordManager,
|
||||
LoadContract,
|
||||
|
||||
Reference in New Issue
Block a user