@@ -29,8 +29,8 @@ import ServerPicker from "../../views/elements/ServerPicker";
2929import PassphraseField from '../../views/auth/PassphraseField' ;
3030import { replaceableComponent } from "../../../utils/replaceableComponent" ;
3131import { PASSWORD_MIN_SCORE } from '../../views/auth/RegistrationForm' ;
32-
33- import { IValidationResult } from "../../views/elements/Validation " ;
32+ import withValidation , { IValidationResult } from "../../views/elements/Validation" ;
33+ import * as Email from "../../../email " ;
3434import InlineSpinner from '../../views/elements/InlineSpinner' ;
3535
3636import { logger } from "matrix-js-sdk/src/logger" ;
@@ -68,6 +68,7 @@ interface IState {
6868 serverErrorIsFatal : boolean ;
6969 serverDeadError : string ;
7070
71+ emailFieldValid : boolean ;
7172 passwordFieldValid : boolean ;
7273 currentHttpRequest ?: Promise < any > ;
7374}
@@ -90,6 +91,7 @@ export default class ForgotPassword extends React.Component<IProps, IState> {
9091 serverIsAlive : true ,
9192 serverErrorIsFatal : false ,
9293 serverDeadError : "" ,
94+ emailFieldValid : false ,
9395 passwordFieldValid : false ,
9496 } ;
9597
@@ -169,10 +171,13 @@ export default class ForgotPassword extends React.Component<IProps, IState> {
169171 // refresh the server errors, just in case the server came back online
170172 await this . handleHttpRequest ( this . checkServerLiveliness ( this . props . serverConfig ) ) ;
171173
174+ await this [ 'email_field' ] . validate ( { allowEmpty : false } ) ;
172175 await this [ 'password_field' ] . validate ( { allowEmpty : false } ) ;
173176
174177 if ( ! this . state . email ) {
175178 this . showErrorDialog ( _t ( 'The email address linked to your account must be entered.' ) ) ;
179+ } else if ( ! this . state . emailFieldValid ) {
180+ this . showErrorDialog ( _t ( "The email address doesn't appear to be valid." ) ) ;
176181 } else if ( ! this . state . password || ! this . state . password2 ) {
177182 this . showErrorDialog ( _t ( 'A new password must be entered.' ) ) ;
178183 } else if ( ! this . state . passwordFieldValid ) {
@@ -222,6 +227,32 @@ export default class ForgotPassword extends React.Component<IProps, IState> {
222227 } ) ;
223228 }
224229
230+ private validateEmailRules = withValidation ( {
231+ rules : [
232+ {
233+ key : "required" ,
234+ test ( { value, allowEmpty } ) {
235+ return allowEmpty || ! ! value ;
236+ } ,
237+ invalid : ( ) => _t ( "Enter email address" ) ,
238+ } , {
239+ key : "email" ,
240+ test : ( { value } ) => ! value || Email . looksValid ( value ) ,
241+ invalid : ( ) => _t ( "Doesn't look like a valid email address" ) ,
242+ } ,
243+ ] ,
244+ } ) ;
245+
246+ private onEmailValidate = async ( fieldState ) => {
247+ const result = await this . validateEmailRules ( fieldState ) ;
248+
249+ this . setState ( {
250+ emailFieldValid : result . valid ,
251+ } ) ;
252+
253+ return result ;
254+ } ;
255+
225256 private onPasswordValidate ( result : IValidationResult ) {
226257 this . setState ( {
227258 passwordFieldValid : result . valid ,
@@ -277,7 +308,9 @@ export default class ForgotPassword extends React.Component<IProps, IState> {
277308 label = { _t ( 'Email' ) }
278309 value = { this . state . email }
279310 onChange = { this . onInputChanged . bind ( this , "email" ) }
311+ ref = { field => this [ 'email_field' ] = field }
280312 autoFocus
313+ onValidate = { this . onEmailValidate }
281314 onFocus = { ( ) => CountlyAnalytics . instance . track ( "onboarding_forgot_password_email_focus" ) }
282315 onBlur = { ( ) => CountlyAnalytics . instance . track ( "onboarding_forgot_password_email_blur" ) }
283316 />
0 commit comments