Merge pull request #2527 from jryans/auth-registration
Style registration flow
This commit is contained in:
commit
4d2a93eaaf
12 changed files with 324 additions and 152 deletions
|
@ -30,6 +30,7 @@
|
|||
@import "./views/auth/_AuthHeader.scss";
|
||||
@import "./views/auth/_AuthHeaderLogo.scss";
|
||||
@import "./views/auth/_AuthPage.scss";
|
||||
@import "./views/auth/_CountryDropdown.scss";
|
||||
@import "./views/auth/_InteractiveAuthEntryComponents.scss";
|
||||
@import "./views/auth/_LanguageSelector.scss";
|
||||
@import "./views/auth/_ServerConfig.scss";
|
||||
|
|
|
@ -15,13 +15,6 @@ See the License for the specific language governing permissions and
|
|||
limitations under the License.
|
||||
*/
|
||||
|
||||
.mx_Login_support {
|
||||
text-align: center;
|
||||
font-size: 13px;
|
||||
margin-top: 0px;
|
||||
opacity: 0.7;
|
||||
}
|
||||
|
||||
.mx_Login_field {
|
||||
width: 100%;
|
||||
box-sizing: border-box;
|
||||
|
@ -33,14 +26,6 @@ limitations under the License.
|
|||
margin-bottom: 14px;
|
||||
}
|
||||
|
||||
.mx_Login_fieldLabel {
|
||||
margin-top: -10px;
|
||||
margin-left: 8px;
|
||||
margin-bottom: 14px;
|
||||
font-size: 13px;
|
||||
opacity: 0.8;
|
||||
}
|
||||
|
||||
.mx_Login_submit {
|
||||
@mixin mx_DialogButton;
|
||||
width: 100%;
|
||||
|
@ -58,16 +43,6 @@ limitations under the License.
|
|||
opacity: 0.3;
|
||||
}
|
||||
|
||||
.mx_Login_label {
|
||||
font-size: 13px;
|
||||
opacity: 0.8;
|
||||
}
|
||||
|
||||
.mx_Login_checkbox,
|
||||
.mx_Login_radio {
|
||||
margin-right: 10px;
|
||||
}
|
||||
|
||||
.mx_AuthBody a.mx_Login_sso_link:link,
|
||||
.mx_AuthBody a.mx_Login_sso_link:hover,
|
||||
.mx_AuthBody a.mx_Login_sso_link:visited {
|
||||
|
@ -119,10 +94,6 @@ limitations under the License.
|
|||
flex: 1 1 auto;
|
||||
}
|
||||
|
||||
.mx_Login_field_group {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.mx_Login_field_prefix {
|
||||
height: 38px;
|
||||
padding: 0px 5px;
|
||||
|
@ -147,7 +118,6 @@ limitations under the License.
|
|||
|
||||
.mx_Login_phoneCountry {
|
||||
margin-bottom: 14px;
|
||||
width: 150px;
|
||||
|
||||
/* To override mx_Login_field_prefix */
|
||||
text-align: left;
|
||||
|
|
|
@ -47,6 +47,24 @@ limitations under the License.
|
|||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.mx_Auth_fieldRow {
|
||||
display: flex;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.mx_Auth_fieldRow > * {
|
||||
margin: 0 5px;
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.mx_Auth_fieldRow > *:first-child {
|
||||
margin-left: 0;
|
||||
}
|
||||
|
||||
.mx_Auth_fieldRow > *:last-child {
|
||||
margin-right: 0;
|
||||
}
|
||||
|
||||
.mx_AuthBody a:link,
|
||||
.mx_AuthBody a:hover,
|
||||
.mx_AuthBody a:visited {
|
||||
|
|
34
res/css/views/auth/_CountryDropdown.scss
Normal file
34
res/css/views/auth/_CountryDropdown.scss
Normal file
|
@ -0,0 +1,34 @@
|
|||
/*
|
||||
Copyright 2019 New Vector Ltd
|
||||
|
||||
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.
|
||||
*/
|
||||
|
||||
.mx_CountryDropdown .mx_Dropdown_input .mx_Dropdown_option {
|
||||
padding: 0 3px;
|
||||
}
|
||||
|
||||
.mx_CountryDropdown .mx_Dropdown_arrow {
|
||||
padding-right: 3px;
|
||||
}
|
||||
|
||||
.mx_CountryDropdown_shortOption {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.mx_CountryDropdown_option {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
|
@ -25,22 +25,6 @@ limitations under the License.
|
|||
color: $authpage-lang-color;
|
||||
}
|
||||
|
||||
/* TODO: Consider using this new arrow for all dropdowns */
|
||||
.mx_Auth_language .mx_Dropdown_arrow {
|
||||
width: 10px;
|
||||
height: 6px;
|
||||
border: none;
|
||||
right: 6px;
|
||||
}
|
||||
|
||||
.mx_Auth_language .mx_Dropdown_arrow::before {
|
||||
content: "";
|
||||
position: absolute;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
mask: url('$(res)/img/feather-icons/dropdown-arrow.svg');
|
||||
mask-repeat: no-repeat;
|
||||
background: $authpage-lang-color;
|
||||
}
|
||||
|
|
|
@ -23,11 +23,12 @@ limitations under the License.
|
|||
}
|
||||
|
||||
.mx_Dropdown_input {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
position: relative;
|
||||
border-radius: 3px;
|
||||
border: 1px solid $strong-input-border-color;
|
||||
font-weight: 300;
|
||||
font-size: 13px;
|
||||
font-size: 12px;
|
||||
user-select: none;
|
||||
}
|
||||
|
||||
|
@ -41,19 +42,23 @@ limitations under the License.
|
|||
}
|
||||
|
||||
.mx_Dropdown_arrow {
|
||||
border-color: $primary-fg-color transparent transparent;
|
||||
border-style: solid;
|
||||
border-width: 5px 5px 0;
|
||||
display: block;
|
||||
height: 0;
|
||||
position: absolute;
|
||||
right: 10px;
|
||||
top: 14px;
|
||||
width: 0
|
||||
position: relative;
|
||||
width: 10px;
|
||||
height: 6px;
|
||||
padding-right: 8px;
|
||||
}
|
||||
|
||||
.mx_Dropdown.left_aligned .mx_Dropdown_arrow {
|
||||
left: 10px;
|
||||
.mx_Dropdown_arrow::before {
|
||||
content: "";
|
||||
position: absolute;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
mask: url('$(res)/img/feather-icons/dropdown-arrow.svg');
|
||||
mask-repeat: no-repeat;
|
||||
background: $primary-fg-color;
|
||||
}
|
||||
|
||||
.mx_Dropdown_input > .mx_Dropdown_option {
|
||||
|
@ -62,10 +67,6 @@ limitations under the License.
|
|||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.mx_Dropdown.left_aligned .mx_Dropdown_input > .mx_Dropdown_option {
|
||||
padding-left: 25px;
|
||||
}
|
||||
|
||||
.mx_Dropdown_option {
|
||||
height: 35px;
|
||||
line-height: 35px;
|
||||
|
@ -81,7 +82,7 @@ limitations under the License.
|
|||
|
||||
.mx_Dropdown_option img {
|
||||
margin: 5px;
|
||||
width: 27px;
|
||||
width: 16px;
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
|
|
|
@ -539,7 +539,7 @@ module.exports = React.createClass({
|
|||
return errorText;
|
||||
},
|
||||
|
||||
serverComponentForStep() {
|
||||
renderServerComponentForStep() {
|
||||
const ServerTypeSelector = sdk.getComponent("auth.ServerTypeSelector");
|
||||
const ServerConfig = sdk.getComponent("auth.ServerConfig");
|
||||
const ModularServerConfig = sdk.getComponent("auth.ModularServerConfig");
|
||||
|
@ -605,7 +605,7 @@ module.exports = React.createClass({
|
|||
</div>;
|
||||
},
|
||||
|
||||
loginComponentForStep() {
|
||||
renderLoginComponentForStep() {
|
||||
if (PHASES_ENABLED && this.state.phase !== PHASE_LOGIN) {
|
||||
return null;
|
||||
}
|
||||
|
@ -707,8 +707,8 @@ module.exports = React.createClass({
|
|||
{loader}
|
||||
</h2>
|
||||
{ errorTextSection }
|
||||
{ this.serverComponentForStep() }
|
||||
{ this.loginComponentForStep() }
|
||||
{ this.renderServerComponentForStep() }
|
||||
{ this.renderLoginComponentForStep() }
|
||||
<a className="mx_Auth_changeFlow" onClick={this.onRegisterClick} href="#">
|
||||
{ _t('Create account') }
|
||||
</a>
|
||||
|
|
|
@ -23,13 +23,22 @@ import React from 'react';
|
|||
import PropTypes from 'prop-types';
|
||||
|
||||
import sdk from '../../../index';
|
||||
import RegistrationForm from '../../views/auth/RegistrationForm';
|
||||
import { _t, _td } from '../../../languageHandler';
|
||||
import SdkConfig from '../../../SdkConfig';
|
||||
import { messageForResourceLimitError } from '../../../utils/ErrorUtils';
|
||||
import * as ServerType from '../../views/auth/ServerTypeSelector';
|
||||
|
||||
const MIN_PASSWORD_LENGTH = 6;
|
||||
|
||||
// Phases
|
||||
// Show controls to configure server details
|
||||
const PHASE_SERVER_DETAILS = 0;
|
||||
// Show the appropriate registration flow(s) for the server
|
||||
const PHASE_REGISTRATION = 1;
|
||||
|
||||
// Enable phases for registration
|
||||
const PHASES_ENABLED = true;
|
||||
|
||||
module.exports = React.createClass({
|
||||
displayName: 'Registration',
|
||||
|
||||
|
@ -82,6 +91,7 @@ module.exports = React.createClass({
|
|||
// If we've been given a session ID, we're resuming
|
||||
// straight back into UI auth
|
||||
doingUIAuth: Boolean(this.props.sessionId),
|
||||
serverType: null,
|
||||
hsUrl: this.props.customHsUrl,
|
||||
isUrl: this.props.customIsUrl,
|
||||
flows: null,
|
||||
|
@ -107,6 +117,39 @@ module.exports = React.createClass({
|
|||
});
|
||||
},
|
||||
|
||||
onServerTypeChange(type) {
|
||||
this.setState({
|
||||
serverType: type,
|
||||
});
|
||||
|
||||
// When changing server types, set the HS / IS URLs to reasonable defaults for the
|
||||
// the new type.
|
||||
switch (type) {
|
||||
case ServerType.FREE: {
|
||||
const { hsUrl, isUrl } = ServerType.TYPES.FREE;
|
||||
this.onServerConfigChange({
|
||||
hsUrl,
|
||||
isUrl,
|
||||
});
|
||||
// Move directly to the registration phase since the server details are fixed.
|
||||
this.setState({
|
||||
phase: PHASE_REGISTRATION,
|
||||
});
|
||||
break;
|
||||
}
|
||||
case ServerType.PREMIUM:
|
||||
case ServerType.ADVANCED:
|
||||
this.onServerConfigChange({
|
||||
hsUrl: this.props.defaultHsUrl,
|
||||
isUrl: this.props.defaultIsUrl,
|
||||
});
|
||||
this.setState({
|
||||
phase: PHASE_SERVER_DETAILS,
|
||||
});
|
||||
break;
|
||||
}
|
||||
},
|
||||
|
||||
_replaceClient: async function() {
|
||||
this._matrixClient = Matrix.createClient({
|
||||
baseUrl: this.state.hsUrl,
|
||||
|
@ -273,6 +316,21 @@ module.exports = React.createClass({
|
|||
this.props.onLoginClick();
|
||||
},
|
||||
|
||||
onServerDetailsNextPhaseClick(ev) {
|
||||
ev.stopPropagation();
|
||||
this.setState({
|
||||
phase: PHASE_REGISTRATION,
|
||||
});
|
||||
},
|
||||
|
||||
onEditServerDetailsClick(ev) {
|
||||
ev.preventDefault();
|
||||
ev.stopPropagation();
|
||||
this.setState({
|
||||
phase: PHASE_SERVER_DETAILS,
|
||||
});
|
||||
},
|
||||
|
||||
_makeRegisterRequest: function(auth) {
|
||||
// Only send the bind params if we're sending username / pw params
|
||||
// (Since we need to send no params at all to use the ones saved in the
|
||||
|
@ -300,18 +358,83 @@ module.exports = React.createClass({
|
|||
};
|
||||
},
|
||||
|
||||
render: function() {
|
||||
const AuthHeader = sdk.getComponent('auth.AuthHeader');
|
||||
const AuthBody = sdk.getComponent("auth.AuthBody");
|
||||
const AuthPage = sdk.getComponent('auth.AuthPage');
|
||||
const InteractiveAuth = sdk.getComponent('structures.InteractiveAuth');
|
||||
const Spinner = sdk.getComponent("elements.Spinner");
|
||||
const ServerConfig = sdk.getComponent('views.auth.ServerConfig');
|
||||
renderServerComponent() {
|
||||
const ServerTypeSelector = sdk.getComponent("auth.ServerTypeSelector");
|
||||
const ServerConfig = sdk.getComponent("auth.ServerConfig");
|
||||
const ModularServerConfig = sdk.getComponent("auth.ModularServerConfig");
|
||||
const AccessibleButton = sdk.getComponent("elements.AccessibleButton");
|
||||
|
||||
// TODO: May need to adjust the behavior of this config option
|
||||
if (SdkConfig.get()['disable_custom_urls']) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// If we're on a different phase, we only show the server type selector,
|
||||
// which is always shown if we allow custom URLs at all.
|
||||
if (PHASES_ENABLED && this.state.phase !== PHASE_SERVER_DETAILS) {
|
||||
return <div>
|
||||
<ServerTypeSelector
|
||||
defaultHsUrl={this.props.defaultHsUrl}
|
||||
onChange={this.onServerTypeChange}
|
||||
/>
|
||||
</div>;
|
||||
}
|
||||
|
||||
let serverDetails = null;
|
||||
switch (this.state.serverType) {
|
||||
case ServerType.FREE:
|
||||
break;
|
||||
case ServerType.PREMIUM:
|
||||
serverDetails = <ModularServerConfig
|
||||
customHsUrl={this.state.discoveredHsUrl || this.props.customHsUrl}
|
||||
defaultHsUrl={this.props.defaultHsUrl}
|
||||
defaultIsUrl={this.props.defaultIsUrl}
|
||||
onServerConfigChange={this.onServerConfigChange}
|
||||
delayTimeMs={1000}
|
||||
/>;
|
||||
break;
|
||||
case ServerType.ADVANCED:
|
||||
serverDetails = <ServerConfig
|
||||
customHsUrl={this.state.discoveredHsUrl || this.props.customHsUrl}
|
||||
customIsUrl={this.state.discoveredIsUrl || this.props.customIsUrl}
|
||||
defaultHsUrl={this.props.defaultHsUrl}
|
||||
defaultIsUrl={this.props.defaultIsUrl}
|
||||
onServerConfigChange={this.onServerConfigChange}
|
||||
delayTimeMs={1000}
|
||||
/>;
|
||||
break;
|
||||
}
|
||||
|
||||
let nextButton = null;
|
||||
if (PHASES_ENABLED) {
|
||||
nextButton = <AccessibleButton className="mx_Login_submit"
|
||||
onClick={this.onServerDetailsNextPhaseClick}
|
||||
>
|
||||
{_t("Next")}
|
||||
</AccessibleButton>;
|
||||
}
|
||||
|
||||
return <div>
|
||||
<ServerTypeSelector
|
||||
defaultHsUrl={this.props.defaultHsUrl}
|
||||
onChange={this.onServerTypeChange}
|
||||
/>
|
||||
{serverDetails}
|
||||
{nextButton}
|
||||
</div>;
|
||||
},
|
||||
|
||||
renderRegisterComponent() {
|
||||
if (PHASES_ENABLED && this.state.phase !== PHASE_REGISTRATION) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const InteractiveAuth = sdk.getComponent('structures.InteractiveAuth');
|
||||
const Spinner = sdk.getComponent('elements.Spinner');
|
||||
const RegistrationForm = sdk.getComponent('auth.RegistrationForm');
|
||||
|
||||
let registerBody;
|
||||
if (this.state.doingUIAuth) {
|
||||
registerBody = (
|
||||
<InteractiveAuth
|
||||
return <InteractiveAuth
|
||||
matrixClient={this._matrixClient}
|
||||
makeRequest={this._makeRegisterRequest}
|
||||
onAuthFinished={this._onUIAuthFinished}
|
||||
|
@ -321,27 +444,21 @@ module.exports = React.createClass({
|
|||
clientSecret={this.props.clientSecret}
|
||||
emailSid={this.props.idSid}
|
||||
poll={true}
|
||||
/>
|
||||
);
|
||||
/>;
|
||||
} else if (this.state.busy || !this.state.flows) {
|
||||
registerBody = <Spinner />;
|
||||
return <Spinner />;
|
||||
} else {
|
||||
let serverConfigSection;
|
||||
if (!SdkConfig.get()['disable_custom_urls']) {
|
||||
serverConfigSection = (
|
||||
<ServerConfig ref="serverConfig"
|
||||
customHsUrl={this.props.customHsUrl}
|
||||
customIsUrl={this.props.customIsUrl}
|
||||
defaultHsUrl={this.props.defaultHsUrl}
|
||||
defaultIsUrl={this.props.defaultIsUrl}
|
||||
onServerConfigChange={this.onServerConfigChange}
|
||||
delayTimeMs={1000}
|
||||
/>
|
||||
);
|
||||
let onEditServerDetailsClick = null;
|
||||
// If custom URLs are allowed and we haven't selected the Free server type, wire
|
||||
// up the server details edit link.
|
||||
if (
|
||||
PHASES_ENABLED &&
|
||||
!SdkConfig.get()['disable_custom_urls'] &&
|
||||
this.state.serverType !== ServerType.FREE
|
||||
) {
|
||||
onEditServerDetailsClick = this.onEditServerDetailsClick;
|
||||
}
|
||||
registerBody = (
|
||||
<div>
|
||||
<RegistrationForm
|
||||
return <RegistrationForm
|
||||
defaultUsername={this.state.formVals.username}
|
||||
defaultEmail={this.state.formVals.email}
|
||||
defaultPhoneCountry={this.state.formVals.phoneCountry}
|
||||
|
@ -350,12 +467,18 @@ module.exports = React.createClass({
|
|||
minPasswordLength={MIN_PASSWORD_LENGTH}
|
||||
onError={this.onFormValidationFailed}
|
||||
onRegisterClick={this.onFormSubmit}
|
||||
onEditServerDetailsClick={onEditServerDetailsClick}
|
||||
flows={this.state.flows}
|
||||
/>
|
||||
{ serverConfigSection }
|
||||
</div>
|
||||
);
|
||||
hsUrl={this.state.hsUrl}
|
||||
hsName={this.props.defaultServerName}
|
||||
/>;
|
||||
}
|
||||
},
|
||||
|
||||
render: function() {
|
||||
const AuthHeader = sdk.getComponent('auth.AuthHeader');
|
||||
const AuthBody = sdk.getComponent("auth.AuthBody");
|
||||
const AuthPage = sdk.getComponent('auth.AuthPage');
|
||||
|
||||
let errorText;
|
||||
const err = this.state.errorText || this.props.defaultServerDiscoveryError;
|
||||
|
@ -377,9 +500,10 @@ module.exports = React.createClass({
|
|||
<AuthHeader />
|
||||
<AuthBody>
|
||||
<h2>{ _t('Create your account') }</h2>
|
||||
{ registerBody }
|
||||
{ signIn }
|
||||
{ errorText }
|
||||
{ this.renderServerComponent() }
|
||||
{ this.renderRegisterComponent() }
|
||||
{ signIn }
|
||||
</AuthBody>
|
||||
</AuthPage>
|
||||
);
|
||||
|
|
|
@ -81,7 +81,7 @@ export default class CountryDropdown extends React.Component {
|
|||
if (this.props.showPrefix) {
|
||||
countryPrefix = '+' + COUNTRIES_BY_ISO2[iso2].prefix;
|
||||
}
|
||||
return <span>
|
||||
return <span className="mx_CountryDropdown_shortOption">
|
||||
{ this._flagImgForIso2(iso2) }
|
||||
{ countryPrefix }
|
||||
</span>;
|
||||
|
@ -111,7 +111,7 @@ export default class CountryDropdown extends React.Component {
|
|||
}
|
||||
|
||||
const options = displayedCountries.map((country) => {
|
||||
return <div key={country.iso2}>
|
||||
return <div className="mx_CountryDropdown_option" key={country.iso2}>
|
||||
{ this._flagImgForIso2(country.iso2) }
|
||||
{ country.name } <span>(+{ country.prefix })</span>
|
||||
</div>;
|
||||
|
@ -121,7 +121,7 @@ export default class CountryDropdown extends React.Component {
|
|||
// values between mounting and the initial value propgating
|
||||
const value = this.props.value || COUNTRIES[0].iso2;
|
||||
|
||||
return <Dropdown className={this.props.className + " left_aligned"}
|
||||
return <Dropdown className={this.props.className + " mx_CountryDropdown"}
|
||||
onOptionChange={this._onOptionChange} onSearchChange={this._onSearchChange}
|
||||
menuWidth={298} getShortOption={this._getShortOption}
|
||||
value={value} searchEnabled={true} disabled={this.props.disabled}
|
||||
|
|
|
@ -40,7 +40,7 @@ class PasswordLogin extends React.Component {
|
|||
initialPhoneNumber: "",
|
||||
initialPassword: "",
|
||||
loginIncorrect: false,
|
||||
hsDomain: "",
|
||||
hsUrl: "",
|
||||
hsName: null,
|
||||
disableSubmit: false,
|
||||
}
|
||||
|
|
|
@ -49,6 +49,7 @@ module.exports = React.createClass({
|
|||
minPasswordLength: PropTypes.number,
|
||||
onError: PropTypes.func,
|
||||
onRegisterClick: PropTypes.func.isRequired, // onRegisterClick(Object) => ?Promise
|
||||
onEditServerDetailsClick: PropTypes.func,
|
||||
flows: PropTypes.arrayOf(PropTypes.object).isRequired,
|
||||
},
|
||||
|
||||
|
@ -256,9 +257,34 @@ module.exports = React.createClass({
|
|||
render: function() {
|
||||
const self = this;
|
||||
|
||||
let yourMatrixAccountText = _t('Create your account');
|
||||
if (this.props.hsName) {
|
||||
yourMatrixAccountText = _t('Create your %(serverName)s account', {
|
||||
serverName: this.props.hsName,
|
||||
});
|
||||
} else {
|
||||
try {
|
||||
const parsedHsUrl = new URL(this.props.hsUrl);
|
||||
yourMatrixAccountText = _t('Create your %(serverName)s account', {
|
||||
serverName: parsedHsUrl.hostname,
|
||||
});
|
||||
} catch (e) {
|
||||
// ignore
|
||||
}
|
||||
}
|
||||
|
||||
let editLink = null;
|
||||
if (this.props.onEditServerDetailsClick) {
|
||||
editLink = <a className="mx_Auth_editServerDetails"
|
||||
href="#" onClick={this.props.onEditServerDetailsClick}
|
||||
>
|
||||
{_t('Edit')}
|
||||
</a>;
|
||||
}
|
||||
|
||||
const emailPlaceholder = this._authStepIsRequired('m.login.email.identity') ?
|
||||
_t("Email address") :
|
||||
_t("Email address (optional)");
|
||||
_t("Email") :
|
||||
_t("Email (optional)");
|
||||
|
||||
const emailSection = (
|
||||
<div>
|
||||
|
@ -275,8 +301,8 @@ module.exports = React.createClass({
|
|||
let phoneSection;
|
||||
if (!SdkConfig.get().disable_3pid_login) {
|
||||
const phonePlaceholder = this._authStepIsRequired('m.login.msisdn') ?
|
||||
_t("Mobile phone number") :
|
||||
_t("Mobile phone number (optional)");
|
||||
_t("Phone") :
|
||||
_t("Phone (optional)");
|
||||
phoneSection = (
|
||||
<div className="mx_Login_phoneSection">
|
||||
<CountryDropdown ref="phone_country" onOptionChange={this._onPhoneCountryChange}
|
||||
|
@ -309,25 +335,36 @@ module.exports = React.createClass({
|
|||
|
||||
return (
|
||||
<div>
|
||||
<h3>
|
||||
{yourMatrixAccountText}
|
||||
{editLink}
|
||||
</h3>
|
||||
<form onSubmit={this.onSubmit}>
|
||||
{ emailSection }
|
||||
{ phoneSection }
|
||||
<div className="mx_Auth_fieldRow">
|
||||
<input type="text" ref="username"
|
||||
placeholder={placeholderUsername} defaultValue={this.props.defaultUsername}
|
||||
className={this._classForField(FIELD_USERNAME, 'mx_Login_field')}
|
||||
onBlur={function() {self.validateField(FIELD_USERNAME);}} />
|
||||
<br />
|
||||
</div>
|
||||
<div className="mx_Auth_fieldRow">
|
||||
<input type="password" ref="password"
|
||||
className={this._classForField(FIELD_PASSWORD, 'mx_Login_field')}
|
||||
onBlur={function() {self.validateField(FIELD_PASSWORD);}}
|
||||
placeholder={_t("Password")} defaultValue={this.props.defaultPassword} />
|
||||
<br />
|
||||
<input type="password" ref="passwordConfirm"
|
||||
placeholder={_t("Confirm password")}
|
||||
placeholder={_t("Confirm")}
|
||||
className={this._classForField(FIELD_PASSWORD_CONFIRM, 'mx_Login_field')}
|
||||
onBlur={function() {self.validateField(FIELD_PASSWORD_CONFIRM);}}
|
||||
defaultValue={this.props.defaultPassword} />
|
||||
<br />
|
||||
</div>
|
||||
<div className="mx_Auth_fieldRow">
|
||||
{ emailSection }
|
||||
{ phoneSection }
|
||||
</div>
|
||||
{_t(
|
||||
"Use an email address to receover your account. Other users " +
|
||||
"can invite you to rooms using your contact details.",
|
||||
)}
|
||||
{ registerButton }
|
||||
</form>
|
||||
</div>
|
||||
|
|
|
@ -1210,8 +1210,13 @@
|
|||
"Sign in with": "Sign in with",
|
||||
"Sign in": "Sign in",
|
||||
"If you don't specify an email address, you won't be able to reset your password. Are you sure?": "If you don't specify an email address, you won't be able to reset your password. Are you sure?",
|
||||
"Email address (optional)": "Email address (optional)",
|
||||
"Mobile phone number (optional)": "Mobile phone number (optional)",
|
||||
"Create your account": "Create your account",
|
||||
"Create your %(serverName)s account": "Create your %(serverName)s account",
|
||||
"Email": "Email",
|
||||
"Email (optional)": "Email (optional)",
|
||||
"Phone (optional)": "Phone (optional)",
|
||||
"Confirm": "Confirm",
|
||||
"Use an email address to receover your account. Other users can invite you to rooms using your contact details.": "Use an email address to receover your account. Other users can invite you to rooms using your contact details.",
|
||||
"Other servers": "Other servers",
|
||||
"Enter custom server URLs <a>What does this mean?</a>": "Enter custom server URLs <a>What does this mean?</a>",
|
||||
"Homeserver URL": "Homeserver URL",
|
||||
|
@ -1372,7 +1377,6 @@
|
|||
"Desktop specific": "Desktop specific",
|
||||
"Missing Media Permissions, click here to request.": "Missing Media Permissions, click here to request.",
|
||||
"VoIP": "VoIP",
|
||||
"Email": "Email",
|
||||
"Add email address": "Add email address",
|
||||
"Display name": "Display name",
|
||||
"To return to your account in future you need to set a password": "To return to your account in future you need to set a password",
|
||||
|
@ -1426,7 +1430,6 @@
|
|||
"A phone number is required to register on this homeserver.": "A phone number is required to register on this homeserver.",
|
||||
"You need to enter a username.": "You need to enter a username.",
|
||||
"An unknown error occurred.": "An unknown error occurred.",
|
||||
"Create your account": "Create your account",
|
||||
"Commands": "Commands",
|
||||
"Results from DuckDuckGo": "Results from DuckDuckGo",
|
||||
"Emoji": "Emoji",
|
||||
|
|
Loading…
Reference in a new issue