import SnackBarAction from '@/forms/components/SnackBars/SnackBarAction'; import Box from '@material-ui/core/Box'; import Icon from '@material-ui/core/Icon'; import { CompareSharp } from '@material-ui/icons'; import { observer } from "mobx-react"; import { useSnackbar } from 'notistack'; import React from 'react'; import GridLayout from 'react-grid-layout'; import 'react-grid-layout/css/styles.css'; import { store } from "./../../store/store"; // import ResizeHandle from './ResizeHandle'; import BuilderFormField from './BuilderFormField'; import builderZoneStyles from './BuilderZoneStyles'; const { __ } = wp.i18n; /** * Returns the last grid item */ const getDefaultGrid = field => { let gridItem = { x: 0, y: Infinity, w: 12, h: 1, maxH: 1, minW: 3, moved: false, static: false, i: field.internalId } gridItem.minW = (field.constraint === 'none' || typeof field.constraint === 'undefined') ? 3 : parseFloat(field.constraint); gridItem.minW = gridItem.minW === 0 ? 3 : gridItem.minW; gridItem.w = gridItem.minW > gridItem.w ? gridItem.minW : gridItem.w; return gridItem; } /** * The actual Builder * * @param {*} props * @returns */ const BuilderZone = observer(props => { const { enqueueSnackbar } = useSnackbar(); // State const classes = builderZoneStyles(); /** * Sets active form field in editor * * @param {*} idx * @param {*} e */ const setFormField = (internalId, e) => { if (e.target.tagName.toLowerCase() !== 'div') { return; } let id = 0; let fieldType = ''; store._FIELD_COMPONENTS_.fieldComponents.map((e, idx) => { if (e.internalId === internalId) { fieldType = e.id; id = idx; } }) if (typeof KaliFormsObject.conditionalLogic === 'undefined' && store._FIELD_COMPONENTS_.isRestrictedField(fieldType)) { enqueueSnackbar( __("Unfortunately, you can't edit this field anymore. This field is part of the PRO package.", 'kaliforms'), { preventDuplicate: true, variant: 'error', action: (key) => } ) return; } //QOL Improvement - check to see if the field does have the tab we are in - and dont change store._UI_.setActiveFormFieldGroupTab('general'); store._UI_.setActiveTabInSidebar('fieldProperties'); store._UI_.setActiveFormFieldInSidebar(id); } /** * Retrieves item style * * @param {*} item * @param {*} idx */ const getItemStyle = (item, idx) => { if (store._UI_.activeTabInSidebar !== 'fieldProperties') { return {}; } let style = {}; if (store._FIELD_COMPONENTS_.getInternalIdByIndex(store._UI_.activeFormFieldInSidebar).toLowerCase() === item.i.toLowerCase()) { style = { ...style, ...{ backgroundColor: '#fafafa' } }; } if (typeof KaliFormsObject.conditionalLogic === 'undefined') { return style; } // @todo // store._ERRORS_.errors.map(error => { // if (error.type === 'field' && typeof error.args.find(erroredItem => erroredItem.internalId === item.i) !== 'undefined') { // style = { ...style, ...{ backgroundColor: 'rgba(208, 2, 31, .15)' } } // console.log(style); // } // }) store._FORM_INFO_.conditionalLogic.map(condition => { if (typeof store._FIELD_COMPONENTS_.fieldComponents[store._UI_.activeFormFieldInSidebar] !== 'undefined' && condition.field === item.i && store._FIELD_COMPONENTS_.fieldComponents[store._UI_.activeFormFieldInSidebar].internalId === condition.conditioner) { style = { ...style, ...{ backgroundColor: 'rgba(162, 162, 250, .15)' } } } }) return style; } const _duplicateField = field => { let duplicateField = {}; store._FIELD_COMPONENTS_.fieldComponents.map(e => { if (e.internalId === field.i) { duplicateField = JSON.parse(JSON.stringify({ ...e })) } }) duplicateField.internalId = duplicateField.id.toLowerCase() + store._FIELD_COMPONENTS_.lastIndex duplicateField.properties.id = duplicateField.internalId duplicateField.properties.name = duplicateField.internalId duplicateField.properties.caption = duplicateField.properties.caption + '(duplicate)' let duplicateFieldGrid = JSON.parse(JSON.stringify({ ...field })); duplicateFieldGrid.i = duplicateField.internalId; duplicateFieldGrid.y += 1; let insertHere = 0; let currentGrid = [...store._GRID_.grid]; currentGrid.map((item, idx) => { if (item.y === field.y) { insertHere = idx; } if (item.y >= duplicateFieldGrid.y) { currentGrid[idx].y += 1; } }) currentGrid.splice(insertHere, 0, duplicateFieldGrid) store._FIELD_COMPONENTS_.addFieldComponent({ ...duplicateField }) store._GRID_.setGrid([...currentGrid]) } /** * Duplicates a field * * @param {*} field */ const duplicateField = field => { store._CONFIRMATION_DIALOG_.setTitle(__('Duplicate field', 'kaliforms')); store._CONFIRMATION_DIALOG_.setMessage(__('Are you sure you want to duplicate this field?', 'kaliforms')); store._CONFIRMATION_DIALOG_.setAction(_duplicateField) store._CONFIRMATION_DIALOG_.setActionProps(field) store._CONFIRMATION_DIALOG_.setState(true); } /** * Gets the last index */ const getLastIndex = () => { return store._FIELD_COMPONENTS_.lastIndex; } /** * Removes a field * @param {*} field * @param {*} idx */ const removeField = field => { store._CONFIRMATION_DIALOG_.setTitle(__('Remove field', 'kaliforms')); store._CONFIRMATION_DIALOG_.setMessage(__('Are you sure you want to delete this field?', 'kaliforms')); store._CONFIRMATION_DIALOG_.setAction(_removeField) store._CONFIRMATION_DIALOG_.setActionProps(field) store._CONFIRMATION_DIALOG_.setState(true); } const _removeField = field => { store._UI_.setActiveTabInSidebar('formFields'); store._UI_.setActiveFormFieldInSidebar(0); store._GRID_.removeGridItem(field.i); // are we a "dependency" in conditionals? let conditions = store._FORM_INFO_.getFieldConditionersByInternalId(field.i); conditions.map(condition => store._FORM_INFO_.removeConditionByAssertion(condition)); store._FIELD_COMPONENTS_.removeFieldComponent(field.i) } const layoutChange = layout => { if (layout.length === store._GRID_.grid.length) { store._GRID_.setGrid(layout); } } const itemDroppedCb = (layout, item, evt) => { evt.preventDefault(); if (!_checkUnique(store._GRID_.draggedItem.id)) { return initAlert(store._GRID_.draggedItem.label); } layout.sort((a, b) => (a.y > b.y) ? 1 : ((b.y > a.y) ? -1 : 0)); store._FIELD_COMPONENTS_.addFieldComponent(store._GRID_.draggedItem) store._GRID_.setGrid(layout) _checkIfAddedPaymentMethod(store._GRID_.draggedItem.id); store._GRID_.setDragStarted(false) store._GRID_.setFieldDragged({}) store._GRID_.setDraggedItemGrid({ i: '', w: 12, h: 0 }) } /** * Already exists field * @param {*} id */ const alreadyExists = id => { return store._FIELD_COMPONENTS_.getFieldsById(id).length > 0 } /** * Checks if the field is unique * @param {*} id * @param {*} label */ const _checkUnique = id => { let uniqueFields = ['stripe', 'paypal', 'submitButton', 'paymentMethod', 'grecaptcha', 'stripeIban', 'wireTransfer', 'total']; if (uniqueFields.includes(id) && alreadyExists(id)) { return false; } return true; } const _abstractedPmLogic = id => { let paymentMethods = [ store._FIELD_COMPONENTS_.getSingleFieldById('paypal'), store._FIELD_COMPONENTS_.getSingleFieldById('wireTransfer'), store._FIELD_COMPONENTS_.getSingleFieldById('stripe') ].filter(Boolean); let paymentMethodChooser = false; paymentMethods.map(pM => { if (paymentMethodChooser) { return; } let pMFound = store._FORM_INFO_.conditionalLogic.find(e => pM.id === e.value); paymentMethodChooser = typeof pMFound !== 'undefined' ? store._FIELD_COMPONENTS_.getFieldByInternalId(pMFound.conditioner) : false; }) return { paymentMethods, paymentMethodChooser }; } /** * Checks if a payment method has been added */ const _checkIfAddedPaymentMethod = id => { let paymentFields = ['stripe', 'paypal', 'wireTransfer'] if (!paymentFields.includes(id)) { return; } const { paymentMethods, paymentMethodChooser } = _abstractedPmLogic(id); if (paymentMethods.length > 1 && !paymentMethodChooser) { store._CONFIRMATION_DIALOG_.setTitle(__('Payment Methods Issue')); store._CONFIRMATION_DIALOG_.setMessage(__('It seems that you have multiple payment methods in your form. In order for this functionality to work correctly you should add a payment method chooser field. Do you want us to do it for you?', 'kaliforms')); store._CONFIRMATION_DIALOG_.setState(true); store._CONFIRMATION_DIALOG_.setAction(_createFieldAndLogic) } if (paymentMethodChooser && paymentMethods.length !== paymentMethodChooser.properties.choices.length) { store._CONFIRMATION_DIALOG_.setTitle(__('Payment Methods Issue')); store._CONFIRMATION_DIALOG_.setMessage(__('Do you want to update the payment method chooser?', 'kaliforms')); store._CONFIRMATION_DIALOG_.setState(true); store._CONFIRMATION_DIALOG_.setAction(_updateFieldAndLogic) store._CONFIRMATION_DIALOG_.setActionProps({ paymentMethods, paymentMethodChooser }) } } /** * Update the radio field and afterwards the logic * * @param {} id */ const _updateFieldAndLogic = (data) => { // Wipe choices from properties let newChoices = []; let choiceValueMap = {}; data.paymentMethods.map(el => { choiceValueMap[el.internalId] = el.id; newChoices.push({ value: el.id, label: el.label }) }); let field = store._FIELD_COMPONENTS_.getFieldByInternalId(data.paymentMethodChooser.internalId) field.properties.choices = newChoices; store._FORM_INFO_.getFieldConditionersByInternalId(data.paymentMethodChooser.internalId).map(condition => { store._FORM_INFO_.removeConditionByAssertion(condition) }); data.paymentMethods.map(pM => { store._FORM_INFO_.addConditional({ name: __('Show ', 'kaliforms') + pM.label, field: pM.internalId, state: 'show', conditioner: data.paymentMethodChooser.internalId, operator: 'equal', value: choiceValueMap[pM.internalId] }) }) } /** * Create field and logic * * @param {*} _ */ const _createFieldAndLogic = _ => { let radioItem = JSON.parse(JSON.stringify(store._FIELD_COMPONENTS_.formFieldTypes[0].fields.find(field => field.id === 'radio'))); let field = { id: radioItem.id, label: radioItem.label, properties: formatObj(radioItem), constraint: 'none', internalId: radioItem.id.toLowerCase() + store._FIELD_COMPONENTS_.lastIndex, } field.properties.name = 'payment-method'; field.properties.caption = __('Select payment method', 'kaliforms'); let pmObj = _getAllPaymentMethods(); field.properties.choices = pmObj.choices; store._FIELD_COMPONENTS_.addFieldComponent(field) store._GRID_.addGridItem(getDefaultGrid(field)) pmObj.paymentMethods.map((e, idx) => { store._FORM_INFO_.addConditional({ name: __('Show ', 'kaliforms') + pmObj.choices[idx].label, field: e.internalId, state: 'show', conditioner: field.internalId, operator: 'equal', value: e.id }) }) } /** * Returns all payment methods */ const _getAllPaymentMethods = () => { let paymentMethods = [ store._FIELD_COMPONENTS_.getSingleFieldById('paypal'), store._FIELD_COMPONENTS_.getSingleFieldById('wireTransfer'), store._FIELD_COMPONENTS_.getSingleFieldById('stripe') ].filter(Boolean); let returnable = []; paymentMethods.map(pM => { let label = _translatePmById(pM.id); returnable.push({ label, value: pM.id }) }); return { paymentMethods, choices: returnable }; } /** * Translates payment methods using id */ const _translatePmById = id => { let label = ''; switch (id) { case 'stripe': label = __('Stripe', 'kaliforms') break; case 'paypal': label = __('PayPal', 'kaliforms') break; case 'wireTransfer': label = __('Wire transfer', 'kaliforms') break; default: break; } return label; } /** * Format object * * @param {*} obj * @returns * @memberof SidebarFieldComponentItem */ const formatObj = (obj) => { let properties = {}; for (const key in obj.properties) { properties[key] = obj.properties[key].value } if (!properties.hasOwnProperty('name')) { properties.name = properties.id } return properties; } /** * Init the alert for unique field * @param {*} label */ const initAlert = label => { store._CONFIRMATION_DIALOG_.setTitle(label + __(' field already exists', 'kaliforms')); store._CONFIRMATION_DIALOG_.setMessage(__('You can add only one field of this type', 'kaliforms')); store._CONFIRMATION_DIALOG_.setHideCancelButton(true); store._CONFIRMATION_DIALOG_.setState(true); } let dragInitiated = store._GRID_.dragStarted && (navigator.userAgent.indexOf('Firefox') !== -1) ? 'removePointerEvents' : ''; return ( } cols={12} droppingItem={store._GRID_.draggedItemGrid} isDroppable={true} onDrop={itemDroppedCb} onLayoutChange={layout => _.debounce(layoutChange(layout), 200)}> { store._GRID_.getGrid.map((item, idx) => { let active = store._UI_.activeTabInSidebar === 'fieldProperties' && store._FIELD_COMPONENTS_.getInternalIdByIndex(store._UI_.activeFormFieldInSidebar).toLowerCase() === item.i.toLowerCase() ? 'active' : ''; return ( setFormField(item.i, e)}> duplicateField(item)} aria-label={__('Duplicate', 'kaliforms')} /> removeField(item, idx)} aria-label={__('Delete', 'kaliforms')} /> ); }) } ); }) export default BuilderZone;