Skip to content

feat: add Webba Booking Calendar action integration#174

Merged
RishadAlam merged 5 commits into
mainfrom
feat/webba-booking
Jun 27, 2026
Merged

feat: add Webba Booking Calendar action integration#174
RishadAlam merged 5 commits into
mainfrom
feat/webba-booking

Conversation

@RishadAlam

Copy link
Copy Markdown
Member

Description

Adds a new Webba Booking Calendar action integration. Lets any Bit Integrations trigger create and manage Webba Booking records — bookings, coupons, services, categories, staff members, and locations — by mapping trigger fields to Webba entities. The action layer is wired in the free plugin and delegates the actual writes to Pro hooks.

Motivation & Context

Webba Booking is a popular WordPress appointment plugin. Users want to push data from their forms/triggers into Webba (e.g. create a booking when a form is submitted) and keep booking state in sync. This integration exposes that capability through the standard Bit Integrations action wizard.

Type of Change

  • 🐛 Bug fix
  • ✨ New feature
  • 💥 Breaking change
  • 📚 Documentation update
  • ⚡ Improvement
  • 🔄 Code refactor

Key Changes

Backend (Action)

  • Added WebbaBookingController — authorization check (WBK_Booking_Factory presence) plus dropdown-population endpoints for services, staff, categories, locations, statuses, bookings, and coupons (read from Webba models / validated tables).
  • Added RecordApiHelper — maps trigger fields to Webba fields and dispatches one of 13 actions (create/update/approve/cancel/delete booking, set paid, create/update coupon, create/update service, create category, create staff, create location) via prefixed Pro hooks; logs success/error through LogHandler.
  • Added Routes.php — AJAX routes for auth and all refresh endpoints.
  • Registered WebbaBooking in AllTriggersName.php (Pro, Webba Booking Calendar).

Frontend

  • Added WebbaBooking/ integration: action wizard (WebbaBooking.jsx), WebbaBookingAuthorization, WebbaBookingIntegLayout, WebbaBookingFieldMap, EditWebbaBooking, WebbaBookingCommonFunc, and staticData.
  • Registered the action in NewInteg, EditInteg, IntegInfo, and SelectAction; added to the custom-form integrations list in webhookIntegrations.js.
  • Added webbaBooking.webp integration icon.

Cleanup

  • Removed orphaned sureDash.svg (no longer referenced anywhere in the frontend).

Checklist

  • Code follows project style guidelines
  • Self-review completed
  • Tests added/updated
  • Documentation updated if needed
  • README updated if needed

Changelog

  • New Actions: Webba Booking Calendar — create & manage bookings, coupons, services, categories, staff, and locations directly from any trigger.

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request introduces a new integration for the Webba Booking Calendar, adding backend API helpers, controllers, routes, and frontend React components for authorization, configuration, and field mapping. The review feedback suggests several improvements: in the backend, we should check for WP_Error objects before accessing responses as arrays, and declare controller methods as static where $this is not used. On the frontend, we should add error handling to the authorization fetch request, safely check for the existence of DOM elements before modifying their scroll position, and use a safer string conversion method for option values to prevent runtime crashes.

Important

The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.

Comment on lines +86 to +87
$responseType = isset($response['success']) && $response['success'] ? 'success' : 'error';
LogHandler::save($this->_integrationID, ['type' => 'WebbaBooking', 'type_name' => $mainAction], $responseType, $response);

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

When handling responses that may return a WP_Error object, always use the is_wp_error() function to validate the response before accessing it as an array or object. This prevents fatal errors in PHP 8.0+.

        if (is_wp_error($response)) {
            $response = [
                'success' => false,
                'message' => $response->get_error_message()
            ];
        }
        $responseType = isset($response['success']) && $response['success'] ? 'success' : 'error';
        LogHandler::save($this->_integrationID, ['type' => 'WebbaBooking', 'type_name' => $mainAction], $responseType, $response);
References
  1. In PHP, when handling responses that may return a WP_Error object, always use the is_wp_error() function to validate the response before accessing it as an array or object. This prevents fatal errors in PHP 8.0+.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done — added an is_wp_error() guard before treating $response as an array:

if (is_wp_error($response)) {
    $response = [
        "success" => false,
        "message" => $response->get_error_message()
    ];
}

