feat(rox-appointment-booking): add action bridge and UI - #216
Conversation
Free holds no integration logic: RecordApiHelper turns the chosen action into a literal filter call and Pro answers it. One switch case per action, each with its own hook string so the wiring is greppable from either plugin, and every path falls through to LogHandler::save so a failed run leaves something in the Task Log. Each Hooks::apply passes only what its handler reads — the field map alone for most, plus $utilities where the action has optional selects, plus the config where it has a catalog dropdown or a required status enum. The argument count, the accepted_args in Pro and the handler signature agree for all 25. The controller also serves the catalog lists behind the config dropdowns (services, agents, categories, locations). Those are read-only fetches, so they stay in Free and never cross the Pro hook. Only lists an action actually uses are exposed; there is no unused refresh route. AllTriggersName registers the trigger side under the same PascalCase key the Pro controller passes to Flow::exists.
Three-step wizard plus the edit screen, cloned from the FluentCart layout so the
field-map header, the centred add-row button, the loader and the section
headings match every other integration.
What goes in the field map versus a dropdown follows one rule: the field map is
for values that change per run, dropdowns are for configuration chosen once.
field map the record the action targets, the customer (a form submission
carries it), dates, amounts, free text
dropdown catalog references that do not vary — service, agent, category,
location — plus the required status enums and, under Utilities,
the optional ones
Every id also offers a natural-key row ("Find Customer by Email", "Find Order by
Number"), so a flow can identify a record with what the trigger actually has.
The pair is mandatory but either half satisfies it, so neither carries a required
flag; generateMappedField seeds the row from the pair instead, leaving it
switchable in the dropdown, and checkRequiredSelect blocks the save when no half
is mapped. Without that seeding an action whose only requirement is an id opened
with a blank row and no sign anything was needed.
Lookup keys are prefixed find_by_ so they can never collide with a writable
column of the same name.
All 25 actions are Pro, so every module carries is_pro and the action select is
gated for non-Pro users.
…uilder Lazy import plus a case in the new, edit and info routers, and an entry in the action picker. The picker entry carries an explicit name. `type` is the routing key that has to stay PascalCase to match the switch cases and Flow::exists, while the card renders `name || type` — so without it the integration showed as "RoxAppointmentBooking" with no spaces. Same split as the NextCrm and ModernCart entries.
…customer mainAction defaulted to create_customer, so a flow whose action was missing or renamed silently created a customer record instead of reporting. It now falls through to the switch default and returns "Invalid action". Verified: an empty and a misspelled mainAction both error, a valid one still succeeds, and no customer row is written by either failing case.
Removes the file headers that only repeat the filename, the arg-count labels above the hook registrations (the 10, N in each line already says it), and the notes that describe the object literal directly underneath them. Several explanations were also duplicated across staticData, IntegLayout and CommonFunc; each now lives once, next to the definition it justifies. What stays is the part that is not in the code: the phpcs pragmas and translator notes, and the reasons a later reader would otherwise undo — why the catalog fields are dropdowns rather than field-map rows, why an either-group carries no required flag, why the status lists are safe to hardcode, and why mainAction has no default.
…g integration data
🔍 WordPress Plugin Check Report
📊 Report
|
| 📍 Line | 🔖 Check | 💬 Message |
|---|---|---|
0 |
mismatched_plugin_name | Plugin name "Bit integrations - Form Integration, Webhook, Spreadsheets, CRM, LMS & Email Automation" is different from the name declared in plugin header "Bit Integrations". |
🤖 Generated by WordPress Plugin Check Action • Learn more about Plugin Check
There was a problem hiding this comment.
🟡 Changes recommended
There are a few concrete correctness/accessibility issues (catalog label fallback edge case, user-facing typo, and a non-descriptive aria-label) that should be fixed before merge.
Once you've addressed the issues Copilot identified, you can request another Copilot review.
Pull request overview
Adds the “Free” half of the Rox Appointment Booking integration to Bit Integrations: a Pro-gated Flow Builder UI plus backend routes/controllers that expose read-only catalogs and forward write actions to Pro via prefixed hooks.
Changes:
- Registers the Rox Appointment Booking integration in the action picker UI and integration routing (new/edit/info).
- Adds a full action configuration UI (action select, required selects, catalog selects, field mapping, and utilities) driven by a new
staticData.js. - Adds backend action routes/controller +
RecordApiHelperthat proxies actions to Pro hooks and logs every execution, plus adds RoxAppointmentBooking toAllTriggersName.
File summaries
| File | Description |
|---|---|
| frontend/src/components/Flow/New/SelectAction.jsx | Adds Rox Appointment Booking to the action selection grid (Pro-gated). |
| frontend/src/components/AllIntegrations/RoxAppointmentBooking/staticData.js | Defines action list, field schemas, option sets, and “required either” rules for mappings. |
| frontend/src/components/AllIntegrations/RoxAppointmentBooking/RoxAppointmentBookingIntegLayout.jsx | Main configuration UI: action picker, required selects, catalog dropdowns, field map, utilities section. |
| frontend/src/components/AllIntegrations/RoxAppointmentBooking/RoxAppointmentBookingFieldMap.jsx | Field mapping row UI (required rows locked; optional rows add/remove). |
| frontend/src/components/AllIntegrations/RoxAppointmentBooking/RoxAppointmentBookingCommonFunc.js | Refresh catalog helpers, mapping validation, required-select validation, and initial field-map generation. |
| frontend/src/components/AllIntegrations/RoxAppointmentBooking/RoxAppointmentBookingAuthorization.jsx | Adds plugin-presence authorization via WP constant check + tutorial link wiring. |
| frontend/src/components/AllIntegrations/RoxAppointmentBooking/RoxAppointmentBookingActions.jsx | Utilities modal UI for optional enum selections stored under conf.utilities.*. |
| frontend/src/components/AllIntegrations/RoxAppointmentBooking/RoxAppointmentBooking.jsx | New-integration wizard wrapper: state init, step transition validation, save config hook. |
| frontend/src/components/AllIntegrations/RoxAppointmentBooking/EditRoxAppointmentBooking.jsx | Edit screen for existing Rox Appointment Booking action configs. |
| frontend/src/components/AllIntegrations/NewInteg.jsx | Adds lazy import + routing case for creating the integration. |
| frontend/src/components/AllIntegrations/IntegInfo.jsx | Adds authorization/info rendering for Rox Appointment Booking in integration info view. |
| frontend/src/components/AllIntegrations/EditInteg.jsx | Adds lazy import + routing case for editing the integration. |
| backend/Core/Util/AllTriggersName.php | Registers Rox Appointment Booking in the triggers list (Pro-gated). |
| backend/Actions/RoxAppointmentBooking/RoxAppointmentBookingController.php | Adds authorize endpoint, catalog refresh endpoints, and execution entrypoint. |
| backend/Actions/RoxAppointmentBooking/Routes.php | Wires AJAX routes for authorize + four catalog refresh endpoints. |
| backend/Actions/RoxAppointmentBooking/RecordApiHelper.php | Proxies 25 actions to prefixed hooks, returns “Invalid action” on unknown, and logs outcomes. |
Review details
- Files reviewed: 16/17 changed files
- Comments generated: 3
- Review effort level: Lite
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
| $defaultResponse = [ | ||
| 'success' => false, | ||
| // translators: %s: Plugin name | ||
| 'message' => wp_sprintf(__('%s plugin is not installed or activate', 'bit-integrations'), 'Bit Integrations Pro') | ||
| ]; |
| function ($row) { | ||
| return (object) [ | ||
| 'value' => (int) $row->id, | ||
| 'label' => $row->label !== '' ? $row->label : '#' . $row->id, | ||
| ]; | ||
| }, |
| <button | ||
| onClick={() => delFieldMap(i, roxAppointmentBookingConf, setRoxAppointmentBookingConf)} | ||
| className="icn-btn sh-sm ml-1" | ||
| type="button" | ||
| aria-label="btn"> |
RoxAppointmentBookingAuthorization reads tutorialLinks.roxAppointmentBooking, which had no entry, so the authorization screen showed no documentation link.
Description
Adds the Free half of the Rox Appointment Booking integration: the action bridge that forwards 25 write actions to Pro, the flow-builder UI, and the trigger registration. Requires the matching bit-integrations-pro PR.
Motivation & Context
Extracted from Bit-Pi so Bit Integrations users can trigger flows from Rox Appointment Booking events and write back to its records. Free holds no integration logic — it fires
bit_integrations_rox_appointment_booking_*filters that Pro answers.Related Links: (if applicable)
Must merge together with Bit-Apps-Pro/bit-integrations-pro#146 — Free only fires the hooks; without the Pro PR every action returns "Bit Integrations Pro plugin is not installed or activate".
Extracted from Bit-Apps-Pro/bit-pi#830.
Type of Change
Key Changes
Backend
RecordApiHelperwith one switch case per action, each carrying its literal hook string, andLogHandler::saveon every path so a failed run leaves a Task Log entry.RoxAppointmentBookingentry toAllTriggersName.mainActiondefaulting tocreate_customer, which silently created a customer record instead of reporting. It now returns "Invalid action".Frontend
Checklist
Changelog