diff --git a/assets/css/src/components/formEditor/components/_custom_field.scss b/assets/css/src/components/formEditor/components/_custom_field.scss
new file mode 100644
index 0000000000..abe09705df
--- /dev/null
+++ b/assets/css/src/components/formEditor/components/_custom_field.scss
@@ -0,0 +1,6 @@
+
+.mailpoet_custom_select {
+ .components-base-control__label {
+ display: block;
+ }
+}
diff --git a/assets/css/src/formEditor.scss b/assets/css/src/formEditor.scss
index 5111e54312..338f174075 100644
--- a/assets/css/src/formEditor.scss
+++ b/assets/css/src/formEditor.scss
@@ -3,7 +3,7 @@
@import '../../../node_modules/@wordpress/components/build-style/style';
@import '../../../node_modules/@wordpress/block-editor/build-style/style';
@import '../../../node_modules/@wordpress/block-library/build-style/editor';
-
@import './components/formEditor/components/form_title';
@import './components/formEditor/components/sidebar';
@import './components/formEditor/components/block_editor';
+@import './components/formEditor/components/custom_field';
diff --git a/assets/js/src/form_editor/blocks/blocks.jsx b/assets/js/src/form_editor/blocks/blocks.jsx
index a9a02fada7..1c85a8768b 100644
--- a/assets/js/src/form_editor/blocks/blocks.jsx
+++ b/assets/js/src/form_editor/blocks/blocks.jsx
@@ -15,6 +15,7 @@ import * as customText from './custom_text/custom_text.jsx';
import * as customTextArea from './custom_textarea/custom_textarea.jsx';
import * as customRadio from './custom_radio/custom_radio.jsx';
import * as customCheckbox from './custom_checkbox/custom_checkbox.jsx';
+import * as customSelect from './custom_select/custom_select.jsx';
const registerCustomFieldBlock = (customField) => {
const namesMap = {
@@ -34,6 +35,10 @@ const registerCustomFieldBlock = (customField) => {
name: customCheckbox.name,
settings: customCheckbox.getSettings(customField),
},
+ select: {
+ name: customSelect.name,
+ settings: customSelect.getSettings(customField),
+ },
};
if (!namesMap[customField.type]) return;
diff --git a/assets/js/src/form_editor/blocks/custom_radio/settings_preview.jsx b/assets/js/src/form_editor/blocks/custom_radio/settings_preview.jsx
index 619e253df7..fbff5735aa 100644
--- a/assets/js/src/form_editor/blocks/custom_radio/settings_preview.jsx
+++ b/assets/js/src/form_editor/blocks/custom_radio/settings_preview.jsx
@@ -16,6 +16,7 @@ const PreviewItem = ({
moveItem,
remove,
onUpdate,
+ onCheck,
dragFinished,
}) => {
const ref = useRef(null);
@@ -80,7 +81,7 @@ const PreviewItem = ({
>
onCheck(value.id, event.target.value)}
key={`check-${value.id}`}
/>
{
+ const value = valuesWhileMoved.find((v) => v.id === valueId);
+ value.isChecked = checked;
+ update(value);
+ };
+
return (
{valuesWhileMoved.map((value, index) => (
@@ -151,6 +159,7 @@ const Preview = ({
value={value}
moveItem={moveItem}
remove={remove}
+ onCheck={onCheck}
onUpdate={onUpdate}
dragFinished={() => onReorder(valuesWhileMoved)}
/>
diff --git a/assets/js/src/form_editor/blocks/custom_select/custom_select.jsx b/assets/js/src/form_editor/blocks/custom_select/custom_select.jsx
new file mode 100644
index 0000000000..7e9a666982
--- /dev/null
+++ b/assets/js/src/form_editor/blocks/custom_select/custom_select.jsx
@@ -0,0 +1,44 @@
+import Icon from '../custom_text/icon.jsx';
+import Edit from './edit.jsx';
+
+export const name = 'mailpoet-form/custom-select';
+
+export function getSettings(customField) {
+ return {
+ title: customField.name,
+ description: '',
+ icon: Icon,
+ category: 'custom-fields',
+ attributes: {
+ label: {
+ type: 'string',
+ default: customField.name,
+ },
+ labelWithinInput: {
+ type: 'boolean',
+ default: true,
+ },
+ mandatory: {
+ type: 'boolean',
+ default: false,
+ },
+ values: {
+ type: 'array',
+ default: [],
+ },
+ customFieldId: {
+ type: 'string',
+ default: customField.id,
+ },
+ },
+ supports: {
+ html: false,
+ customClassName: false,
+ multiple: false,
+ },
+ edit: Edit,
+ save() {
+ return null;
+ },
+ };
+}
diff --git a/assets/js/src/form_editor/blocks/custom_select/edit.jsx b/assets/js/src/form_editor/blocks/custom_select/edit.jsx
new file mode 100644
index 0000000000..755d54c7ca
--- /dev/null
+++ b/assets/js/src/form_editor/blocks/custom_select/edit.jsx
@@ -0,0 +1,115 @@
+import React from 'react';
+import {
+ Panel,
+ PanelBody,
+ SelectControl,
+ TextControl,
+ ToggleControl,
+} from '@wordpress/components';
+import { InspectorControls } from '@wordpress/block-editor';
+import PropTypes from 'prop-types';
+import MailPoet from 'mailpoet';
+import { useDispatch, useSelect } from '@wordpress/data';
+
+import CustomFieldSettings from '../custom_radio/custom_field_settings.jsx';
+
+const CustomSelectEdit = ({ attributes, setAttributes }) => {
+ const isSaving = useSelect(
+ (sel) => sel('mailpoet-form-editor').getIsCustomFieldSaving(),
+ []
+ );
+ const { saveCustomField } = useDispatch('mailpoet-form-editor');
+
+ const inspectorControls = (
+
+
+
+ saveCustomField({
+ customFieldId: attributes.customFieldId,
+ data: {
+ params: {
+ required: params.mandatory ? '1' : undefined,
+ values: params.values.map((value) => ({
+ value: value.name,
+ is_checked: value.isChecked ? '1' : undefined,
+ })),
+ },
+ },
+ onFinish: () => setAttributes({
+ mandatory: params.mandatory,
+ values: params.values,
+ }),
+ })}
+ />
+
+
+
+
+ (setAttributes({ label }))}
+ />
+ (setAttributes({ labelWithinInput }))}
+ />
+
+
+
+ );
+
+ const getLabel = () => {
+ if (attributes.mandatory) {
+ return `${attributes.label} *`;
+ }
+ return attributes.label;
+ };
+
+ const getInput = () => {
+ const options = [{
+ label: attributes.labelWithinInput ? getLabel() : '-',
+ value: null,
+ }];
+ if (Array.isArray(attributes.values) || !attributes.values.length) {
+ attributes.values.forEach((value) => options.push({ label: value.name }));
+ }
+ return (
+
+ {}}
+ />
+
+ );
+ };
+
+ return (
+ <>
+ {inspectorControls}
+ {getInput()}
+ >
+ );
+};
+
+CustomSelectEdit.propTypes = {
+ attributes: PropTypes.shape({
+ label: PropTypes.string.isRequired,
+ values: PropTypes.arrayOf(PropTypes.shape({
+ name: PropTypes.string.isRequired,
+ isChecked: PropTypes.bool,
+ id: PropTypes.string.isRequired,
+ })),
+ mandatory: PropTypes.bool.isRequired,
+ }).isRequired,
+ setAttributes: PropTypes.func.isRequired,
+};
+
+export default CustomSelectEdit;
diff --git a/assets/js/src/form_editor/store/blocks_to_form_body.jsx b/assets/js/src/form_editor/store/blocks_to_form_body.jsx
index 0c3257f6eb..ea720f4e51 100644
--- a/assets/js/src/form_editor/store/blocks_to_form_body.jsx
+++ b/assets/js/src/form_editor/store/blocks_to_form_body.jsx
@@ -20,6 +20,9 @@ const mapCustomField = (block, customFields, mappedCommonProperties) => {
if (block.name.startsWith('mailpoet-form/custom-checkbox')) {
mapped.type = 'checkbox';
}
+ if (block.name.startsWith('mailpoet-form/custom-select')) {
+ mapped.type = 'select';
+ }
if (has(block.attributes, 'validate')) {
mapped.params.validate = block.attributes.validate;
}
diff --git a/assets/js/src/form_editor/store/form_body_to_blocks.jsx b/assets/js/src/form_editor/store/form_body_to_blocks.jsx
index be459bc354..d272999473 100644
--- a/assets/js/src/form_editor/store/form_body_to_blocks.jsx
+++ b/assets/js/src/form_editor/store/form_body_to_blocks.jsx
@@ -10,6 +10,7 @@ const mapCustomField = (item, customFields, mappedCommonProperties) => {
textarea: 'mailpoet-form/custom-textarea',
radio: 'mailpoet-form/custom-radio',
checkbox: 'mailpoet-form/custom-checkbox',
+ select: 'mailpoet-form/custom-select',
};
const mapped = {
...mappedCommonProperties,
diff --git a/tests/javascript/form_editor/store/blocks_to_form_body.spec.js b/tests/javascript/form_editor/store/blocks_to_form_body.spec.js
index 33cea6b34b..d74cc41179 100644
--- a/tests/javascript/form_editor/store/blocks_to_form_body.spec.js
+++ b/tests/javascript/form_editor/store/blocks_to_form_body.spec.js
@@ -107,6 +107,22 @@ const customCheckBox = {
},
};
+const customSelectBlock = {
+ clientId: '5',
+ isValid: true,
+ innerBlocks: [],
+ name: 'mailpoet-form/custom-select',
+ attributes: {
+ label: 'Select',
+ labelWithinInput: false,
+ mandatory: false,
+ customFieldId: 6,
+ values: [
+ { name: 'option 1' },
+ { name: 'option 2' },
+ ],
+ },
+};
const dividerBlock = {
clientId: 'some_random_123',
@@ -297,6 +313,33 @@ describe('Blocks to Form Body', () => {
expect(input.params.validate).to.eq('alphanum');
});
+ it('Should map custom select field', () => {
+ const customField = {
+ created_at: '2019-12-10T15:05:06+00:00',
+ id: 6,
+ name: 'Custom Select',
+ params: {
+ label: 'Select',
+ required: '1',
+ values: [
+ { value: 'option 1' },
+ ],
+ },
+ type: 'select',
+ updated_at: '2019-12-10T15:05:06+00:00',
+ };
+ const [input] = formBlocksToBody([customSelectBlock], [customField]);
+ checkBodyInputBasics(input);
+ expect(input.id).to.be.equal('6');
+ expect(input.name).to.be.equal('Custom Select');
+ expect(input.type).to.be.equal('select');
+ expect(input.position).to.be.equal('1');
+ expect(input.params.label).to.be.equal('Select');
+ expect(input.params.values).to.be.an('Array').that.has.length(2);
+ expect(input.params.values[0]).to.have.property('value', 'option 1');
+ expect(input.params.values[1]).to.have.property('value', 'option 2');
+ });
+
it('Should map custom radio field', () => {
const customField = {
created_at: '2019-12-10T15:05:06+00:00',
diff --git a/tests/javascript/form_editor/store/form_body_to_blocks.spec.js b/tests/javascript/form_editor/store/form_body_to_blocks.spec.js
index 69367889e9..e0e1da646c 100644
--- a/tests/javascript/form_editor/store/form_body_to_blocks.spec.js
+++ b/tests/javascript/form_editor/store/form_body_to_blocks.spec.js
@@ -103,6 +103,24 @@ const customRadioInput = {
},
position: null,
};
+const customSelectInput = {
+ type: 'select',
+ name: 'Custom select',
+ id: '5',
+ unique: '1',
+ static: '0',
+ params: {
+ required: '',
+ label: 'Select',
+ label_within: '1',
+ values: [
+ {
+ value: 'option 1',
+ },
+ ],
+ },
+ position: null,
+};
const customCheckboxInput = {
type: 'checkbox',
name: 'Custom check',
@@ -365,6 +383,33 @@ describe('Form Body To Blocks', () => {
expect(block.attributes.values[0]).to.have.property('isChecked', true);
});
+ it('Should map custom select input to block', () => {
+ const customField = {
+ type: 'select',
+ name: 'Custom select',
+ id: 5,
+ params: {
+ required: '',
+ label: 'Select',
+ values: [
+ {
+ value: 'option 1',
+ },
+ ],
+ },
+ position: null,
+ };
+ const [block] = formBodyToBlocks([{ ...customSelectInput, position: '1' }], [customField]);
+ checkBlockBasics(block);
+ expect(block.clientId).to.be.equal('5_0');
+ expect(block.name).to.be.equal('mailpoet-form/custom-select-customselect');
+ expect(block.attributes.label).to.be.equal('Select');
+ expect(block.attributes.mandatory).to.be.equal(false);
+ expect(block.attributes.labelWithinInput).to.be.equal(true);
+ expect(block.attributes.values).to.be.an('Array').that.has.length(1);
+ expect(block.attributes.values[0]).to.have.property('name', 'option 1');
+ });
+
it('Should ignore unknown input type', () => {
const blocks = formBodyToBlocks([{ ...submitInput, id: 'some-nonsense' }]);
expect(blocks).to.be.empty;