Migrate ForgotPassword to TypeScript

This commit is contained in:
Germain Souquet 2021-07-03 11:55:10 +01:00
parent 298a338676
commit f4ec197513

View file

@ -17,7 +17,6 @@ limitations under the License.
*/ */
import React from 'react'; import React from 'react';
import PropTypes from 'prop-types';
import { _t, _td } from '../../../languageHandler'; import { _t, _td } from '../../../languageHandler';
import * as sdk from '../../../index'; import * as sdk from '../../../index';
import Modal from "../../../Modal"; import Modal from "../../../Modal";
@ -31,27 +30,50 @@ import PassphraseField from '../../views/auth/PassphraseField';
import { replaceableComponent } from "../../../utils/replaceableComponent"; import { replaceableComponent } from "../../../utils/replaceableComponent";
import { PASSWORD_MIN_SCORE } from '../../views/auth/RegistrationForm'; import { PASSWORD_MIN_SCORE } from '../../views/auth/RegistrationForm';
// Phases import { IValidationResult } from "../../views/elements/Validation";
// Show the forgot password inputs
const PHASE_FORGOT = 1; enum Phase {
// Email is in the process of being sent // Show the forgot password inputs
const PHASE_SENDING_EMAIL = 2; Forgot = 1,
// Email has been sent // Email is in the process of being sent
const PHASE_EMAIL_SENT = 3; SendingEmail = 2,
// User has clicked the link in email and completed reset // Email has been sent
const PHASE_DONE = 4; EmailSent = 3,
// User has clicked the link in email and completed reset
Done = 4,
}
interface IProps {
serverConfig: ValidatedServerConfig;
onServerConfigChange: () => void;
onLoginClick?: () => void;
onComplete: () => void;
}
interface IState {
phase: Phase;
email: string;
password: string;
password2: string;
errorText: string;
// We perform liveliness checks later, but for now suppress the errors.
// We also track the server dead errors independently of the regular errors so
// that we can render it differently, and override any other error the user may
// be seeing.
serverIsAlive: boolean;
serverErrorIsFatal: boolean;
serverDeadError: string;
passwordFieldValid: boolean;
}
@replaceableComponent("structures.auth.ForgotPassword") @replaceableComponent("structures.auth.ForgotPassword")
export default class ForgotPassword extends React.Component { export default class ForgotPassword extends React.Component<IProps, IState> {
static propTypes = { private reset: PasswordReset;
serverConfig: PropTypes.instanceOf(ValidatedServerConfig).isRequired,
onServerConfigChange: PropTypes.func.isRequired,
onLoginClick: PropTypes.func,
onComplete: PropTypes.func.isRequired,
};
state = { state = {
phase: PHASE_FORGOT, phase: Phase.Forgot,
email: "", email: "",
password: "", password: "",
password2: "", password2: "",
@ -64,30 +86,31 @@ export default class ForgotPassword extends React.Component {
serverIsAlive: true, serverIsAlive: true,
serverErrorIsFatal: false, serverErrorIsFatal: false,
serverDeadError: "", serverDeadError: "",
passwordFieldValid: false,
}; };
constructor(props) { constructor(props: IProps) {
super(props); super(props);
CountlyAnalytics.instance.track("onboarding_forgot_password_begin"); CountlyAnalytics.instance.track("onboarding_forgot_password_begin");
} }
componentDidMount() { public componentDidMount() {
this.reset = null; this.reset = null;
this._checkServerLiveliness(this.props.serverConfig); this.checkServerLiveliness(this.props.serverConfig);
} }
// TODO: [REACT-WARNING] Replace with appropriate lifecycle event // TODO: [REACT-WARNING] Replace with appropriate lifecycle event
// eslint-disable-next-line camelcase // eslint-disable-next-line camelcase
UNSAFE_componentWillReceiveProps(newProps) { public UNSAFE_componentWillReceiveProps(newProps: IProps): void {
if (newProps.serverConfig.hsUrl === this.props.serverConfig.hsUrl && if (newProps.serverConfig.hsUrl === this.props.serverConfig.hsUrl &&
newProps.serverConfig.isUrl === this.props.serverConfig.isUrl) return; newProps.serverConfig.isUrl === this.props.serverConfig.isUrl) return;
// Do a liveliness check on the new URLs // Do a liveliness check on the new URLs
this._checkServerLiveliness(newProps.serverConfig); this.checkServerLiveliness(newProps.serverConfig);
} }
async _checkServerLiveliness(serverConfig) { private async checkServerLiveliness(serverConfig): Promise<void> {
try { try {
await AutoDiscoveryUtils.validateServerConfigWithStaticUrls( await AutoDiscoveryUtils.validateServerConfigWithStaticUrls(
serverConfig.hsUrl, serverConfig.hsUrl,
@ -98,28 +121,28 @@ export default class ForgotPassword extends React.Component {
serverIsAlive: true, serverIsAlive: true,
}); });
} catch (e) { } catch (e) {
this.setState(AutoDiscoveryUtils.authComponentStateForError(e, "forgot_password")); this.setState(AutoDiscoveryUtils.authComponentStateForError(e, "forgot_password") as IState);
} }
} }
submitPasswordReset(email, password) { public submitPasswordReset(email: string, password: string): void {
this.setState({ this.setState({
phase: PHASE_SENDING_EMAIL, phase: Phase.SendingEmail,
}); });
this.reset = new PasswordReset(this.props.serverConfig.hsUrl, this.props.serverConfig.isUrl); this.reset = new PasswordReset(this.props.serverConfig.hsUrl, this.props.serverConfig.isUrl);
this.reset.resetPassword(email, password).then(() => { this.reset.resetPassword(email, password).then(() => {
this.setState({ this.setState({
phase: PHASE_EMAIL_SENT, phase: Phase.EmailSent,
}); });
}, (err) => { }, (err) => {
this.showErrorDialog(_t('Failed to send email') + ": " + err.message); this.showErrorDialog(_t('Failed to send email') + ": " + err.message);
this.setState({ this.setState({
phase: PHASE_FORGOT, phase: Phase.Forgot,
}); });
}); });
} }
onVerify = async ev => { private onVerify = async (ev: React.MouseEvent): Promise<void> => {
ev.preventDefault(); ev.preventDefault();
if (!this.reset) { if (!this.reset) {
console.error("onVerify called before submitPasswordReset!"); console.error("onVerify called before submitPasswordReset!");
@ -127,17 +150,17 @@ export default class ForgotPassword extends React.Component {
} }
try { try {
await this.reset.checkEmailLinkClicked(); await 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);
} }
}; };
onSubmitForm = async ev => { private onSubmitForm = async (ev: React.FormEvent): Promise<void> => {
ev.preventDefault(); ev.preventDefault();
// 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.checkServerLiveliness(this.props.serverConfig);
await this['password_field'].validate({ allowEmpty: false }); await this['password_field'].validate({ allowEmpty: false });
@ -172,27 +195,27 @@ export default class ForgotPassword extends React.Component {
} }
}; };
onInputChanged = (stateKey, ev) => { private onInputChanged = (stateKey: string, ev: React.FormEvent<HTMLInputElement>) => {
this.setState({ this.setState({
[stateKey]: ev.target.value, [stateKey]: ev.currentTarget.value,
}); } as any);
}; };
onLoginClick = ev => { private onLoginClick = (ev: React.MouseEvent): void => {
ev.preventDefault(); ev.preventDefault();
ev.stopPropagation(); ev.stopPropagation();
this.props.onLoginClick(); this.props.onLoginClick();
}; };
showErrorDialog(body, title) { public showErrorDialog(description: string, title?: string) {
const ErrorDialog = sdk.getComponent("dialogs.ErrorDialog"); const ErrorDialog = sdk.getComponent("dialogs.ErrorDialog");
Modal.createTrackedDialog('Forgot Password Error', '', ErrorDialog, { Modal.createTrackedDialog('Forgot Password Error', '', ErrorDialog, {
title: title, title,
description: body, description,
}); });
} }
onPasswordValidate(result) { private onPasswordValidate(result: IValidationResult) {
this.setState({ this.setState({
passwordFieldValid: result.valid, passwordFieldValid: result.valid,
}); });
@ -316,16 +339,16 @@ export default class ForgotPassword extends React.Component {
let resetPasswordJsx; let resetPasswordJsx;
switch (this.state.phase) { switch (this.state.phase) {
case PHASE_FORGOT: case Phase.Forgot:
resetPasswordJsx = this.renderForgot(); resetPasswordJsx = this.renderForgot();
break; break;
case PHASE_SENDING_EMAIL: case Phase.SendingEmail:
resetPasswordJsx = this.renderSendingEmail(); resetPasswordJsx = this.renderSendingEmail();
break; break;
case PHASE_EMAIL_SENT: case Phase.EmailSent:
resetPasswordJsx = this.renderEmailSent(); resetPasswordJsx = this.renderEmailSent();
break; break;
case PHASE_DONE: case Phase.Done:
resetPasswordJsx = this.renderDone(); resetPasswordJsx = this.renderDone();
break; break;
} }