#26: email resend count down for forgot-password

This commit is contained in:
SleepWalker 2016-05-22 17:01:31 +03:00
parent 291a498f19
commit 4eaefd1d9b
8 changed files with 61 additions and 13 deletions

View File

@ -13,7 +13,10 @@ export default class BaseAuthBody extends Component {
resolve: PropTypes.func.isRequired, resolve: PropTypes.func.isRequired,
requestRedraw: PropTypes.func.isRequired, requestRedraw: PropTypes.func.isRequired,
auth: PropTypes.shape({ auth: PropTypes.shape({
error: PropTypes.string, error: PropTypes.oneOfType([PropTypes.string, PropTypes.shape({
type: PropTypes.string,
payload: PropTypes.object
})]),
scopes: PropTypes.array scopes: PropTypes.array
}), }),
user: userShape user: userShape
@ -22,7 +25,7 @@ export default class BaseAuthBody extends Component {
renderErrors() { renderErrors() {
return this.context.auth.error return this.context.auth.error
? <AuthError error={this.context.auth.error} onClose={this.onClearErrors} /> ? <AuthError error={this.context.auth.error} onClose={this.onClearErrors} />
: '' : null
; ;
} }

View File

@ -59,7 +59,10 @@ class PanelTransition extends Component {
static propTypes = { static propTypes = {
// context props // context props
auth: PropTypes.shape({ auth: PropTypes.shape({
error: PropTypes.string, error: PropTypes.oneOfType([PropTypes.string, PropTypes.shape({
type: PropTypes.string,
payload: PropTypes.object
})]),
isLoading: PropTypes.bool, isLoading: PropTypes.bool,
login: PropTypes.shape({ login: PropTypes.shape({
login: PropTypes.string, login: PropTypes.string,
@ -82,7 +85,10 @@ class PanelTransition extends Component {
static childContextTypes = { static childContextTypes = {
auth: PropTypes.shape({ auth: PropTypes.shape({
error: PropTypes.string, error: PropTypes.oneOfType([PropTypes.string, PropTypes.shape({
type: PropTypes.string,
payload: PropTypes.object
})]),
login: PropTypes.shape({ login: PropTypes.shape({
login: PropTypes.string, login: PropTypes.string,
password: PropTypes.string password: PropTypes.string

View File

@ -335,7 +335,14 @@ function needActivation() {
function validationErrorsHandler(dispatch) { function validationErrorsHandler(dispatch) {
return (resp) => { return (resp) => {
if (resp.errors) { if (resp.errors) {
const errorMessage = resp.errors[Object.keys(resp.errors)[0]]; let errorMessage = resp.errors[Object.keys(resp.errors)[0]];
if (resp.data) {
errorMessage = {
type: errorMessage,
payload: resp.data
};
}
dispatch(setError(errorMessage)); dispatch(setError(errorMessage));
return Promise.reject(errorMessage); return Promise.reject(errorMessage);
} }

View File

@ -3,9 +3,30 @@ import React, { PropTypes } from 'react';
import errorsDict from 'services/errorsDict'; import errorsDict from 'services/errorsDict';
import { PanelBodyHeader } from 'components/ui/Panel'; import { PanelBodyHeader } from 'components/ui/Panel';
let autoHideTimer;
function resetTimer() {
if (autoHideTimer) {
clearTimeout(autoHideTimer);
autoHideTimer = null;
}
}
export default function AuthError({error, onClose = function() {}}) { export default function AuthError({error, onClose = function() {}}) {
resetTimer();
if (error.type === 'error.email_frequency') {
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
} else {
// TODO: it would be greate to log this case, when we will setup frontend logging
}
}
return ( return (
<PanelBodyHeader type="error" onClose={onClose}> <PanelBodyHeader type="error" onClose={() => {
resetTimer();
onClose();
}}>
{errorsDict.resolve(error)} {errorsDict.resolve(error)}
</PanelBodyHeader> </PanelBodyHeader>
); );
@ -13,6 +34,9 @@ export default function AuthError({error, onClose = function() {}}) {
AuthError.displayName = 'AuthError'; AuthError.displayName = 'AuthError';
AuthError.propTypes = { AuthError.propTypes = {
error: PropTypes.string.isRequired, error: PropTypes.oneOfType([PropTypes.string, PropTypes.shape({
type: PropTypes.string,
payload: PropTypes.object
})]).isRequired,
onClose: PropTypes.func onClose: PropTypes.func
}; };

View File

@ -100,7 +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.emailFrequency": "Please cool down, you are requesting emails too often. New key can be retrieved after 30 minutes from the previous request.", "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",
"services.emailNotAvailable": "This email is already registered.", "services.emailNotAvailable": "This email is already registered.",

View File

@ -100,7 +100,7 @@
"components.userbar.register": "Регистрация", "components.userbar.register": "Регистрация",
"pages.root.siteName": "Ely.by", "pages.root.siteName": "Ely.by",
"services.accountNotActivated": "Аккаунт не активирован", "services.accountNotActivated": "Аккаунт не активирован",
"services.emailFrequency": "Пожалуйста, успокойтесь, вы запрашиваете E-mail слишком часто. Новый ключ можно будет заказать через 30 минут от предыдущего запроса.", "services.emailFrequency": "Пожалуйста, успокойтесь, вы запрашиваете E-mail слишком часто. Новый ключ можно будет заказать {time}.",
"services.emailInvalid": "Указан неправильный E-mail", "services.emailInvalid": "Указан неправильный E-mail",
"services.emailIsTempmail": "Использование сервисов временных E-mail адресов запрещено", "services.emailIsTempmail": "Использование сервисов временных E-mail адресов запрещено",
"services.emailNotAvailable": "На указанный E-mail адрес уже зарегистрирован аккаунт.", "services.emailNotAvailable": "На указанный E-mail адрес уже зарегистрирован аккаунт.",

View File

@ -23,7 +23,7 @@
"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",
"emailFrequency": "Please cool down, you are requesting emails too often. New key can be retrieved after 30 minutes from the previous request.", "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,12 +1,18 @@
import React from 'react'; import React from 'react';
import { FormattedMessage as Message } from 'react-intl'; import { FormattedMessage as Message, FormattedRelative as Relative } from 'react-intl';
import messages from './errorsDict.intl.json'; import messages from './errorsDict.intl.json';
export default { export default {
resolve(error) { resolve(error) {
return errorsMap[error] ? errorsMap[error]() : error; let payload = {};
if (error.type) {
payload = error.payload;
error = error.type;
}
return errorsMap[error] ? errorsMap[error](payload) : error;
} }
}; };
@ -70,5 +76,7 @@ const errorsMap = {
'error.account_not_activated': () => <Message {...messages.accountNotActivated} />, 'error.account_not_activated': () => <Message {...messages.accountNotActivated} />,
'error.email_frequency': () => <Message {...messages.emailFrequency} /> 'error.email_frequency': (props) => <Message {...messages.emailFrequency} values={{
time: <Relative value={props.msLeft} updateInterval={1000} />
}} />
}; };