Merge pull request #6636 from matrix-org/palid/fix/forgot-password-ux

Make ForgotPassword UX slightly more user friendly
This commit is contained in:
Dariusz Niemczyk 2021-09-06 10:55:25 +02:00 committed by GitHub
commit 1e50246a78
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 31 additions and 3 deletions

View file

@ -96,3 +96,10 @@ div.mx_AccessibleButton_kind_link.mx_Login_forgot {
cursor: not-allowed; cursor: not-allowed;
} }
} }
.mx_Login_spinner {
display: flex;
justify-content: center;
align-items: center;
align-content: center;
padding: 14px;
}

View file

@ -31,6 +31,7 @@ import { replaceableComponent } from "../../../utils/replaceableComponent";
import { PASSWORD_MIN_SCORE } from '../../views/auth/RegistrationForm'; import { PASSWORD_MIN_SCORE } from '../../views/auth/RegistrationForm';
import { IValidationResult } from "../../views/elements/Validation"; import { IValidationResult } from "../../views/elements/Validation";
import InlineSpinner from '../../views/elements/InlineSpinner';
enum Phase { enum Phase {
// Show the forgot password inputs // Show the forgot password inputs
@ -66,13 +67,14 @@ interface IState {
serverDeadError: string; serverDeadError: string;
passwordFieldValid: boolean; passwordFieldValid: boolean;
currentHttpRequest?: Promise<any>;
} }
@replaceableComponent("structures.auth.ForgotPassword") @replaceableComponent("structures.auth.ForgotPassword")
export default class ForgotPassword extends React.Component<IProps, IState> { export default class ForgotPassword extends React.Component<IProps, IState> {
private reset: PasswordReset; private reset: PasswordReset;
state = { state: IState = {
phase: Phase.Forgot, phase: Phase.Forgot,
email: "", email: "",
password: "", password: "",
@ -148,8 +150,10 @@ export default class ForgotPassword extends React.Component<IProps, IState> {
console.error("onVerify called before submitPasswordReset!"); console.error("onVerify called before submitPasswordReset!");
return; return;
} }
if (this.state.currentHttpRequest) return;
try { try {
await this.reset.checkEmailLinkClicked(); await this.handleHttpRequest(this.reset.checkEmailLinkClicked());
this.setState({ phase: Phase.Done }); this.setState({ phase: Phase.Done });
} catch (err) { } catch (err) {
this.showErrorDialog(err.message); this.showErrorDialog(err.message);
@ -158,9 +162,10 @@ export default class ForgotPassword extends React.Component<IProps, IState> {
private onSubmitForm = async (ev: React.FormEvent): Promise<void> => { private onSubmitForm = async (ev: React.FormEvent): Promise<void> => {
ev.preventDefault(); ev.preventDefault();
if (this.state.currentHttpRequest) return;
// refresh the server errors, just in case the server came back online // 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 }); await this['password_field'].validate({ allowEmpty: false });
@ -221,6 +226,17 @@ export default class ForgotPassword extends React.Component<IProps, IState> {
}); });
} }
private handleHttpRequest<T = unknown>(request: Promise<T>): Promise<T> {
this.setState({
currentHttpRequest: request,
});
return request.finally(() => {
this.setState({
currentHttpRequest: undefined,
});
});
}
renderForgot() { renderForgot() {
const Field = sdk.getComponent('elements.Field'); const Field = sdk.getComponent('elements.Field');
@ -320,6 +336,9 @@ export default class ForgotPassword extends React.Component<IProps, IState> {
type="button" type="button"
onClick={this.onVerify} onClick={this.onVerify}
value={_t('I have verified my email address')} /> value={_t('I have verified my email address')} />
{ this.state.currentHttpRequest && (
<div className="mx_Login_spinner"><InlineSpinner w={64} h={64} /></div>)
}
</div>; </div>;
} }
@ -357,6 +376,8 @@ export default class ForgotPassword extends React.Component<IProps, IState> {
case Phase.Done: case Phase.Done:
resetPasswordJsx = this.renderDone(); resetPasswordJsx = this.renderDone();
break; break;
default:
resetPasswordJsx = <div className="mx_Login_spinner"><InlineSpinner w={64} h={64} /></div>;
} }
return ( return (