-
- }
- label={
-
- }
- onChange={ this.onEditPhrase }
- value={ phrase }
- />
-
- }
- label={
-
- }
- onChange={ this.onEditName }
- value={ name }
- />
-
- }
- label={
-
- }
- onChange={ this.onEditPasswordHint }
- value={ passwordHint }
- />
-
-
-
-
-
- }
- onCheck={ this.onToggleWindowsPhrase }
- />
-
+
+
+
+ }
+ onCheck={ this.onToggleWindowsPhrase }
+ />
+
+
);
}
+ renderWarning () {
+ const { isTest, phrase } = this.props.createStore;
+
+ if (!isTest && phrase.length === 0) {
+ return (
+
+ }
+ />
+ );
+ }
+
+ if (phrase.length === 0) {
+ return (
+
+ }
+ />
+ );
+ }
+
+ const words = phrase.split(' ');
+
+ if (words.length < 11) {
+ return (
+
+ }
+ />
+ );
+ }
+
+ return null;
+ }
+
onToggleWindowsPhrase = (event) => {
const { createStore } = this.props;
diff --git a/js/src/modals/CreateAccount/createAccount.js b/js/src/modals/CreateAccount/createAccount.js
index 56f1db751..06809adf0 100644
--- a/js/src/modals/CreateAccount/createAccount.js
+++ b/js/src/modals/CreateAccount/createAccount.js
@@ -63,8 +63,14 @@ const TITLES = {
),
import: (
+ ),
+ restore: (
+
),
qr: (
@@ -76,25 +82,37 @@ const TITLES = {
};
const STAGE_NAMES = [TITLES.type, TITLES.create, TITLES.info];
const STAGE_IMPORT = [TITLES.type, TITLES.import, TITLES.info];
+const STAGE_RESTORE = [TITLES.restore, TITLES.info];
const STAGE_QR = [TITLES.type, TITLES.qr, TITLES.info];
@observer
class CreateAccount extends Component {
static contextTypes = {
api: PropTypes.object.isRequired
- }
+ };
static propTypes = {
accounts: PropTypes.object.isRequired,
+ isTest: PropTypes.bool.isRequired,
newError: PropTypes.func.isRequired,
onClose: PropTypes.func,
- onUpdate: PropTypes.func
- }
+ onUpdate: PropTypes.func,
+ restore: PropTypes.bool
+ };
- createStore = new Store(this.context.api, this.props.accounts);
+ static defaultProps = {
+ restore: false
+ };
+
+ createStore = new Store(this.context.api, this.props.accounts, this.props.isTest);
vaultStore = VaultStore.get(this.context.api);
componentWillMount () {
+ if (this.props.restore) {
+ this.createStore.setCreateType('fromPhrase');
+ this.createStore.nextStage();
+ }
+
return this.vaultStore.loadVaults();
}
@@ -107,6 +125,8 @@ class CreateAccount extends Component {
steps = STAGE_NAMES;
} else if (createType === 'fromQr') {
steps = STAGE_QR;
+ } else if (createType === 'fromPhrase') {
+ steps = STAGE_RESTORE;
}
return (
@@ -199,6 +219,7 @@ class CreateAccount extends Component {
}
renderDialogActions () {
+ const { restore } = this.props;
const { createType, canCreate, isBusy, stage } = this.createStore;
const cancelBtn = (
@@ -215,6 +236,22 @@ class CreateAccount extends Component {
/>
);
+ const backBtn = restore
+ ? null
+ : (
+ }
+ key='back'
+ label={
+
+ }
+ onClick={ this.createStore.prevStage }
+ />
+ );
+
switch (stage) {
case STAGE_SELECT_TYPE:
return [
@@ -235,17 +272,7 @@ class CreateAccount extends Component {
case STAGE_CREATE:
return [
cancelBtn,
- }
- key='back'
- label={
-
- }
- onClick={ this.createStore.prevStage }
- />,
+ backBtn,
}
@@ -335,6 +362,12 @@ class CreateAccount extends Component {
}
}
+function mapStateToProps (state) {
+ const { isTest } = state.nodeStatus;
+
+ return { isTest };
+}
+
function mapDispatchToProps (dispatch) {
return bindActionCreators({
newError
@@ -342,6 +375,6 @@ function mapDispatchToProps (dispatch) {
}
export default connect(
- null,
+ mapStateToProps,
mapDispatchToProps
)(CreateAccount);
diff --git a/js/src/modals/CreateAccount/createAccount.test.js b/js/src/modals/CreateAccount/createAccount.test.js
index d4ba5a0a4..1cbc62329 100644
--- a/js/src/modals/CreateAccount/createAccount.test.js
+++ b/js/src/modals/CreateAccount/createAccount.test.js
@@ -54,7 +54,11 @@ function createRedux () {
dispatch: sinon.stub(),
subscribe: sinon.stub(),
getState: () => {
- return {};
+ return {
+ nodeStatus: {
+ isTest: true
+ }
+ };
}
};
}
diff --git a/js/src/modals/CreateAccount/store.js b/js/src/modals/CreateAccount/store.js
index 9f78360fa..afc13cd54 100644
--- a/js/src/modals/CreateAccount/store.js
+++ b/js/src/modals/CreateAccount/store.js
@@ -50,9 +50,10 @@ export default class Store {
@observable walletFileError = ERRORS.noFile;
@observable walletJson = '';
- constructor (api, accounts, loadGeth = true) {
+ constructor (api, accounts, isTest, loadGeth = true) {
this._api = api;
this.accounts = Object.assign({}, accounts);
+ this.isTest = isTest;
if (loadGeth) {
this.loadAvailableGethAccounts();
@@ -72,7 +73,7 @@ export default class Store {
return !(this.nameError || this.passwordRepeatError) && this.hasAddress;
case 'fromPhrase':
- return !(this.nameError || this.passwordRepeatError);
+ return !(this.nameError || this.passwordRepeatError || this.passPhraseError);
case 'fromQr':
return this.qrAddressValid && !this.nameError;
@@ -85,6 +86,10 @@ export default class Store {
}
}
+ @computed get passPhraseError () {
+ return !this.isTest && this.phrase.length === 0;
+ }
+
@computed get hasAddress () {
return !!(this.address);
}
diff --git a/js/src/modals/CreateAccount/store.spec.js b/js/src/modals/CreateAccount/store.spec.js
index 9d7bc10a2..6ec59fb85 100644
--- a/js/src/modals/CreateAccount/store.spec.js
+++ b/js/src/modals/CreateAccount/store.spec.js
@@ -37,7 +37,7 @@ function createStore (loadGeth) {
createVaultStore();
api = createApi();
- store = new Store(api, ACCOUNTS, loadGeth);
+ store = new Store(api, ACCOUNTS, true, loadGeth);
return store;
}
diff --git a/js/src/modals/FirstRun/firstRun.js b/js/src/modals/FirstRun/firstRun.js
index 1376a71b0..60f375a84 100644
--- a/js/src/modals/FirstRun/firstRun.js
+++ b/js/src/modals/FirstRun/firstRun.js
@@ -77,7 +77,7 @@ class FirstRun extends Component {
visible: PropTypes.bool.isRequired
}
- createStore = new CreateStore(this.context.api, {}, false);
+ createStore = new CreateStore(this.context.api, {}, true, false);
state = {
stage: 0,
diff --git a/js/src/ui/Icons/index.js b/js/src/ui/Icons/index.js
index e637a239a..b62eeef11 100644
--- a/js/src/ui/Icons/index.js
+++ b/js/src/ui/Icons/index.js
@@ -56,6 +56,7 @@ export PrintIcon from 'material-ui/svg-icons/action/print';
export RefreshIcon from 'material-ui/svg-icons/action/autorenew';
export ReorderIcon from 'material-ui/svg-icons/action/reorder';
export ReplayIcon from 'material-ui/svg-icons/av/replay';
+export RestoreIcon from 'material-ui/svg-icons/action/restore';
export SaveIcon from 'material-ui/svg-icons/content/save';
export SearchIcon from 'material-ui/svg-icons/action/search';
export SendIcon from 'material-ui/svg-icons/content/send';
diff --git a/js/src/views/Accounts/accounts.js b/js/src/views/Accounts/accounts.js
index c597ddf15..2280f9c5d 100644
--- a/js/src/views/Accounts/accounts.js
+++ b/js/src/views/Accounts/accounts.js
@@ -53,6 +53,7 @@ class Accounts extends Component {
newDialog: false,
newWalletDialog: false,
newExportDialog: false,
+ restoreDialog: false,
sortOrder: '',
searchValues: [],
searchTokens: [],
@@ -96,6 +97,7 @@ class Accounts extends Component {
return (
{ this.renderNewDialog() }
+ { this.renderRestoreDialog() }
{ this.renderNewWalletDialog() }
{ this.renderNewExportDialog() }
{ this.renderActionbar() }
@@ -284,6 +286,17 @@ class Accounts extends Component {
}
onClick={ this.onNewWalletClick }
/>,
+ }
+ label={
+
+ }
+ onClick={ this.onRestoreAccountClick }
+ />,
}
@@ -336,7 +349,23 @@ class Accounts extends Component {
+ );
+ }
+
+ renderRestoreDialog () {
+ const { accounts } = this.props;
+ const { restoreDialog } = this.state;
+
+ if (!restoreDialog) {
+ return null;
+ }
+
+ return (
+
);
}
@@ -384,6 +413,12 @@ class Accounts extends Component {
});
}
+ onRestoreAccountClick = () => {
+ this.setState({
+ restoreDialog: true
+ });
+ }
+
onNewWalletClick = () => {
this.setState({
newWalletDialog: true
@@ -402,6 +437,12 @@ class Accounts extends Component {
});
}
+ onRestoreAccountClose = () => {
+ this.setState({
+ restoreDialog: false
+ });
+ }
+
onNewWalletClose = () => {
this.setState({
newWalletDialog: false
@@ -414,9 +455,6 @@ class Accounts extends Component {
});
}
- onNewAccountUpdate = () => {
- }
-
onHardwareChange = () => {
const { accountsInfo } = this.props;
const { wallets } = this.hwstore;