From 36d162cb257c329dc4105fdee39bdb785b83feea Mon Sep 17 00:00:00 2001 From: "J. Ryan Stinnett" Date: Tue, 29 Jan 2019 23:47:35 -0600 Subject: [PATCH 1/9] Validate server URLs on blur instead of change --- src/components/structures/auth/Login.js | 4 +- .../structures/auth/Registration.js | 7 ++- .../views/auth/ModularServerConfig.js | 24 ++++++---- src/components/views/auth/ServerConfig.js | 48 +++++++++++-------- 4 files changed, 49 insertions(+), 34 deletions(-) diff --git a/src/components/structures/auth/Login.js b/src/components/structures/auth/Login.js index 8d846112b65..fc33d9b54f6 100644 --- a/src/components/structures/auth/Login.js +++ b/src/components/structures/auth/Login.js @@ -571,7 +571,7 @@ module.exports = React.createClass({ defaultHsUrl={this.props.defaultHsUrl} defaultIsUrl={this.props.defaultIsUrl} onServerConfigChange={this.onServerConfigChange} - delayTimeMs={1000} + delayTimeMs={250} />; break; case ServerType.ADVANCED: @@ -581,7 +581,7 @@ module.exports = React.createClass({ defaultHsUrl={this.props.defaultHsUrl} defaultIsUrl={this.props.defaultIsUrl} onServerConfigChange={this.onServerConfigChange} - delayTimeMs={1000} + delayTimeMs={250} />; break; } diff --git a/src/components/structures/auth/Registration.js b/src/components/structures/auth/Registration.js index ca2d7716a9c..2a2d0eb4d67 100644 --- a/src/components/structures/auth/Registration.js +++ b/src/components/structures/auth/Registration.js @@ -151,6 +151,9 @@ module.exports = React.createClass({ }, _replaceClient: async function() { + this.setState({ + errorText: null, + }); this._matrixClient = Matrix.createClient({ baseUrl: this.state.hsUrl, idBaseUrl: this.state.isUrl, @@ -390,7 +393,7 @@ module.exports = React.createClass({ defaultHsUrl={this.props.defaultHsUrl} defaultIsUrl={this.props.defaultIsUrl} onServerConfigChange={this.onServerConfigChange} - delayTimeMs={1000} + delayTimeMs={250} />; break; case ServerType.ADVANCED: @@ -400,7 +403,7 @@ module.exports = React.createClass({ defaultHsUrl={this.props.defaultHsUrl} defaultIsUrl={this.props.defaultIsUrl} onServerConfigChange={this.onServerConfigChange} - delayTimeMs={1000} + delayTimeMs={250} />; break; } diff --git a/src/components/views/auth/ModularServerConfig.js b/src/components/views/auth/ModularServerConfig.js index 34b600dd403..61bfba11252 100644 --- a/src/components/views/auth/ModularServerConfig.js +++ b/src/components/views/auth/ModularServerConfig.js @@ -77,19 +77,22 @@ export default class ModularServerConfig extends React.PureComponent { }); } - onHomeserverChanged = (ev) => { - this.setState({hsUrl: ev.target.value}, () => { - this._hsTimeoutId = this._waitThenInvoke(this._hsTimeoutId, () => { - let hsUrl = this.state.hsUrl.trim().replace(/\/$/, ""); - if (hsUrl === "") hsUrl = this.props.defaultHsUrl; - this.props.onServerConfigChange({ - hsUrl: this.state.hsUrl, - isUrl: this.props.defaultIsUrl, - }); + onHomeserverBlur = (ev) => { + this._hsTimeoutId = this._waitThenInvoke(this._hsTimeoutId, () => { + let hsUrl = this.state.hsUrl.trim().replace(/\/$/, ""); + if (hsUrl === "") hsUrl = this.props.defaultHsUrl; + this.props.onServerConfigChange({ + hsUrl: this.state.hsUrl, + isUrl: this.props.defaultIsUrl, }); }); } + onHomeserverChange = (ev) => { + const hsUrl = ev.target.value; + this.setState({ hsUrl }); + } + _waitThenInvoke(existingTimeoutId, fn) { if (existingTimeoutId) { clearTimeout(existingTimeoutId); @@ -117,7 +120,8 @@ export default class ModularServerConfig extends React.PureComponent { label={_t("Server Name")} placeholder={this.props.defaultHsUrl} value={this.state.hsUrl} - onChange={this.onHomeserverChanged} + onBlur={this.onHomeserverBlur} + onChange={this.onHomeserverChange} /> diff --git a/src/components/views/auth/ServerConfig.js b/src/components/views/auth/ServerConfig.js index fb35104e49f..d90e2c36b50 100644 --- a/src/components/views/auth/ServerConfig.js +++ b/src/components/views/auth/ServerConfig.js @@ -76,32 +76,38 @@ export default class ServerConfig extends React.PureComponent { }); } - onHomeserverChanged = (ev) => { - this.setState({hsUrl: ev.target.value}, () => { - this._hsTimeoutId = this._waitThenInvoke(this._hsTimeoutId, () => { - let hsUrl = this.state.hsUrl.trim().replace(/\/$/, ""); - if (hsUrl === "") hsUrl = this.props.defaultHsUrl; - this.props.onServerConfigChange({ - hsUrl: this.state.hsUrl, - isUrl: this.state.isUrl, - }); + onHomeserverBlur = (ev) => { + this._hsTimeoutId = this._waitThenInvoke(this._hsTimeoutId, () => { + let hsUrl = this.state.hsUrl.trim().replace(/\/$/, ""); + if (hsUrl === "") hsUrl = this.props.defaultHsUrl; + this.props.onServerConfigChange({ + hsUrl: this.state.hsUrl, + isUrl: this.state.isUrl, }); }); } - onIdentityServerChanged = (ev) => { - this.setState({isUrl: ev.target.value}, () => { - this._isTimeoutId = this._waitThenInvoke(this._isTimeoutId, () => { - let isUrl = this.state.isUrl.trim().replace(/\/$/, ""); - if (isUrl === "") isUrl = this.props.defaultIsUrl; - this.props.onServerConfigChange({ - hsUrl: this.state.hsUrl, - isUrl: this.state.isUrl, - }); + onHomeserverChange = (ev) => { + const hsUrl = ev.target.value; + this.setState({ hsUrl }); + } + + onIdentityServerBlur = (ev) => { + this._isTimeoutId = this._waitThenInvoke(this._isTimeoutId, () => { + let isUrl = this.state.isUrl.trim().replace(/\/$/, ""); + if (isUrl === "") isUrl = this.props.defaultIsUrl; + this.props.onServerConfigChange({ + hsUrl: this.state.hsUrl, + isUrl: this.state.isUrl, }); }); } + onIdentityServerChange = (ev) => { + const isUrl = ev.target.value; + this.setState({ isUrl }); + } + _waitThenInvoke(existingTimeoutId, fn) { if (existingTimeoutId) { clearTimeout(existingTimeoutId); @@ -130,13 +136,15 @@ export default class ServerConfig extends React.PureComponent { label={_t("Homeserver URL")} placeholder={this.props.defaultHsUrl} value={this.state.hsUrl} - onChange={this.onHomeserverChanged} + onBlur={this.onHomeserverBlur} + onChange={this.onHomeserverChange} /> From f5e3b90fc38ac5b9476959eecad3fa5dde915272 Mon Sep 17 00:00:00 2001 From: "J. Ryan Stinnett" Date: Tue, 29 Jan 2019 23:50:31 -0600 Subject: [PATCH 2/9] Clear out discovery errors on each try --- src/components/structures/auth/Login.js | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/components/structures/auth/Login.js b/src/components/structures/auth/Login.js index fc33d9b54f6..95e81b4e6f6 100644 --- a/src/components/structures/auth/Login.js +++ b/src/components/structures/auth/Login.js @@ -265,7 +265,10 @@ module.exports = React.createClass({ }, onUsernameBlur: function(username) { - this.setState({ username: username }); + this.setState({ + username: username, + discoveryError: null, + }); if (username[0] === "@") { const serverName = username.split(':').slice(1).join(':'); try { From cfe19d710b37bd07230f8baedf71973a703b0ac4 Mon Sep 17 00:00:00 2001 From: "J. Ryan Stinnett" Date: Wed, 30 Jan 2019 00:33:29 -0600 Subject: [PATCH 3/9] Avoid hsName for auth headers which can be outdated `hsName` uses only the default HS, so that can easily be outdated if the HS URL is customized. --- src/components/structures/MatrixChat.js | 2 -- src/components/structures/auth/Login.js | 5 ----- src/components/structures/auth/Registration.js | 5 ----- src/components/views/auth/PasswordLogin.js | 18 +++++++----------- src/components/views/auth/RegistrationForm.js | 17 ++++++----------- 5 files changed, 13 insertions(+), 34 deletions(-) diff --git a/src/components/structures/MatrixChat.js b/src/components/structures/MatrixChat.js index 9f3db9b531b..d0a5aa42c45 100644 --- a/src/components/structures/MatrixChat.js +++ b/src/components/structures/MatrixChat.js @@ -1892,7 +1892,6 @@ export default React.createClass({ idSid={this.state.register_id_sid} email={this.props.startingFragmentQueryParams.email} referrer={this.props.startingFragmentQueryParams.referrer} - defaultServerName={this.getDefaultServerName()} defaultServerDiscoveryError={this.state.defaultServerDiscoveryError} defaultHsUrl={this.getDefaultHsUrl()} defaultIsUrl={this.getDefaultIsUrl()} @@ -1932,7 +1931,6 @@ export default React.createClass({ ); diff --git a/src/components/structures/auth/Registration.js b/src/components/structures/auth/Registration.js index 2a2d0eb4d67..e2d1bf13215 100644 --- a/src/components/structures/auth/Registration.js +++ b/src/components/structures/auth/Registration.js @@ -56,10 +56,6 @@ module.exports = React.createClass({ email: PropTypes.string, referrer: PropTypes.string, - // The default server name to use when the user hasn't specified - // one. This is used when displaying the defaultHsUrl in the UI. - defaultServerName: PropTypes.string, - // An error passed along from higher up explaining that something // went wrong when finding the defaultHsUrl. defaultServerDiscoveryError: PropTypes.string, @@ -473,7 +469,6 @@ module.exports = React.createClass({ onEditServerDetailsClick={onEditServerDetailsClick} flows={this.state.flows} hsUrl={this.state.hsUrl} - hsName={this.props.defaultServerName} />; } }, diff --git a/src/components/views/auth/PasswordLogin.js b/src/components/views/auth/PasswordLogin.js index 60f9c5b8aa8..f692c31b356 100644 --- a/src/components/views/auth/PasswordLogin.js +++ b/src/components/views/auth/PasswordLogin.js @@ -41,7 +41,6 @@ class PasswordLogin extends React.Component { initialPassword: "", loginIncorrect: false, hsUrl: "", - hsName: null, disableSubmit: false, } @@ -251,15 +250,13 @@ class PasswordLogin extends React.Component { } let yourMatrixAccountText = _t('Your account'); - if (this.props.hsName) { - yourMatrixAccountText = _t('Your %(serverName)s account', {serverName: this.props.hsName}); - } else { - try { - const parsedHsUrl = new URL(this.props.hsUrl); - yourMatrixAccountText = _t('Your %(serverName)s account', {serverName: parsedHsUrl.hostname}); - } catch (e) { - // ignore - } + try { + const parsedHsUrl = new URL(this.props.hsUrl); + yourMatrixAccountText = _t('Your %(serverName)s account', { + serverName: parsedHsUrl.hostname, + }); + } catch (e) { + // ignore } let editLink = null; @@ -341,7 +338,6 @@ PasswordLogin.propTypes = { onPhoneNumberChanged: PropTypes.func, onPasswordChanged: PropTypes.func, loginIncorrect: PropTypes.bool, - hsName: PropTypes.string, disableSubmit: PropTypes.bool, }; diff --git a/src/components/views/auth/RegistrationForm.js b/src/components/views/auth/RegistrationForm.js index fcd306c5dac..e43537364b9 100644 --- a/src/components/views/auth/RegistrationForm.js +++ b/src/components/views/auth/RegistrationForm.js @@ -51,6 +51,7 @@ module.exports = React.createClass({ onRegisterClick: PropTypes.func.isRequired, // onRegisterClick(Object) => ?Promise onEditServerDetailsClick: PropTypes.func, flows: PropTypes.arrayOf(PropTypes.object).isRequired, + hsUrl: PropTypes.string, }, getDefaultProps: function() { @@ -258,19 +259,13 @@ module.exports = React.createClass({ const self = this; let yourMatrixAccountText = _t('Create your account'); - if (this.props.hsName) { + try { + const parsedHsUrl = new URL(this.props.hsUrl); yourMatrixAccountText = _t('Create your %(serverName)s account', { - serverName: this.props.hsName, + serverName: parsedHsUrl.hostname, }); - } else { - try { - const parsedHsUrl = new URL(this.props.hsUrl); - yourMatrixAccountText = _t('Create your %(serverName)s account', { - serverName: parsedHsUrl.hostname, - }); - } catch (e) { - // ignore - } + } catch (e) { + // ignore } let editLink = null; From eafd7e12d05ce6fbe4ee502351460b290f21242a Mon Sep 17 00:00:00 2001 From: "J. Ryan Stinnett" Date: Wed, 30 Jan 2019 10:50:51 -0600 Subject: [PATCH 4/9] Validate login phone number on blur --- src/components/structures/auth/Login.js | 19 +++++++++++++------ src/components/views/auth/PasswordLogin.js | 7 +++++++ 2 files changed, 20 insertions(+), 6 deletions(-) diff --git a/src/components/structures/auth/Login.js b/src/components/structures/auth/Login.js index 51f05c3a4d5..91d8001e726 100644 --- a/src/components/structures/auth/Login.js +++ b/src/components/structures/auth/Login.js @@ -284,16 +284,22 @@ module.exports = React.createClass({ }, onPhoneNumberChanged: function(phoneNumber) { - // Validate the phone number entered - if (!PHONE_NUMBER_REGEX.test(phoneNumber)) { - this.setState({ errorText: _t('The phone number entered looks invalid') }); - return; - } - this.setState({ phoneNumber: phoneNumber, + }); + }, + + onPhoneNumberBlur: function(phoneNumber) { + this.setState({ errorText: null, }); + + // Validate the phone number entered + if (!PHONE_NUMBER_REGEX.test(phoneNumber)) { + this.setState({ + errorText: _t('The phone number entered looks invalid'), + }); + } }, onServerConfigChange: function(config) { @@ -648,6 +654,7 @@ module.exports = React.createClass({ onUsernameBlur={this.onUsernameBlur} onPhoneCountryChanged={this.onPhoneCountryChanged} onPhoneNumberChanged={this.onPhoneNumberChanged} + onPhoneNumberBlur={this.onPhoneNumberBlur} onForgotPasswordClick={this.props.onForgotPasswordClick} loginIncorrect={this.state.loginIncorrect} hsUrl={this.state.enteredHomeserverUrl} diff --git a/src/components/views/auth/PasswordLogin.js b/src/components/views/auth/PasswordLogin.js index f692c31b356..0dbf52a4b99 100644 --- a/src/components/views/auth/PasswordLogin.js +++ b/src/components/views/auth/PasswordLogin.js @@ -35,6 +35,7 @@ class PasswordLogin extends React.Component { onPasswordChanged: function() {}, onPhoneCountryChanged: function() {}, onPhoneNumberChanged: function() {}, + onPhoneNumberBlur: function() {}, initialUsername: "", initialPhoneCountry: "", initialPhoneNumber: "", @@ -60,6 +61,7 @@ class PasswordLogin extends React.Component { this.onLoginTypeChange = this.onLoginTypeChange.bind(this); this.onPhoneCountryChanged = this.onPhoneCountryChanged.bind(this); this.onPhoneNumberChanged = this.onPhoneNumberChanged.bind(this); + this.onPhoneNumberBlur = this.onPhoneNumberBlur.bind(this); this.onPasswordChanged = this.onPasswordChanged.bind(this); this.isLoginEmpty = this.isLoginEmpty.bind(this); } @@ -153,6 +155,10 @@ class PasswordLogin extends React.Component { this.props.onPhoneNumberChanged(ev.target.value); } + onPhoneNumberBlur(ev) { + this.props.onPhoneNumberBlur(ev.target.value); + } + onPasswordChanged(ev) { this.setState({password: ev.target.value}); this.props.onPasswordChanged(ev.target.value); @@ -214,6 +220,7 @@ class PasswordLogin extends React.Component { type="text" name="phoneNumber" onChange={this.onPhoneNumberChanged} + onBlur={this.onPhoneNumberBlur} placeholder={_t("Mobile phone number")} value={this.state.phoneNumber} autoFocus From 9a17181f2cbfe5c26c734ac06456307f0cdea179 Mon Sep 17 00:00:00 2001 From: "J. Ryan Stinnett" Date: Wed, 30 Jan 2019 11:25:47 -0600 Subject: [PATCH 5/9] Use event value for username blur --- src/components/views/auth/PasswordLogin.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/views/auth/PasswordLogin.js b/src/components/views/auth/PasswordLogin.js index 0dbf52a4b99..d0ffe8fa1ab 100644 --- a/src/components/views/auth/PasswordLogin.js +++ b/src/components/views/auth/PasswordLogin.js @@ -131,7 +131,7 @@ class PasswordLogin extends React.Component { } onUsernameBlur(ev) { - this.props.onUsernameBlur(this.state.username); + this.props.onUsernameBlur(ev.target.value); } onLoginTypeChange(loginType) { From 2f006939f2067fc36f9ce8f167120ebee2fb62a8 Mon Sep 17 00:00:00 2001 From: "J. Ryan Stinnett" Date: Wed, 30 Jan 2019 12:46:40 -0600 Subject: [PATCH 6/9] Use mx_AuthBody prefix for consistency --- res/css/views/auth/_AuthBody.scss | 12 ++++++------ res/css/views/auth/_LanguageSelector.scss | 6 +++--- src/components/structures/auth/ForgotPassword.js | 2 +- src/components/structures/auth/Login.js | 4 ++-- src/components/structures/auth/Registration.js | 2 +- src/components/views/auth/LanguageSelector.js | 2 +- src/components/views/auth/PasswordLogin.js | 2 +- src/components/views/auth/RegistrationForm.js | 8 ++++---- 8 files changed, 19 insertions(+), 19 deletions(-) diff --git a/res/css/views/auth/_AuthBody.scss b/res/css/views/auth/_AuthBody.scss index 08a8b4ff4a7..fd54cd135a9 100644 --- a/res/css/views/auth/_AuthBody.scss +++ b/res/css/views/auth/_AuthBody.scss @@ -36,7 +36,7 @@ limitations under the License. color: $primary-fg-color; } -.mx_Auth_editServerDetails { +.mx_AuthBody_editServerDetails { padding-left: 1em; font-size: 12px; font-weight: normal; @@ -47,21 +47,21 @@ limitations under the License. box-sizing: border-box; } -.mx_Auth_fieldRow { +.mx_AuthBody_fieldRow { display: flex; margin-bottom: 10px; } -.mx_Auth_fieldRow > * { +.mx_AuthBody_fieldRow > * { margin: 0 5px; flex: 1; } -.mx_Auth_fieldRow > *:first-child { +.mx_AuthBody_fieldRow > *:first-child { margin-left: 0; } -.mx_Auth_fieldRow > *:last-child { +.mx_AuthBody_fieldRow > *:last-child { margin-right: 0; } @@ -72,7 +72,7 @@ limitations under the License. text-decoration: none; } -.mx_Auth_changeFlow { +.mx_AuthBody_changeFlow { display: block; text-align: center; width: 100%; diff --git a/res/css/views/auth/_LanguageSelector.scss b/res/css/views/auth/_LanguageSelector.scss index 89232ab8afc..6f7eac0cf6c 100644 --- a/res/css/views/auth/_LanguageSelector.scss +++ b/res/css/views/auth/_LanguageSelector.scss @@ -14,17 +14,17 @@ See the License for the specific language governing permissions and limitations under the License. */ -.mx_Auth_language { +.mx_AuthBody_language { width: 100%; } -.mx_Auth_language .mx_Dropdown_input { +.mx_AuthBody_language .mx_Dropdown_input { border: none; font-size: 14px; font-weight: 600; color: $authpage-lang-color; } -.mx_Auth_language .mx_Dropdown_arrow { +.mx_AuthBody_language .mx_Dropdown_arrow { background: $authpage-lang-color; } diff --git a/src/components/structures/auth/ForgotPassword.js b/src/components/structures/auth/ForgotPassword.js index 1b8b15981b0..7b7a700d60e 100644 --- a/src/components/structures/auth/ForgotPassword.js +++ b/src/components/structures/auth/ForgotPassword.js @@ -255,7 +255,7 @@ module.exports = React.createClass({ { serverConfigSection } { errorText } - + { _t('Sign in instead') } diff --git a/src/components/structures/auth/Login.js b/src/components/structures/auth/Login.js index 91d8001e726..d1b0aad31ad 100644 --- a/src/components/structures/auth/Login.js +++ b/src/components/structures/auth/Login.js @@ -689,7 +689,7 @@ module.exports = React.createClass({ let loginAsGuestJsx; if (this.props.enableGuest) { loginAsGuestJsx = - + { _t('Try the app first') } ; } @@ -714,7 +714,7 @@ module.exports = React.createClass({ { errorTextSection } { this.renderServerComponentForStep() } { this.renderLoginComponentForStep() } - + { _t('Create account') } { loginAsGuestJsx } diff --git a/src/components/structures/auth/Registration.js b/src/components/structures/auth/Registration.js index e2d1bf13215..03b071ed485 100644 --- a/src/components/structures/auth/Registration.js +++ b/src/components/structures/auth/Registration.js @@ -487,7 +487,7 @@ module.exports = React.createClass({ let signIn; if (!this.state.doingUIAuth) { signIn = ( - + { _t('Sign in instead') } ); diff --git a/src/components/views/auth/LanguageSelector.js b/src/components/views/auth/LanguageSelector.js index d964af184c8..32862478f4d 100644 --- a/src/components/views/auth/LanguageSelector.js +++ b/src/components/views/auth/LanguageSelector.js @@ -32,7 +32,7 @@ export default function LanguageSelector() { if (SdkConfig.get()['disable_login_language_selector']) return
; const LanguageDropdown = sdk.getComponent('views.elements.LanguageDropdown'); - return ; diff --git a/src/components/views/auth/PasswordLogin.js b/src/components/views/auth/PasswordLogin.js index d0ffe8fa1ab..022de34011e 100644 --- a/src/components/views/auth/PasswordLogin.js +++ b/src/components/views/auth/PasswordLogin.js @@ -268,7 +268,7 @@ class PasswordLogin extends React.Component { let editLink = null; if (this.props.onEditServerDetailsClick) { - editLink = {_t('Edit')} diff --git a/src/components/views/auth/RegistrationForm.js b/src/components/views/auth/RegistrationForm.js index e43537364b9..14d170ecaa5 100644 --- a/src/components/views/auth/RegistrationForm.js +++ b/src/components/views/auth/RegistrationForm.js @@ -270,7 +270,7 @@ module.exports = React.createClass({ let editLink = null; if (this.props.onEditServerDetailsClick) { - editLink = {_t('Edit')} @@ -335,13 +335,13 @@ module.exports = React.createClass({ {editLink}
-
+
-
+
-
+
{ emailSection } { phoneSection }
From e3f3a94980b6c380ab8c812d303268e1ef0d8f4e Mon Sep 17 00:00:00 2001 From: "J. Ryan Stinnett" Date: Wed, 30 Jan 2019 13:07:47 -0600 Subject: [PATCH 7/9] Remove shake animation from auth field errors --- src/UiEffects.js | 27 ------------------- src/components/views/auth/PasswordLogin.js | 7 ----- src/components/views/auth/RegistrationForm.js | 2 -- 3 files changed, 36 deletions(-) delete mode 100644 src/UiEffects.js diff --git a/src/UiEffects.js b/src/UiEffects.js deleted file mode 100644 index 06b0a0e3b7c..00000000000 --- a/src/UiEffects.js +++ /dev/null @@ -1,27 +0,0 @@ -/* -Copyright 2016 OpenMarket 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. -*/ - -/** - * Functions for applying common thematic effects to UI elements. - * Ideally this would be themeable. - */ - -import Velocity from 'velocity-vector'; -import 'velocity-vector/velocity.ui'; - -export function fieldInputIncorrect(element) { - Velocity(element, "callout.shake", 300); -} diff --git a/src/components/views/auth/PasswordLogin.js b/src/components/views/auth/PasswordLogin.js index 022de34011e..5bc6d6e05be 100644 --- a/src/components/views/auth/PasswordLogin.js +++ b/src/components/views/auth/PasswordLogin.js @@ -20,7 +20,6 @@ import PropTypes from 'prop-types'; import classNames from 'classnames'; import sdk from '../../../index'; import { _t } from '../../../languageHandler'; -import {fieldInputIncorrect} from '../../../UiEffects'; import SdkConfig from '../../../SdkConfig'; /** @@ -71,12 +70,6 @@ class PasswordLogin extends React.Component { this._loginField = null; } - componentWillReceiveProps(nextProps) { - if (!this.props.loginIncorrect && nextProps.loginIncorrect) { - fieldInputIncorrect(this.isLoginEmpty() ? this._loginField : this._passwordField); - } - } - onSubmitForm(ev) { ev.preventDefault(); diff --git a/src/components/views/auth/RegistrationForm.js b/src/components/views/auth/RegistrationForm.js index 14d170ecaa5..b38a7d47fc0 100644 --- a/src/components/views/auth/RegistrationForm.js +++ b/src/components/views/auth/RegistrationForm.js @@ -18,7 +18,6 @@ limitations under the License. import React from 'react'; import PropTypes from 'prop-types'; -import { fieldInputIncorrect } from '../../../UiEffects'; import sdk from '../../../index'; import Email from '../../../email'; import { looksValid as phoneNumberLooksValid } from '../../../phonenumber'; @@ -211,7 +210,6 @@ module.exports = React.createClass({ fieldValid[fieldID] = val; this.setState({fieldValid: fieldValid}); if (!val) { - fieldInputIncorrect(this.fieldElementById(fieldID)); this.props.onError(errorCode); } }, From c560fd32c455e4510b9a8341dd834559d67fc517 Mon Sep 17 00:00:00 2001 From: "J. Ryan Stinnett" Date: Wed, 30 Jan 2019 14:48:12 -0600 Subject: [PATCH 8/9] Allow empty user / pass on blur, check on submit --- src/components/views/auth/RegistrationForm.js | 62 +++++++++++++------ 1 file changed, 43 insertions(+), 19 deletions(-) diff --git a/src/components/views/auth/RegistrationForm.js b/src/components/views/auth/RegistrationForm.js index b38a7d47fc0..ba48239cc6c 100644 --- a/src/components/views/auth/RegistrationForm.js +++ b/src/components/views/auth/RegistrationForm.js @@ -78,11 +78,11 @@ module.exports = React.createClass({ // is the one from the first invalid field. // It's not super ideal that this just calls // onError once for each invalid field. - this.validateField(FIELD_PASSWORD_CONFIRM); - this.validateField(FIELD_PASSWORD); - this.validateField(FIELD_USERNAME); - this.validateField(FIELD_PHONE_NUMBER); - this.validateField(FIELD_EMAIL); + this.validateField(FIELD_PASSWORD_CONFIRM, ev.type); + this.validateField(FIELD_PASSWORD, ev.type); + this.validateField(FIELD_USERNAME, ev.type); + this.validateField(FIELD_PHONE_NUMBER, ev.type); + this.validateField(FIELD_EMAIL, ev.type); const self = this; if (this.allFieldsValid()) { @@ -139,9 +139,10 @@ module.exports = React.createClass({ return true; }, - validateField: function(fieldID) { + validateField: function(fieldID, eventType) { const pwd1 = this.refs.password.value.trim(); const pwd2 = this.refs.passwordConfirm.value.trim(); + const allowEmpty = eventType === "blur"; switch (fieldID) { case FIELD_EMAIL: { @@ -162,7 +163,9 @@ module.exports = React.createClass({ } case FIELD_USERNAME: { const username = this.refs.username.value.trim(); - if (!SAFE_LOCALPART_REGEX.test(username)) { + if (allowEmpty && username === '') { + this.markFieldValid(fieldID, true); + } else if (!SAFE_LOCALPART_REGEX.test(username)) { this.markFieldValid( fieldID, false, @@ -180,7 +183,9 @@ module.exports = React.createClass({ break; } case FIELD_PASSWORD: - if (pwd1 == '') { + if (allowEmpty && pwd1 === "") { + this.markFieldValid(fieldID, true); + } else if (pwd1 == '') { this.markFieldValid( fieldID, false, @@ -238,13 +243,33 @@ module.exports = React.createClass({ return cls; }, - _onPhoneCountryChange(newVal) { + onEmailBlur(ev) { + this.validateField(FIELD_EMAIL, ev.type); + }, + + onPasswordBlur(ev) { + this.validateField(FIELD_PASSWORD, ev.type); + }, + + onPasswordConfirmBlur(ev) { + this.validateField(FIELD_PASSWORD_CONFIRM, ev.type); + }, + + onPhoneCountryChange(newVal) { this.setState({ phoneCountry: newVal.iso2, phonePrefix: newVal.prefix, }); }, + onPhoneNumberBlur(ev) { + this.validateField(FIELD_PHONE_NUMBER, ev.type); + }, + + onUsernameBlur(ev) { + this.validateField(FIELD_USERNAME, ev.type); + }, + _authStepIsRequired(step) { // A step is required if no flow exists which does not include that step // (Notwithstanding setups like either email or msisdn being required) @@ -254,8 +279,6 @@ module.exports = React.createClass({ }, render: function() { - const self = this; - let yourMatrixAccountText = _t('Create your account'); try { const parsedHsUrl = new URL(this.props.hsUrl); @@ -285,8 +308,8 @@ module.exports = React.createClass({ autoFocus={true} placeholder={emailPlaceholder} defaultValue={this.props.defaultEmail} className={this._classForField(FIELD_EMAIL, 'mx_Login_field')} - onBlur={function() {self.validateField(FIELD_EMAIL);}} - value={self.state.email} /> + onBlur={this.onEmailBlur} + value={this.state.email} />
); @@ -298,11 +321,12 @@ module.exports = React.createClass({ _t("Phone (optional)"); phoneSection = (
-
); @@ -337,17 +361,17 @@ module.exports = React.createClass({ + onBlur={this.onUsernameBlur} />
From 346f73bb1d29f589509a35175c8f2d27b5b18b0f Mon Sep 17 00:00:00 2001 From: "J. Ryan Stinnett" Date: Thu, 31 Jan 2019 10:01:31 -0600 Subject: [PATCH 9/9] Remove dead code tweaking server URLs on blur --- src/components/views/auth/ModularServerConfig.js | 2 -- src/components/views/auth/ServerConfig.js | 4 ---- 2 files changed, 6 deletions(-) diff --git a/src/components/views/auth/ModularServerConfig.js b/src/components/views/auth/ModularServerConfig.js index 61bfba11252..9c6c4b01bf6 100644 --- a/src/components/views/auth/ModularServerConfig.js +++ b/src/components/views/auth/ModularServerConfig.js @@ -79,8 +79,6 @@ export default class ModularServerConfig extends React.PureComponent { onHomeserverBlur = (ev) => { this._hsTimeoutId = this._waitThenInvoke(this._hsTimeoutId, () => { - let hsUrl = this.state.hsUrl.trim().replace(/\/$/, ""); - if (hsUrl === "") hsUrl = this.props.defaultHsUrl; this.props.onServerConfigChange({ hsUrl: this.state.hsUrl, isUrl: this.props.defaultIsUrl, diff --git a/src/components/views/auth/ServerConfig.js b/src/components/views/auth/ServerConfig.js index d90e2c36b50..cb0e0dc38ec 100644 --- a/src/components/views/auth/ServerConfig.js +++ b/src/components/views/auth/ServerConfig.js @@ -78,8 +78,6 @@ export default class ServerConfig extends React.PureComponent { onHomeserverBlur = (ev) => { this._hsTimeoutId = this._waitThenInvoke(this._hsTimeoutId, () => { - let hsUrl = this.state.hsUrl.trim().replace(/\/$/, ""); - if (hsUrl === "") hsUrl = this.props.defaultHsUrl; this.props.onServerConfigChange({ hsUrl: this.state.hsUrl, isUrl: this.state.isUrl, @@ -94,8 +92,6 @@ export default class ServerConfig extends React.PureComponent { onIdentityServerBlur = (ev) => { this._isTimeoutId = this._waitThenInvoke(this._isTimeoutId, () => { - let isUrl = this.state.isUrl.trim().replace(/\/$/, ""); - if (isUrl === "") isUrl = this.props.defaultIsUrl; this.props.onServerConfigChange({ hsUrl: this.state.hsUrl, isUrl: this.state.isUrl,