diff --git a/src/components/auth/BaseAuthBody.jsx b/src/components/auth/BaseAuthBody.jsx index 2c12589..82bcd29 100644 --- a/src/components/auth/BaseAuthBody.jsx +++ b/src/components/auth/BaseAuthBody.jsx @@ -18,10 +18,21 @@ export default class BaseAuthBody extends Component { payload: PropTypes.object })]), scopes: PropTypes.array - }), + }).isRequired, user: userShape }; + componentWillReceiveProps(nextProps, nextContext) { + // TODO: we must not access Form#fields. This is a temporary + // solution to reset Captcha, when the form does not handle errors + if (nextContext.auth.error + && this.form.fields.captcha + && nextContext.auth.error !== this.context.auth.error + ) { + this.form.fields.captcha.reset(); + } + } + renderErrors() { return this.context.auth.error ? diff --git a/src/components/auth/PanelTransition.jsx b/src/components/auth/PanelTransition.jsx index e2e122e..55bc198 100644 --- a/src/components/auth/PanelTransition.jsx +++ b/src/components/auth/PanelTransition.jsx @@ -241,12 +241,12 @@ class PanelTransition extends Component { willLeave = (config) => this.getTransitionStyles(config, {isLeave: true}); /** - * @param {Object} config - * @param {string} config.key - * @param {Object} [options] - * @param {Object} [options.isLeave=false] - true, if this is a leave transition + * @param {object} config + * @param {string} config.key + * @param {object} [options] + * @param {object} [options.isLeave=false] - true, if this is a leave transition * - * @return {Object} + * @return {object} */ getTransitionStyles({key}, options = {}) { const {isLeave = false} = options; @@ -298,7 +298,7 @@ class PanelTransition extends Component { /** * Tries to auto focus form fields after transition end * - * @param {number} length number of panels transitioned + * @param {number} length number of panels transitioned */ tryToAutoFocus(length) { if (!this.body) { @@ -337,7 +337,11 @@ class PanelTransition extends Component { }; const backButton = ( - ); @@ -412,11 +416,11 @@ class PanelTransition extends Component { } /** - * @param {string} key - * @param {Object} style - * @param {number} style.opacitySpring + * @param {string} key + * @param {object} style + * @param {number} style.opacitySpring * - * @return {Object} + * @return {object} */ getDefaultTransitionStyles(key, {opacitySpring}) { return { @@ -430,11 +434,11 @@ class PanelTransition extends Component { } /** - * @param {number} value - * @param {string} direction='X' - X|Y - * @param {string} unit='%' - %|px etc + * @param {number} value + * @param {string} direction='X' - X|Y + * @param {string} unit='%' - %|px etc * - * @return {Object} + * @return {object} */ translate(value, direction = 'X', unit = '%') { return { diff --git a/src/components/ui/form/Captcha.jsx b/src/components/ui/form/Captcha.jsx index 06d6efd..2073ce7 100644 --- a/src/components/ui/form/Captcha.jsx +++ b/src/components/ui/form/Captcha.jsx @@ -23,10 +23,14 @@ export default class Captcha extends FormInputComponent { }; componentDidMount() { - setTimeout(() => captcha.render(this.el, { - skin: this.props.skin, - onSetCode: this.setCode - }), this.props.delay); + setTimeout(() => + captcha.render(this.el, { + skin: this.props.skin, + onSetCode: this.setCode + }) + .then((captchaId) => this.captchaId = captchaId), + this.props.delay + ); } render() { @@ -37,10 +41,12 @@ export default class Captcha extends FormInputComponent {
+
+ {this.renderError()}
); @@ -50,5 +56,15 @@ export default class Captcha extends FormInputComponent { return this.state && this.state.code; } + reset() { + captcha.reset(this.captchaId); + } + + setError(error) { + super.setError(error); + + this.reset(); + } + setCode = (code) => this.setState({code}); } diff --git a/src/services/captcha.js b/src/services/captcha.js index c458d97..a47cf4f 100644 --- a/src/services/captcha.js +++ b/src/services/captcha.js @@ -12,7 +12,7 @@ export default { * @param {function} options.onSetCode - the callback, that will be called with * captcha verification code, after user successfully solves captcha * - * @return {Promise} + * @return {Promise} - resolves to captchaId */ render(el, {skin: theme, onSetCode: callback}) { return this.loadApi().then(() => @@ -24,6 +24,13 @@ export default { ); }, + /** + * @param {string} captchaId - captcha id, returned from render promise + */ + reset(captchaId) { + this.loadApi().then(() => window.grecaptcha.reset(captchaId)); + }, + /** * @param {stirng} newLang * diff --git a/src/services/errorsDict/errorsDict.js b/src/services/errorsDict/errorsDict.js index 86a500d..8d0ef4b 100644 --- a/src/services/errorsDict/errorsDict.js +++ b/src/services/errorsDict/errorsDict.js @@ -77,6 +77,7 @@ const errorsMap = { 'error.account_already_activated': () => , 'error.captcha_required': () => , + 'error.captcha_invalid': () => errorsMap['error.captcha_required'](), suggestResetPassword: () => (