#26: suggest resend confirmation key in validation errors

This commit is contained in:
SleepWalker 2016-05-22 18:16:51 +03:00
parent 24fbde289f
commit 87d48c8722
8 changed files with 88 additions and 40 deletions

View File

@ -84,7 +84,7 @@ export function recoverPassword({
return dispatch(authenticate(resp.jwt)); return dispatch(authenticate(resp.jwt));
}) })
.catch(validationErrorsHandler(dispatch)) .catch(validationErrorsHandler(dispatch, '/forgot-password'))
); );
} }
@ -126,7 +126,7 @@ export function activate({key = ''}) {
return dispatch(authenticate(resp.jwt)); return dispatch(authenticate(resp.jwt));
}) })
.catch(validationErrorsHandler(dispatch)) .catch(validationErrorsHandler(dispatch, '/reactivate'))
); );
} }
@ -332,19 +332,27 @@ function needActivation() {
}); });
} }
function validationErrorsHandler(dispatch) { function validationErrorsHandler(dispatch, repeatUrl) {
return (resp) => { return (resp) => {
if (resp.errors) { if (resp.errors) {
let errorMessage = resp.errors[Object.keys(resp.errors)[0]]; const error = {
if (resp.data) { type: resp.errors[Object.keys(resp.errors)[0]],
errorMessage = { payload: {
type: errorMessage, isGuest: true
payload: resp.data }
}; };
if (resp.data) {
Object.assign(error.payload, resp.data);
} }
dispatch(setError(errorMessage)); if (['error.key_not_exists', 'error.key_expire'].includes(error.type) && repeatUrl) {
return Promise.reject(errorMessage); Object.assign(error.payload, {
repeatUrl
});
}
dispatch(setError(error));
} }
return Promise.reject(resp); return Promise.reject(resp);

View File

@ -13,7 +13,7 @@ function resetTimer() {
export default function AuthError({error, onClose = function() {}}) { export default function AuthError({error, onClose = function() {}}) {
resetTimer(); resetTimer();
if (error.type === 'error.email_frequency') { if (error.payload && error.payload.canRepeatIn) {
if (error.payload && error.payload.canRepeatIn) { if (error.payload && error.payload.canRepeatIn) {
error.payload.msLeft = error.payload.canRepeatIn * 1000; error.payload.msLeft = error.payload.canRepeatIn * 1000;
setTimeout(onClose, error.payload.msLeft - Date.now() + 1500); // 1500 to let the user see, that time is elapsed setTimeout(onClose, error.payload.msLeft - Date.now() + 1500); // 1500 to let the user see, that time is elapsed

View File

@ -51,6 +51,7 @@ export default class RecoverPasswordBody extends BaseAuthBody {
required required
value={key} value={key}
readOnly={!!key} readOnly={!!key}
autoComplete="off"
placeholder={messages.enterTheCode} placeholder={messages.enterTheCode}
/> />

View File

@ -100,6 +100,7 @@
"components.userbar.register": "Join", "components.userbar.register": "Join",
"pages.root.siteName": "Ely.by", "pages.root.siteName": "Ely.by",
"services.accountNotActivated": "The account is not activated", "services.accountNotActivated": "The account is not activated",
"services.doYouWantRequestKey": "Do you want to request a new key?",
"services.emailFrequency": "Please cool down, you are requesting emails too often. New key can be retrieved {time}.", "services.emailFrequency": "Please cool down, you are requesting emails too often. New key can be retrieved {time}.",
"services.emailInvalid": "Email is invalid", "services.emailInvalid": "Email is invalid",
"services.emailIsTempmail": "Tempmail E-mail addresses is not allowed", "services.emailIsTempmail": "Tempmail E-mail addresses is not allowed",
@ -108,7 +109,7 @@
"services.emailToLong": "Email is too long", "services.emailToLong": "Email is too long",
"services.forgotYourPassword": "forgot your password", "services.forgotYourPassword": "forgot your password",
"services.invalidPassword": "You have entered wrong account password.", "services.invalidPassword": "You have entered wrong account password.",
"services.keyNotExists": "The key is incorrect", "services.keyNotExists": "The key is incorrect or has expired.",
"services.keyRequired": "Please, enter an activation key", "services.keyRequired": "Please, enter an activation key",
"services.loginNotExist": "Sorry, Ely doesn't recognise your login.", "services.loginNotExist": "Sorry, Ely doesn't recognise your login.",
"services.loginRequired": "Please enter email or username", "services.loginRequired": "Please enter email or username",

View File

@ -100,6 +100,7 @@
"components.userbar.register": "Регистрация", "components.userbar.register": "Регистрация",
"pages.root.siteName": "Ely.by", "pages.root.siteName": "Ely.by",
"services.accountNotActivated": "Аккаунт не активирован", "services.accountNotActivated": "Аккаунт не активирован",
"services.doYouWantRequestKey": "Не хотите отправить новый код?",
"services.emailFrequency": "Пожалуйста, успокойтесь, вы запрашиваете E-mail слишком часто. Новый ключ можно будет заказать {time}.", "services.emailFrequency": "Пожалуйста, успокойтесь, вы запрашиваете E-mail слишком часто. Новый ключ можно будет заказать {time}.",
"services.emailInvalid": "Указан неправильный E-mail", "services.emailInvalid": "Указан неправильный E-mail",
"services.emailIsTempmail": "Использование сервисов временных E-mail адресов запрещено", "services.emailIsTempmail": "Использование сервисов временных E-mail адресов запрещено",
@ -108,7 +109,7 @@
"services.emailToLong": "E-mail слишком длинный", "services.emailToLong": "E-mail слишком длинный",
"services.forgotYourPassword": "забыли свой пароль", "services.forgotYourPassword": "забыли свой пароль",
"services.invalidPassword": "Вы указали неверный пароль от аккаунта.", "services.invalidPassword": "Вы указали неверный пароль от аккаунта.",
"services.keyNotExists": "Указанный ключ не существует или устарел", "services.keyNotExists": "Указанный ключ не существует или устарел.",
"services.keyRequired": "Пожалуйста, введите код активации", "services.keyRequired": "Пожалуйста, введите код активации",
"services.loginNotExist": "К сожалению, на Ely нет пользователя с указанным логином.", "services.loginNotExist": "К сожалению, на Ely нет пользователя с указанным логином.",
"services.loginRequired": "Пожалуйста, укажите E-mail или ник", "services.loginRequired": "Пожалуйста, укажите E-mail или ник",

View File

@ -59,11 +59,11 @@ class ChangeEmailPage extends Component {
switch (step) { switch (step) {
case 0: case 0:
return accounts.requestEmailChange(); return accounts.requestEmailChange().catch(handleErrors());
case 1: case 1:
return accounts.setNewEmail(data); return accounts.setNewEmail(data).catch(handleErrors('/profile/change-email'));
case 2: case 2:
return accounts.confirmNewEmail(data); return accounts.confirmNewEmail(data).catch(handleErrors('/profile/change-email'));
default: default:
throw new Error(`Unsupported step ${step}`); throw new Error(`Unsupported step ${step}`);
} }
@ -74,6 +74,27 @@ class ChangeEmailPage extends Component {
}; };
} }
function handleErrors(repeatUrl) {
return (resp) => {
if (resp.errors) {
if (resp.errors.key) {
resp.errors.key = {
type: resp.errors.key,
payload: {}
};
if (['error.key_not_exists', 'error.key_expire'].includes(resp.errors.key.type) && repeatUrl) {
Object.assign(resp.errors.key.payload, {
repeatUrl
});
}
}
}
return Promise.reject(resp);
};
}
import { connect } from 'react-redux'; import { connect } from 'react-redux';
export default connect((state) => ({ export default connect((state) => ({

View File

@ -22,7 +22,8 @@
"passwordsDoesNotMatch": "The passwords does not match", "passwordsDoesNotMatch": "The passwords does not match",
"rulesAgreementRequired": "You must accept rules in order to create an account", "rulesAgreementRequired": "You must accept rules in order to create an account",
"keyRequired": "Please, enter an activation key", "keyRequired": "Please, enter an activation key",
"keyNotExists": "The key is incorrect", "keyNotExists": "The key is incorrect or has expired.",
"doYouWantRequestKey": "Do you want to request a new key?",
"emailFrequency": "Please cool down, you are requesting emails too often. New key can be retrieved {time}.", "emailFrequency": "Please cool down, you are requesting emails too often. New key can be retrieved {time}.",
"accountNotActivated": "The account is not activated", "accountNotActivated": "The account is not activated",
"oldHashStrategy": "Sorry, but your account's password is too old. Please change your password in order to perform this action." "oldHashStrategy": "Sorry, but your account's password is too old. Please change your password in order to perform this action."

View File

@ -1,6 +1,7 @@
import React from 'react'; import React from 'react';
import { FormattedMessage as Message, FormattedRelative as Relative } from 'react-intl'; import { FormattedMessage as Message, FormattedRelative as Relative } from 'react-intl';
import { Link } from 'react-router';
import messages from './errorsDict.intl.json'; import messages from './errorsDict.intl.json';
@ -9,7 +10,7 @@ export default {
let payload = {}; let payload = {};
if (error.type) { if (error.type) {
payload = error.payload; payload = error.payload || {};
error = error.type; error = error.type;
} }
return errorsMap[error] ? errorsMap[error](payload) : error; return errorsMap[error] ? errorsMap[error](payload) : error;
@ -23,17 +24,10 @@ const errorsMap = {
'error.password_invalid': () => <Message {...messages.invalidPassword} />, 'error.password_invalid': () => <Message {...messages.invalidPassword} />,
'error.old_hash_strategy': () => <Message {...messages.oldHashStrategy} />, 'error.old_hash_strategy': () => <Message {...messages.oldHashStrategy} />,
'error.password_incorrect': () => ( 'error.password_incorrect': (props) => (
<span> <span>
<Message {...messages.invalidPassword} /> <Message {...messages.invalidPassword} />
<br/> {props.isGuest ? errorsMap.suggestResetPassword() : null}
<Message {...messages.suggestResetPassword} values={{
link: (
<a href="#">
<Message {...messages.forgotYourPassword} />
</a>
)
}} />
</span> </span>
), ),
@ -47,17 +41,10 @@ const errorsMap = {
'error.email_too_long': () => <Message {...messages.emailToLong} />, 'error.email_too_long': () => <Message {...messages.emailToLong} />,
'error.email_invalid': () => <Message {...messages.emailInvalid} />, 'error.email_invalid': () => <Message {...messages.emailInvalid} />,
'error.email_is_tempmail': () => <Message {...messages.emailIsTempmail} />, 'error.email_is_tempmail': () => <Message {...messages.emailIsTempmail} />,
'error.email_not_available': () => ( 'error.email_not_available': (props) => (
<span> <span>
<Message {...messages.emailNotAvailable} /> <Message {...messages.emailNotAvailable} />
<br/> {props.isGuest ? errorsMap.suggestResetPassword() : null}
<Message {...messages.suggestResetPassword} values={{
link: (
<a href="#">
<Message {...messages.forgotYourPassword} />
</a>
)
}} />
</span> </span>
), ),
@ -65,10 +52,16 @@ const errorsMap = {
'error.password_too_short': () => <Message {...messages.passwordTooShort} />, 'error.password_too_short': () => <Message {...messages.passwordTooShort} />,
'error.rePassword_does_not_match': () => <Message {...messages.passwordsDoesNotMatch} />, 'error.rePassword_does_not_match': () => <Message {...messages.passwordsDoesNotMatch} />,
'error.rulesAgreement_required': () => <Message {...messages.rulesAgreementRequired} />, 'error.rulesAgreement_required': () => <Message {...messages.rulesAgreementRequired} />,
'error.you_must_accept_rules': () => this.errorsMap['error.rulesAgreement_required'](), 'error.you_must_accept_rules': () => errorsMap['error.rulesAgreement_required'](),
'error.key_required': () => <Message {...messages.keyRequired} />, 'error.key_required': () => <Message {...messages.keyRequired} />,
'error.key_is_required': () => this.errorsMap['error.key_required'](), 'error.key_is_required': () => errorsMap['error.key_required'](),
'error.key_not_exists': () => <Message {...messages.keyNotExists} />, 'error.key_not_exists': (props) => (
<span>
<Message {...messages.keyNotExists} />
{props.repeatUrl ? errorsMap.resendKey(props.repeatUrl) : null}
</span>
),
'error.key_expire': (props) => errorsMap['error.key_not_exists'](props),
'error.newPassword_required': () => <Message {...messages.newPasswordRequired} />, 'error.newPassword_required': () => <Message {...messages.newPasswordRequired} />,
'error.newRePassword_required': () => <Message {...messages.newRePasswordRequired} />, 'error.newRePassword_required': () => <Message {...messages.newRePasswordRequired} />,
@ -78,5 +71,27 @@ const errorsMap = {
'error.email_frequency': (props) => <Message {...messages.emailFrequency} values={{ 'error.email_frequency': (props) => <Message {...messages.emailFrequency} values={{
time: <Relative value={props.msLeft} updateInterval={1000} /> time: <Relative value={props.msLeft} updateInterval={1000} />
}} />,
suggestResetPassword: () => (
<span>
<br/>
<Message {...messages.suggestResetPassword} values={{
link: (
<Link to="/forgot-password">
<Message {...messages.forgotYourPassword} />
</Link>
)
}} /> }} />
</span>
),
resendKey: (url) => (
<span>
{' '}
<Link to={url}>
<Message {...messages.doYouWantRequestKey} />
</Link>
</span>
)
}; };