From 6dfe4805e4fb375e64041bb8fdde1fb34e2f86ff Mon Sep 17 00:00:00 2001
From: Rishad Alam <101513331+RishadAlam@users.noreply.github.com>
Date: Fri, 1 May 2026 18:15:09 +0600
Subject: [PATCH 1/3] feat: Add BookingPress integration
- Implemented BookingPress integration in the frontend, including components for editing, creating, and authorizing the integration.
- Added backend functionality for BookingPress actions, including authorization and record handling.
- Introduced field mapping for BookingPress actions, allowing users to map form fields to BookingPress fields.
- Created static data for BookingPress actions and fields.
- Added a new image asset for BookingPress integration.
---
.../BookingPress/BookingPressController.php | 37 ++++++
.../Actions/BookingPress/RecordApiHelper.php | 118 +++++++++++++++++
backend/Actions/BookingPress/Routes.php | 10 ++
backend/Core/Util/AllTriggersName.php | 1 +
.../Utils/StaticData/webhookIntegrations.js | 1 +
.../BookingPress/BookingPress.jsx | 104 +++++++++++++++
.../BookingPressAuthorization.jsx | 111 ++++++++++++++++
.../BookingPress/BookingPressCommonFunc.js | 32 +++++
.../BookingPress/BookingPressFieldMap.jsx | 110 ++++++++++++++++
.../BookingPress/BookingPressIntegLayout.jsx | 120 ++++++++++++++++++
.../BookingPress/EditBookingPress.jsx | 76 +++++++++++
.../BookingPress/staticData.js | 38 ++++++
.../components/AllIntegrations/EditInteg.jsx | 3 +
.../components/AllIntegrations/IntegInfo.jsx | 3 +
.../components/AllIntegrations/NewInteg.jsx | 10 ++
.../src/components/Flow/New/SelectAction.jsx | 1 +
.../src/resource/img/integ/bookingPress.webp | Bin 0 -> 4154 bytes
17 files changed, 775 insertions(+)
create mode 100644 backend/Actions/BookingPress/BookingPressController.php
create mode 100644 backend/Actions/BookingPress/RecordApiHelper.php
create mode 100644 backend/Actions/BookingPress/Routes.php
create mode 100644 frontend/src/components/AllIntegrations/BookingPress/BookingPress.jsx
create mode 100644 frontend/src/components/AllIntegrations/BookingPress/BookingPressAuthorization.jsx
create mode 100644 frontend/src/components/AllIntegrations/BookingPress/BookingPressCommonFunc.js
create mode 100644 frontend/src/components/AllIntegrations/BookingPress/BookingPressFieldMap.jsx
create mode 100644 frontend/src/components/AllIntegrations/BookingPress/BookingPressIntegLayout.jsx
create mode 100644 frontend/src/components/AllIntegrations/BookingPress/EditBookingPress.jsx
create mode 100644 frontend/src/components/AllIntegrations/BookingPress/staticData.js
create mode 100644 frontend/src/resource/img/integ/bookingPress.webp
diff --git a/backend/Actions/BookingPress/BookingPressController.php b/backend/Actions/BookingPress/BookingPressController.php
new file mode 100644
index 000000000..6ceef1895
--- /dev/null
+++ b/backend/Actions/BookingPress/BookingPressController.php
@@ -0,0 +1,37 @@
+flow_details;
+ $integId = $integrationData->id;
+ $fieldMap = $integrationDetails->field_map;
+
+ if (empty($fieldMap)) {
+ return new WP_Error('field_map_empty', __('Field map is empty', 'bit-integrations'));
+ }
+
+ return (new RecordApiHelper($integrationDetails, $integId))->execute($fieldValues, $fieldMap);
+ }
+}
diff --git a/backend/Actions/BookingPress/RecordApiHelper.php b/backend/Actions/BookingPress/RecordApiHelper.php
new file mode 100644
index 000000000..3db344e61
--- /dev/null
+++ b/backend/Actions/BookingPress/RecordApiHelper.php
@@ -0,0 +1,118 @@
+_integrationDetails = $integrationDetails;
+ $this->_integrationID = $integId;
+ }
+
+ public function execute($fieldValues, $fieldMap)
+ {
+ if (!class_exists('BookingPress')) {
+ return [
+ 'success' => false,
+ 'message' => __('BookingPress is not installed or activated', 'bit-integrations'),
+ ];
+ }
+
+ $fieldData = static::generateReqDataFromFieldMap($fieldMap, $fieldValues);
+ $mainAction = $this->_integrationDetails->mainAction ?? 'cancel_appointment';
+
+ $defaultResponse = [
+ 'success' => false,
+ // translators: %s: Plugin name
+ 'message' => wp_sprintf(__('%s plugin is not installed or activated', 'bit-integrations'), 'Bit Integrations Pro'),
+ ];
+
+ switch ($mainAction) {
+ case 'cancel_appointment':
+ $response = Hooks::apply(Config::withPrefix('bookingpress_cancel_appointment'), $defaultResponse, $fieldData);
+ $type = 'appointment';
+ $actionType = 'cancel_appointment';
+
+ break;
+
+ case 'update_appointment_status':
+ $response = Hooks::apply(Config::withPrefix('bookingpress_update_appointment_status'), $defaultResponse, $fieldData);
+ $type = 'appointment';
+ $actionType = 'update_appointment_status';
+
+ break;
+
+ case 'create_customer':
+ $response = Hooks::apply(Config::withPrefix('bookingpress_create_customer'), $defaultResponse, $fieldData);
+ $type = 'customer';
+ $actionType = 'create_customer';
+
+ break;
+
+ case 'update_customer':
+ $response = Hooks::apply(Config::withPrefix('bookingpress_update_customer'), $defaultResponse, $fieldData);
+ $type = 'customer';
+ $actionType = 'update_customer';
+
+ break;
+
+ case 'delete_appointment':
+ $response = Hooks::apply(Config::withPrefix('bookingpress_delete_appointment'), $defaultResponse, $fieldData);
+ $type = 'appointment';
+ $actionType = 'delete_appointment';
+
+ break;
+
+ case 'delete_customer':
+ $response = Hooks::apply(Config::withPrefix('bookingpress_delete_customer'), $defaultResponse, $fieldData);
+ $type = 'customer';
+ $actionType = 'delete_customer';
+
+ break;
+
+ default:
+ $response = [
+ 'success' => false,
+ 'message' => __('Invalid action', 'bit-integrations'),
+ ];
+ $type = 'BookingPress';
+ $actionType = 'unknown';
+
+ break;
+ }
+
+ $responseType = isset($response['success']) && $response['success'] ? 'success' : 'error';
+ LogHandler::save($this->_integrationID, ['type' => $type, 'type_name' => $actionType], $responseType, $response);
+
+ return $response;
+ }
+
+ private function generateReqDataFromFieldMap($fieldMap, $fieldValues)
+ {
+ $dataFinal = [];
+ foreach ($fieldMap as $item) {
+ if (empty($item->formField) || empty($item->bookingPressField)) {
+ continue;
+ }
+
+ $triggerValue = $item->formField;
+ $actionValue = $item->bookingPressField;
+
+ $dataFinal[$actionValue] = $triggerValue === 'custom' && isset($item->customValue)
+ ? Common::replaceFieldWithValue($item->customValue, $fieldValues)
+ : $fieldValues[$triggerValue] ?? '';
+ }
+
+ return $dataFinal;
+ }
+}
diff --git a/backend/Actions/BookingPress/Routes.php b/backend/Actions/BookingPress/Routes.php
new file mode 100644
index 000000000..e4e17c50e
--- /dev/null
+++ b/backend/Actions/BookingPress/Routes.php
@@ -0,0 +1,10 @@
+ ['name' => 'Buddypress', 'isPro' => true, 'is_active' => false],
'BbPress' => ['name' => 'bbPress', 'isPro' => true, 'is_active' => false],
'BookingCalendarContactForm' => ['name' => 'Booking Calendar Contact Form', 'isPro' => true, 'is_active' => false],
+ 'BookingPress' => ['name' => 'BookingPress', 'isPro' => true, 'is_active' => false],
'CalculatedFieldsForm' => ['name' => 'Calculated Fields Form Pro', 'isPro' => true, 'is_active' => false],
'CartFlow' => ['name' => 'CartFlow', 'isPro' => true, 'is_active' => false],
'CustomTrigger' => ['name' => 'Custom Trigger', 'isPro' => true, 'is_active' => false],
diff --git a/frontend/src/Utils/StaticData/webhookIntegrations.js b/frontend/src/Utils/StaticData/webhookIntegrations.js
index 69b3101d6..ff9562767 100644
--- a/frontend/src/Utils/StaticData/webhookIntegrations.js
+++ b/frontend/src/Utils/StaticData/webhookIntegrations.js
@@ -94,6 +94,7 @@ export const customFormIntegrations = [
'WeDocs',
'UserRegistrationMembership',
'UltimateAffiliatePro',
+ 'BookingPress',
]
export const actionHookIntegrations = ['ActionHook']
diff --git a/frontend/src/components/AllIntegrations/BookingPress/BookingPress.jsx b/frontend/src/components/AllIntegrations/BookingPress/BookingPress.jsx
new file mode 100644
index 000000000..1f63c4a45
--- /dev/null
+++ b/frontend/src/components/AllIntegrations/BookingPress/BookingPress.jsx
@@ -0,0 +1,104 @@
+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 BookingPressAuthorization from './BookingPressAuthorization'
+import { checkMappedFields } from './BookingPressCommonFunc'
+import BookingPressIntegLayout from './BookingPressIntegLayout'
+
+export default function BookingPress({ 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 [bookingPressConf, setBookingPressConf] = useState({
+ name: 'BookingPress',
+ type: 'BookingPress',
+ field_map: [{ formField: '', bookingPressField: '' }],
+ mainAction: '',
+ })
+
+ const nextPage = val => {
+ setTimeout(() => {
+ document.getElementById('btcd-settings-wrp').scrollTop = 0
+ }, 300)
+
+ if (val === 3) {
+ if (!checkMappedFields(bookingPressConf)) {
+ setSnackbar({
+ show: true,
+ msg: __('Please map all required fields to continue.', 'bit-integrations'),
+ })
+ return
+ }
+
+ if (bookingPressConf.name !== '' && bookingPressConf.field_map.length > 0) {
+ setStep(val)
+ }
+ } else {
+ setStep(val)
+ }
+ }
+
+ return (
+
+
+
+
+ {/* STEP 1 */}
+
+
+ {/* STEP 2 */}
+
+
+
+
+
+
+
+
+ {/* STEP 3 */}
+
+ saveIntegConfig(flow, setFlow, allIntegURL, bookingPressConf, navigate, '', '', setIsLoading)
+ }
+ isLoading={isLoading}
+ />
+
+ )
+}
diff --git a/frontend/src/components/AllIntegrations/BookingPress/BookingPressAuthorization.jsx b/frontend/src/components/AllIntegrations/BookingPress/BookingPressAuthorization.jsx
new file mode 100644
index 000000000..059530a71
--- /dev/null
+++ b/frontend/src/components/AllIntegrations/BookingPress/BookingPressAuthorization.jsx
@@ -0,0 +1,111 @@
+import { useState } from 'react'
+import BackIcn from '../../../Icons/BackIcn'
+import bitsFetch from '../../../Utils/bitsFetch'
+import { __ } from '../../../Utils/i18nwrap'
+import LoaderSm from '../../Loaders/LoaderSm'
+import TutorialLink from '../../Utilities/TutorialLink'
+
+export default function BookingPressAuthorization({
+ bookingPressConf,
+ setBookingPressConf,
+ step,
+ nextPage,
+ isLoading,
+ setIsLoading,
+ setSnackbar
+}) {
+ const [isAuthorized, setIsAuthorized] = useState(false)
+ const [showAuthMsg, setShowAuthMsg] = useState(false)
+
+ const authorizeHandler = () => {
+ setIsLoading('auth')
+ bitsFetch({}, 'bookingpress_authorize').then(result => {
+ if (result?.success) {
+ setIsAuthorized(true)
+ setSnackbar({
+ show: true,
+ msg: __('Connected with BookingPress Successfully', 'bit-integrations'),
+ })
+ }
+ setIsLoading(false)
+ setShowAuthMsg(true)
+ })
+ }
+
+ const handleInput = e => {
+ const newConf = { ...bookingPressConf }
+ newConf[e.target.name] = e.target.value
+ setBookingPressConf(newConf)
+ }
+
+ return (
+
+
+
+ {__('Integration Name:', 'bit-integrations')}
+
+
+
+ {isLoading === 'auth' && (
+
+
+ {__('Checking if BookingPress is authorized!!!', 'bit-integrations')}
+
+ )}
+
+ {showAuthMsg && !isAuthorized && !isLoading && (
+
+
+
+ ✕
+
+
+ {__('BookingPress is not activated or not installed', 'bit-integrations')}
+
+
+
+ )}
+
+ {showAuthMsg && isAuthorized && !isLoading && (
+
+
+ ✓
+
+
{__('BookingPress is activated', 'bit-integrations')}
+
+ )}
+
+
+
+
+
+ )
+}
diff --git a/frontend/src/components/AllIntegrations/BookingPress/BookingPressCommonFunc.js b/frontend/src/components/AllIntegrations/BookingPress/BookingPressCommonFunc.js
new file mode 100644
index 000000000..4214ffe32
--- /dev/null
+++ b/frontend/src/components/AllIntegrations/BookingPress/BookingPressCommonFunc.js
@@ -0,0 +1,32 @@
+import { create } from 'mutative'
+
+export const handleInput = (e, bookingPressConf, setBookingPressConf) => {
+ const { name, value } = e.target
+ setBookingPressConf(prevConf =>
+ create(prevConf, draftConf => {
+ draftConf[name] = value
+ })
+ )
+}
+
+export const checkMappedFields = bookingPressConf => {
+ const mappedFields = bookingPressConf?.field_map
+ ? bookingPressConf.field_map.filter(
+ mappedField =>
+ !mappedField.formField ||
+ !mappedField.bookingPressField ||
+ (mappedField.formField === 'custom' && !mappedField.customValue)
+ )
+ : []
+ return mappedFields.length === 0
+}
+
+export const generateMappedField = fields => {
+ const requiredFlds = fields.filter(fld => fld.required === true)
+ return requiredFlds.length > 0
+ ? requiredFlds.map(field => ({
+ formField: '',
+ bookingPressField: field.key,
+ }))
+ : [{ formField: '', bookingPressField: '' }]
+}
diff --git a/frontend/src/components/AllIntegrations/BookingPress/BookingPressFieldMap.jsx b/frontend/src/components/AllIntegrations/BookingPress/BookingPressFieldMap.jsx
new file mode 100644
index 000000000..67f2a59a9
--- /dev/null
+++ b/frontend/src/components/AllIntegrations/BookingPress/BookingPressFieldMap.jsx
@@ -0,0 +1,110 @@
+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 BookingPressFieldMap({
+ i,
+ formFields,
+ field,
+ bookingPressConf,
+ setBookingPressConf,
+}) {
+ const btcbi = useRecoilValue($appConfigState)
+ const { isPro } = btcbi
+
+ const requiredFlds = bookingPressConf?.bookingPressFields?.filter(fld => fld.required === true) || []
+ const nonRequiredFlds = bookingPressConf?.bookingPressFields?.filter(fld => fld.required === false) || []
+
+ return (
+
+
+
+
+
+ {field.formField === 'custom' && (
+ handleCustomValue(e, i, bookingPressConf, setBookingPressConf)}
+ 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/BookingPress/BookingPressIntegLayout.jsx b/frontend/src/components/AllIntegrations/BookingPress/BookingPressIntegLayout.jsx
new file mode 100644
index 000000000..96dd94170
--- /dev/null
+++ b/frontend/src/components/AllIntegrations/BookingPress/BookingPressIntegLayout.jsx
@@ -0,0 +1,120 @@
+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 { checkIsPro, getProLabel } from '../../Utilities/ProUtilHelpers'
+import { addFieldMap } from '../IntegrationHelpers/IntegrationHelpers'
+import { generateMappedField } from './BookingPressCommonFunc'
+import BookingPressFieldMap from './BookingPressFieldMap'
+import {
+ appointmentIdField,
+ CreateCustomerFields,
+ DeleteCustomerFields,
+ modules,
+ UpdateAppointmentStatusFields,
+ UpdateCustomerFields
+} from './staticData'
+
+export default function BookingPressIntegLayout({
+ formID,
+ formFields,
+ bookingPressConf,
+ setBookingPressConf,
+ setSnackbar,
+}) {
+ const btcbi = useRecoilValue($appConfigState)
+ const { isPro } = btcbi
+
+ const handleMainAction = value => {
+ setBookingPressConf(prevConf =>
+ create(prevConf, draftConf => {
+ draftConf.mainAction = value
+
+ switch (value) {
+ case 'cancel_appointment':
+ draftConf.bookingPressFields = appointmentIdField
+ break
+ case 'update_appointment_status':
+ draftConf.bookingPressFields = UpdateAppointmentStatusFields
+ break
+ case 'create_customer':
+ draftConf.bookingPressFields = CreateCustomerFields
+ break
+ case 'update_customer':
+ draftConf.bookingPressFields = UpdateCustomerFields
+ break
+ case 'delete_appointment':
+ draftConf.bookingPressFields = appointmentIdField
+ break
+ case 'delete_customer':
+ draftConf.bookingPressFields = DeleteCustomerFields
+ break
+ default:
+ draftConf.bookingPressFields = []
+ }
+
+ draftConf.field_map = generateMappedField(draftConf.bookingPressFields)
+ })
+ )
+ }
+
+ 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) ? false : true,
+ }))}
+ singleSelect
+ closeOnSelect
+ />
+
+
+ {bookingPressConf?.mainAction && bookingPressConf.bookingPressFields && (
+
+
{__('Map Fields', 'bit-integrations')}
+
+
+
+ {__('Form Fields', 'bit-integrations')}
+
+
+ {__('BookingPress Fields', 'bit-integrations')}
+
+
+
+ {bookingPressConf?.field_map?.map((itm, i) => (
+
+ ))}
+
+
+
+
+
+ )}
+ >
+ )
+}
diff --git a/frontend/src/components/AllIntegrations/BookingPress/EditBookingPress.jsx b/frontend/src/components/AllIntegrations/BookingPress/EditBookingPress.jsx
new file mode 100644
index 000000000..55958b2d3
--- /dev/null
+++ b/frontend/src/components/AllIntegrations/BookingPress/EditBookingPress.jsx
@@ -0,0 +1,76 @@
+import { useState } from 'react'
+import { useNavigate, useParams } from 'react-router'
+import { useRecoilState, useRecoilValue } from 'recoil'
+import { $actionConf, $formFields, $newFlow } from '../../../GlobalStates'
+import { __ } from '../../../Utils/i18nwrap'
+import SnackMsg from '../../Utilities/SnackMsg'
+import { saveActionConf } from '../IntegrationHelpers/IntegrationHelpers'
+import IntegrationStepThree from '../IntegrationHelpers/IntegrationStepThree'
+import SetEditIntegComponents from '../IntegrationHelpers/SetEditIntegComponents'
+import { checkMappedFields, handleInput } from './BookingPressCommonFunc'
+import BookingPressIntegLayout from './BookingPressIntegLayout'
+
+export default function EditBookingPress({ allIntegURL }) {
+ const navigate = useNavigate()
+ const { id, formID } = useParams()
+
+ const [bookingPressConf, setBookingPressConf] = useRecoilState($actionConf)
+ const [flow, setFlow] = useRecoilState($newFlow)
+ const formFields = useRecoilValue($formFields)
+ const [isLoading, setIsLoading] = useState(false)
+ const [snack, setSnackbar] = useState({ show: false })
+
+ return (
+
+
+
+
+ {__('Integration Name:', 'bit-integrations')}
+ handleInput(e, bookingPressConf, setBookingPressConf)}
+ name="name"
+ value={bookingPressConf.name}
+ type="text"
+ placeholder={__('Integration Name...', 'bit-integrations')}
+ />
+
+
+
+
+
+
+
+
+ saveActionConf({
+ flow,
+ setFlow,
+ allIntegURL,
+ conf: bookingPressConf,
+ navigate,
+ id,
+ edit: 1,
+ setIsLoading,
+ setSnackbar,
+ })
+ }
+ disabled={!checkMappedFields(bookingPressConf)}
+ isLoading={isLoading}
+ dataConf={bookingPressConf}
+ setDataConf={setBookingPressConf}
+ formFields={formFields}
+ />
+
+
+ )
+}
diff --git a/frontend/src/components/AllIntegrations/BookingPress/staticData.js b/frontend/src/components/AllIntegrations/BookingPress/staticData.js
new file mode 100644
index 000000000..15d84cdaa
--- /dev/null
+++ b/frontend/src/components/AllIntegrations/BookingPress/staticData.js
@@ -0,0 +1,38 @@
+import { __ } from '../../../Utils/i18nwrap'
+
+export const modules = [
+ { name: 'cancel_appointment', label: __('Cancel Appointment', 'bit-integrations'), is_pro: true },
+ { name: 'update_appointment_status', label: __('Update Appointment Status', 'bit-integrations'), is_pro: true },
+ { name: 'create_customer', label: __('Create Customer', 'bit-integrations'), is_pro: true },
+ { name: 'update_customer', label: __('Update Customer', 'bit-integrations'), is_pro: true },
+ { name: 'delete_appointment', label: __('Delete Appointment', 'bit-integrations'), is_pro: true },
+ { name: 'delete_customer', label: __('Delete Customer', 'bit-integrations'), is_pro: true },
+]
+
+export const appointmentIdField = [
+ { key: 'appointment_id', label: __('Appointment ID', 'bit-integrations'), required: true },
+]
+
+export const UpdateAppointmentStatusFields = [
+ { key: 'appointment_id', label: __('Appointment ID', 'bit-integrations'), required: true },
+ { key: 'status', label: __('Status', 'bit-integrations'), required: true },
+]
+
+export const CreateCustomerFields = [
+ { key: 'first_name', label: __('First Name', 'bit-integrations'), required: true },
+ { key: 'last_name', label: __('Last Name', 'bit-integrations'), required: true },
+ { key: 'email', label: __('Email', 'bit-integrations'), required: true },
+ { key: 'phone', label: __('Phone', 'bit-integrations'), required: false },
+]
+
+export const UpdateCustomerFields = [
+ { key: 'customer_id', label: __('Customer ID', 'bit-integrations'), required: true },
+ { key: 'bookingpress_user_firstname', label: __('First Name', 'bit-integrations'), required: false },
+ { key: 'bookingpress_user_lastname', label: __('Last Name', 'bit-integrations'), required: false },
+ { key: 'bookingpress_user_email', label: __('Email', 'bit-integrations'), required: false },
+ { key: 'bookingpress_user_phone', label: __('Phone', 'bit-integrations'), required: false },
+]
+
+export const DeleteCustomerFields = [
+ { key: 'customer_id', label: __('Customer ID', 'bit-integrations'), required: true },
+]
diff --git a/frontend/src/components/AllIntegrations/EditInteg.jsx b/frontend/src/components/AllIntegrations/EditInteg.jsx
index c4201bb07..f3a0cf09e 100644
--- a/frontend/src/components/AllIntegrations/EditInteg.jsx
+++ b/frontend/src/components/AllIntegrations/EditInteg.jsx
@@ -74,6 +74,7 @@ const EditLearnDash = lazy(() => import('./LearnDash/EditLearnDash'))
const EditRestrictContent = lazy(() => import('./RestrictContent/EditRestrictContent'))
const EditAffiliate = lazy(() => import('./Affiliate/EditAffiliate'))
const EditBuddyBoss = lazy(() => import('./BuddyBoss/EditBuddyBoss'))
+const EditBookingPress = lazy(() => import('./BookingPress/EditBookingPress'))
const EditGoogleContacts = lazy(() => import('./GoogleContacts/EditGoogleContacts'))
const EditKirimEmail = lazy(() => import('./KirimEmail/EditKirimEmail'))
const EditGamiPress = lazy(() => import('./GamiPress/EditGamiPress'))
@@ -395,6 +396,8 @@ const IntegType = memo(({ allIntegURL, flow }) => {
return
case 'BuddyBoss':
return
+ case 'BookingPress':
+ return
case 'GamiPress':
return
case 'Google Contacts':
diff --git a/frontend/src/components/AllIntegrations/IntegInfo.jsx b/frontend/src/components/AllIntegrations/IntegInfo.jsx
index 03de88b5b..04756add1 100644
--- a/frontend/src/components/AllIntegrations/IntegInfo.jsx
+++ b/frontend/src/components/AllIntegrations/IntegInfo.jsx
@@ -175,6 +175,7 @@ const UltimateAffiliateProAuthorization = lazy(
() => import('./UltimateAffiliatePro/UltimateAffiliateProAuthorization')
)
const FluentCartAuthorization = lazy(() => import('./FluentCart/FluentCartAuthorization'))
+const BookingPressAuthorization = lazy(() => import('./BookingPress/BookingPressAuthorization'))
const PeepSoAuthorization = lazy(() => import('./PeepSo/PeepSoAuthorization'))
const NinjaTablesAuthorization = lazy(() => import('./NinjaTables/NinjaTablesAuthorization'))
const WCAffiliateAuthorization = lazy(() => import('./WCAffiliate/WCAffiliateAuthorization'))
@@ -637,6 +638,8 @@ export default function IntegInfo() {
)
case 'FluentCart':
return
+ case 'BookingPress':
+ return
case 'PeepSo':
return
case 'Ninja Tables':
diff --git a/frontend/src/components/AllIntegrations/NewInteg.jsx b/frontend/src/components/AllIntegrations/NewInteg.jsx
index 505955d35..f849fa767 100644
--- a/frontend/src/components/AllIntegrations/NewInteg.jsx
+++ b/frontend/src/components/AllIntegrations/NewInteg.jsx
@@ -75,6 +75,7 @@ const WhatsApp = lazy(() => import('./WhatsApp/WhatsApp'))
const LearnDesh = lazy(() => import('./LearnDash/LearnDash'))
const Affiliate = lazy(() => import('./Affiliate/Affiliate'))
const BuddyBoss = lazy(() => import('./BuddyBoss/BuddyBoss'))
+const BookingPress = lazy(() => import('./BookingPress/BookingPress'))
const GoogleContacts = lazy(() => import('./GoogleContacts/GoogleContacts'))
const KirimEmail = lazy(() => import('./KirimEmail/KirimEmail'))
const Salesforce = lazy(() => import('./Salesforce/Salesforce'))
@@ -767,6 +768,15 @@ export default function NewInteg({ allIntegURL }) {
setFlow={setFlow}
/>
)
+ case 'BookingPress':
+ return (
+
+ )
case 'GamiPress':
return (
@@;wkH2dhdnZ5E>wVHO?0
zO%cBBZQsiFzBl}5T$g!HONv3@U9H+mE)B3>h)KA0*MbbD2T%
zAA&$hQ}7jZ0*nU0NL&OFc>A=Tm#zi~?cD_amKaQw2CLQxmxq~^3YJRvTw+8k(-$ke
zE|@dZ;~D&()^}Xp!}YZF!FLGDtMg?2bl#Mz?_!+jJ6go>|M36t|M36t|M36t|M36t
z|M36t|M36t|4?wJ?`TbZr?yw$RmtDrp#ftN?mioN;E$0iV^{vrss@nyy
zhLpr-+{;EF$|6Br*539G04BUJin~npt=V4^0^ZvxI*a=98Yq9kKr@l#s;z&uoj4S-
zS~~Mp&I&n#iS^G95g^h#)T*_Vi`5Lj?}ZGIQ#9|GS?wLfF;-AGAao7@08m2!odGHU
z0RRC2001S8yM@rW3ee&2>%Wj3D4B=#pT+;ykMO@Tw72FTb$?L5w{F!{URYdZ{WI|U
z`j5?j>Hq4#oc@4()$;@W5&pIKFWQUDC-blA-_<|3{r~;Lf2i_R_YnOY`TzQr_H6VA
z{!jet(u@2@`2WBE!~fUs^?%wv0{@TyJ^BCe0Q3O$N9p(XAHrVvKev7+b&q(**={Yb
zEA)@;|I>e9e>FZT@F##5-`VrKlRRi8UTMD{>T3-{CBUX{a@C74gO93d;V9rU-A#>U+cd&|9|;ezg^Eq5)_wt
z{f7om8fkf77si`J#+yXOn?%N&M8=ypM0iz$&7C?5uIz{~I=HjD
zi^u}|RN4u|AtzSo$aP1(;da1BBcBSCI?T_j_SR(es_mPQ?=?i#bL-QOIC=@6o|F`m
zpw|yApQqZGDR1|VrgzN$=LJ;T)PCBw{!f{EGI$@hUmMsYO+w(j$9EP>CyvvjIE*&T
zWG&3nh#P$Z>?;C(aLHux+H#b6A&E#t3DoO5#%Yml@ar{o{c*xgc?8wqg{KVLYkx^(!r1Iowp%B2!^v2ah9zYzH3I=2Y$!@vl^5$eC`54R6tZYx(s*O&>to
zo#JUMfUGXgX?g6e>N}9zry~LVYbP{q@9|XMnO?iKPuokXaoSTM^>vO#3O>Tz{}U0}
z>Tya4OVbV5-s!_fG$0`(1SOG0Nm~xEc;6#q#LCJX1l!e{-@bg5w2QNR;u*V14%X->#_~kEn!NhXT$p5Y6Oh)ZZPbP?
zKxwHfida2Jm}+JI=)3WwF?@&KJ^6gCtT)wne%_JU9J+PP3mvS9jaZAYZs-*IT%9mTB|z7mbI|qWsoLL>KbT~>(l{K$81n|3Da#>F
zG`AApS-!30uPS>sz|tjq(d=p-Yb?P_yS0nxNTm=uTfP`FcT@K$&>T%!y4(Yp#>jfQ
z5kvJ7aSMtB$&De5&tmpHp>oU#550un8nR%;89y3n#k`9cJ)p_1IwRjw-J{*f
zt2_73p#9)*$Pk~-Z0eXUeiV65l_|YLWAZAIQu)_pBEWAT{9hR&NgEFaZ#7<|_)%Ff
zvvz{#n|5`)#Vy{%*9@_NlMlhto!6TtsXW=9MdblgD(NR-IOPYKO;*TeXlh0#DF(AXW*mjepD}O#y*1ZBC)P*as
z9+b^Xd8{S)Eq)Ce2=;0*3ibhFko$H5!&GZeI&5^a+u!z<%INSZR`OTu6ti|Z0ykG*
z{dA*z7gyeyJFnZZn^_RRG=x*gKu_aFRmJ>|dpin{8!BzK+MI48a8cP*#ja4C65sGc
zs{#tp6-`uB5gs(Vu8RMJohh>wNY(9b0e@OACO_cM=M@UibTGwx`(6ihi?LxZ5
zkQim!C(@7_g#=L~#DnMcC+Ie`6v4Z8zUtd~3RwgH?pBd_VJ}`d9HS6yEZLl``?}6A
zGq6&b$MGZ?t4ljkgzZy3H_dY_YCvdgwwq+yl58ffZ6yygdtzN)RbOk<0T3E{+XK=6
zrdE`S99>SJ7?nd{A-l`N_Y%CU}Rv6KzM5xH)saSjT
z_)D3`ZUOif=zhO;609<KCC5YDf}{zbIS{xhf$0hRU+A
zEaSv%8^6ke!LSDd8Pw8a)a|gs5go$r|K9m}WO7;5`9v-#*n>S^q7-Fp
zuqS|4Q(B;bsknU(oAx9;JhoYtou~fv#FUjJ0^jT^l3i&A+rXy#QfIQ3>
zgyyy@&3nKl0l?FsmZC6ONG`PB<&`@}567zwfXkE)4b_(y_S=m2haiyS}PN&MUAA?)FKnS;sywSKP%VYJxG-B@d8gaSdp1jSB
zxUrVO@5-4y9ExAa7-&i@@4(!Xb}C986XymNWxqM_3MW6WE#y*F@qBNy!(xJB%Nmr{
zI?iE}UGnW+r5?c+#P|Oad*NOqKDrJ)LgG0_Kci8_5c#)>OiU1ode>e+HHK`{kw1Jo
zUKSMdRVsq7t_WX5fyKzj%^pw~P#U;1)&W|2VBP{ATpXsq!3SJ^~CW0%WKa}cQVJ|Ez05fQ)YRLa-WG0Nws<*?q(p)h{>J~QpwTb;_mFdcw3v9ili29>Shca-^i&*P`SPU0Ab@7owPsIr#TYcU9m|4Owg3a_ODANFoZHGyLt!R_{z9O6JOBUy0oZ*KreiPM
ziPhFzu9H253elW{{$zIAU0d(P6TFZ{Aek{V)ZO`rtt6Y3*WF%Ub;x_HrnCv3d#PGp
z;y9(0QSRmDDS9k}Tl=+~hi&Z0wZCEOpJ4K+(ld)Kr-l4QYed|ce*^OIu0!3?H9!CW
E0FX&f00000
literal 0
HcmV?d00001
From 38e75b3e6427d1a67dedee9697858212c651c0a7 Mon Sep 17 00:00:00 2001
From: Rishad Alam <101513331+RishadAlam@users.noreply.github.com>
Date: Fri, 1 May 2026 18:22:07 +0600
Subject: [PATCH 2/3] feat: Add bookingPress tutorial links and create .codex
file
---
frontend/src/Utils/StaticData/tutorialLinks.js | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/frontend/src/Utils/StaticData/tutorialLinks.js b/frontend/src/Utils/StaticData/tutorialLinks.js
index 97d2258b4..26d7e34e2 100644
--- a/frontend/src/Utils/StaticData/tutorialLinks.js
+++ b/frontend/src/Utils/StaticData/tutorialLinks.js
@@ -670,6 +670,10 @@ const tutorialLinks = {
userRegistrationMembership: {
youTubeLink: '',
docLink: 'https://bit-integrations.com/wp-docs/actions/user-registration-and-membership-as-action/'
+ },
+ bookingPress: {
+ youTubeLink: '',
+ docLink: ''
}
}
export default tutorialLinks
From 7a75d9e1f6795a4b893ebd389142880f7cea5229 Mon Sep 17 00:00:00 2001
From: Rishad Alam <101513331+RishadAlam@users.noreply.github.com>
Date: Sat, 2 May 2026 10:35:43 +0600
Subject: [PATCH 3/3] refactor: Update BookingPress integration to improve code
consistency and readability
---
.../Actions/BookingPress/RecordApiHelper.php | 2 +-
.../BookingPress/BookingPress.jsx | 2 --
.../BookingPressAuthorization.jsx | 3 ++-
.../BookingPress/BookingPressIntegLayout.jsx | 19 +++++++++----------
.../BookingPress/EditBookingPress.jsx | 3 +--
.../BookingPress/staticData.js | 8 ++++----
6 files changed, 17 insertions(+), 20 deletions(-)
diff --git a/backend/Actions/BookingPress/RecordApiHelper.php b/backend/Actions/BookingPress/RecordApiHelper.php
index 3db344e61..0d0147085 100644
--- a/backend/Actions/BookingPress/RecordApiHelper.php
+++ b/backend/Actions/BookingPress/RecordApiHelper.php
@@ -28,7 +28,7 @@ public function execute($fieldValues, $fieldMap)
];
}
- $fieldData = static::generateReqDataFromFieldMap($fieldMap, $fieldValues);
+ $fieldData = $this->generateReqDataFromFieldMap($fieldMap, $fieldValues);
$mainAction = $this->_integrationDetails->mainAction ?? 'cancel_appointment';
$defaultResponse = [
diff --git a/frontend/src/components/AllIntegrations/BookingPress/BookingPress.jsx b/frontend/src/components/AllIntegrations/BookingPress/BookingPress.jsx
index 1f63c4a45..5287ab414 100644
--- a/frontend/src/components/AllIntegrations/BookingPress/BookingPress.jsx
+++ b/frontend/src/components/AllIntegrations/BookingPress/BookingPress.jsx
@@ -12,7 +12,6 @@ import BookingPressIntegLayout from './BookingPressIntegLayout'
export default function BookingPress({ 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 })
@@ -70,7 +69,6 @@ export default function BookingPress({ formFields, setFlow, flow, allIntegURL })
minHeight: step === 2 && '500px',
}}>
{
- setIsLoading('auth')
+ setIsLoading(true)
bitsFetch({}, 'bookingpress_authorize').then(result => {
if (result?.success) {
setIsAuthorized(true)
diff --git a/frontend/src/components/AllIntegrations/BookingPress/BookingPressIntegLayout.jsx b/frontend/src/components/AllIntegrations/BookingPress/BookingPressIntegLayout.jsx
index 96dd94170..fd76bd2f0 100644
--- a/frontend/src/components/AllIntegrations/BookingPress/BookingPressIntegLayout.jsx
+++ b/frontend/src/components/AllIntegrations/BookingPress/BookingPressIntegLayout.jsx
@@ -9,15 +9,14 @@ import { generateMappedField } from './BookingPressCommonFunc'
import BookingPressFieldMap from './BookingPressFieldMap'
import {
appointmentIdField,
- CreateCustomerFields,
- DeleteCustomerFields,
+ createCustomerFields,
+ deleteCustomerFields,
modules,
- UpdateAppointmentStatusFields,
- UpdateCustomerFields
+ updateAppointmentStatusFields,
+ updateCustomerFields
} from './staticData'
export default function BookingPressIntegLayout({
- formID,
formFields,
bookingPressConf,
setBookingPressConf,
@@ -36,19 +35,19 @@ export default function BookingPressIntegLayout({
draftConf.bookingPressFields = appointmentIdField
break
case 'update_appointment_status':
- draftConf.bookingPressFields = UpdateAppointmentStatusFields
+ draftConf.bookingPressFields = updateAppointmentStatusFields
break
case 'create_customer':
- draftConf.bookingPressFields = CreateCustomerFields
+ draftConf.bookingPressFields = createCustomerFields
break
case 'update_customer':
- draftConf.bookingPressFields = UpdateCustomerFields
+ draftConf.bookingPressFields = updateCustomerFields
break
case 'delete_appointment':
draftConf.bookingPressFields = appointmentIdField
break
case 'delete_customer':
- draftConf.bookingPressFields = DeleteCustomerFields
+ draftConf.bookingPressFields = deleteCustomerFields
break
default:
draftConf.bookingPressFields = []
@@ -72,7 +71,7 @@ export default function BookingPressIntegLayout({
options={modules?.map(action => ({
label: checkIsPro(isPro, action.is_pro) ? action.label : getProLabel(action.label),
value: action.name,
- disabled: checkIsPro(isPro, action.is_pro) ? false : true,
+ disabled: !checkIsPro(isPro, action.is_pro),
}))}
singleSelect
closeOnSelect
diff --git a/frontend/src/components/AllIntegrations/BookingPress/EditBookingPress.jsx b/frontend/src/components/AllIntegrations/BookingPress/EditBookingPress.jsx
index 55958b2d3..ed12785ae 100644
--- a/frontend/src/components/AllIntegrations/BookingPress/EditBookingPress.jsx
+++ b/frontend/src/components/AllIntegrations/BookingPress/EditBookingPress.jsx
@@ -12,7 +12,7 @@ import BookingPressIntegLayout from './BookingPressIntegLayout'
export default function EditBookingPress({ allIntegURL }) {
const navigate = useNavigate()
- const { id, formID } = useParams()
+ const { id } = useParams()
const [bookingPressConf, setBookingPressConf] = useRecoilState($actionConf)
const [flow, setFlow] = useRecoilState($newFlow)
@@ -40,7 +40,6 @@ export default function EditBookingPress({ allIntegURL }) {