diff --git a/features/login.feature b/features/login.feature
index ed5188940..ba3189ef2 100644
--- a/features/login.feature
+++ b/features/login.feature
@@ -32,7 +32,6 @@ Feature: Login page
Then I should be logged in
And I should see text "Testnet" in "peer network" element
- @ignore
Scenario: should allow to create a new account
Given I'm on login page
When I click "new account button"
diff --git a/src/components/app/index.js b/src/components/app/index.js
index 8f516fa21..25f392af0 100644
--- a/src/components/app/index.js
+++ b/src/components/app/index.js
@@ -31,6 +31,7 @@ const App = () => (
)} />
+
diff --git a/src/components/dialog/dialog.js b/src/components/dialog/dialog.js
index e1bdfa7ac..65adec27b 100644
--- a/src/components/dialog/dialog.js
+++ b/src/components/dialog/dialog.js
@@ -10,56 +10,81 @@ class DialogElement extends Component {
constructor() {
super();
this.state = {};
- this.path = {
- name: '/',
+ this.routesReg = [
+ {
+ regex: /\/main\/transactions(?:\/[^/]*)?$/,
+ path: '/main/transactions/',
+ params: 'dialog',
+ name: 'transactions',
+ }, {
+ regex: /\/main\/voting(?:\/[^/]*)?$/,
+ path: '/main/voting/',
+ params: 'dialog',
+ name: 'voting',
+ }, {
+ regex: /\/main\/forging(?:\/[^/]*)?$/,
+ path: '/main/forging/',
+ params: 'dialog',
+ name: 'forging',
+ }, {
+ regex: /\/(\w+)?$/,
+ path: '/',
+ params: 'dialog',
+ name: 'login',
+ },
+ ];
+ this.current = {
+ pathname: '/',
+ reg: this.routesReg[3],
list: [],
dialog: '',
};
}
componentDidMount() {
- this.checkForDialog(this.props.history.location);
+ this.checkForDialog();
}
componentDidUpdate() {
- if (this.path.name !== this.props.history.location.pathname) {
- this.path.name = this.props.history.location.pathname;
- this.checkForDialog(this.props.history.location);
+ this.checkForDialog();
+ }
+
+ checkForDialog() {
+ if (this.current.pathname !== this.props.history.location.pathname) {
+ this.current.reg = this.routesReg.find(item =>
+ item.regex.test(this.props.history.location.pathname));
+ this.current.pathname = this.props.history.location.pathname;
+ const dialogName = this.props.history.location.pathname.replace(this.current.reg.path, '');
+ if (dialogs[dialogName] !== undefined) {
+ this.open(this.current.reg, dialogs[dialogName]);
+ } else {
+ this.close();
+ }
}
}
- checkForDialog(location) {
- const parseParams = search => search.replace(/^\?/, '').split('&&').reduce((acc, param) => {
+ // eslint-disable-next-line class-methods-use-this
+ parseParams(search) {
+ return search.replace(/^\?/, '').split('&&').reduce((acc, param) => {
const keyValue = param.split('=');
if (keyValue[0] !== '' && keyValue[1] !== 'undefined') {
acc[keyValue[0]] = keyValue[1];
}
return acc;
}, {});
-
- this.path.list = location.pathname.replace(/\/$/, '').split('/');
- this.dialog = this.path.list[3];
-
- if (this.path.list.length === 5) {
- this.props.history.push(`/${this.path.list[1]}/${this.path.list[2]}/${this.path.list[4]}`);
- } else if (this.path.list.length === 4 && Object.keys(dialogs).includes(this.dialog)) {
- this.routeWithDialog(dialogs[this.dialog], parseParams(location.search));
- } else {
- this.routeWithOutDialog();
- }
}
- routeWithDialog(dialog, childComponentProps) {
+ open(config, dialog) {
clearTimeout(this.timeout);
this.setState({ hidden: false });
this.props.dialogDisplayed({
title: dialog.title,
childComponent: dialog.component,
- childComponentProps,
+ childComponentProps: this.parseParams(this.props.history.location.search),
});
}
- routeWithOutDialog() {
+ close() {
this.timeout = setTimeout(() => {
this.props.dialogHidden();
this.setState({ hidden: false });
@@ -67,13 +92,8 @@ class DialogElement extends Component {
this.setState({ hidden: true });
}
- closeDialog() {
- if (this.props.dialog.childComponentProps.noRouter) {
- this.routeWithOutDialog();
- } else {
- const upperRoute = this.path.name.replace(/\/$/, '').replace(this.dialog, '');
- this.props.history.push(upperRoute);
- }
+ goBack() {
+ this.props.history.push(this.current.reg.path);
}
render() {
@@ -85,14 +105,14 @@ class DialogElement extends Component {
-
+
{this.props.dialog.childComponent ?
:
null
}
diff --git a/src/components/dialog/dialogs.js b/src/components/dialog/dialogs.js
index 89f81eeda..9256dbb27 100644
--- a/src/components/dialog/dialogs.js
+++ b/src/components/dialog/dialogs.js
@@ -6,6 +6,7 @@ import SecondPassphrase from '../secondPassphrase';
import VoteDialog from '../voteDialog';
import ReceiveDialog from '../receiveDialog';
import SaveAccount from '../saveAccount';
+import Register from '../register';
export default {
send: {
@@ -36,6 +37,10 @@ export default {
title: 'Receive LSK',
component: ReceiveDialog,
},
+ register: {
+ title: 'New Account',
+ component: Register,
+ },
'save-account': {
title: 'Remember this account',
component: SaveAccount,
diff --git a/src/components/login/login.js b/src/components/login/login.js
index 83439f1fa..0b54a5b18 100644
--- a/src/components/login/login.js
+++ b/src/components/login/login.js
@@ -7,7 +7,7 @@ import networksRaw from './networks';
import PassphraseInput from '../passphraseInput';
import styles from './login.css';
import env from '../../constants/env';
-import Passphrase from '../passphrase';
+import RelativeLink from '../relativeLink';
/**
* The container component containing login
@@ -188,25 +188,13 @@ class Login extends React.Component {
onChange={this.changeHandler.bind(this, 'passphrase')} />
diff --git a/src/components/register/index.js b/src/components/register/index.js
new file mode 100644
index 000000000..299aed481
--- /dev/null
+++ b/src/components/register/index.js
@@ -0,0 +1,15 @@
+import { connect } from 'react-redux';
+import { translate } from 'react-i18next';
+import { dialogDisplayed } from '../../actions/dialog';
+import { activePeerSet } from '../../actions/peers';
+import Register from './register';
+
+const mapDispatchToProps = dispatch => ({
+ setActiveDialog: data => dispatch(dialogDisplayed(data)),
+ activePeerSet: data => dispatch(activePeerSet(data)),
+});
+
+export default connect(
+ null,
+ mapDispatchToProps,
+)(translate()(Register));
diff --git a/src/components/register/index.test.js b/src/components/register/index.test.js
new file mode 100644
index 000000000..9d4631d4c
--- /dev/null
+++ b/src/components/register/index.test.js
@@ -0,0 +1,31 @@
+import React from 'react';
+import { expect } from 'chai';
+import { mount } from 'enzyme';
+import { Provider } from 'react-redux';
+import { I18nextProvider } from 'react-i18next';
+import configureMockStore from 'redux-mock-store';
+import i18n from '../../i18n';
+import Register from './index';
+
+
+describe('RegisterHOC', () => {
+ let wrapper;
+ const peers = {};
+ const account = {};
+ const store = configureMockStore([])({
+ peers,
+ account,
+ });
+
+ beforeEach(() => {
+ wrapper = mount(
+
+
+
+ );
+ });
+
+ it('should render Register', () => {
+ expect(wrapper.find('Register')).to.have.lengthOf(1);
+ });
+});
diff --git a/src/components/register/register.css b/src/components/register/register.css
new file mode 100644
index 000000000..f4d336fdf
--- /dev/null
+++ b/src/components/register/register.css
@@ -0,0 +1,3 @@
+.hidden {
+ display: none;
+}
diff --git a/src/components/register/register.js b/src/components/register/register.js
new file mode 100644
index 000000000..0b2a95901
--- /dev/null
+++ b/src/components/register/register.js
@@ -0,0 +1,60 @@
+import React from 'react';
+import Passphrase from '../passphrase';
+import networksRaw from '../login/networks';
+
+const Register = ({
+ activePeerSet, closeDialog, t,
+}) => {
+ const validateUrl = (value) => {
+ const addHttp = (url) => {
+ const reg = /^(?:f|ht)tps?:\/\//i;
+ return reg.test(url) ? url : `http://${url}`;
+ };
+
+ const errorMessage = 'URL is invalid';
+
+ const isValidLocalhost = url => url.hostname === 'localhost' && url.port.length > 1;
+ const isValidRemote = url => /(([a-z\d]([a-z\d-]*[a-z\d])*)\.)+[a-z]{2,}|((\d{1,3}\.){3}\d{1,3})/.test(url.hostname);
+
+ let addressValidity = '';
+ try {
+ const url = new URL(addHttp(value));
+ addressValidity = url && (isValidRemote(url) || isValidLocalhost(url)) ? '' : errorMessage;
+ } catch (e) {
+ addressValidity = errorMessage;
+ }
+
+ return addressValidity === '';
+ };
+
+ const onLoginSubmission = (passphrase) => {
+ let NetworkIndex = parseInt(localStorage.getItem('network'), 10) || 0;
+ const address = localStorage.getItem('address') || '';
+ if (!NetworkIndex || (NetworkIndex === 2 && !validateUrl(address))) {
+ NetworkIndex = 0;
+ }
+
+ const network = Object.assign({}, networksRaw[NetworkIndex]);
+ if (NetworkIndex === 2) {
+ network.address = address;
+ }
+
+ // set active peer
+ activePeerSet({
+ passphrase,
+ network,
+ });
+ };
+
+ return (
+
+ );
+};
+
+export default Register;
diff --git a/src/components/register/register.test.js b/src/components/register/register.test.js
new file mode 100644
index 000000000..3c820897d
--- /dev/null
+++ b/src/components/register/register.test.js
@@ -0,0 +1,56 @@
+import React from 'react';
+import { expect } from 'chai';
+import { mount } from 'enzyme';
+import { spy } from 'sinon';
+import PropTypes from 'prop-types';
+import configureMockStore from 'redux-mock-store';
+import Register from './register';
+
+describe('Register', () => {
+ let wrapper;
+ const peers = { data: {} };
+ const account = {};
+ const store = configureMockStore([])({
+ peers,
+ account,
+ activePeerSet: () => {},
+ });
+ const options = {
+ context: { store },
+ childContextTypes: {
+ store: PropTypes.object.isRequired,
+ },
+ };
+ const prop = {
+ account,
+ peers,
+ activePeerSet: spy(),
+ t: key => key,
+ };
+
+ beforeEach(() => {
+ wrapper = mount(
, options);
+ });
+
+ it('renders Passphrase component', () => {
+ expect(wrapper.find('Passphrase')).to.have.length(1);
+ });
+
+ it('should mount Register with appropriate properties', () => {
+ const props = wrapper.find('Passphrase').props();
+ expect(props.useCaseNote).to.be.equal('your passphrase will be required for logging in to your account.');
+ expect(props.securityNote).to.be.equal('This passphrase is not recoverable and if you lose it, you will lose access to your account forever.');
+ expect(props.confirmButton).to.be.equal('Login');
+ expect(props.keepModal).to.be.equal(false);
+ expect(typeof props.onPassGenerated).to.be.equal('function');
+ });
+
+ it('should call activePeerSet if props.onPassGenerated is called', () => {
+ const props = wrapper.find('Passphrase').props();
+ props.onPassGenerated('sample passphrase');
+ expect(prop.activePeerSet).to.have.been.calledWith({
+ network: { name: 'Mainnet', port: 443, ssl: true },
+ passphrase: 'sample passphrase',
+ });
+ });
+});