Skip to content
This repository has been archived by the owner on Sep 11, 2024. It is now read-only.

Make ForgotPassword UX slightly more user friendly #6636

Merged
merged 4 commits into from
Sep 6, 2021
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions res/css/structures/auth/_Login.scss
Original file line number Diff line number Diff line change
Expand Up @@ -96,3 +96,10 @@ div.mx_AccessibleButton_kind_link.mx_Login_forgot {
cursor: not-allowed;
}
}
.mx_Login_spinner {
Palid marked this conversation as resolved.
Show resolved Hide resolved
display: flex;
justify-content: center;
align-items: center;
align-content: center;
padding: 14px;
}
27 changes: 24 additions & 3 deletions src/components/structures/auth/ForgotPassword.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -66,13 +67,14 @@ interface IState {
serverDeadError: string;

passwordFieldValid: boolean;
currentHttpRequest?: Promise<any>;
}

@replaceableComponent("structures.auth.ForgotPassword")
export default class ForgotPassword extends React.Component<IProps, IState> {
private reset: PasswordReset;

state = {
state: IState = {
phase: Phase.Forgot,
email: "",
password: "",
Expand Down Expand Up @@ -148,8 +150,10 @@ export default class ForgotPassword extends React.Component<IProps, IState> {
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);
Expand All @@ -158,9 +162,10 @@ export default class ForgotPassword extends React.Component<IProps, IState> {

private onSubmitForm = async (ev: React.FormEvent): Promise<void> => {
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 });

Expand Down Expand Up @@ -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() {
const Field = sdk.getComponent('elements.Field');

Expand Down Expand Up @@ -320,6 +336,9 @@ export default class ForgotPassword extends React.Component<IProps, IState> {
type="button"
onClick={this.onVerify}
value={_t('I have verified my email address')} />
{ this.state.currentHttpRequest && (
<div className="mx_Login--spinner"><InlineSpinner w={64} h={64} /></div>)
Palid marked this conversation as resolved.
Show resolved Hide resolved
}
</div>;
}

Expand Down Expand Up @@ -357,6 +376,8 @@ export default class ForgotPassword extends React.Component<IProps, IState> {
case Phase.Done:
resetPasswordJsx = this.renderDone();
break;
default:
resetPasswordJsx = <div className="mx_Login--spinner"><InlineSpinner w={64} h={64} /></div>;
Palid marked this conversation as resolved.
Show resolved Hide resolved
}

return (
Expand Down