password reset works, missing translations

This commit is contained in:
or-else
2023-01-26 15:58:33 -08:00
parent 6c36324ed4
commit d8f7a41bdd
55 changed files with 490 additions and 390 deletions
+8 -8
View File
@@ -32,8 +32,6 @@ export default class CreateAccountView extends React.PureComponent {
newAvatarMime: null,
errorCleared: false,
buttonDisabled: false,
// method: '',
method: 'tel',
saveToken: LocalStorageUtil.getObject('keep-logged-in')
};
@@ -49,12 +47,11 @@ export default class CreateAccountView extends React.PureComponent {
this.uploadAvatar = this.uploadAvatar.bind(this);
this.handleSubmit = this.handleSubmit.bind(this);
// Connection will trigger change by changing the this.props.serverVersion.
props.tinode.connect()
.catch(err => {
this.props.onError(err.message, 'err');
})
// "reqCred":{"auth":["email"]}
//.finally(_ => this.setState({method: (props.tinode.getServerParam('reqCred', {}).auth || [])[0] || 'email'}));
});
}
handleLoginChange(e) {
@@ -147,6 +144,9 @@ export default class CreateAccountView extends React.PureComponent {
}
render() {
// "reqCred":{"auth":["email"]}
const method = (this.props.tinode.getServerParam('reqCred', {}).auth || [])[0] || 'email';
if (this.state.newAvatar) {
return (
<AvatarCrop
@@ -166,7 +166,7 @@ export default class CreateAccountView extends React.PureComponent {
return (
<form className="panel-form-column" onSubmit={this.handleSubmit}>
<div className="panel-form-row">
<div className="panel-form-column">
<div className="umn">
<FormattedMessage id="login_prompt" defaultMessage="Login"
description="Placeholer for username/login">{
(login_prompt) => <input type="text" placeholder={login_prompt} autoComplete="user-name"
@@ -192,7 +192,7 @@ export default class CreateAccountView extends React.PureComponent {
value={this.state.fn} onChange={this.handleFnChange} required/>
}</FormattedMessage>
</div>
{this.state.method == 'email' ?
{method == 'email' ?
<div className="panel-form-row">
<FormattedMessage id="email_prompt" defaultMessage="Email, e.g. jdoe@example.com"
description="Input placeholder for email entry">{
@@ -200,7 +200,7 @@ export default class CreateAccountView extends React.PureComponent {
value={this.state.email} onChange={this.handleEmailChange} required/>
}</FormattedMessage>
</div>
: this.state.method == 'tel' ?
: method == 'tel' ?
<><div className="panel-form-row">
<label className="small gray"><FormattedMessage id="mobile_phone_number" defaultMessage="Mobile phone number"
description="Prompt for entering a mobile phone number" /></label>
+100 -67
View File
@@ -16,21 +16,21 @@ export default class PasswordResetView extends React.PureComponent {
email: '',
password: '',
sent: false,
method: '',
haveCode: false
haveCode: false,
code: ''
};
this.handleSubmit = this.handleSubmit.bind(this);
this.handleEmailChange = this.handleEmailChange.bind(this);
this.handlePasswordChange = this.handlePasswordChange.bind(this);
this.handleCodeChange = this.handleCodeChange.bind(this);
this.handleShowCodeField = this.handleShowCodeField.bind(this);
// Connection will trigger change by changing the this.props.serverVersion.
props.tinode.connect()
.catch(err => {
this.props.onError(err.message, 'err');
})
// "reqCred":{"auth":["email"]}
.finally(_ => this.setState({method: (props.tinode.getServerParam('reqCred', {}).auth || [])[0] || 'email'}));
});
}
componentDidMount() {
@@ -41,13 +41,24 @@ export default class PasswordResetView extends React.PureComponent {
handleSubmit(e) {
e.preventDefault();
if (this.state.token) {
this.props.onReset(this.state.scheme, this.state.password.trim(), this.state.token);
} else if (this.state.sent) {
this.props.onCancel();
// Reset using token.
this.props.onReset(this.state.password.trim(), {
scheme: 'token',
token: this.state.token
});
} else if (this.state.code && this.method) {
// Reset using security code.
// The secret is structured as <code>:<cred_method>:<cred_value>, "123456:email:alice@example.com".
const cred = this.state.email.trim() || this.state.tel.trim();
this.props.onReset(this.state.password.trim(), {
scheme: 'code',
secret: `${this.state.code}:${this.method}:${cred}`
});
} else {
const email = this.state.email.trim();
this.setState({email: email});
this.props.onRequest('email', email).then(_ => this.setState({sent: true}));
const tel = this.state.tel.trim();
this.setState({email: email, tel: tel});
this.props.onRequest(this.method, email || tel).then(_ => this.setState({sent: true}));
}
}
@@ -59,15 +70,24 @@ export default class PasswordResetView extends React.PureComponent {
this.setState({password: e.target.value});
}
handleCodeChange(e) {
this.setState({code: e.target.value.replace(/[^\d]/g, '')});
}
handleShowCodeField(e) {
e.preventDefault();
this.setState({haveCode: true});
}
render() {
const showPasswordInput = (this.state.token && this.state.scheme) || this.state.haveCode;
// "reqCred":{"auth":["email"]}
this.method = (this.props.tinode.getServerParam('reqCred', {}).auth || [])[0] || 'email';
const showCredentialInput = !(this.state.token && this.state.scheme);
const showPasswordInput = !showCredentialInput || this.state.haveCode || this.state.sent;
const passwordInput = (<>
<label htmlFor="new-password">
<label className="small gray" htmlFor="new-password">
<FormattedMessage id="label_new_password"
defaultMessage="New password"
description="Label for entering a new password" />
@@ -89,7 +109,7 @@ export default class PasswordResetView extends React.PureComponent {
null :
<label htmlFor="inputEmail">
<FormattedMessage id="label_reset_password"
defaultMessage="Send a password reset email:"
defaultMessage="Send a password reset email"
description="Label for password reset field" />
</label>
}
@@ -107,71 +127,84 @@ export default class PasswordResetView extends React.PureComponent {
const phoneInput = (<>
{this.state.haveCode ?
null :
<label>
<div><label>
<FormattedMessage id="label_reset_password_tel"
defaultMessage="Send a password reset SMS:"
defaultMessage="Send SMS to reset password"
description="Label for password reset field by phone" />
</label>
</label></div>
}
<label className="small gray">
<FormattedMessage id="mobile_phone_number" defaultMessage="Mobile phone number"
description="Prompt for entering a mobile phone number" />
</label>
<Suspense fallback={<div><FormattedMessage id="loading_note" defaultMessage="Loading..."
description="Message shown when component is loading"/></div>}>
<PhoneEdit
autoFocus={false}
onShowCountrySelector={(code, dial) => console.log('onShowCountrySelector', code, dial)}
onSubmit={(code, dial) => console.log('onSubmit', code, dial)} />
</Suspense>
<div>
<label className="small gray">
<FormattedMessage id="mobile_phone_number" defaultMessage="Mobile phone number"
description="Prompt for entering a mobile phone number" />
</label>
</div>
<div className="panel-form-row">
<Suspense fallback={<div className="panel-form-row"><FormattedMessage id="loading_note"
defaultMessage="Loading..." description="Message shown when component is loading"/></div>}>
<PhoneEdit
autoFocus={true}
onShowCountrySelector={this.props.onShowCountrySelector}
onSubmit={number => this.setState({tel: number})} />
</Suspense>
</div>
</>);
const sentNotification = (<>{
this.method == 'email' ?
<FormattedMessage id="password_reset_email_sent"
defaultMessage="An email with security code has been sent to {email}. Enter the code below."
values={{email: <tt>{this.state.email}</tt>}}
description="Notification that the email with password reset instructions has been sent" />
: this.method == 'tel' ?
<FormattedMessage id="password_reset_sms_sent"
defaultMessage="A text message with security code has been sent to {phone}. Enter the code below."
values={{phone: <tt>{this.state.tel}</tt>}}
description="Notification that the SMS with password reset instructions has been sent" />
:
null
}</>);
const codeInput = (<>
<div>
<label className="small gray" htmlFor="enter-confirmation-code">
<FormattedMessage id="enter_confirmation_code_prompt"
defaultMessage="Confirmation code"
description="Request to enter confirmation code" />
</label>
</div>
<div>
<FormattedMessage id="numeric_confirmation_code_prompt"
defaultMessage="Numbers only" description="Prompt for numeric conformation code">{
(numbers_only) => <input type="text" id="enter-confirmation-code"
placeholder={numbers_only} maxLength={10}
value={this.state.code} onChange={this.handleCodeChange} required />
}</FormattedMessage>
</div>
</>);
const credentialInput = this.method == 'email' ? emailInput : this.method == 'tel' ? phoneInput : null;
return (
<form id="password-reset-form" onSubmit={this.handleSubmit}>
{showPasswordInput ?
passwordInput
: this.state.sent ?
<>
<br/>
<center><i className="material-icons huge green">task_alt</i></center>
<br/>
<center>{
this.state.method == 'email' ?
<FormattedMessage id="password_reset_email_sent"
defaultMessage="An email with security code has been sent to {email}. Enter the code below."
values={{ email: <tt>{this.state.email}</tt> }}
description="Notification that the email with password reset instructions has been sent" />
: this.state.method == 'tel' ?
<FormattedMessage id="password_reset_sms_sent"
defaultMessage="A text message with security code has been sent to {phone}. Enter the code below."
values={{ email: <tt>{this.state.tel}</tt> }}
description="Notification that the SMS with password reset instructions has been sent" />
:
null
}</center>
</>
: this.state.method == 'email' ? emailInput : this.state.method == 'tel' ? phoneInput : null
}
{this.state.sent ? sentNotification : showCredentialInput ? credentialInput : null}
{this.state.haveCode || this.state.sent ? codeInput : null}
{showPasswordInput ? passwordInput : null}
<div className="dialog-buttons">
<button className="primary" type="submit">{
(this.state.token && this.state.scheme) ?
<FormattedMessage id="button_reset" defaultMessage="Reset" description="Button [Reset]" />
: this.state.sent ?
<FormattedMessage id="button_ok" defaultMessage="OK"
description="Button [OK]" />
:
<FormattedMessage id="button_send_request" defaultMessage="Send request"
description="Button [Send request]" />
}</button>
</div>
{this.state.haveCode ? null :
<div className="panel-form-row">
<a href="#" onClick={this.handleShowCodeField}>
{this.state.haveCode || this.state.sent ? null :
<a href="#" onClick={this.handleShowCodeField} style={{marginRight: 'auto'}}>
<FormattedMessage id="password_i_have_code" defaultMessage="I have code"
description="Call to open field to enter password reset code" />
</a>
</div>
}
}
<button className="primary" type="submit">{
showPasswordInput ?
<FormattedMessage id="button_reset" defaultMessage="Reset" description="Button [Reset]" />
:
<FormattedMessage id="button_send_request" defaultMessage="Send request"
description="Button [Send request]" />
}</button>
</div>
</form>
);
}
+3
View File
@@ -157,6 +157,7 @@ class SidepanelView extends React.PureComponent {
view === 'register' ?
<CreateAccountView
tinode={this.props.tinode}
serverVersion={this.props.serverVersion}
onShowCountrySelector={this.props.onShowCountrySelector}
onCreateAccount={this.props.onCreateAccount}
onCancel={this.props.onCancel}
@@ -247,6 +248,8 @@ class SidepanelView extends React.PureComponent {
view === 'reset' ?
<PasswordResetView
tinode={this.props.tinode}
serverVersion={this.props.serverVersion}
onShowCountrySelector={this.props.onShowCountrySelector}
onRequest={this.props.onPasswordResetRequest}
onReset={this.props.onResetPassword}
onCancel={this.props.onCancel} /> :
+4 -4
View File
@@ -1712,13 +1712,13 @@ class TinodeWeb extends React.Component {
});
}
handleResetPassword(scheme, newPassword, token) {
token = base64ReEncode(token);
if (!token) {
handleResetPassword(newPassword, tempAuth) {
const secret = base64ReEncode(tempAuth.secret);
if (!secret || !tempAuth.scheme) {
this.handleError(this.props.intl.formatMessage(messages.invalid_security_token), 'err');
} else {
this.tinode.connect()
.then(_ => this.tinode.updateAccountBasic(null, null, newPassword, {token: token}))
.then(_ => this.tinode.updateAccountBasic(null, null, newPassword, {scheme: tempAuth.scheme, secret: secret}))
.then(_ => HashNavigation.navigateTo(''))
.catch(err => {
// Socket error
+9 -9
View File
@@ -87,21 +87,21 @@ class ValidationView extends React.PureComponent {
return (
<div className="panel-form">
<div className="panel-form-row">
<label className="small" htmlFor="enter-confirmation-code">
<label className="small gray" htmlFor="enter-confirmation-code">
<FormattedMessage id="enter_confirmation_code_prompt"
defaultMessage="Enter confirmation code sent to you by {method}:"
defaultMessage="Confirmation code"
description="Request to enter confirmation code"
values={{method: method}} />
</label>
</div>
<div className="panel-form-row">
<FormattedMessage id="numeric_confirmation_code_prompt"
defaultMessage="Numbers only" description="Prompt for numeric conformation code">{
(numbers_only) => <input type="text" id="enter-confirmation-code"
placeholder={numbers_only}
value={this.state.code} onChange={this.handleChange}
onKeyPress={this.handleKeyPress} required />
}</FormattedMessage>
<FormattedMessage id="numeric_confirmation_code_prompt"
defaultMessage="Numbers only" description="Prompt for numeric conformation code">{
(numbers_only) => <input type="text" id="enter-confirmation-code"
placeholder={numbers_only}
value={this.state.code} onChange={this.handleChange}
onKeyPress={this.handleKeyPress} required />
}</FormattedMessage>
</div>
<div className="dialog-buttons">
<button className="secondary" onClick={this.handleCancel}>