Consolidate PasswordLogin state and input control/ownership

previously data was stored in two places which drifted
This commit is contained in:
Michael Telatynski 2020-11-18 12:38:56 +00:00
parent 0b74d3a0ef
commit 85fbc6d89f
2 changed files with 26 additions and 41 deletions

View file

@ -566,9 +566,9 @@ export default class LoginComponent extends React.Component {
<PasswordLogin <PasswordLogin
onSubmit={this.onPasswordLogin} onSubmit={this.onPasswordLogin}
onEditServerDetailsClick={onEditServerDetailsClick} onEditServerDetailsClick={onEditServerDetailsClick}
initialUsername={this.state.username} username={this.state.username}
initialPhoneCountry={this.state.phoneCountry} phoneCountry={this.state.phoneCountry}
initialPhoneNumber={this.state.phoneNumber} phoneNumber={this.state.phoneNumber}
onUsernameChanged={this.onUsernameChanged} onUsernameChanged={this.onUsernameChanged}
onUsernameBlur={this.onUsernameBlur} onUsernameBlur={this.onUsernameBlur}
onPhoneCountryChanged={this.onPhoneCountryChanged} onPhoneCountryChanged={this.onPhoneCountryChanged}

View file

@ -31,22 +31,21 @@ import * as Email from "../../../email";
// For validating phone numbers without country codes // For validating phone numbers without country codes
const PHONE_NUMBER_REGEX = /^[0-9()\-\s]*$/; const PHONE_NUMBER_REGEX = /^[0-9()\-\s]*$/;
/** /*
* A pure UI component which displays a username/password form. * A pure UI component which displays a username/password form.
* The email/username/phone fields are fully-controlled, the password field is not.
*/ */
export default class PasswordLogin extends React.Component { export default class PasswordLogin extends React.Component {
static propTypes = { static propTypes = {
onSubmit: PropTypes.func.isRequired, // fn(username, password) onSubmit: PropTypes.func.isRequired, // fn(username, password)
onEditServerDetailsClick: PropTypes.func, onEditServerDetailsClick: PropTypes.func,
onForgotPasswordClick: PropTypes.func, // fn() onForgotPasswordClick: PropTypes.func, // fn()
initialUsername: PropTypes.string, username: PropTypes.string,
initialPhoneCountry: PropTypes.string, phoneCountry: PropTypes.string,
initialPhoneNumber: PropTypes.string, phoneNumber: PropTypes.string,
initialPassword: PropTypes.string,
onUsernameChanged: PropTypes.func, onUsernameChanged: PropTypes.func,
onPhoneCountryChanged: PropTypes.func, onPhoneCountryChanged: PropTypes.func,
onPhoneNumberChanged: PropTypes.func, onPhoneNumberChanged: PropTypes.func,
onPasswordChanged: PropTypes.func,
loginIncorrect: PropTypes.bool, loginIncorrect: PropTypes.bool,
disableSubmit: PropTypes.bool, disableSubmit: PropTypes.bool,
serverConfig: PropTypes.instanceOf(ValidatedServerConfig).isRequired, serverConfig: PropTypes.instanceOf(ValidatedServerConfig).isRequired,
@ -57,13 +56,11 @@ export default class PasswordLogin extends React.Component {
onEditServerDetailsClick: null, onEditServerDetailsClick: null,
onUsernameChanged: function() {}, onUsernameChanged: function() {},
onUsernameBlur: function() {}, onUsernameBlur: function() {},
onPasswordChanged: function() {},
onPhoneCountryChanged: function() {}, onPhoneCountryChanged: function() {},
onPhoneNumberChanged: function() {}, onPhoneNumberChanged: function() {},
initialUsername: "", username: "",
initialPhoneCountry: "", phoneCountry: "",
initialPhoneNumber: "", phoneNumber: "",
initialPassword: "",
loginIncorrect: false, loginIncorrect: false,
disableSubmit: false, disableSubmit: false,
}; };
@ -78,11 +75,8 @@ export default class PasswordLogin extends React.Component {
this.state = { this.state = {
// Field error codes by field ID // Field error codes by field ID
fieldValid: {}, fieldValid: {},
username: this.props.initialUsername,
password: this.props.initialPassword,
phoneCountry: this.props.initialPhoneCountry,
phoneNumber: this.props.initialPhoneNumber,
loginType: PasswordLogin.LOGIN_FIELD_MXID, loginType: PasswordLogin.LOGIN_FIELD_MXID,
password: "",
}; };
this.onForgotPasswordClick = this.onForgotPasswordClick.bind(this); this.onForgotPasswordClick = this.onForgotPasswordClick.bind(this);
@ -120,11 +114,11 @@ export default class PasswordLogin extends React.Component {
switch (this.state.loginType) { switch (this.state.loginType) {
case PasswordLogin.LOGIN_FIELD_EMAIL: case PasswordLogin.LOGIN_FIELD_EMAIL:
case PasswordLogin.LOGIN_FIELD_MXID: case PasswordLogin.LOGIN_FIELD_MXID:
username = this.state.username; username = this.props.username;
break; break;
case PasswordLogin.LOGIN_FIELD_PHONE: case PasswordLogin.LOGIN_FIELD_PHONE:
phoneCountry = this.state.phoneCountry; phoneCountry = this.props.phoneCountry;
phoneNumber = this.state.phoneNumber; phoneNumber = this.props.phoneNumber;
break; break;
} }
@ -137,7 +131,6 @@ export default class PasswordLogin extends React.Component {
} }
onUsernameChanged(ev) { onUsernameChanged(ev) {
this.setState({username: ev.target.value});
this.props.onUsernameChanged(ev.target.value); this.props.onUsernameChanged(ev.target.value);
} }
@ -160,23 +153,16 @@ export default class PasswordLogin extends React.Component {
onLoginTypeChange(ev) { onLoginTypeChange(ev) {
const loginType = ev.target.value; const loginType = ev.target.value;
this.setState({ this.setState({ loginType });
loginType: loginType, this.props.onUsernameChanged(""); // Reset because email and username use the same state
username: "", // Reset because email and username use the same state
});
CountlyAnalytics.instance.track("onboarding_login_type_changed", { loginType }); CountlyAnalytics.instance.track("onboarding_login_type_changed", { loginType });
} }
onPhoneCountryChanged(country) { onPhoneCountryChanged(country) {
this.setState({
phoneCountry: country.iso2,
phonePrefix: country.prefix,
});
this.props.onPhoneCountryChanged(country.iso2); this.props.onPhoneCountryChanged(country.iso2);
} }
onPhoneNumberChanged(ev) { onPhoneNumberChanged(ev) {
this.setState({phoneNumber: ev.target.value});
this.props.onPhoneNumberChanged(ev.target.value); this.props.onPhoneNumberChanged(ev.target.value);
} }
@ -190,7 +176,6 @@ export default class PasswordLogin extends React.Component {
onPasswordChanged(ev) { onPasswordChanged(ev) {
this.setState({password: ev.target.value}); this.setState({password: ev.target.value});
this.props.onPasswordChanged(ev.target.value);
} }
async verifyFieldsBeforeSubmit() { async verifyFieldsBeforeSubmit() {
@ -355,7 +340,7 @@ export default class PasswordLogin extends React.Component {
switch (loginType) { switch (loginType) {
case PasswordLogin.LOGIN_FIELD_EMAIL: case PasswordLogin.LOGIN_FIELD_EMAIL:
classes.error = this.props.loginIncorrect && !this.state.username; classes.error = this.props.loginIncorrect && !this.props.username;
return <Field return <Field
className={classNames(classes)} className={classNames(classes)}
name="username" // make it a little easier for browser's remember-password name="username" // make it a little easier for browser's remember-password
@ -363,7 +348,7 @@ export default class PasswordLogin extends React.Component {
type="text" type="text"
label={_t("Email")} label={_t("Email")}
placeholder="joe@example.com" placeholder="joe@example.com"
value={this.state.username} value={this.props.username}
onChange={this.onUsernameChanged} onChange={this.onUsernameChanged}
onFocus={this.onUsernameFocus} onFocus={this.onUsernameFocus}
onBlur={this.onUsernameBlur} onBlur={this.onUsernameBlur}
@ -373,14 +358,14 @@ export default class PasswordLogin extends React.Component {
ref={field => this[PasswordLogin.LOGIN_FIELD_EMAIL] = field} ref={field => this[PasswordLogin.LOGIN_FIELD_EMAIL] = field}
/>; />;
case PasswordLogin.LOGIN_FIELD_MXID: case PasswordLogin.LOGIN_FIELD_MXID:
classes.error = this.props.loginIncorrect && !this.state.username; classes.error = this.props.loginIncorrect && !this.props.username;
return <Field return <Field
className={classNames(classes)} className={classNames(classes)}
name="username" // make it a little easier for browser's remember-password name="username" // make it a little easier for browser's remember-password
key="username_input" key="username_input"
type="text" type="text"
label={_t("Username")} label={_t("Username")}
value={this.state.username} value={this.props.username}
onChange={this.onUsernameChanged} onChange={this.onUsernameChanged}
onFocus={this.onUsernameFocus} onFocus={this.onUsernameFocus}
onBlur={this.onUsernameBlur} onBlur={this.onUsernameBlur}
@ -391,10 +376,10 @@ export default class PasswordLogin extends React.Component {
/>; />;
case PasswordLogin.LOGIN_FIELD_PHONE: { case PasswordLogin.LOGIN_FIELD_PHONE: {
const CountryDropdown = sdk.getComponent('views.auth.CountryDropdown'); const CountryDropdown = sdk.getComponent('views.auth.CountryDropdown');
classes.error = this.props.loginIncorrect && !this.state.phoneNumber; classes.error = this.props.loginIncorrect && !this.props.phoneNumber;
const phoneCountry = <CountryDropdown const phoneCountry = <CountryDropdown
value={this.state.phoneCountry} value={this.props.phoneCountry}
isSmall={true} isSmall={true}
showPrefix={true} showPrefix={true}
onOptionChange={this.onPhoneCountryChanged} onOptionChange={this.onPhoneCountryChanged}
@ -406,7 +391,7 @@ export default class PasswordLogin extends React.Component {
key="phone_input" key="phone_input"
type="text" type="text"
label={_t("Phone")} label={_t("Phone")}
value={this.state.phoneNumber} value={this.props.phoneNumber}
prefixComponent={phoneCountry} prefixComponent={phoneCountry}
onChange={this.onPhoneNumberChanged} onChange={this.onPhoneNumberChanged}
onFocus={this.onPhoneNumberFocus} onFocus={this.onPhoneNumberFocus}
@ -424,9 +409,9 @@ export default class PasswordLogin extends React.Component {
switch (this.state.loginType) { switch (this.state.loginType) {
case PasswordLogin.LOGIN_FIELD_EMAIL: case PasswordLogin.LOGIN_FIELD_EMAIL:
case PasswordLogin.LOGIN_FIELD_MXID: case PasswordLogin.LOGIN_FIELD_MXID:
return !this.state.username; return !this.props.username;
case PasswordLogin.LOGIN_FIELD_PHONE: case PasswordLogin.LOGIN_FIELD_PHONE:
return !this.state.phoneCountry || !this.state.phoneNumber; return !this.props.phoneCountry || !this.props.phoneNumber;
} }
} }