From b9604d1fb5a9babeda29ab2153b633eb2081c83a Mon Sep 17 00:00:00 2001 From: Dariusz Niemczyk Date: Thu, 19 Aug 2021 09:12:22 +0200 Subject: [PATCH] Make ForgotPassword UX slightly more user friendly --- res/css/structures/auth/_Login.scss | 7 +++++ .../structures/auth/ForgotPassword.tsx | 27 ++++++++++++++++--- 2 files changed, 31 insertions(+), 3 deletions(-) diff --git a/res/css/structures/auth/_Login.scss b/res/css/structures/auth/_Login.scss index 9c98ca3a1c..390e091289 100644 --- a/res/css/structures/auth/_Login.scss +++ b/res/css/structures/auth/_Login.scss @@ -96,3 +96,10 @@ div.mx_AccessibleButton_kind_link.mx_Login_forgot { cursor: not-allowed; } } +.mx_Login--spinner { + display: flex; + justify-content: center; + align-items: center; + align-content: center; + padding: 14px; +} diff --git a/src/components/structures/auth/ForgotPassword.tsx b/src/components/structures/auth/ForgotPassword.tsx index f978a6cded..45ef86d793 100644 --- a/src/components/structures/auth/ForgotPassword.tsx +++ b/src/components/structures/auth/ForgotPassword.tsx @@ -31,6 +31,7 @@ import { replaceableComponent } from "../../../utils/replaceableComponent"; import { PASSWORD_MIN_SCORE } from '../../views/auth/RegistrationForm'; import { IValidationResult } from "../../views/elements/Validation"; +import InlineSpinner from '../../views/elements/InlineSpinner'; enum Phase { // Show the forgot password inputs @@ -66,13 +67,14 @@ interface IState { serverDeadError: string; passwordFieldValid: boolean; + currentHttpRequest?: Promise; } @replaceableComponent("structures.auth.ForgotPassword") export default class ForgotPassword extends React.Component { private reset: PasswordReset; - state = { + state: IState = { phase: Phase.Forgot, email: "", password: "", @@ -148,8 +150,10 @@ export default class ForgotPassword extends React.Component { console.error("onVerify called before submitPasswordReset!"); return; } + if (this.state.currentHttpRequest) return; + try { - await this.reset.checkEmailLinkClicked(); + await this.handleHttpRequest(this.reset.checkEmailLinkClicked()); this.setState({ phase: Phase.Done }); } catch (err) { this.showErrorDialog(err.message); @@ -158,9 +162,10 @@ export default class ForgotPassword extends React.Component { private onSubmitForm = async (ev: React.FormEvent): Promise => { ev.preventDefault(); + if (this.state.currentHttpRequest) return; // refresh the server errors, just in case the server came back online - await this.checkServerLiveliness(this.props.serverConfig); + await this.handleHttpRequest(this.checkServerLiveliness(this.props.serverConfig)); await this['password_field'].validate({ allowEmpty: false }); @@ -221,6 +226,17 @@ export default class ForgotPassword extends React.Component { }); } + private handleHttpRequest(request: Promise): Promise { + this.setState({ + currentHttpRequest: request, + }); + return request.finally(() => { + this.setState({ + currentHttpRequest: undefined, + }); + }); + } + renderForgot() { const Field = sdk.getComponent('elements.Field'); @@ -320,6 +336,9 @@ export default class ForgotPassword extends React.Component { type="button" onClick={this.onVerify} value={_t('I have verified my email address')} /> + { this.state.currentHttpRequest && ( +
) + } ; } @@ -357,6 +376,8 @@ export default class ForgotPassword extends React.Component { case Phase.Done: resetPasswordJsx = this.renderDone(); break; + default: + resetPasswordJsx =
; } return (