Comment on lines +39 to +40
public function refreshServices()
{

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

Declare methods as static if they do not access any instance properties ($this) and are intended to be called statically.

    public static function refreshServices()
    {
References
  1. In PHP, declare methods as static if they do not access any instance properties ($this) and are intended to be called statically.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done — refreshServices() is now static (no $this usage; matches the convention in sibling controllers e.g. Bookly).

Comment on lines +63 to +64
public function refreshStaff()
{

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

Declare methods as static if they do not access any instance properties ($this) and are intended to be called statically.

    public static function refreshStaff()
    {
References
  1. In PHP, declare methods as static if they do not access any instance properties ($this) and are intended to be called statically.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done — refreshStaff() is now static.

Comment on lines +87 to +88
public function refreshCategories()
{

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

Declare methods as static if they do not access any instance properties ($this) and are intended to be called statically.

    public static function refreshCategories()
    {
References
  1. In PHP, declare methods as static if they do not access any instance properties ($this) and are intended to be called statically.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done — refreshCategories() is now static.

Comment on lines +105 to +106
public function refreshLocations()
{

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

Declare methods as static if they do not access any instance properties ($this) and are intended to be called statically.

    public static function refreshLocations()
    {
References
  1. In PHP, declare methods as static if they do not access any instance properties ($this) and are intended to be called statically.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done — refreshLocations() is now static.

Comment on lines +172 to +173
public function refreshCoupons()
{

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

Declare methods as static if they do not access any instance properties ($this) and are intended to be called statically.

    public static function refreshCoupons()
    {
References
  1. In PHP, declare methods as static if they do not access any instance properties ($this) and are intended to be called statically.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done — refreshCoupons() is now static.

Comment on lines +196 to +197
public function execute($integrationData, $fieldValues)
{

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

Declare methods as static if they do not access any instance properties ($this) and are intended to be called statically.

    public static function execute($integrationData, $fieldValues)
    {
References
  1. In PHP, declare methods as static if they do not access any instance properties ($this) and are intended to be called statically.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Skipped intentionally. execute() is the Flow-engine entry point — it is resolved and invoked as an instance method ($controller->execute($flowData, $triggerData)) and is declared non-static across all action controllers (e.g. Bookly, BookingPress) for contract consistency. Making it static would deviate from that contract, so it stays an instance method. The stateless refresh* helpers were made static as suggested.

Comment on lines +21 to +34
const authorizeHandler = () => {
setIsLoading('auth')
bitsFetch({}, 'webba_booking_authorize').then(result => {
if (result?.success) {
setIsAuthorized(true)
setSnackbar({
show: true,
msg: __('Connected with Webba Booking Successfully', 'bit-integrations')
})
}
setIsLoading(false)
setShowAuthMsg(true)
})
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

Add a .catch() block to the bitsFetch promise to handle network or request failures gracefully and prevent the UI from being stuck in a loading state.

  const authorizeHandler = () => {
    setIsLoading('auth')
    bitsFetch({}, 'webba_booking_authorize')
      .then(result => {
        if (result?.success) {
          setIsAuthorized(true)
          setSnackbar({
            show: true,
            msg: __('Connected with Webba Booking Successfully', 'bit-integrations')
          })
        }
        setIsLoading(false)
        setShowAuthMsg(true)
      })
      .catch(() => {
        setIsLoading(false)
        setShowAuthMsg(true)
      })
  }

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done — added a .catch() so a failed request resets the loading state instead of leaving the UI stuck:

bitsFetch({}, "webba_booking_authorize")
  .then(result => { /* ... */ })
  .catch(() => {
    setIsLoading(false)
    setShowAuthMsg(true)
  })

Comment on lines +63 to +65
setTimeout(() => {
document.getElementById('btcd-settings-wrp').scrollTop = 0
}, 300)

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

Ensure that the element returned by document.getElementById exists before accessing its properties to avoid potential runtime TypeError exceptions.

    setTimeout(() => {
      const settingsWrp = document.getElementById('btcd-settings-wrp')
      if (settingsWrp) {
        settingsWrp.scrollTop = 0
      }
    }, 300)

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done — guarded the lookup before touching scrollTop:

const settingsWrp = document.getElementById("btcd-settings-wrp")
if (settingsWrp) {
  settingsWrp.scrollTop = 0
}

Comment on lines +115 to +118
options={(webbaBookingConf?.[optionSource] ?? []).map(opt => ({
label: opt.label,
value: opt.value.toString()
}))}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

Use String(opt.value ?? '') instead of opt.value.toString() to safely handle cases where opt.value might be null or undefined, preventing potential runtime crashes.

Suggested change
options={(webbaBookingConf?.[optionSource] ?? []).map(opt => ({
label: opt.label,
value: opt.value.toString()
}))}
options={(webbaBookingConf?.[optionSource] ?? []).map(opt => ({
label: opt.label,
value: String(opt.value ?? '')
}))}

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done — switched to String(opt.value ?? "") to safely handle null/undefined values.

abdul-kaioum
abdul-kaioum previously approved these changes Jun 27, 2026
@github-actions

github-actions Bot commented Jun 27, 2026

Copy link
Copy Markdown

🔍 WordPress Plugin Check Report

⚠️ Status: Passed with warnings

📊 Report

🎯 Total Issues ❌ Errors ⚠️ Warnings
1 0 1

⚠️ Warnings (1)

📁 readme.txt (1 warning)
📍 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

@RishadAlam RishadAlam merged commit a9507a6 into main Jun 27, 2026
1 check passed
@RishadAlam RishadAlam deleted the feat/webba-booking branch June 27, 2026 06:11
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants