From 87d48c87222b6061526630e81e346ed3f1a3c871 Mon Sep 17 00:00:00 2001 From: SleepWalker Date: Sun, 22 May 2016 18:16:51 +0300 Subject: [PATCH] #26: suggest resend confirmation key in validation errors --- src/components/auth/actions.js | 28 ++++++--- src/components/auth/authError/AuthError.jsx | 2 +- .../recoverPassword/RecoverPasswordBody.jsx | 1 + src/i18n/en.json | 3 +- src/i18n/ru.json | 3 +- src/pages/profile/ChangeEmailPage.jsx | 27 +++++++- src/services/errorsDict.intl.json | 3 +- src/services/errorsDict.js | 61 ++++++++++++------- 8 files changed, 88 insertions(+), 40 deletions(-) diff --git a/src/components/auth/actions.js b/src/components/auth/actions.js index 1b0a090..4e59a52 100644 --- a/src/components/auth/actions.js +++ b/src/components/auth/actions.js @@ -84,7 +84,7 @@ export function recoverPassword({ 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)); }) - .catch(validationErrorsHandler(dispatch)) + .catch(validationErrorsHandler(dispatch, '/reactivate')) ); } @@ -332,19 +332,27 @@ function needActivation() { }); } -function validationErrorsHandler(dispatch) { +function validationErrorsHandler(dispatch, repeatUrl) { return (resp) => { if (resp.errors) { - let errorMessage = resp.errors[Object.keys(resp.errors)[0]]; + const error = { + type: resp.errors[Object.keys(resp.errors)[0]], + payload: { + isGuest: true + } + }; + if (resp.data) { - errorMessage = { - type: errorMessage, - payload: resp.data - }; + Object.assign(error.payload, resp.data); } - dispatch(setError(errorMessage)); - return Promise.reject(errorMessage); + if (['error.key_not_exists', 'error.key_expire'].includes(error.type) && repeatUrl) { + Object.assign(error.payload, { + repeatUrl + }); + } + + dispatch(setError(error)); } return Promise.reject(resp); diff --git a/src/components/auth/authError/AuthError.jsx b/src/components/auth/authError/AuthError.jsx index cf51c94..1c0a20c 100644 --- a/src/components/auth/authError/AuthError.jsx +++ b/src/components/auth/authError/AuthError.jsx @@ -13,7 +13,7 @@ function resetTimer() { export default function AuthError({error, onClose = function() {}}) { resetTimer(); - if (error.type === 'error.email_frequency') { + if (error.payload && error.payload.canRepeatIn) { if (error.payload && error.payload.canRepeatIn) { 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 diff --git a/src/components/auth/recoverPassword/RecoverPasswordBody.jsx b/src/components/auth/recoverPassword/RecoverPasswordBody.jsx index 71d70d8..5f8daa2 100644 --- a/src/components/auth/recoverPassword/RecoverPasswordBody.jsx +++ b/src/components/auth/recoverPassword/RecoverPasswordBody.jsx @@ -51,6 +51,7 @@ export default class RecoverPasswordBody extends BaseAuthBody { required value={key} readOnly={!!key} + autoComplete="off" placeholder={messages.enterTheCode} /> diff --git a/src/i18n/en.json b/src/i18n/en.json index ea64d51..cad9db9 100644 --- a/src/i18n/en.json +++ b/src/i18n/en.json @@ -100,6 +100,7 @@ "components.userbar.register": "Join", "pages.root.siteName": "Ely.by", "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.emailInvalid": "Email is invalid", "services.emailIsTempmail": "Tempmail E-mail addresses is not allowed", @@ -108,7 +109,7 @@ "services.emailToLong": "Email is too long", "services.forgotYourPassword": "forgot your 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.loginNotExist": "Sorry, Ely doesn't recognise your login.", "services.loginRequired": "Please enter email or username", diff --git a/src/i18n/ru.json b/src/i18n/ru.json index e8db73a..5178511 100644 --- a/src/i18n/ru.json +++ b/src/i18n/ru.json @@ -100,6 +100,7 @@ "components.userbar.register": "Регистрация", "pages.root.siteName": "Ely.by", "services.accountNotActivated": "Аккаунт не активирован", + "services.doYouWantRequestKey": "Не хотите отправить новый код?", "services.emailFrequency": "Пожалуйста, успокойтесь, вы запрашиваете E-mail слишком часто. Новый ключ можно будет заказать {time}.", "services.emailInvalid": "Указан неправильный E-mail", "services.emailIsTempmail": "Использование сервисов временных E-mail адресов запрещено", @@ -108,7 +109,7 @@ "services.emailToLong": "E-mail слишком длинный", "services.forgotYourPassword": "забыли свой пароль", "services.invalidPassword": "Вы указали неверный пароль от аккаунта.", - "services.keyNotExists": "Указанный ключ не существует или устарел", + "services.keyNotExists": "Указанный ключ не существует или устарел.", "services.keyRequired": "Пожалуйста, введите код активации", "services.loginNotExist": "К сожалению, на Ely нет пользователя с указанным логином.", "services.loginRequired": "Пожалуйста, укажите E-mail или ник", diff --git a/src/pages/profile/ChangeEmailPage.jsx b/src/pages/profile/ChangeEmailPage.jsx index 0cb4d5a..e991092 100644 --- a/src/pages/profile/ChangeEmailPage.jsx +++ b/src/pages/profile/ChangeEmailPage.jsx @@ -59,11 +59,11 @@ class ChangeEmailPage extends Component { switch (step) { case 0: - return accounts.requestEmailChange(); + return accounts.requestEmailChange().catch(handleErrors()); case 1: - return accounts.setNewEmail(data); + return accounts.setNewEmail(data).catch(handleErrors('/profile/change-email')); case 2: - return accounts.confirmNewEmail(data); + return accounts.confirmNewEmail(data).catch(handleErrors('/profile/change-email')); default: 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'; export default connect((state) => ({ diff --git a/src/services/errorsDict.intl.json b/src/services/errorsDict.intl.json index 33641d7..03c05eb 100644 --- a/src/services/errorsDict.intl.json +++ b/src/services/errorsDict.intl.json @@ -22,7 +22,8 @@ "passwordsDoesNotMatch": "The passwords does not match", "rulesAgreementRequired": "You must accept rules in order to create an account", "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}.", "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." diff --git a/src/services/errorsDict.js b/src/services/errorsDict.js index 158d932..19805fc 100644 --- a/src/services/errorsDict.js +++ b/src/services/errorsDict.js @@ -1,6 +1,7 @@ import React from 'react'; import { FormattedMessage as Message, FormattedRelative as Relative } from 'react-intl'; +import { Link } from 'react-router'; import messages from './errorsDict.intl.json'; @@ -9,7 +10,7 @@ export default { let payload = {}; if (error.type) { - payload = error.payload; + payload = error.payload || {}; error = error.type; } return errorsMap[error] ? errorsMap[error](payload) : error; @@ -23,17 +24,10 @@ const errorsMap = { 'error.password_invalid': () => , 'error.old_hash_strategy': () => , - 'error.password_incorrect': () => ( + 'error.password_incorrect': (props) => ( -
- - - - ) - }} /> + {props.isGuest ? errorsMap.suggestResetPassword() : null}
), @@ -47,17 +41,10 @@ const errorsMap = { 'error.email_too_long': () => , 'error.email_invalid': () => , 'error.email_is_tempmail': () => , - 'error.email_not_available': () => ( + 'error.email_not_available': (props) => ( -
- - - - ) - }} /> + {props.isGuest ? errorsMap.suggestResetPassword() : null}
), @@ -65,10 +52,16 @@ const errorsMap = { 'error.password_too_short': () => , 'error.rePassword_does_not_match': () => , 'error.rulesAgreement_required': () => , - 'error.you_must_accept_rules': () => this.errorsMap['error.rulesAgreement_required'](), + 'error.you_must_accept_rules': () => errorsMap['error.rulesAgreement_required'](), 'error.key_required': () => , - 'error.key_is_required': () => this.errorsMap['error.key_required'](), - 'error.key_not_exists': () => , + 'error.key_is_required': () => errorsMap['error.key_required'](), + 'error.key_not_exists': (props) => ( + + + {props.repeatUrl ? errorsMap.resendKey(props.repeatUrl) : null} + + ), + 'error.key_expire': (props) => errorsMap['error.key_not_exists'](props), 'error.newPassword_required': () => , 'error.newRePassword_required': () => , @@ -78,5 +71,27 @@ const errorsMap = { 'error.email_frequency': (props) => - }} /> + }} />, + + suggestResetPassword: () => ( + +
+ + + + ) + }} /> +
+ ), + + resendKey: (url) => ( + + {' '} + + + + + ) };