diff --git a/assets/js/src/form_editor/store/actions.jsx b/assets/js/src/form_editor/store/actions.jsx index e07efc9fe8..48d5efbe3b 100644 --- a/assets/js/src/form_editor/store/actions.jsx +++ b/assets/js/src/form_editor/store/actions.jsx @@ -75,9 +75,10 @@ export function createCustomFieldDone(response) { }; } -export function createCustomFieldStarted() { +export function createCustomFieldStarted(customField) { return { type: 'CREATE_CUSTOM_FIELD_STARTED', + customField, }; } diff --git a/assets/js/src/form_editor/store/controls.jsx b/assets/js/src/form_editor/store/controls.jsx index dc9efa1d75..5b1a1236c9 100644 --- a/assets/js/src/form_editor/store/controls.jsx +++ b/assets/js/src/form_editor/store/controls.jsx @@ -68,7 +68,14 @@ export default { }, CREATE_CUSTOM_FIELD(action) { - dispatch('mailpoet-form-editor').createCustomFieldStarted(); + if (select('mailpoet-form-editor').getIsCustomFieldCreating()) { + return; + } + dispatch('mailpoet-form-editor').createCustomFieldStarted(action.data); + // Check if it really started. Could been blocked by an error. + if (!select('mailpoet-form-editor').getIsCustomFieldCreating()) { + return; + } MailPoet.Ajax.post({ api_version: window.mailpoet_api_version, endpoint: 'customFields', diff --git a/assets/js/src/form_editor/store/reducer.jsx b/assets/js/src/form_editor/store/reducer.jsx index 46f7b2d0ea..a3380813c9 100644 --- a/assets/js/src/form_editor/store/reducer.jsx +++ b/assets/js/src/form_editor/store/reducer.jsx @@ -1,7 +1,7 @@ import MailPoet from 'mailpoet'; import createCustomFieldDone from './reducers/create_custom_field_done.jsx'; import createCustomFieldFailed from './reducers/create_custom_field_failed.jsx'; -import createCustomFieldStarted from './reducers/create_custom_field_started.jsx'; +import createCustomFieldStartedFactory from './reducers/create_custom_field_started.jsx'; import changeFormName from './reducers/change_form_name.jsx'; import changeFormSettings from './reducers/change_form_settings.jsx'; import changeFormStyles from './reducers/change_form_styles.jsx'; @@ -22,6 +22,7 @@ import { customFieldDeleteFailed, } from './reducers/custom_field_delete.jsx'; +const createCustomFieldStarted = createCustomFieldStartedFactory(MailPoet); const saveFormStarted = saveFormStartedFactory(MailPoet); export default (defaultState) => (state = defaultState, action) => { diff --git a/assets/js/src/form_editor/store/reducers/create_custom_field_started.jsx b/assets/js/src/form_editor/store/reducers/create_custom_field_started.jsx index 25b7323c3a..b5c25b6cfd 100644 --- a/assets/js/src/form_editor/store/reducers/create_custom_field_started.jsx +++ b/assets/js/src/form_editor/store/reducers/create_custom_field_started.jsx @@ -1,8 +1,20 @@ -export default (state) => { +import { trim } from 'lodash'; + +export default (MailPoet) => (state, action) => { const notices = state.notices.filter((notice) => notice.id !== 'custom-field'); + const fieldName = trim(action.customField.name); + const duplicity = state.customFields.find((field) => (field.name === fieldName)); + if (duplicity) { + notices.push({ + id: 'custom-field', + content: MailPoet.I18n.t('customFieldWithNameExists').replace('[name]', fieldName), + isDismissible: true, + status: 'error', + }); + } return { ...state, - isCustomFieldCreating: true, + isCustomFieldCreating: !duplicity, notices, }; }; diff --git a/tests/javascript/form_editor/store/reducers/create_custom_field_started.spec.js b/tests/javascript/form_editor/store/reducers/create_custom_field_started.spec.js new file mode 100644 index 0000000000..90b9ddc2b3 --- /dev/null +++ b/tests/javascript/form_editor/store/reducers/create_custom_field_started.spec.js @@ -0,0 +1,46 @@ +import { expect } from 'chai'; +import reducerFactory from '../../../../../assets/js/src/form_editor/store/reducers/create_custom_field_started.jsx'; + +const MailPoetStub = { + I18n: { + t: () => ('Error [name]!'), + }, +}; +const reducer = reducerFactory(MailPoetStub); + +const dummyCustomField = { + name: 'My custom field', +}; + +describe('Create Custom Field Started Reducer', () => { + let initialState = null; + beforeEach(() => { + initialState = { + notices: [], + isCustomFieldCreating: false, + customFields: [dummyCustomField], + }; + }); + + it('Should set isCustomFieldCreating when there are no errors', () => { + const customField = { ...dummyCustomField, name: 'Unique custom field' }; + const action = { + type: 'CREATE_CUSTOM_FIELD_STARTED', + customField, + }; + const finalState = reducer(initialState, action); + expect(finalState.isCustomFieldCreating).to.equal(true); + }); + + it('Should create error notice and stop creation process', () => { + const customField = { ...dummyCustomField }; + const action = { + type: 'CREATE_CUSTOM_FIELD_STARTED', + customField, + }; + const finalState = reducer(initialState, action); + expect(finalState.isCustomFieldCreating).to.equal(false); + expect(finalState.notices.length).to.equal(1); + expect(finalState.notices[0].content).to.equal('Error My custom field!'); + }); +}); diff --git a/views/form/editor.html b/views/form/editor.html index 7a61d96239..12e4e976d8 100644 --- a/views/form/editor.html +++ b/views/form/editor.html @@ -106,7 +106,8 @@ 'blockAddCustomFieldFormHeading': __('New Custom Field.'), 'blockCreateButton': _x('Create', 'Label on form submit button.'), 'customFieldName': _x('Field name', 'Label for form field for custom input name'), - 'selectCustomFieldType': _x('Select a field type', 'Label for form field for custom input type') + 'selectCustomFieldType': _x('Select a field type', 'Label for form field for custom input type'), + 'customFieldWithNameExists': __('The custom field [name] already exists. Please choose another name.') }) %> <% endblock %>