Migrate ForgotPassword to TypeScript
This commit is contained in:
parent
298a338676
commit
f4ec197513
1 changed files with 68 additions and 45 deletions
|
@ -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;
|
||||||
}
|
}
|
Loading…
Add table
Add a link
Reference in a new issue