diff --git a/backend/Actions/PopupMaker/PopupMakerController.php b/backend/Actions/PopupMaker/PopupMakerController.php new file mode 100644 index 000000000..891a994c1 --- /dev/null +++ b/backend/Actions/PopupMaker/PopupMakerController.php @@ -0,0 +1,88 @@ +flow_details; + $integId = $integrationData->id; + $fieldMap = $integrationDetails->field_map; + $utilities = isset($integrationDetails->utilities) ? $integrationDetails->utilities : []; + + if (empty($fieldMap)) { + return new WP_Error('field_map_empty', __('Field map is empty', 'bit-integrations')); + } + + $recordApiHelper = new RecordApiHelper($integrationDetails, $integId); + + return $recordApiHelper->execute($fieldValues, $fieldMap, $utilities); + } + + private static function postDropdown($postType) + { + $options = []; + + $posts = get_posts( + [ + 'post_type' => $postType, + 'post_status' => ['publish', 'draft', 'pending', 'private'], + 'orderby' => 'title', + 'order' => 'ASC', + 'posts_per_page' => -1, + 'update_post_meta_cache' => false, + 'update_post_term_cache' => false, + ] + ); + + foreach ($posts as $post) { + $options[] = (object) [ + 'id' => $post->ID, + 'title' => $post->post_title !== '' ? $post->post_title : \sprintf('#%d', $post->ID), + ]; + } + + return $options; + } +} diff --git a/backend/Actions/PopupMaker/RecordApiHelper.php b/backend/Actions/PopupMaker/RecordApiHelper.php new file mode 100644 index 000000000..1315e1dd4 --- /dev/null +++ b/backend/Actions/PopupMaker/RecordApiHelper.php @@ -0,0 +1,157 @@ +_integrationDetails = $integrationDetails; + $this->_integrationID = $integId; + } + + /** + * Execute the integration + * + * @param array $fieldValues Field values from trigger + * @param array $fieldMap Field mapping + * @param array $utilities Optional actions to perform + * + * @return array + */ + public function execute($fieldValues, $fieldMap, $utilities) + { + if (!\defined('POPMAKE_VERSION')) { + return [ + 'success' => false, + 'message' => __('Popup Maker is not installed or activated', 'bit-integrations') + ]; + } + + $fieldData = static::generateReqDataFromFieldMap($fieldMap, $fieldValues); + + $mainAction = $this->_integrationDetails->mainAction ?? ''; + + $defaultResponse = [ + 'success' => false, + // translators: %s: Plugin name + 'message' => wp_sprintf(__('%s plugin is not installed or activate', 'bit-integrations'), 'Bit Integrations Pro') + ]; + + switch ($mainAction) { + case 'create_popup': + $response = Hooks::apply(Config::withPrefix('popup_maker_create_popup'), $defaultResponse, $fieldData, $utilities, $this->_integrationDetails); + $type = 'popup'; + $actionType = 'create_popup'; + + break; + + case 'update_popup': + $response = Hooks::apply(Config::withPrefix('popup_maker_update_popup'), $defaultResponse, $fieldData, $utilities, $this->_integrationDetails); + $type = 'popup'; + $actionType = 'update_popup'; + + break; + + case 'delete_popup': + $response = Hooks::apply(Config::withPrefix('popup_maker_delete_popup'), $defaultResponse, $fieldData, $utilities); + $type = 'popup'; + $actionType = 'delete_popup'; + + break; + + case 'change_popup_status': + $response = Hooks::apply(Config::withPrefix('popup_maker_change_popup_status'), $defaultResponse, $fieldData, $this->_integrationDetails); + $type = 'popup'; + $actionType = 'change_popup_status'; + + break; + + case 'reset_popup_counts': + $response = Hooks::apply(Config::withPrefix('popup_maker_reset_popup_counts'), $defaultResponse, $fieldData); + $type = 'popup'; + $actionType = 'reset_popup_counts'; + + break; + + case 'track_popup_event': + $response = Hooks::apply(Config::withPrefix('popup_maker_track_popup_event'), $defaultResponse, $fieldData, $this->_integrationDetails); + $type = 'popup'; + $actionType = 'track_popup_event'; + + break; + + case 'create_subscriber': + $response = Hooks::apply(Config::withPrefix('popup_maker_create_subscriber'), $defaultResponse, $fieldData, $utilities, $this->_integrationDetails); + $type = 'subscriber'; + $actionType = 'create_subscriber'; + + break; + + case 'update_subscriber': + $response = Hooks::apply(Config::withPrefix('popup_maker_update_subscriber'), $defaultResponse, $fieldData, $utilities, $this->_integrationDetails); + $type = 'subscriber'; + $actionType = 'update_subscriber'; + + break; + + case 'delete_subscriber': + $response = Hooks::apply(Config::withPrefix('popup_maker_delete_subscriber'), $defaultResponse, $fieldData); + $type = 'subscriber'; + $actionType = 'delete_subscriber'; + + break; + + default: + $response = [ + 'success' => false, + 'message' => __('Invalid action', 'bit-integrations') + ]; + $type = 'PopupMaker'; + $actionType = 'unknown'; + + break; + } + + $responseType = isset($response['success']) && $response['success'] ? 'success' : 'error'; + LogHandler::save($this->_integrationID, ['type' => $type, 'type_name' => $actionType], $responseType, $response); + + return $response; + } + + protected static function generateReqDataFromFieldMap($fieldMap, $fieldValues) + { + $dataFinal = []; + + foreach ($fieldMap as $item) { + $triggerValue = $item->formField; + $actionValue = $item->popupMakerField; + + if (empty($actionValue)) { + continue; + } + + $dataFinal[$actionValue] = $triggerValue === 'custom' && isset($item->customValue) + ? Common::replaceFieldWithValue($item->customValue, $fieldValues) + : $fieldValues[$triggerValue] ?? ''; + } + + return $dataFinal; + } +} diff --git a/backend/Actions/PopupMaker/Routes.php b/backend/Actions/PopupMaker/Routes.php new file mode 100644 index 000000000..dfef415fa --- /dev/null +++ b/backend/Actions/PopupMaker/Routes.php @@ -0,0 +1,11 @@ + import('./Bookly/EditBookly')) const EditSureContact = lazy(() => import('./SureContact/EditSureContact')) const EditBrilliantDirectories = lazy(() => import('./BrilliantDirectories/EditBrilliantDirectories')) const EditFluentCart = lazy(() => import('./FluentCart/EditFluentCart')) +const EditPopupMaker = lazy(() => import('./PopupMaker/EditPopupMaker')) const EditNextCrm = lazy(() => import('./NextCrm/EditNextCrm')) const EditFluentPlayer = lazy(() => import('./FluentPlayer/EditFluentPlayer')) const EditBitCrm = lazy(() => import('./BitCrm/EditBitCrm')) @@ -640,6 +641,8 @@ const IntegType = memo(({ allIntegURL, flow }) => { return case 'FluentCart': return + case 'PopupMaker': + return case 'FluentPlayer': return case 'BitCrm': diff --git a/frontend/src/components/AllIntegrations/IntegInfo.jsx b/frontend/src/components/AllIntegrations/IntegInfo.jsx index da1859aee..27684c440 100644 --- a/frontend/src/components/AllIntegrations/IntegInfo.jsx +++ b/frontend/src/components/AllIntegrations/IntegInfo.jsx @@ -184,13 +184,12 @@ const UltimateAffiliateProAuthorization = lazy( () => import('./UltimateAffiliatePro/UltimateAffiliateProAuthorization') ) const BooklyAuthorization = lazy(() => import('./Bookly/BooklyAuthorization')) -const SureContactAuthorization = lazy( - () => import('./SureContact/SureContactAuthorization') -) +const SureContactAuthorization = lazy(() => import('./SureContact/SureContactAuthorization')) const BrilliantDirectoriesAuthorization = lazy( () => import('./BrilliantDirectories/BrilliantDirectoriesAuthorization') ) const FluentCartAuthorization = lazy(() => import('./FluentCart/FluentCartAuthorization')) +const PopupMakerAuthorization = lazy(() => import('./PopupMaker/PopupMakerAuthorization')) const NextCrmAuthorization = lazy(() => import('./NextCrm/NextCrmAuthorization')) const FluentPlayerAuthorization = lazy(() => import('./FluentPlayer/FluentPlayerAuthorization')) const BitCrmAuthorization = lazy(() => import('./BitCrm/BitCrmAuthorization')) @@ -679,14 +678,12 @@ const IntegrationInfo = memo(({ integrationConf, location, editUrl }) => { return case 'BrilliantDirectories': return ( - + ) case 'FluentCart': return + case 'PopupMaker': + return case 'NextCrm': return case 'FluentPlayer': diff --git a/frontend/src/components/AllIntegrations/NewInteg.jsx b/frontend/src/components/AllIntegrations/NewInteg.jsx index 30abdf32d..90129b7cf 100644 --- a/frontend/src/components/AllIntegrations/NewInteg.jsx +++ b/frontend/src/components/AllIntegrations/NewInteg.jsx @@ -181,6 +181,7 @@ const Bookly = lazy(() => import('./Bookly/Bookly')) const SureContact = lazy(() => import('./SureContact/SureContact')) const BrilliantDirectories = lazy(() => import('./BrilliantDirectories/BrilliantDirectories')) const FluentCart = lazy(() => import('./FluentCart/FluentCart')) +const PopupMaker = lazy(() => import('./PopupMaker/PopupMaker')) const NextCrm = lazy(() => import('./NextCrm/NextCrm')) const FluentPlayer = lazy(() => import('./FluentPlayer/FluentPlayer')) const BitCrm = lazy(() => import('./BitCrm/BitCrm')) @@ -1780,6 +1781,15 @@ const NewIntegs = memo(({ integUrlName, allIntegURL, flow, setFlow }) => { setFlow={setFlow} /> ) + case 'PopupMaker': + return ( + + ) case 'FluentPlayer': return ( + + +
+ {__('Integration Name:', 'bit-integrations')} + handleInput(e, popupMakerConf, setPopupMakerConf)} + name="name" + value={popupMakerConf.name} + type="text" + placeholder={__('Integration Name...', 'bit-integrations')} + /> +
+
+ + + + + + + saveActionConf({ + flow, + setFlow, + allIntegURL, + conf: popupMakerConf, + navigate, + id, + edit: 1, + setIsLoading, + setSnackbar + }) + } + disabled={!checkMappedFields(popupMakerConf)} + isLoading={isLoading} + dataConf={popupMakerConf} + setDataConf={setPopupMakerConf} + formFields={formFields} + /> +
+ + ) +} diff --git a/frontend/src/components/AllIntegrations/PopupMaker/PopupMaker.jsx b/frontend/src/components/AllIntegrations/PopupMaker/PopupMaker.jsx new file mode 100644 index 000000000..98d7f71ad --- /dev/null +++ b/frontend/src/components/AllIntegrations/PopupMaker/PopupMaker.jsx @@ -0,0 +1,126 @@ +import { useState } from 'react' +import 'react-multiple-select-dropdown-lite/dist/index.css' +import { useNavigate, useParams } from 'react-router' +import BackIcn from '../../../Icons/BackIcn' +import { __ } from '../../../Utils/i18nwrap' +import SnackMsg from '../../Utilities/SnackMsg' +import { saveIntegConfig } from '../IntegrationHelpers/IntegrationHelpers' +import IntegrationStepThree from '../IntegrationHelpers/IntegrationStepThree' +import PopupMakerAuthorization from './PopupMakerAuthorization' +import { checkMappedFields } from './PopupMakerCommonFunc' +import PopupMakerIntegLayout from './PopupMakerIntegLayout' +import { needsEvent, needsStatus } from './staticData' + +export default function PopupMaker({ formFields, setFlow, flow, allIntegURL }) { + const navigate = useNavigate() + const { formID } = useParams() + const [isLoading, setIsLoading] = useState(false) + const [step, setStep] = useState(1) + const [snack, setSnackbar] = useState({ show: false }) + const [popupMakerConf, setPopupMakerConf] = useState({ + name: 'PopupMaker', + type: 'PopupMaker', + field_map: [{ formField: '', popupMakerField: '' }], + actions: {}, + mainAction: '' + }) + + const nextPage = val => { + setTimeout(() => { + document.getElementById('btcd-settings-wrp').scrollTop = 0 + }, 300) + + if (val === 3) { + if (needsStatus.includes(popupMakerConf.mainAction) && !popupMakerConf?.selectedStatus) { + setSnackbar({ + show: true, + msg: __('Please select a status to continue.', 'bit-integrations') + }) + return + } + + if (needsEvent.includes(popupMakerConf.mainAction) && !popupMakerConf?.selectedEvent) { + setSnackbar({ + show: true, + msg: __('Please select an event to continue.', 'bit-integrations') + }) + return + } + + if (!checkMappedFields(popupMakerConf)) { + setSnackbar({ + show: true, + msg: __('Please map all required fields to continue.', 'bit-integrations') + }) + return + } + + if (popupMakerConf.name !== '' && popupMakerConf.field_map.length > 0) { + setStep(val) + } + } else { + setStep(val) + } + } + + return ( +
+ +
+ + {/* STEP 1 */} + + + {/* STEP 2 */} +
+ +
+
+
+ +
+ + {/* STEP 3 */} + + saveIntegConfig(flow, setFlow, allIntegURL, popupMakerConf, navigate, '', '', setIsLoading) + } + isLoading={isLoading} + dataConf={popupMakerConf} + setDataConf={setPopupMakerConf} + formFields={formFields} + /> +
+ ) +} diff --git a/frontend/src/components/AllIntegrations/PopupMaker/PopupMakerActions.jsx b/frontend/src/components/AllIntegrations/PopupMaker/PopupMakerActions.jsx new file mode 100644 index 000000000..397f2c827 --- /dev/null +++ b/frontend/src/components/AllIntegrations/PopupMaker/PopupMakerActions.jsx @@ -0,0 +1,156 @@ +/* eslint-disable no-param-reassign */ + +import { useState } from 'react' +import { create } from 'mutative' +import MultiSelect from 'react-multiple-select-dropdown-lite' +import { __ } from '../../../Utils/i18nwrap' +import ConfirmModal from '../../Utilities/ConfirmModal' +import TableCheckBox from '../../Utilities/TableCheckBox' +import 'react-multiple-select-dropdown-lite/dist/index.css' +import { + animationOptions, + consentOptions, + forceDeleteOptions, + needsPopup, + needsTheme, + sizeOptions, + statusOptions +} from './staticData' + +export default function PopupMakerActions({ popupMakerConf, setPopupMakerConf }) { + const [actionMdl, setActionMdl] = useState({ show: false, action: () => {} }) + + const actionHandler = type => setActionMdl({ show: type }) + + const clsActionMdl = () => { + setActionMdl({ show: false }) + } + + const setAction = (val, name) => { + setPopupMakerConf(prevConf => + create(prevConf, draftConf => { + if (!draftConf.utilities) { + draftConf.utilities = {} + } + draftConf.utilities[name] = val + }) + ) + } + + const renderActionModal = (type, title, options, valueName) => ( + +
+
{title}
+
+ setAction(val, valueName)} + /> +
+ + ) + + const isPopupWrite = needsTheme.includes(popupMakerConf?.mainAction) + const isSubscriberWrite = needsPopup.includes(popupMakerConf?.mainAction) + + return ( +
+ {isPopupWrite && ( + <> + actionHandler('status')} + className="wdt-200 mt-4 mr-2" + value="status" + title={__('Popup Status', 'bit-integrations')} + subTitle={__('Set the popup status', 'bit-integrations')} + /> + + actionHandler('size')} + className="wdt-200 mt-4 mr-2" + value="size" + title={__('Size', 'bit-integrations')} + subTitle={__('Set the popup size', 'bit-integrations')} + /> + + actionHandler('animation_type')} + className="wdt-200 mt-4 mr-2" + value="animation_type" + title={__('Animation Type', 'bit-integrations')} + subTitle={__('Set the popup animation', 'bit-integrations')} + /> + + {renderActionModal( + 'status', + __('Popup Status', 'bit-integrations'), + statusOptions, + 'selected_status' + )} + {renderActionModal('size', __('Size', 'bit-integrations'), sizeOptions, 'selected_size')} + {renderActionModal( + 'animation_type', + __('Animation Type', 'bit-integrations'), + animationOptions, + 'selected_animation_type' + )} + + )} + + {popupMakerConf?.mainAction === 'delete_popup' && ( + <> + actionHandler('force_delete')} + className="wdt-200 mt-4 mr-2" + value="force_delete" + title={__('Force Delete', 'bit-integrations')} + subTitle={__('Delete permanently instead of trashing', 'bit-integrations')} + /> + + {renderActionModal( + 'force_delete', + __('Force Delete', 'bit-integrations'), + forceDeleteOptions, + 'selected_force_delete' + )} + + )} + + {isSubscriberWrite && ( + <> + actionHandler('consent')} + className="wdt-200 mt-4 mr-2" + value="consent" + title={__('Consent', 'bit-integrations')} + subTitle={__('Set the subscriber consent', 'bit-integrations')} + /> + + {renderActionModal( + 'consent', + __('Consent', 'bit-integrations'), + consentOptions, + 'selected_consent' + )} + + )} +
+ ) +} diff --git a/frontend/src/components/AllIntegrations/PopupMaker/PopupMakerAuthorization.jsx b/frontend/src/components/AllIntegrations/PopupMaker/PopupMakerAuthorization.jsx new file mode 100644 index 000000000..f9ab0cc86 --- /dev/null +++ b/frontend/src/components/AllIntegrations/PopupMaker/PopupMakerAuthorization.jsx @@ -0,0 +1,36 @@ +import { useCallback } from 'react' +import { AUTH_TYPES } from '../../../Utils/connectionAuth' +import { __ } from '../../../Utils/i18nwrap' +import tutorialLinks from '../../../Utils/StaticData/tutorialLinks' +import Authorization from '../../Connections/Authorization' + +export default function PopupMakerAuthorization({ + popupMakerConf, + setPopupMakerConf, + step, + nextPage, + isInfo +}) { + const setStep = useCallback(value => nextPage(value), [nextPage]) + return ( + + ) +} diff --git a/frontend/src/components/AllIntegrations/PopupMaker/PopupMakerCommonFunc.js b/frontend/src/components/AllIntegrations/PopupMaker/PopupMakerCommonFunc.js new file mode 100644 index 000000000..3ceb1782b --- /dev/null +++ b/frontend/src/components/AllIntegrations/PopupMaker/PopupMakerCommonFunc.js @@ -0,0 +1,81 @@ +import { create } from 'mutative' +import toast from 'react-hot-toast' +import bitsFetch from '../../../Utils/bitsFetch' +import { __ } from '../../../Utils/i18nwrap' + +export const handleInput = (e, popupMakerConf, setPopupMakerConf) => { + const { name, value } = e.target + + setPopupMakerConf(prevConf => + create(prevConf, draftConf => { + draftConf[name] = value + }) + ) +} + +export const refreshPopupMakerPopups = (setPopupMakerConf, setIsLoading) => { + setIsLoading(true) + bitsFetch(null, 'refresh_popup_maker_popups') + .then(result => { + if (result && result?.success && result?.data?.popups) { + setPopupMakerConf(prevConf => + create(prevConf, draftConf => { + draftConf.allPopups = result.data.popups + }) + ) + + setIsLoading(false) + toast.success(__('All popups fetched successfully', 'bit-integrations')) + return + } + setIsLoading(false) + toast.error(__('Popup Maker popups fetch failed. Please try again', 'bit-integrations')) + }) + .catch(() => setIsLoading(false)) +} + +export const refreshPopupMakerThemes = (setPopupMakerConf, setIsLoading) => { + setIsLoading(true) + bitsFetch(null, 'refresh_popup_maker_themes') + .then(result => { + if (result && result?.success && result?.data?.themes) { + setPopupMakerConf(prevConf => + create(prevConf, draftConf => { + draftConf.allThemes = result.data.themes + }) + ) + + setIsLoading(false) + toast.success(__('All popup themes fetched successfully', 'bit-integrations')) + return + } + setIsLoading(false) + toast.error(__('Popup Maker themes fetch failed. Please try again', 'bit-integrations')) + }) + .catch(() => setIsLoading(false)) +} + +export const checkMappedFields = popupMakerConf => { + const mappedFields = popupMakerConf?.field_map + ? popupMakerConf.field_map.filter( + mappedField => + !mappedField.formField || + !mappedField.popupMakerField || + (mappedField.formField === 'custom' && !mappedField.customValue) + ) + : [] + if (mappedFields.length > 0) { + return false + } + return true +} + +export const generateMappedField = fields => { + const requiredFlds = fields.filter(fld => fld.required === true) + return requiredFlds.length > 0 + ? requiredFlds.map(field => ({ + formField: '', + popupMakerField: field.key + })) + : [{ formField: '', popupMakerField: '' }] +} diff --git a/frontend/src/components/AllIntegrations/PopupMaker/PopupMakerFieldMap.jsx b/frontend/src/components/AllIntegrations/PopupMaker/PopupMakerFieldMap.jsx new file mode 100644 index 000000000..bffd46985 --- /dev/null +++ b/frontend/src/components/AllIntegrations/PopupMaker/PopupMakerFieldMap.jsx @@ -0,0 +1,104 @@ +import { useRecoilValue } from 'recoil' +import { $appConfigState } from '../../../GlobalStates' +import { __, sprintf } from '../../../Utils/i18nwrap' +import { SmartTagField } from '../../../Utils/StaticData/SmartTagField' +import TagifyInput from '../../Utilities/TagifyInput' +import { + addFieldMap, + delFieldMap, + handleCustomValue, + handleFieldMapping +} from '../GlobalIntegrationHelper' + +export default function PopupMakerFieldMap({ i, formFields, field, popupMakerConf, setPopupMakerConf }) { + const btcbi = useRecoilValue($appConfigState) + const { isPro } = btcbi + + const requiredFlds = popupMakerConf?.popupMakerFields?.filter(fld => fld.required === true) || [] + const nonRequiredFlds = popupMakerConf?.popupMakerFields?.filter(fld => fld.required === false) || [] + + return ( +
+
+
+ + + {field.formField === 'custom' && ( + handleCustomValue(e, i, popupMakerConf, setPopupMakerConf)} + label={__('Custom Value', 'bit-integrations')} + className="mr-2" + type="text" + value={field.customValue} + placeholder={__('Custom Value', 'bit-integrations')} + formFields={formFields} + /> + )} + + +
+ {i >= requiredFlds.length && ( + <> + + + + )} +
+
+ ) +} diff --git a/frontend/src/components/AllIntegrations/PopupMaker/PopupMakerIntegLayout.jsx b/frontend/src/components/AllIntegrations/PopupMaker/PopupMakerIntegLayout.jsx new file mode 100644 index 000000000..30047517e --- /dev/null +++ b/frontend/src/components/AllIntegrations/PopupMaker/PopupMakerIntegLayout.jsx @@ -0,0 +1,278 @@ +import { create } from 'mutative' +import MultiSelect from 'react-multiple-select-dropdown-lite' +import { useRecoilValue } from 'recoil' +import { $appConfigState } from '../../../GlobalStates' +import { __ } from '../../../Utils/i18nwrap' +import Loader from '../../Loaders/Loader' +import { checkIsPro, getProLabel } from '../../Utilities/ProUtilHelpers' +import { addFieldMap } from '../IntegrationHelpers/IntegrationHelpers' +import PopupMakerActions from './PopupMakerActions' +import { + generateMappedField, + refreshPopupMakerPopups, + refreshPopupMakerThemes +} from './PopupMakerCommonFunc' +import PopupMakerFieldMap from './PopupMakerFieldMap' +import { + changeStatusOptions, + eventOptions, + hasUtilities, + modules, + needsEvent, + needsPopup, + needsStatus, + needsTheme, + PopupFields, + PopupIdField, + PopupUpdateFields, + SubscriberFields, + SubscriberIdField, + SubscriberUpdateFields +} from './staticData' + +export default function PopupMakerIntegLayout({ + formID, + formFields, + popupMakerConf, + setPopupMakerConf, + isLoading, + setIsLoading, + setSnackbar +}) { + const btcbi = useRecoilValue($appConfigState) + const { isPro } = btcbi + + const setField = (key, val) => + setPopupMakerConf(prevConf => + create(prevConf, draftConf => { + draftConf[key] = val + }) + ) + + const handleMainAction = value => { + setPopupMakerConf(prevConf => + create(prevConf, draftConf => { + draftConf.mainAction = value + + switch (value) { + case 'create_popup': + draftConf.popupMakerFields = PopupFields + break + case 'update_popup': + draftConf.popupMakerFields = PopupUpdateFields + break + case 'delete_popup': + case 'change_popup_status': + case 'reset_popup_counts': + case 'track_popup_event': + draftConf.popupMakerFields = PopupIdField + break + case 'create_subscriber': + draftConf.popupMakerFields = SubscriberFields + break + case 'update_subscriber': + draftConf.popupMakerFields = SubscriberUpdateFields + break + case 'delete_subscriber': + draftConf.popupMakerFields = SubscriberIdField + break + default: + draftConf.popupMakerFields = [] + } + + draftConf.field_map = generateMappedField(draftConf.popupMakerFields) + }) + ) + + if (needsTheme.includes(value) && !popupMakerConf?.allThemes?.length) { + refreshPopupMakerThemes(setPopupMakerConf, setIsLoading) + } + + if (needsPopup.includes(value) && !popupMakerConf?.allPopups?.length) { + refreshPopupMakerPopups(setPopupMakerConf, setIsLoading) + } + } + + return ( + <> +
+
+ {__('Action:', 'bit-integrations')} + handleMainAction(value)} + options={modules?.map(action => ({ + label: checkIsPro(isPro, action.is_pro) ? action.label : getProLabel(action.label), + value: action.name, + disabled: !checkIsPro(isPro, action.is_pro) + }))} + singleSelect + closeOnSelect + /> +
+ + {needsStatus.includes(popupMakerConf?.mainAction) && ( + <> +
+
+ {__('Status:', 'bit-integrations')} + setField('selectedStatus', val)} + singleSelect + closeOnSelect + /> +
+ + )} + + {needsEvent.includes(popupMakerConf?.mainAction) && ( + <> +
+
+ {__('Event:', 'bit-integrations')} + setField('selectedEvent', val)} + singleSelect + closeOnSelect + /> +
+ + )} + + {needsTheme.includes(popupMakerConf?.mainAction) && ( + <> +
+
+ {__('Popup Theme:', 'bit-integrations')} + ({ + label: theme.title, + value: theme.id.toString() + })) + } + onChange={val => setField('selectedTheme', val)} + singleSelect + closeOnSelect + /> + +
+ + )} + + {needsPopup.includes(popupMakerConf?.mainAction) && ( + <> +
+
+ {__('Popup:', 'bit-integrations')} + ({ + label: popup.title, + value: popup.id.toString() + })) + } + onChange={val => setField('selectedPopup', val)} + singleSelect + closeOnSelect + /> + +
+ + )} + + {isLoading && ( + + )} + + {popupMakerConf?.mainAction && popupMakerConf.popupMakerFields && ( +
+ {__('Map Fields', 'bit-integrations')} +
+
+
+ {__('Form Fields', 'bit-integrations')} +
+
+ {__('Popup Maker Fields', 'bit-integrations')} +
+
+ + {popupMakerConf?.field_map?.map((itm, i) => ( + + ))} +
+ +
+
+
+ )} + + {popupMakerConf?.mainAction && + popupMakerConf.popupMakerFields && + hasUtilities.includes(popupMakerConf?.mainAction) && ( +
+ {__('Utilities', 'bit-integrations')} +
+ +
+ )} + + ) +} diff --git a/frontend/src/components/AllIntegrations/PopupMaker/staticData.js b/frontend/src/components/AllIntegrations/PopupMaker/staticData.js new file mode 100644 index 000000000..60e39b672 --- /dev/null +++ b/frontend/src/components/AllIntegrations/PopupMaker/staticData.js @@ -0,0 +1,121 @@ +import { __ } from '../../../Utils/i18nwrap' + +export const modules = [ + { name: 'create_popup', label: __('Create Popup', 'bit-integrations'), is_pro: true }, + { name: 'update_popup', label: __('Update Popup', 'bit-integrations'), is_pro: true }, + { name: 'delete_popup', label: __('Delete Popup', 'bit-integrations'), is_pro: true }, + { + name: 'change_popup_status', + label: __('Change Popup Status', 'bit-integrations'), + is_pro: true + }, + { + name: 'reset_popup_counts', + label: __('Reset Popup Counts', 'bit-integrations'), + is_pro: true + }, + { name: 'track_popup_event', label: __('Track Popup Event', 'bit-integrations'), is_pro: true }, + { name: 'create_subscriber', label: __('Create Subscriber', 'bit-integrations'), is_pro: true }, + { name: 'update_subscriber', label: __('Update Subscriber', 'bit-integrations'), is_pro: true }, + { name: 'delete_subscriber', label: __('Delete Subscriber', 'bit-integrations'), is_pro: true } +] + +export const PopupFields = [ + { key: 'title', label: __('Popup Name', 'bit-integrations'), required: true }, + { key: 'popup_title', label: __('Popup Title', 'bit-integrations'), required: false }, + { key: 'content', label: __('Content', 'bit-integrations'), required: false } +] + +export const PopupUpdateFields = [ + { key: 'popup_id', label: __('Popup ID', 'bit-integrations'), required: true }, + { key: 'title', label: __('Popup Name', 'bit-integrations'), required: false }, + { key: 'popup_title', label: __('Popup Title', 'bit-integrations'), required: false }, + { key: 'content', label: __('Content', 'bit-integrations'), required: false } +] + +export const PopupIdField = [ + { key: 'popup_id', label: __('Popup ID', 'bit-integrations'), required: true } +] + +export const SubscriberFields = [ + { key: 'email', label: __('Email', 'bit-integrations'), required: true }, + { key: 'name', label: __('Name', 'bit-integrations'), required: false }, + { key: 'fname', label: __('First Name', 'bit-integrations'), required: false }, + { key: 'lname', label: __('Last Name', 'bit-integrations'), required: false }, + { key: 'consent_args', label: __('Consent Args', 'bit-integrations'), required: false } +] + +export const SubscriberUpdateFields = [ + { key: 'subscriber_id', label: __('Subscriber ID', 'bit-integrations'), required: true }, + { key: 'email', label: __('Email', 'bit-integrations'), required: false }, + { key: 'name', label: __('Name', 'bit-integrations'), required: false }, + { key: 'fname', label: __('First Name', 'bit-integrations'), required: false }, + { key: 'lname', label: __('Last Name', 'bit-integrations'), required: false } +] + +export const SubscriberIdField = [ + { key: 'subscriber_id', label: __('Subscriber ID', 'bit-integrations'), required: true } +] + +export const statusOptions = [ + { label: __('Publish', 'bit-integrations'), value: 'publish' }, + { label: __('Draft', 'bit-integrations'), value: 'draft' }, + { label: __('Pending', 'bit-integrations'), value: 'pending' }, + { label: __('Private', 'bit-integrations'), value: 'private' } +] + +export const changeStatusOptions = [ + ...statusOptions, + { label: __('Trash', 'bit-integrations'), value: 'trash' } +] + +export const eventOptions = [ + { label: __('Open', 'bit-integrations'), value: 'open' }, + { label: __('Conversion', 'bit-integrations'), value: 'conversion' } +] + +export const sizeOptions = [ + { label: __('Nano - 10%', 'bit-integrations'), value: 'nano' }, + { label: __('Micro - 20%', 'bit-integrations'), value: 'micro' }, + { label: __('Tiny - 30%', 'bit-integrations'), value: 'tiny' }, + { label: __('Small - 40%', 'bit-integrations'), value: 'small' }, + { label: __('Medium - 60%', 'bit-integrations'), value: 'medium' }, + { label: __('Normal - 70%', 'bit-integrations'), value: 'normal' }, + { label: __('Large - 80%', 'bit-integrations'), value: 'large' }, + { label: __('X Large - 95%', 'bit-integrations'), value: 'xlarge' }, + { label: __('Auto', 'bit-integrations'), value: 'auto' }, + { label: __('Custom', 'bit-integrations'), value: 'custom' } +] + +export const animationOptions = [ + { label: __('None', 'bit-integrations'), value: 'none' }, + { label: __('Slide', 'bit-integrations'), value: 'slide' }, + { label: __('Fade', 'bit-integrations'), value: 'fade' }, + { label: __('Fade and Slide', 'bit-integrations'), value: 'fadeAndSlide' } +] + +export const consentOptions = [ + { label: __('Yes', 'bit-integrations'), value: 'yes' }, + { label: __('No', 'bit-integrations'), value: 'no' } +] + +export const forceDeleteOptions = [ + { label: __('Yes, delete permanently', 'bit-integrations'), value: 'yes' }, + { label: __('No, move to trash', 'bit-integrations'), value: 'no' } +] + +export const needsTheme = ['create_popup', 'update_popup'] + +export const needsPopup = ['create_subscriber', 'update_subscriber'] + +export const needsStatus = ['change_popup_status'] + +export const needsEvent = ['track_popup_event'] + +export const hasUtilities = [ + 'create_popup', + 'update_popup', + 'delete_popup', + 'create_subscriber', + 'update_subscriber' +] diff --git a/frontend/src/components/Flow/New/SelectAction.jsx b/frontend/src/components/Flow/New/SelectAction.jsx index b42656e4b..0da46d53c 100644 --- a/frontend/src/components/Flow/New/SelectAction.jsx +++ b/frontend/src/components/Flow/New/SelectAction.jsx @@ -188,6 +188,7 @@ export default function SelectAction() { { type: 'SureContact', is_pro: false }, { type: 'BrilliantDirectories', name: 'Brilliant Directories', logo: 'brilliantDirectories', is_pro: false }, { type: 'FluentCart', is_pro: true }, + { type: 'PopupMaker', name: 'Popup Maker', logo: 'popupMaker', is_pro: true }, { type: 'FluentPlayer', is_pro: true }, { type: 'BitCrm', name: 'Bit CRM', logo: 'bitCrm', is_pro: false }, { type: 'MoreConvert Wishlist', logo: 'moreConvertWishlist', is_pro: true },