diff --git a/src/components/profile/changeEmail/ChangeEmail.jsx b/src/components/profile/changeEmail/ChangeEmail.jsx index 9bfdde2..51b07dc 100644 --- a/src/components/profile/changeEmail/ChangeEmail.jsx +++ b/src/components/profile/changeEmail/ChangeEmail.jsx @@ -5,7 +5,7 @@ import classNames from 'classnames'; import Helmet from 'react-helmet'; import { Motion, spring } from 'react-motion'; -import { Input, Button, Form, FormModel } from 'components/ui/form'; +import { Input, Button, Form, FormModel, FormError } from 'components/ui/form'; import { BackButton } from 'components/profile/ProfileForm'; import styles from 'components/profile/profileForm.scss'; import helpLinks from 'components/auth/helpLinks.scss'; @@ -181,7 +181,7 @@ export default class ChangeEmail extends Component { ); } - renderStep0({email}) { + renderStep0({email, form}) { return (
@@ -194,6 +194,8 @@ export default class ChangeEmail extends Component {

{email}

+ +
diff --git a/src/components/ui/form/FormError.jsx b/src/components/ui/form/FormError.jsx new file mode 100644 index 0000000..8835da5 --- /dev/null +++ b/src/components/ui/form/FormError.jsx @@ -0,0 +1,17 @@ +import React, { PropTypes } from 'react'; + +import errorsDict from 'services/errorsDict'; + +import styles from './form.scss'; + +export default function FormError({error}) { + return error ? ( +
+ {errorsDict.resolve(error)} +
+ ) : null; +} + +FormError.propTypes = { + error: PropTypes.string +}; diff --git a/src/components/ui/form/FormInputComponent.jsx b/src/components/ui/form/FormInputComponent.jsx index 4f05053..a85eb33 100644 --- a/src/components/ui/form/FormInputComponent.jsx +++ b/src/components/ui/form/FormInputComponent.jsx @@ -1,9 +1,7 @@ import React, { PropTypes } from 'react'; -import errorsDict from 'services/errorsDict'; - -import styles from './form.scss'; import FormComponent from './FormComponent'; +import FormError from './FormError'; export default class FormInputComponent extends FormComponent { static displayName = 'FormInputComponent'; @@ -27,15 +25,7 @@ export default class FormInputComponent extends FormComponent { renderError() { const error = this.state && this.state.error || this.props.error; - if (error) { - return ( -
- {errorsDict.resolve(error)} -
- ); - } - - return null; + return ; } setError(error) { diff --git a/src/components/ui/form/FormModel.js b/src/components/ui/form/FormModel.js index 35ee711..b6f08c7 100644 --- a/src/components/ui/form/FormModel.js +++ b/src/components/ui/form/FormModel.js @@ -11,9 +11,9 @@ export default class FormModel { * Usage: * * - * @param {string} name - the name of field + * @param {string} name - the name of field * - * @return {Object} ref and name props for component + * @return {object} - ref and name props for component */ bindField(name) { this.fields[name] = {}; @@ -36,6 +36,11 @@ export default class FormModel { return props; } + /** + * Focuses field + * + * @param {string} fieldId - an id of field to focus + */ focus(fieldId) { if (!this.fields[fieldId]) { throw new Error(`Can not focus. The field with an id ${fieldId} does not exists`); @@ -44,6 +49,13 @@ export default class FormModel { this.fields[fieldId].focus(); } + /** + * Get a value of field + * + * @param {string} fieldId - an id of field to get value of + * + * @return {string} + */ value(fieldId) { const field = this.fields[fieldId]; @@ -58,6 +70,11 @@ export default class FormModel { return field.getValue(); } + /** + * Add errors to form fields + * + * @param {object} errors - object maping {fieldId: errorMessage} + */ setErrors(errors) { const oldErrors = this.errors; this.errors = errors; @@ -69,14 +86,29 @@ export default class FormModel { }); } + /** + * Get error by id + * + * @param {string} fieldId - an id of field to get error for + * + * @return {string|null} + */ getError(fieldId) { return this.errors[fieldId] || null; } + /** + * @return {bool} + */ hasErrors() { return Object.keys(this.errors).length > 0; } + /** + * Convert form into key-value object representation + * + * @return {object} + */ serialize() { return Object.keys(this.fields).reduce((acc, fieldId) => { acc[fieldId] = this.fields[fieldId].getValue(); @@ -88,7 +120,7 @@ export default class FormModel { /** * Bind handler to listen for form loading state change * - * @param {Function} fn + * @param {function} fn */ addLoadingListener(fn) { this.removeLoadingListener(fn); @@ -98,22 +130,31 @@ export default class FormModel { /** * Remove form loading state handler * - * @param {Function} fn + * @param {function} fn */ removeLoadingListener(fn) { this.handlers = this.handlers.filter((handler) => handler !== fn); } + /** + * Switch form in loading state + */ beginLoading() { this._isLoading = true; this.notifyHandlers(); } + /** + * Disable loading state + */ endLoading() { this._isLoading = false; this.notifyHandlers(); } + /** + * @api private + */ notifyHandlers() { this.handlers.forEach((fn) => fn(this._isLoading)); } diff --git a/src/components/ui/form/index.js b/src/components/ui/form/index.js index c6e6150..5de4a7c 100644 --- a/src/components/ui/form/index.js +++ b/src/components/ui/form/index.js @@ -5,6 +5,7 @@ import Button from './Button'; import Form from './Form'; import FormModel from './FormModel'; import Dropdown from './Dropdown'; +import FormError from './FormError'; export { Input, @@ -13,5 +14,6 @@ export { Checkbox, Form, FormModel, - Dropdown + Dropdown, + FormError }; diff --git a/src/pages/profile/ProfilePage.jsx b/src/pages/profile/ProfilePage.jsx index 846b5a1..91dbc87 100644 --- a/src/pages/profile/ProfilePage.jsx +++ b/src/pages/profile/ProfilePage.jsx @@ -61,6 +61,15 @@ export default connect(null, { if (resp.errors) { Reflect.deleteProperty(resp.errors, 'password'); + if (resp.errors.email && resp.data && resp.data.canRepeatIn) { + resp.errors.email = { + type: resp.errors.email, + payload: { + msLeft: resp.data.canRepeatIn * 1000 + } + }; + } + if (Object.keys(resp.errors).length) { form.setErrors(resp.errors); return Promise.reject(resp);