2015-11-30 21:11:04 +03:00
|
|
|
/*
|
2016-01-07 07:06:39 +03:00
|
|
|
Copyright 2015, 2016 OpenMarket Ltd
|
2017-02-24 14:41:23 +03:00
|
|
|
Copyright 2017 Vector Creations Ltd
|
2015-11-30 21:11:04 +03:00
|
|
|
|
|
|
|
Licensed under the Apache License, Version 2.0 (the "License");
|
|
|
|
you may not use this file except in compliance with the License.
|
|
|
|
You may obtain a copy of the License at
|
|
|
|
|
|
|
|
http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
|
|
|
|
Unless required by applicable law or agreed to in writing, software
|
|
|
|
distributed under the License is distributed on an "AS IS" BASIS,
|
|
|
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
|
|
See the License for the specific language governing permissions and
|
|
|
|
limitations under the License.
|
|
|
|
*/
|
|
|
|
|
2017-02-24 14:41:23 +03:00
|
|
|
import Matrix from 'matrix-js-sdk';
|
2015-11-30 21:11:04 +03:00
|
|
|
|
2017-02-28 18:05:49 +03:00
|
|
|
import q from 'q';
|
|
|
|
import React from 'react';
|
2015-11-30 21:11:04 +03:00
|
|
|
|
2017-02-28 18:05:49 +03:00
|
|
|
import sdk from '../../../index';
|
|
|
|
import dis from '../../../dispatcher';
|
|
|
|
import ServerConfig from '../../views/login/ServerConfig';
|
|
|
|
import MatrixClientPeg from '../../../MatrixClientPeg';
|
|
|
|
import RegistrationForm from '../../views/login/RegistrationForm';
|
|
|
|
import CaptchaForm from '../../views/login/CaptchaForm';
|
|
|
|
import RtsClient from '../../../RtsClient';
|
2015-11-30 21:11:04 +03:00
|
|
|
|
2017-02-28 18:05:49 +03:00
|
|
|
const MIN_PASSWORD_LENGTH = 6;
|
2015-11-30 21:11:04 +03:00
|
|
|
|
|
|
|
module.exports = React.createClass({
|
|
|
|
displayName: 'Registration',
|
|
|
|
|
|
|
|
propTypes: {
|
|
|
|
onLoggedIn: React.PropTypes.func.isRequired,
|
|
|
|
clientSecret: React.PropTypes.string,
|
|
|
|
sessionId: React.PropTypes.string,
|
2017-03-02 18:04:10 +03:00
|
|
|
makeRegistrationUrl: React.PropTypes.func.isRequired,
|
2015-11-30 21:11:04 +03:00
|
|
|
idSid: React.PropTypes.string,
|
2016-03-15 16:48:46 +03:00
|
|
|
customHsUrl: React.PropTypes.string,
|
|
|
|
customIsUrl: React.PropTypes.string,
|
2016-03-06 22:33:36 +03:00
|
|
|
defaultHsUrl: React.PropTypes.string,
|
|
|
|
defaultIsUrl: React.PropTypes.string,
|
2016-06-02 13:50:00 +03:00
|
|
|
brand: React.PropTypes.string,
|
2015-12-17 17:56:55 +03:00
|
|
|
email: React.PropTypes.string,
|
2017-01-31 14:13:05 +03:00
|
|
|
referrer: React.PropTypes.string,
|
2016-01-07 20:23:32 +03:00
|
|
|
username: React.PropTypes.string,
|
|
|
|
guestAccessToken: React.PropTypes.string,
|
2017-01-30 18:50:31 +03:00
|
|
|
teamServerConfig: React.PropTypes.shape({
|
2017-01-18 14:48:28 +03:00
|
|
|
// Email address to request new teams
|
2017-01-30 18:50:31 +03:00
|
|
|
supportEmail: React.PropTypes.string.isRequired,
|
|
|
|
// URL of the riot-team-server to get team configurations and track referrals
|
|
|
|
teamServerURL: React.PropTypes.string.isRequired,
|
2017-01-18 14:48:28 +03:00
|
|
|
}),
|
2017-01-31 16:17:01 +03:00
|
|
|
teamSelected: React.PropTypes.object,
|
2016-08-11 18:15:42 +03:00
|
|
|
|
|
|
|
defaultDeviceDisplayName: React.PropTypes.string,
|
|
|
|
|
2015-11-30 21:11:04 +03:00
|
|
|
// registration shouldn't know or care how login is done.
|
2016-03-16 00:04:11 +03:00
|
|
|
onLoginClick: React.PropTypes.func.isRequired,
|
|
|
|
onCancelClick: React.PropTypes.func
|
2015-11-30 21:11:04 +03:00
|
|
|
},
|
|
|
|
|
|
|
|
getInitialState: function() {
|
|
|
|
return {
|
|
|
|
busy: false,
|
2017-01-30 19:23:52 +03:00
|
|
|
teamServerBusy: false,
|
2015-11-30 21:11:04 +03:00
|
|
|
errorText: null,
|
2016-07-07 13:26:35 +03:00
|
|
|
// We remember the values entered by the user because
|
|
|
|
// the registration form will be unmounted during the
|
|
|
|
// course of registration, but if there's an error we
|
|
|
|
// want to bring back the registration form with the
|
2016-07-07 15:03:27 +03:00
|
|
|
// values the user entered still in it. We can keep
|
2016-07-07 13:26:35 +03:00
|
|
|
// them in this component's state since this component
|
|
|
|
// persist for the duration of the registration process.
|
2016-07-06 17:22:06 +03:00
|
|
|
formVals: {
|
|
|
|
email: this.props.email,
|
|
|
|
},
|
2017-02-24 14:41:23 +03:00
|
|
|
// true if we're waiting for the user to complete
|
|
|
|
// user-interactive auth
|
|
|
|
// If we've been given a session ID, we're resuming
|
|
|
|
// straight back into UI auth
|
|
|
|
doingUIAuth: Boolean(this.props.sessionId),
|
2017-02-27 20:24:28 +03:00
|
|
|
hsUrl: this.props.customHsUrl,
|
|
|
|
isUrl: this.props.customIsUrl,
|
2015-11-30 21:11:04 +03:00
|
|
|
};
|
|
|
|
},
|
|
|
|
|
|
|
|
componentWillMount: function() {
|
2017-01-27 19:31:36 +03:00
|
|
|
this._unmounted = false;
|
2017-02-24 14:41:23 +03:00
|
|
|
|
|
|
|
this._replaceClient();
|
2017-01-30 18:50:31 +03:00
|
|
|
|
2017-01-30 19:13:57 +03:00
|
|
|
if (
|
|
|
|
this.props.teamServerConfig &&
|
|
|
|
this.props.teamServerConfig.teamServerURL &&
|
|
|
|
!this._rtsClient
|
|
|
|
) {
|
2017-01-30 18:50:31 +03:00
|
|
|
this._rtsClient = new RtsClient(this.props.teamServerConfig.teamServerURL);
|
|
|
|
|
2017-01-30 19:23:52 +03:00
|
|
|
this.setState({
|
|
|
|
teamServerBusy: true,
|
|
|
|
});
|
2017-01-30 18:50:31 +03:00
|
|
|
// GET team configurations including domains, names and icons
|
2017-02-01 13:39:52 +03:00
|
|
|
this._rtsClient.getTeamsConfig().then((data) => {
|
2017-01-30 18:50:31 +03:00
|
|
|
const teamsConfig = {
|
2017-02-01 13:39:52 +03:00
|
|
|
teams: data,
|
2017-01-30 18:50:31 +03:00
|
|
|
supportEmail: this.props.teamServerConfig.supportEmail,
|
|
|
|
};
|
|
|
|
console.log('Setting teams config to ', teamsConfig);
|
|
|
|
this.setState({
|
|
|
|
teamsConfig: teamsConfig,
|
2017-02-01 13:39:52 +03:00
|
|
|
teamServerBusy: false,
|
2017-01-30 18:50:31 +03:00
|
|
|
});
|
|
|
|
}, (err) => {
|
|
|
|
console.error('Error retrieving config for teams', err);
|
2017-01-30 19:23:52 +03:00
|
|
|
this.setState({
|
|
|
|
teamServerBusy: false,
|
|
|
|
});
|
2017-02-01 13:39:52 +03:00
|
|
|
});
|
2017-01-30 18:50:31 +03:00
|
|
|
}
|
2015-11-30 21:11:04 +03:00
|
|
|
},
|
|
|
|
|
|
|
|
onHsUrlChanged: function(newHsUrl) {
|
2017-02-27 20:24:28 +03:00
|
|
|
this.setState({
|
|
|
|
hsUrl: newHsUrl,
|
|
|
|
});
|
2017-02-24 14:41:23 +03:00
|
|
|
this._replaceClient();
|
2015-11-30 21:11:04 +03:00
|
|
|
},
|
|
|
|
|
|
|
|
onIsUrlChanged: function(newIsUrl) {
|
2017-02-27 20:24:28 +03:00
|
|
|
this.setState({
|
|
|
|
isUrl: newIsUrl,
|
|
|
|
});
|
2017-02-24 14:41:23 +03:00
|
|
|
this._replaceClient();
|
2015-11-30 21:11:04 +03:00
|
|
|
},
|
|
|
|
|
2017-02-24 14:41:23 +03:00
|
|
|
_replaceClient: function() {
|
|
|
|
this._matrixClient = Matrix.createClient({
|
2017-02-27 20:24:28 +03:00
|
|
|
baseUrl: this.state.hsUrl,
|
|
|
|
idBaseUrl: this.state.isUrl,
|
2016-01-27 18:44:12 +03:00
|
|
|
});
|
2015-11-30 21:11:04 +03:00
|
|
|
},
|
|
|
|
|
|
|
|
onFormSubmit: function(formVals) {
|
|
|
|
this.setState({
|
|
|
|
errorText: "",
|
2016-07-06 17:22:06 +03:00
|
|
|
busy: true,
|
|
|
|
formVals: formVals,
|
2017-02-24 14:41:23 +03:00
|
|
|
doingUIAuth: true,
|
2015-11-30 21:11:04 +03:00
|
|
|
});
|
|
|
|
},
|
|
|
|
|
2017-02-27 20:24:28 +03:00
|
|
|
_onUIAuthFinished: function(success, response) {
|
|
|
|
if (!success) {
|
|
|
|
this.setState({
|
|
|
|
busy: false,
|
|
|
|
doingUIAuth: false,
|
|
|
|
errorText: response.message || response.toString(),
|
|
|
|
});
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2017-02-24 14:41:23 +03:00
|
|
|
this.setState({
|
|
|
|
// we're still busy until we get unmounted: don't show the registration form again
|
|
|
|
busy: true,
|
|
|
|
doingUIAuth: false,
|
|
|
|
});
|
|
|
|
this.props.onLoggedIn({
|
|
|
|
userId: response.user_id,
|
|
|
|
deviceId: response.device_id,
|
2017-02-27 20:24:28 +03:00
|
|
|
homeserverUrl: this.state.hsUrl,
|
|
|
|
identityServerUrl: this.state.isUrl,
|
2017-02-24 14:41:23 +03:00
|
|
|
accessToken: response.access_token,
|
|
|
|
});
|
2016-06-02 15:14:52 +03:00
|
|
|
|
2017-02-24 14:41:23 +03:00
|
|
|
// Done regardless of `teamSelected`. People registering with non-team emails
|
|
|
|
// will just nop. The point of this being we might not have the email address
|
|
|
|
// that the user registered with at this stage (depending on whether this
|
|
|
|
// is the client they initiated registration).
|
2017-03-02 18:08:15 +03:00
|
|
|
let trackPromise = q(null);
|
2017-03-01 13:45:17 +03:00
|
|
|
if (this._rtsClient) {
|
|
|
|
// Track referral if this.props.referrer set, get team_token in order to
|
2017-02-24 14:41:23 +03:00
|
|
|
// retrieve team config and see welcome page etc.
|
2017-03-02 18:08:15 +03:00
|
|
|
trackPromise = this._rtsClient.trackReferral(
|
2017-03-01 13:45:17 +03:00
|
|
|
this.props.referrer || '', // Default to empty string = not referred
|
|
|
|
this.registerLogic.params.idSid,
|
|
|
|
this.registerLogic.params.clientSecret
|
2017-02-24 14:41:23 +03:00
|
|
|
).then((data) => {
|
|
|
|
const teamToken = data.team_token;
|
|
|
|
// Store for use /w welcome pages
|
|
|
|
window.localStorage.setItem('mx_team_token', teamToken);
|
2017-03-01 13:45:17 +03:00
|
|
|
this.props.onTeamMemberRegistered(teamToken);
|
2017-02-24 14:41:23 +03:00
|
|
|
|
2017-03-01 13:45:17 +03:00
|
|
|
this._rtsClient.getTeam(teamToken).then((team) => {
|
2017-02-24 14:41:23 +03:00
|
|
|
console.log(
|
|
|
|
`User successfully registered with team ${team.name}`
|
|
|
|
);
|
|
|
|
if (!team.rooms) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
// Auto-join rooms
|
|
|
|
team.rooms.forEach((room) => {
|
|
|
|
if (room.auto_join && room.room_id) {
|
|
|
|
console.log(`Auto-joining ${room.room_id}`);
|
|
|
|
MatrixClientPeg.get().joinRoom(room.room_id);
|
2017-01-19 13:05:08 +03:00
|
|
|
}
|
2017-01-31 14:13:05 +03:00
|
|
|
});
|
|
|
|
}, (err) => {
|
2017-02-24 14:41:23 +03:00
|
|
|
console.error('Error getting team config', err);
|
2017-01-31 14:13:05 +03:00
|
|
|
});
|
2017-03-03 13:28:10 +03:00
|
|
|
|
|
|
|
return teamToken;
|
2017-02-24 14:41:23 +03:00
|
|
|
}, (err) => {
|
|
|
|
console.error('Error tracking referral', err);
|
|
|
|
});
|
|
|
|
}
|
2016-06-02 15:14:52 +03:00
|
|
|
|
2017-03-01 13:45:17 +03:00
|
|
|
trackPromise.then((teamToken) => {
|
|
|
|
console.info('Team token promise',teamToken);
|
|
|
|
this.props.onLoggedIn({
|
|
|
|
userId: response.user_id,
|
|
|
|
deviceId: response.device_id,
|
|
|
|
homeserverUrl: this.registerLogic.getHomeserverUrl(),
|
|
|
|
identityServerUrl: this.registerLogic.getIdentityServerUrl(),
|
|
|
|
accessToken: response.access_token
|
|
|
|
}, teamToken);
|
|
|
|
}).then(() => {
|
|
|
|
return this._setupPushers();
|
2017-03-01 21:33:45 +03:00
|
|
|
}).done();
|
2015-11-30 21:11:04 +03:00
|
|
|
},
|
|
|
|
|
2017-02-28 18:05:49 +03:00
|
|
|
_setupPushers: function() {
|
2017-02-28 18:18:00 +03:00
|
|
|
if (!this.props.brand) {
|
2017-03-01 13:45:17 +03:00
|
|
|
return q();
|
2017-02-24 14:41:23 +03:00
|
|
|
}
|
2017-03-01 13:45:17 +03:00
|
|
|
return MatrixClientPeg.get().getPushers().then((resp)=>{
|
|
|
|
const pushers = resp.pushers;
|
|
|
|
for (let i = 0; i < pushers.length; ++i) {
|
2017-02-28 18:05:49 +03:00
|
|
|
if (pushers[i].kind == 'email') {
|
2017-03-01 13:45:17 +03:00
|
|
|
const emailPusher = pushers[i];
|
2017-02-28 18:18:00 +03:00
|
|
|
emailPusher.data = { brand: this.props.brand };
|
2017-02-28 18:05:49 +03:00
|
|
|
MatrixClientPeg.get().setPusher(emailPusher).done(() => {
|
2017-02-28 18:18:00 +03:00
|
|
|
console.log("Set email branding to " + this.props.brand);
|
2017-02-28 18:05:49 +03:00
|
|
|
}, (error) => {
|
|
|
|
console.error("Couldn't set email branding: " + error);
|
|
|
|
});
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}, (error) => {
|
|
|
|
console.error("Couldn't get pushers: " + error);
|
|
|
|
});
|
2015-11-30 21:11:04 +03:00
|
|
|
},
|
|
|
|
|
|
|
|
onFormValidationFailed: function(errCode) {
|
|
|
|
var errMsg;
|
|
|
|
switch (errCode) {
|
|
|
|
case "RegistrationForm.ERR_PASSWORD_MISSING":
|
|
|
|
errMsg = "Missing password.";
|
|
|
|
break;
|
|
|
|
case "RegistrationForm.ERR_PASSWORD_MISMATCH":
|
|
|
|
errMsg = "Passwords don't match.";
|
|
|
|
break;
|
|
|
|
case "RegistrationForm.ERR_PASSWORD_LENGTH":
|
|
|
|
errMsg = `Password too short (min ${MIN_PASSWORD_LENGTH}).`;
|
|
|
|
break;
|
2016-01-15 16:31:41 +03:00
|
|
|
case "RegistrationForm.ERR_EMAIL_INVALID":
|
|
|
|
errMsg = "This doesn't look like a valid email address";
|
|
|
|
break;
|
|
|
|
case "RegistrationForm.ERR_USERNAME_INVALID":
|
|
|
|
errMsg = "User names may only contain letters, numbers, dots, hyphens and underscores.";
|
|
|
|
break;
|
|
|
|
case "RegistrationForm.ERR_USERNAME_BLANK":
|
|
|
|
errMsg = "You need to enter a user name";
|
|
|
|
break;
|
2015-11-30 21:11:04 +03:00
|
|
|
default:
|
|
|
|
console.error("Unknown error code: %s", errCode);
|
|
|
|
errMsg = "An unknown error occurred.";
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
this.setState({
|
|
|
|
errorText: errMsg
|
|
|
|
});
|
|
|
|
},
|
|
|
|
|
2017-01-31 14:13:05 +03:00
|
|
|
onTeamSelected: function(teamSelected) {
|
2017-01-27 19:31:36 +03:00
|
|
|
if (!this._unmounted) {
|
2017-01-31 14:13:05 +03:00
|
|
|
this.setState({ teamSelected });
|
2017-01-27 19:31:36 +03:00
|
|
|
}
|
|
|
|
},
|
|
|
|
|
2017-02-24 14:41:23 +03:00
|
|
|
_makeRegisterRequest: function(auth) {
|
|
|
|
let guestAccessToken = this.props.guestAccessToken;
|
2016-03-16 00:04:11 +03:00
|
|
|
|
2017-02-27 20:24:28 +03:00
|
|
|
if (
|
|
|
|
this.state.formVals.username !== this.props.username ||
|
|
|
|
this.state.hsUrl != this.props.defaultHsUrl
|
|
|
|
) {
|
2017-02-24 14:41:23 +03:00
|
|
|
// don't try to upgrade if we changed our username
|
2017-02-27 20:24:28 +03:00
|
|
|
// or are registering on a different HS
|
2017-02-24 14:41:23 +03:00
|
|
|
guestAccessToken = null;
|
2016-03-16 00:04:11 +03:00
|
|
|
}
|
|
|
|
|
2017-02-24 14:41:23 +03:00
|
|
|
return this._matrixClient.register(
|
|
|
|
this.state.formVals.username,
|
|
|
|
this.state.formVals.password,
|
|
|
|
undefined, // session id: included in the auth dict already
|
|
|
|
auth,
|
|
|
|
// Only send the bind_email param if we're sending username / pw params
|
|
|
|
// (Since we need to send no params at all to use the ones saved in the
|
|
|
|
// session).
|
|
|
|
Boolean(this.state.formVals.username) || undefined,
|
|
|
|
guestAccessToken,
|
2015-11-30 21:11:04 +03:00
|
|
|
);
|
|
|
|
},
|
|
|
|
|
2017-02-24 14:41:23 +03:00
|
|
|
_getUIAuthInputs() {
|
|
|
|
return {
|
|
|
|
emailAddress: this.state.formVals.email,
|
|
|
|
phoneCountry: this.state.formVals.phoneCountry,
|
|
|
|
phoneNumber: this.state.formVals.phoneNumber,
|
|
|
|
}
|
|
|
|
},
|
|
|
|
|
2015-11-30 21:11:04 +03:00
|
|
|
render: function() {
|
2017-02-24 14:41:23 +03:00
|
|
|
const LoginHeader = sdk.getComponent('login.LoginHeader');
|
|
|
|
const LoginFooter = sdk.getComponent('login.LoginFooter');
|
|
|
|
const InteractiveAuth = sdk.getComponent('structures.InteractiveAuth');
|
|
|
|
const Spinner = sdk.getComponent("elements.Spinner");
|
2017-02-27 20:24:28 +03:00
|
|
|
const ServerConfig = sdk.getComponent('views.login.ServerConfig');
|
2017-02-24 14:41:23 +03:00
|
|
|
|
|
|
|
let registerBody;
|
|
|
|
if (this.state.doingUIAuth) {
|
|
|
|
registerBody = (
|
|
|
|
<InteractiveAuth
|
|
|
|
matrixClient={this._matrixClient}
|
|
|
|
makeRequest={this._makeRegisterRequest}
|
2017-03-03 15:08:26 +03:00
|
|
|
onAuthFinished={this._onUIAuthFinished}
|
2017-02-24 14:41:23 +03:00
|
|
|
inputs={this._getUIAuthInputs()}
|
|
|
|
makeRegistrationUrl={this.props.makeRegistrationUrl}
|
|
|
|
sessionId={this.props.sessionId}
|
|
|
|
clientSecret={this.props.clientSecret}
|
|
|
|
emailSid={this.props.idSid}
|
2017-02-24 20:24:10 +03:00
|
|
|
poll={true}
|
2017-02-24 14:41:23 +03:00
|
|
|
/>
|
|
|
|
);
|
|
|
|
} else if (this.state.busy || this.state.teamServerBusy) {
|
|
|
|
registerBody = <Spinner />;
|
|
|
|
} else {
|
2017-02-27 20:24:28 +03:00
|
|
|
let guestUsername = this.props.username;
|
|
|
|
if (this.state.hsUrl != this.props.defaultHsUrl) {
|
|
|
|
guestUsername = null;
|
|
|
|
}
|
|
|
|
let errorSection;
|
|
|
|
if (this.state.errorText) {
|
|
|
|
errorSection = <div className="mx_Login_error">{this.state.errorText}</div>;
|
|
|
|
}
|
2017-02-24 14:41:23 +03:00
|
|
|
registerBody = (
|
2017-02-27 20:24:28 +03:00
|
|
|
<div>
|
|
|
|
<RegistrationForm
|
|
|
|
defaultUsername={this.state.formVals.username}
|
|
|
|
defaultEmail={this.state.formVals.email}
|
|
|
|
defaultPassword={this.state.formVals.password}
|
|
|
|
teamsConfig={this.state.teamsConfig}
|
|
|
|
guestUsername={guestUsername}
|
|
|
|
minPasswordLength={MIN_PASSWORD_LENGTH}
|
|
|
|
onError={this.onFormValidationFailed}
|
|
|
|
onRegisterClick={this.onFormSubmit}
|
|
|
|
onTeamSelected={this.onTeamSelected}
|
|
|
|
/>
|
|
|
|
{errorSection}
|
|
|
|
<ServerConfig ref="serverConfig"
|
|
|
|
withToggleButton={true}
|
|
|
|
customHsUrl={this.props.customHsUrl}
|
|
|
|
customIsUrl={this.props.customIsUrl}
|
|
|
|
defaultHsUrl={this.props.defaultHsUrl}
|
|
|
|
defaultIsUrl={this.props.defaultIsUrl}
|
|
|
|
onHsUrlChanged={this.onHsUrlChanged}
|
|
|
|
onIsUrlChanged={this.onIsUrlChanged}
|
|
|
|
delayTimeMs={1000}
|
|
|
|
/>
|
|
|
|
</div>
|
2017-02-24 14:41:23 +03:00
|
|
|
);
|
|
|
|
}
|
|
|
|
|
2017-02-27 20:24:28 +03:00
|
|
|
let returnToAppJsx;
|
|
|
|
if (this.props.onCancelClick) {
|
|
|
|
returnToAppJsx = (
|
|
|
|
<a className="mx_Login_create" onClick={this.props.onCancelClick} href="#">
|
|
|
|
Return to app
|
|
|
|
</a>
|
|
|
|
);
|
|
|
|
}
|
2015-11-30 21:11:04 +03:00
|
|
|
return (
|
|
|
|
<div className="mx_Login">
|
|
|
|
<div className="mx_Login_box">
|
2017-02-09 12:24:46 +03:00
|
|
|
<LoginHeader
|
|
|
|
icon={this.state.teamSelected ?
|
2017-02-09 16:16:46 +03:00
|
|
|
this.props.teamServerConfig.teamServerURL + "/static/common/" +
|
2017-02-09 12:24:46 +03:00
|
|
|
this.state.teamSelected.domain + "/icon.png" :
|
|
|
|
null}
|
|
|
|
/>
|
2017-02-27 20:24:28 +03:00
|
|
|
<h2>Create an account</h2>
|
2017-02-24 14:41:23 +03:00
|
|
|
{registerBody}
|
2017-02-27 20:24:28 +03:00
|
|
|
<a className="mx_Login_create" onClick={this.props.onLoginClick} href="#">
|
|
|
|
I already have an account
|
|
|
|
</a>
|
|
|
|
{returnToAppJsx}
|
2016-03-06 22:33:36 +03:00
|
|
|
<LoginFooter />
|
2015-11-30 21:11:04 +03:00
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
);
|
|
|
|
}
|
|
|
|
});
|