feat: initial scaffold

This commit is contained in:
Moko Consulting
2026-06-27 15:35:18 -05:00
parent 8bd3650fe5
commit 1c5cd4007f
70 changed files with 410 additions and 1269 deletions
+13 -11
View File
@@ -1,19 +1,21 @@
<!--
Copyright (C) 2026 Moko Consulting <hello@mokoconsulting.tech>
SPDX-License-Identifier: GPL-3.0-or-later
INGROUP: MokoSuitebooking.Documentation
BRIEF: Version history using Keep a Changelog
SPDX-License-Identifier: GPL-3.0-or-later
Authored-by: Moko Consulting
-->
# Changelog
All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/).
## [Unreleased]
### Added
- **Repository** -- initial scaffold
- **System Plugin** -- Extension class, service provider
- **SQL Schema** -- 8 tables: locations, services, staff, schedules, availability_overrides, bookings, booking_services, waitlist
- **Admin Component** -- 6 views: dashboard, bookings, services, staff, schedules, locations
- **Webservices Plugin** -- 7 API routes
- **Configuration** -- plugin settings across 4 fieldsets
- **Access Control** -- granular permissions
- **Repository** -- initial scaffold for MokoSuiteBooking
- **System Plugin** (`plg_system_mokosuitebooking`) -- configuration and schema management
- **SQL Schema** -- services, staff, staff_services, schedules, bookings, locations, waitlist, booking_history tables
- **Admin Component** (`com_mokosuitebooking`) -- Dashboard, Services, Staff, Schedules, Bookings, Locations, Waitlist views
- **Webservices Plugin** (`plg_webservices_mokosuitebooking`) -- REST API route stubs
- **Configuration** -- basic, booking, notifications, display fieldsets
+5 -4
View File
@@ -1,6 +1,6 @@
# MokoSuitebooking
# MokoSuiteBooking
Appointment and resource booking for service businesses for Joomla 6.
Appointment and resource booking for service businesses
## Quick Reference
@@ -10,10 +10,11 @@ Appointment and resource booking for service businesses for Joomla 6.
| **Layer** | 2 (requires: Client, CRM) |
| **Language** | PHP 8.3+ |
| **Branch** | develop on `dev`, merge to `main` (protected) |
| **Wiki** | [MokoSuiteBooking Wiki](https://git.mokoconsulting.tech/MokoConsulting/MokoSuiteBooking/wiki) |
## Architecture
Joomla **package** -- Layer 2 add-on. CRM contacts as clients, service catalog with staff scheduling and online booking.
Joomla **package** -- Layer 2 add-on. Manages services, staff, schedules, bookings, locations, and waitlist.
## Rules
@@ -27,4 +28,4 @@ Joomla **package** -- Layer 2 add-on. CRM contacts as clients, service catalog w
- PHP 8.3+ / Joomla 6 patterns
- `$this->getDatabase()` in models, `Factory::getContainer()->get(DatabaseInterface::class)` in helpers
- `Factory::getApplication()->getIdentity()` for user
- `Factory::getApplication()->getIdentity()` for user
+14 -27
View File
@@ -1,45 +1,32 @@
<!--
Copyright (C) 2026 Moko Consulting <hello@mokoconsulting.tech>
SPDX-License-Identifier: GPL-3.0-or-later
-->
# MokoSuiteBooking
# MokoSuite booking
Appointment and resource booking for service businesses for MokoSuite on Joomla 6.
Appointment and resource booking for service businesses for Joomla 6.
## Overview
MokoSuitebooking is a **Layer 2** extension in the MokoSuite platform, building on MokoSuiteClient (Layer 0) and MokoSuiteCRM (Layer 1).
## Features
- **Service Catalog** -- services with duration, pricing, staff assignment
- **Online Booking** -- real-time availability with booking widget
- **Staff Scheduling** -- recurring availability patterns with overrides
- **Multi-Location** -- support for multiple business locations
- **Walk-In Queue** -- walk-in queue management
- **Client History** -- CRM contact-linked visit frequency and spend tracking
- **Waitlist** -- automated notification when slots open
- **REST API** -- full CRUD for services, staff, bookings, schedules, locations
- **Access Control** -- granular permissions
MokoSuiteBooking provides appointment scheduling, staff management, calendar schedules, booking lifecycle, multi-location support, and waitlist functionality as a Layer 2 MokoSuite extension.
## Requirements
- Joomla 6.x
- Joomla 6+
- PHP 8.3+
- MokoSuiteClient (Layer 0)
- MokoSuiteClient (Layer 1)
- MokoSuiteCRM (Layer 1)
## Installation
Install via Joomla Extension Manager using the package file `pkg_mokosuitebooking.zip`.
Install via the Joomla extension manager. The package includes:
- **System Plugin** (`plg_system_mokosuitebooking`) -- database schema and configuration
- **Component** (`com_mokosuitebooking`) -- admin interface
- **Webservices Plugin** (`plg_webservices_mokosuitebooking`) -- REST API routes
## License
GNU General Public License v3.0 or later.
GPL-3.0-or-later
## Links
- [Documentation](https://git.mokoconsulting.tech/MokoConsulting/MokoSuitebooking/wiki)
- [Issues](https://git.mokoconsulting.tech/MokoConsulting/MokoSuitebooking/issues)
- [MokoSuite Platform](https://mokoconsulting.tech)
- [Wiki](https://git.mokoconsulting.tech/MokoConsulting/MokoSuiteBooking/wiki)
- [Issues](https://git.mokoconsulting.tech/MokoConsulting/MokoSuiteBooking/issues)
- [MokoSuite](https://mokoconsulting.tech)
@@ -1,17 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright (C) 2026 Moko Consulting <hello@mokoconsulting.tech>
SPDX-License-Identifier: GPL-3.0-or-later
Authored-by: Moko Consulting
-->
<access component="com_mokosuitebooking">
<section name="component">
<action name="core.admin" title="JACTION_ADMIN" />
<action name="core.manage" title="JACTION_MANAGE" />
<action name="core.create" title="JACTION_CREATE" />
<action name="core.delete" title="JACTION_DELETE" />
<action name="core.edit" title="JACTION_EDIT" />
<action name="core.edit.state" title="JACTION_EDITSTATE" />
<action name="core.edit.own" title="JACTION_EDITOWN" />
</section>
</access>
@@ -1,19 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright (C) 2026 Moko Consulting <hello@mokoconsulting.tech>
SPDX-License-Identifier: GPL-3.0-or-later
Authored-by: Moko Consulting
-->
<config>
<fieldset name="permissions" label="JCONFIG_PERMISSIONS_LABEL" description="JCONFIG_PERMISSIONS_DESC">
<field
name="rules"
type="rules"
label="JCONFIG_PERMISSIONS_LABEL"
validate="rules"
filter="rules"
component="com_mokosuitebooking"
section="component"
/>
</fieldset>
</config>
@@ -1,14 +0,0 @@
; Copyright (C) 2026 Moko Consulting <hello@mokoconsulting.tech>
; SPDX-License-Identifier: GPL-3.0-or-later
; Authored-by: Moko Consulting
COM_MOKOSUITEBOOKING="MokoSuiteBooking"
COM_MOKOSUITEBOOKING_DESCRIPTION="Appointment and resource booking for service businesses."
COM_MOKOSUITEBOOKING_MENU_DASHBOARD="Dashboard"
COM_MOKOSUITEBOOKING_MENU_BOOKINGS="Bookings"
COM_MOKOSUITEBOOKING_MENU_SERVICES="Services"
COM_MOKOSUITEBOOKING_MENU_STAFF="Staff"
COM_MOKOSUITEBOOKING_MENU_SCHEDULES="Schedules"
COM_MOKOSUITEBOOKING_MENU_LOCATIONS="Locations"
COM_MOKOSUITEBOOKING_MENU_WAITLIST="Waitlist"
@@ -1,14 +0,0 @@
; Copyright (C) 2026 Moko Consulting <hello@mokoconsulting.tech>
; SPDX-License-Identifier: GPL-3.0-or-later
; Authored-by: Moko Consulting
COM_MOKOSUITEBOOKING="MokoSuiteBooking"
COM_MOKOSUITEBOOKING_DESCRIPTION="Appointment and resource booking for service businesses."
COM_MOKOSUITEBOOKING_MENU_DASHBOARD="Dashboard"
COM_MOKOSUITEBOOKING_MENU_BOOKINGS="Bookings"
COM_MOKOSUITEBOOKING_MENU_SERVICES="Services"
COM_MOKOSUITEBOOKING_MENU_STAFF="Staff"
COM_MOKOSUITEBOOKING_MENU_SCHEDULES="Schedules"
COM_MOKOSUITEBOOKING_MENU_LOCATIONS="Locations"
COM_MOKOSUITEBOOKING_MENU_WAITLIST="Waitlist"
@@ -1,41 +0,0 @@
<?php
/**
* @copyright Copyright (C) 2026 Moko Consulting <hello@mokoconsulting.tech>
* @license GPL-3.0-or-later
*/
defined('_JEXEC') or die;
use Joomla\CMS\Dispatcher\ComponentDispatcherFactoryInterface;
use Joomla\CMS\Extension\ComponentInterface;
use Joomla\CMS\Extension\Service\Provider\ComponentDispatcherFactory;
use Joomla\CMS\Extension\Service\Provider\MVCFactory;
use Joomla\CMS\Extension\Service\Provider\RouterFactory;
use Joomla\CMS\HTML\Registry;
use Joomla\CMS\MVC\Factory\MVCFactoryInterface;
use Joomla\CMS\Component\Router\RouterFactoryInterface;
use Joomla\DI\Container;
use Joomla\DI\ServiceProviderInterface;
return new class () implements ServiceProviderInterface {
public function register(Container $container): void
{
$container->registerServiceProvider(new ComponentDispatcherFactory('\\Moko\\Component\\MokoSuiteBooking'));
$container->registerServiceProvider(new MVCFactory('\\Moko\\Component\\MokoSuiteBooking'));
$container->registerServiceProvider(new RouterFactory('\\Moko\\Component\\MokoSuiteBooking'));
$container->set(
ComponentInterface::class,
function (Container $container) {
$component = new \Joomla\CMS\Extension\MVCComponent();
$component->setMVCFactory($container->get(MVCFactoryInterface::class));
$component->setRouterFactory($container->get(RouterFactoryInterface::class));
$component->setRegistry($container->get(Registry::class));
$component->setDispatcherFactory($container->get(ComponentDispatcherFactoryInterface::class));
return $component;
}
);
}
};
@@ -1,17 +0,0 @@
<?php
/**
* @copyright Copyright (C) 2026 Moko Consulting <hello@mokoconsulting.tech>
* @license GPL-3.0-or-later
*/
namespace Moko\Component\MokoSuiteBooking\Administrator\Controller;
defined('_JEXEC') or die;
use Joomla\CMS\MVC\Controller\BaseController;
class DisplayController extends BaseController
{
protected $default_view = 'bookingdashboard';
}
@@ -1,23 +0,0 @@
<?php
/**
* @copyright Copyright (C) 2026 Moko Consulting <hello@mokoconsulting.tech>
* @license GPL-3.0-or-later
*/
namespace Moko\Component\MokoSuiteBooking\Administrator\View\BookingBookings;
defined('_JEXEC') or die;
use Joomla\CMS\MVC\View\HtmlView as BaseHtmlView;
use Joomla\CMS\Toolbar\ToolbarHelper;
class HtmlView extends BaseHtmlView
{
public function display($tpl = null): void
{
ToolbarHelper::title('MokoSuiteBooking: Bookings', 'calendar');
parent::display($tpl);
}
}
@@ -1,23 +0,0 @@
<?php
/**
* @copyright Copyright (C) 2026 Moko Consulting <hello@mokoconsulting.tech>
* @license GPL-3.0-or-later
*/
namespace Moko\Component\MokoSuiteBooking\Administrator\View\BookingDashboard;
defined('_JEXEC') or die;
use Joomla\CMS\MVC\View\HtmlView as BaseHtmlView;
use Joomla\CMS\Toolbar\ToolbarHelper;
class HtmlView extends BaseHtmlView
{
public function display($tpl = null): void
{
ToolbarHelper::title('MokoSuiteBooking: Dashboard', 'calendar');
parent::display($tpl);
}
}
@@ -1,23 +0,0 @@
<?php
/**
* @copyright Copyright (C) 2026 Moko Consulting <hello@mokoconsulting.tech>
* @license GPL-3.0-or-later
*/
namespace Moko\Component\MokoSuiteBooking\Administrator\View\BookingLocations;
defined('_JEXEC') or die;
use Joomla\CMS\MVC\View\HtmlView as BaseHtmlView;
use Joomla\CMS\Toolbar\ToolbarHelper;
class HtmlView extends BaseHtmlView
{
public function display($tpl = null): void
{
ToolbarHelper::title('MokoSuiteBooking: Locations', 'location');
parent::display($tpl);
}
}
@@ -1,23 +0,0 @@
<?php
/**
* @copyright Copyright (C) 2026 Moko Consulting <hello@mokoconsulting.tech>
* @license GPL-3.0-or-later
*/
namespace Moko\Component\MokoSuiteBooking\Administrator\View\BookingSchedules;
defined('_JEXEC') or die;
use Joomla\CMS\MVC\View\HtmlView as BaseHtmlView;
use Joomla\CMS\Toolbar\ToolbarHelper;
class HtmlView extends BaseHtmlView
{
public function display($tpl = null): void
{
ToolbarHelper::title('MokoSuiteBooking: Schedules', 'clock');
parent::display($tpl);
}
}
@@ -1,23 +0,0 @@
<?php
/**
* @copyright Copyright (C) 2026 Moko Consulting <hello@mokoconsulting.tech>
* @license GPL-3.0-or-later
*/
namespace Moko\Component\MokoSuiteBooking\Administrator\View\BookingServices;
defined('_JEXEC') or die;
use Joomla\CMS\MVC\View\HtmlView as BaseHtmlView;
use Joomla\CMS\Toolbar\ToolbarHelper;
class HtmlView extends BaseHtmlView
{
public function display($tpl = null): void
{
ToolbarHelper::title('MokoSuiteBooking: Services', 'list');
parent::display($tpl);
}
}
@@ -1,23 +0,0 @@
<?php
/**
* @copyright Copyright (C) 2026 Moko Consulting <hello@mokoconsulting.tech>
* @license GPL-3.0-or-later
*/
namespace Moko\Component\MokoSuiteBooking\Administrator\View\BookingStaff;
defined('_JEXEC') or die;
use Joomla\CMS\MVC\View\HtmlView as BaseHtmlView;
use Joomla\CMS\Toolbar\ToolbarHelper;
class HtmlView extends BaseHtmlView
{
public function display($tpl = null): void
{
ToolbarHelper::title('MokoSuiteBooking: Staff', 'users');
parent::display($tpl);
}
}
@@ -1,23 +0,0 @@
<?php
/**
* @copyright Copyright (C) 2026 Moko Consulting <hello@mokoconsulting.tech>
* @license GPL-3.0-or-later
*/
namespace Moko\Component\MokoSuiteBooking\Administrator\View\BookingWaitlist;
defined('_JEXEC') or die;
use Joomla\CMS\MVC\View\HtmlView as BaseHtmlView;
use Joomla\CMS\Toolbar\ToolbarHelper;
class HtmlView extends BaseHtmlView
{
public function display($tpl = null): void
{
ToolbarHelper::title('MokoSuiteBooking: Waitlist', 'list');
parent::display($tpl);
}
}
@@ -1,12 +0,0 @@
<?php
/**
* @copyright Copyright (C) 2026 Moko Consulting <hello@mokoconsulting.tech>
* @license GPL-3.0-or-later
*/
defined('_JEXEC') or die;
?>
<div class="mokosuitebooking-bookings">
<h2>Bookings</h2>
</div>
@@ -1,12 +0,0 @@
<?php
/**
* @copyright Copyright (C) 2026 Moko Consulting <hello@mokoconsulting.tech>
* @license GPL-3.0-or-later
*/
defined('_JEXEC') or die;
?>
<div class="mokosuitebooking-dashboard">
<h2>MokoSuiteBooking Dashboard</h2>
</div>
@@ -1,12 +0,0 @@
<?php
/**
* @copyright Copyright (C) 2026 Moko Consulting <hello@mokoconsulting.tech>
* @license GPL-3.0-or-later
*/
defined('_JEXEC') or die;
?>
<div class="mokosuitebooking-locations">
<h2>Locations</h2>
</div>
@@ -1,12 +0,0 @@
<?php
/**
* @copyright Copyright (C) 2026 Moko Consulting <hello@mokoconsulting.tech>
* @license GPL-3.0-or-later
*/
defined('_JEXEC') or die;
?>
<div class="mokosuitebooking-schedules">
<h2>Schedules</h2>
</div>
@@ -1,12 +0,0 @@
<?php
/**
* @copyright Copyright (C) 2026 Moko Consulting <hello@mokoconsulting.tech>
* @license GPL-3.0-or-later
*/
defined('_JEXEC') or die;
?>
<div class="mokosuitebooking-services">
<h2>Services</h2>
</div>
@@ -1,12 +0,0 @@
<?php
/**
* @copyright Copyright (C) 2026 Moko Consulting <hello@mokoconsulting.tech>
* @license GPL-3.0-or-later
*/
defined('_JEXEC') or die;
?>
<div class="mokosuitebooking-staff">
<h2>Staff</h2>
</div>
@@ -1,12 +0,0 @@
<?php
/**
* @copyright Copyright (C) 2026 Moko Consulting <hello@mokoconsulting.tech>
* @license GPL-3.0-or-later
*/
defined('_JEXEC') or die;
?>
<div class="mokosuitebooking-waitlist">
<h2>Waitlist</h2>
</div>
@@ -1,39 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright (C) 2026 Moko Consulting <hello@mokoconsulting.tech>
SPDX-License-Identifier: GPL-3.0-or-later
Authored-by: Moko Consulting
-->
<extension type="component" method="upgrade">
<name>com_mokosuitebooking</name>
<version>0.0.1</version>
<creationDate>2026-06-27</creationDate>
<author>Moko Consulting</author>
<authorEmail>hello@mokoconsulting.tech</authorEmail>
<authorUrl>https://mokoconsulting.tech</authorUrl>
<copyright>Copyright (C) 2026 Moko Consulting</copyright>
<license>GPL-3.0-or-later</license>
<description>COM_MOKOSUITEBOOKING_DESCRIPTION</description>
<namespace path="admin/src">Moko\Component\MokoSuiteBooking</namespace>
<administration>
<menu>COM_MOKOSUITEBOOKING</menu>
<submenu>
<menu link="option=com_mokosuitebooking&amp;view=bookingdashboard">COM_MOKOSUITEBOOKING_MENU_DASHBOARD</menu>
<menu link="option=com_mokosuitebooking&amp;view=bookingbookings">COM_MOKOSUITEBOOKING_MENU_BOOKINGS</menu>
<menu link="option=com_mokosuitebooking&amp;view=bookingservices">COM_MOKOSUITEBOOKING_MENU_SERVICES</menu>
<menu link="option=com_mokosuitebooking&amp;view=bookingstaff">COM_MOKOSUITEBOOKING_MENU_STAFF</menu>
<menu link="option=com_mokosuitebooking&amp;view=bookingschedules">COM_MOKOSUITEBOOKING_MENU_SCHEDULES</menu>
<menu link="option=com_mokosuitebooking&amp;view=bookinglocations">COM_MOKOSUITEBOOKING_MENU_LOCATIONS</menu>
<menu link="option=com_mokosuitebooking&amp;view=bookingwaitlist">COM_MOKOSUITEBOOKING_MENU_WAITLIST</menu>
</submenu>
<files folder="admin">
<folder>language</folder>
<folder>services</folder>
<folder>src</folder>
<folder>tmpl</folder>
<filename>access.xml</filename>
<filename>config.xml</filename>
</files>
</administration>
</extension>
@@ -2,16 +2,14 @@
<access component="com_mokosuitebooking">
<section name="component">
<action name="core.admin" title="JACTION_ADMIN" />
<action name="core.options" title="JACTION_OPTIONS" />
<action name="core.manage" title="JACTION_MANAGE" />
<action name="core.create" title="JACTION_CREATE" />
<action name="core.delete" title="JACTION_DELETE" />
<action name="core.edit" title="JACTION_EDIT" />
<action name="core.edit.state" title="JACTION_EDITSTATE" />
<action name="core.edit.own" title="JACTION_EDITOWN" />
<action name="booking.manage.services" title="Manage Services" />
<action name="booking.manage.staff" title="Manage Staff" />
<action name="booking.manage.schedules" title="Manage Schedules" />
<action name="booking.view.reports" title="View Reports" />
<action name="booking.manage.services" title="COM_MOKOSUITEBOOKING_ACTION_MANAGE_SERVICES" />
<action name="booking.manage.staff" title="COM_MOKOSUITEBOOKING_ACTION_MANAGE_STAFF" />
<action name="booking.manage.bookings" title="COM_MOKOSUITEBOOKING_ACTION_MANAGE_BOOKINGS" />
<action name="booking.view.waitlist" title="COM_MOKOSUITEBOOKING_ACTION_VIEW_WAITLIST" />
</section>
</access>
</access>
@@ -1,6 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<config>
<fieldset name="permissions" label="JCONFIG_PERMISSIONS_LABEL" description="JCONFIG_PERMISSIONS_DESC">
<field name="rules" type="rules" label="JCONFIG_PERMISSIONS_LABEL" validate="rules" filter="rules" component="com_mokosuitebooking" section="component" />
<fieldset name="component"
label="COM_MOKOSUITEBOOKING"
description="COM_MOKOSUITEBOOKING_CONFIG_DESCRIPTION">
</fieldset>
</config>
</config>
@@ -1,9 +1,14 @@
; Copyright (C) 2026 Moko Consulting <hello@mokoconsulting.tech>
; SPDX-License-Identifier: GPL-3.0-or-later
COM_MOKOSUITEBOOKING="MokoSuite Booking"
COM_MOKOSUITEBOOKING_DASHBOARD="Dashboard"
COM_MOKOSUITEBOOKING_BOOKINGS="Bookings"
COM_MOKOSUITEBOOKING_SERVICES="Services"
COM_MOKOSUITEBOOKING_STAFF="Staff"
COM_MOKOSUITEBOOKING_SCHEDULES="Schedules"
COM_MOKOSUITEBOOKING_LOCATIONS="Locations"
COM_MOKOSUITEBOOKING="MokoSuiteBooking"
COM_MOKOSUITEBOOKING_DESCRIPTION="Appointment and resource booking for service businesses"
COM_MOKOSUITEBOOKING_CONFIG_DESCRIPTION="Configuration is managed in the system plugin."
COM_MOKOSUITEBOOKING_MENU_DASHBOARD="Dashboard"
COM_MOKOSUITEBOOKING_MENU_SERVICES="Services"
COM_MOKOSUITEBOOKING_MENU_STAFF="Staff"
COM_MOKOSUITEBOOKING_MENU_SCHEDULES="Schedules"
COM_MOKOSUITEBOOKING_MENU_BOOKINGS="Bookings"
COM_MOKOSUITEBOOKING_MENU_LOCATIONS="Locations"
COM_MOKOSUITEBOOKING_MENU_WAITLIST="Waitlist"
COM_MOKOSUITEBOOKING_ACTION_MANAGE_SERVICES="Manage Services"
COM_MOKOSUITEBOOKING_ACTION_MANAGE_STAFF="Manage Staff"
COM_MOKOSUITEBOOKING_ACTION_MANAGE_BOOKINGS="Manage Bookings"
COM_MOKOSUITEBOOKING_ACTION_VIEW_WAITLIST="View Waitlist"
@@ -1,4 +1,9 @@
; Copyright (C) 2026 Moko Consulting <hello@mokoconsulting.tech>
; SPDX-License-Identifier: GPL-3.0-or-later
COM_MOKOSUITEBOOKING="MokoSuite Booking"
COM_MOKOSUITEBOOKING_XML_DESCRIPTION="Appointment and resource booking"
COM_MOKOSUITEBOOKING="MokoSuiteBooking"
COM_MOKOSUITEBOOKING_DESCRIPTION="Appointment and resource booking for service businesses"
COM_MOKOSUITEBOOKING_MENU_DASHBOARD="Dashboard"
COM_MOKOSUITEBOOKING_MENU_SERVICES="Services"
COM_MOKOSUITEBOOKING_MENU_STAFF="Staff"
COM_MOKOSUITEBOOKING_MENU_SCHEDULES="Schedules"
COM_MOKOSUITEBOOKING_MENU_BOOKINGS="Bookings"
COM_MOKOSUITEBOOKING_MENU_LOCATIONS="Locations"
COM_MOKOSUITEBOOKING_MENU_WAITLIST="Waitlist"
@@ -8,21 +8,27 @@
defined('_JEXEC') or die;
use Joomla\CMS\Dispatcher\ComponentDispatcherFactoryInterface;
use Joomla\CMS\Extension\ComponentInterface;
use Joomla\CMS\Extension\MVCComponent;
use Joomla\CMS\Dispatcher\ComponentDispatcherFactoryInterface;
use Joomla\CMS\MVC\Factory\MVCFactoryInterface;
use Joomla\CMS\Component\Router\RouterFactoryInterface;
use Joomla\DI\Container;
use Joomla\DI\ServiceProviderInterface;
return new class implements ServiceProviderInterface {
public function register(Container $container): void {
$container->set(ComponentInterface::class, function (Container $container) {
$c = new MVCComponent($container->get(ComponentDispatcherFactoryInterface::class));
$c->setMVCFactory($container->get(MVCFactoryInterface::class));
$c->setRouterFactory($container->get(RouterFactoryInterface::class));
return $c;
});
return new class implements ServiceProviderInterface
{
public function register(Container $container): void
{
$container->set(
ComponentInterface::class,
function (Container $container) {
$component = new MVCComponent($container->get(ComponentDispatcherFactoryInterface::class));
$component->setMVCFactory($container->get(MVCFactoryInterface::class));
$component->setRouterFactory($container->get(RouterFactoryInterface::class));
return $component;
}
);
}
};
};
@@ -6,7 +6,7 @@
* Authored-by: Moko Consulting
*/
namespace Moko\Component\MokoSuiteBooking\Administrator\Controller;
namespace Moko\Component\MokoSuiteBooking\Controller;
defined('_JEXEC') or die;
@@ -15,4 +15,4 @@ use Joomla\CMS\MVC\Controller\BaseController;
class DisplayController extends BaseController
{
protected $default_view = 'bookingdashboard';
}
}
@@ -1,17 +0,0 @@
<?php
/**
* Copyright (C) 2026 Moko Consulting <hello@mokoconsulting.tech>
* SPDX-License-Identifier: GPL-3.0-or-later
* Authored-by: Moko Consulting
*/
namespace Moko\Component\MokoSuiteBooking\Administrator\Model;
defined('_JEXEC') or die;
use Joomla\CMS\MVC\Model\BaseDatabaseModel;
class BookingDashboardModel extends BaseDatabaseModel
{
}
@@ -6,7 +6,7 @@
* Authored-by: Moko Consulting
*/
namespace Moko\Component\MokoSuiteBooking\Administrator\View\BookingDashboard;
namespace Moko\Component\MokoSuiteBooking\View\BookingDashboard;
defined('_JEXEC') or die;
@@ -17,7 +17,8 @@ class HtmlView extends BaseHtmlView
{
public function display($tpl = null): void
{
ToolbarHelper::title('MokoSuite Booking - Dashboard');
ToolbarHelper::title('Dashboard', 'home');
parent::display($tpl);
}
}
}
@@ -1,23 +0,0 @@
<?php
/**
* Copyright (C) 2026 Moko Consulting <hello@mokoconsulting.tech>
* SPDX-License-Identifier: GPL-3.0-or-later
* Authored-by: Moko Consulting
*/
namespace Moko\Component\MokoSuiteBooking\Administrator\View\BookingLocations;
defined('_JEXEC') or die;
use Joomla\CMS\MVC\View\HtmlView as BaseHtmlView;
use Joomla\CMS\Toolbar\ToolbarHelper;
class HtmlView extends BaseHtmlView
{
public function display($tpl = null): void
{
ToolbarHelper::title('MokoSuite Booking - Locations');
parent::display($tpl);
}
}
@@ -6,7 +6,7 @@
* Authored-by: Moko Consulting
*/
namespace Moko\Component\MokoSuiteBooking\Administrator\View\BookingStaff;
namespace Moko\Component\MokoSuiteBooking\View\Bookings;
defined('_JEXEC') or die;
@@ -17,7 +17,8 @@ class HtmlView extends BaseHtmlView
{
public function display($tpl = null): void
{
ToolbarHelper::title('MokoSuite Booking - Staff');
ToolbarHelper::title('Bookings', 'book');
parent::display($tpl);
}
}
}
@@ -6,7 +6,7 @@
* Authored-by: Moko Consulting
*/
namespace Moko\Component\MokoSuiteBooking\Administrator\View\BookingBookings;
namespace Moko\Component\MokoSuiteBooking\View\Locations;
defined('_JEXEC') or die;
@@ -17,7 +17,8 @@ class HtmlView extends BaseHtmlView
{
public function display($tpl = null): void
{
ToolbarHelper::title('MokoSuite Booking - Bookings');
ToolbarHelper::title('Locations', 'location');
parent::display($tpl);
}
}
}
@@ -6,7 +6,7 @@
* Authored-by: Moko Consulting
*/
namespace Moko\Component\MokoSuiteBooking\Administrator\View\BookingServices;
namespace Moko\Component\MokoSuiteBooking\View\Schedules;
defined('_JEXEC') or die;
@@ -17,7 +17,8 @@ class HtmlView extends BaseHtmlView
{
public function display($tpl = null): void
{
ToolbarHelper::title('MokoSuite Booking - Services');
ToolbarHelper::title('Schedules', 'calendar');
parent::display($tpl);
}
}
}
@@ -6,7 +6,7 @@
* Authored-by: Moko Consulting
*/
namespace Moko\Component\MokoSuiteBooking\Administrator\View\BookingSchedules;
namespace Moko\Component\MokoSuiteBooking\View\Services;
defined('_JEXEC') or die;
@@ -17,7 +17,8 @@ class HtmlView extends BaseHtmlView
{
public function display($tpl = null): void
{
ToolbarHelper::title('MokoSuite Booking - Schedules');
ToolbarHelper::title('Services', 'list');
parent::display($tpl);
}
}
}
@@ -0,0 +1,24 @@
<?php
/**
* Copyright (C) 2026 Moko Consulting <hello@mokoconsulting.tech>
* SPDX-License-Identifier: GPL-3.0-or-later
* Authored-by: Moko Consulting
*/
namespace Moko\Component\MokoSuiteBooking\View\Staff;
defined('_JEXEC') or die;
use Joomla\CMS\MVC\View\HtmlView as BaseHtmlView;
use Joomla\CMS\Toolbar\ToolbarHelper;
class HtmlView extends BaseHtmlView
{
public function display($tpl = null): void
{
ToolbarHelper::title('Staff', 'users');
parent::display($tpl);
}
}
@@ -0,0 +1,24 @@
<?php
/**
* Copyright (C) 2026 Moko Consulting <hello@mokoconsulting.tech>
* SPDX-License-Identifier: GPL-3.0-or-later
* Authored-by: Moko Consulting
*/
namespace Moko\Component\MokoSuiteBooking\View\Waitlist;
defined('_JEXEC') or die;
use Joomla\CMS\MVC\View\HtmlView as BaseHtmlView;
use Joomla\CMS\Toolbar\ToolbarHelper;
class HtmlView extends BaseHtmlView
{
public function display($tpl = null): void
{
ToolbarHelper::title('Waitlist', 'clock');
parent::display($tpl);
}
}
@@ -1,9 +1,13 @@
<?php
/**
* Copyright (C) 2026 Moko Consulting <hello@mokoconsulting.tech>
* SPDX-License-Identifier: GPL-3.0-or-later
* Authored-by: Moko Consulting
*/
defined('_JEXEC') or die;
?>
<div class="container">
<h2>Dashboard</h2>
@@ -1,9 +1,13 @@
<?php
/**
* Copyright (C) 2026 Moko Consulting <hello@mokoconsulting.tech>
* SPDX-License-Identifier: GPL-3.0-or-later
* Authored-by: Moko Consulting
*/
defined('_JEXEC') or die;
?>
<div class="container">
<h2>Bookings</h2>
@@ -1,9 +1,13 @@
<?php
/**
* Copyright (C) 2026 Moko Consulting <hello@mokoconsulting.tech>
* SPDX-License-Identifier: GPL-3.0-or-later
* Authored-by: Moko Consulting
*/
defined('_JEXEC') or die;
?>
<div class="container">
<h2>Locations</h2>
@@ -1,9 +1,13 @@
<?php
/**
* Copyright (C) 2026 Moko Consulting <hello@mokoconsulting.tech>
* SPDX-License-Identifier: GPL-3.0-or-later
* Authored-by: Moko Consulting
*/
defined('_JEXEC') or die;
?>
<div class="container">
<h2>Schedules</h2>
@@ -1,9 +1,13 @@
<?php
/**
* Copyright (C) 2026 Moko Consulting <hello@mokoconsulting.tech>
* SPDX-License-Identifier: GPL-3.0-or-later
* Authored-by: Moko Consulting
*/
defined('_JEXEC') or die;
?>
<div class="container">
<h2>Services</h2>
@@ -1,9 +1,13 @@
<?php
/**
* Copyright (C) 2026 Moko Consulting <hello@mokoconsulting.tech>
* SPDX-License-Identifier: GPL-3.0-or-later
* Authored-by: Moko Consulting
*/
defined('_JEXEC') or die;
?>
<div class="container">
<h2>Staff</h2>
@@ -0,0 +1,15 @@
<?php
/**
* Copyright (C) 2026 Moko Consulting <hello@mokoconsulting.tech>
* SPDX-License-Identifier: GPL-3.0-or-later
* Authored-by: Moko Consulting
*/
defined('_JEXEC') or die;
?>
<div class="container">
<h2>Waitlist</h2>
<p>Coming soon.</p>
</div>
@@ -1,36 +1,35 @@
<?xml version="1.0" encoding="utf-8"?>
<extension type="component" method="upgrade">
<name>MokoSuite Booking</name>
<author>Moko Consulting</author>
<authorEmail>hello@mokoconsulting.tech</authorEmail>
<authorUrl>https://mokoconsulting.tech</authorUrl>
<creationDate>2026-06-27</creationDate>
<copyright>Copyright (C) 2026 Moko Consulting.</copyright>
<license>GPL-3.0-or-later</license>
<version>06.00.00</version>
<description>Appointment and resource booking</description>
<namespace path="src">Moko\Component\MokoSuiteBooking</namespace>
<administration>
<files folder="admin">
<filename>access.xml</filename>
<filename>config.xml</filename>
<folder>language</folder>
<folder>services</folder>
<folder>src</folder>
<folder>tmpl</folder>
</files>
<name>com_mokosuitebooking</name>
<version>06.00.00</version>
<creationDate>2026-06-27</creationDate>
<author>Moko Consulting</author>
<authorEmail>hello@mokoconsulting.tech</authorEmail>
<authorUrl>https://mokoconsulting.tech</authorUrl>
<copyright>Copyright (C) 2026 Moko Consulting</copyright>
<license>GPL-3.0-or-later</license>
<description>COM_MOKOSUITEBOOKING_DESCRIPTION</description>
<namespace path="admin/src">Moko\Component\MokoSuiteBooking</namespace>
<administration>
<menu>COM_MOKOSUITEBOOKING</menu>
<submenu>
<menu link="option=com_mokosuitebooking&amp;view=bookingdashboard">COM_MOKOSUITEBOOKING_MENU_DASHBOARD</menu>
<menu link="option=com_mokosuitebooking&amp;view=services">COM_MOKOSUITEBOOKING_MENU_SERVICES</menu>
<menu link="option=com_mokosuitebooking&amp;view=staff">COM_MOKOSUITEBOOKING_MENU_STAFF</menu>
<menu link="option=com_mokosuitebooking&amp;view=schedules">COM_MOKOSUITEBOOKING_MENU_SCHEDULES</menu>
<menu link="option=com_mokosuitebooking&amp;view=bookings">COM_MOKOSUITEBOOKING_MENU_BOOKINGS</menu>
<menu link="option=com_mokosuitebooking&amp;view=locations">COM_MOKOSUITEBOOKING_MENU_LOCATIONS</menu>
<menu link="option=com_mokosuitebooking&amp;view=waitlist">COM_MOKOSUITEBOOKING_MENU_WAITLIST</menu>
</submenu>
<files folder="admin">
<folder>language</folder>
<folder>services</folder>
<folder>src</folder>
<folder>tmpl</folder>
</files>
</administration>
<languages folder="admin/language">
<language tag="en-GB">en-GB/com_mokosuitebooking.ini</language>
<language tag="en-GB">en-GB/com_mokosuitebooking.sys.ini</language>
<language tag="en-GB">en-GB/com_mokosuitebooking.ini</language>
<language tag="en-GB">en-GB/com_mokosuitebooking.sys.ini</language>
</languages>
<menu>COM_MOKOSUITEBOOKING</menu>
<submenu>
<menu link="option=com_mokosuitebooking&amp;view=bookingdashboard">COM_MOKOSUITEBOOKING_DASHBOARD</menu>
<menu link="option=com_mokosuitebooking&amp;view=bookingbookings">COM_MOKOSUITEBOOKING_BOOKINGS</menu>
<menu link="option=com_mokosuitebooking&amp;view=bookingservices">COM_MOKOSUITEBOOKING_SERVICES</menu>
<menu link="option=com_mokosuitebooking&amp;view=bookingstaff">COM_MOKOSUITEBOOKING_STAFF</menu>
<menu link="option=com_mokosuitebooking&amp;view=bookingschedules">COM_MOKOSUITEBOOKING_SCHEDULES</menu>
<menu link="option=com_mokosuitebooking&amp;view=bookinglocations">COM_MOKOSUITEBOOKING_LOCATIONS</menu>
</submenu>
</administration>
</extension>
</extension>
@@ -1,4 +1,20 @@
; Copyright (C) 2026 Moko Consulting <hello@mokoconsulting.tech>
; SPDX-License-Identifier: GPL-3.0-or-later
PLG_SYSTEM_MOKOSUITEBOOKING="System - MokoSuite Booking"
PLG_SYSTEM_MOKOSUITEBOOKING_DESC="Appointment booking helpers and schema"
PLG_SYSTEM_MOKOSUITEBOOKING="System - MokoSuiteBooking"
PLG_SYSTEM_MOKOSUITEBOOKING_DESCRIPTION="MokoSuiteBooking system plugin — schema and configuration management"
PLG_SYSTEM_MOKOSUITEBOOKING_FIELDSET_BASIC="Basic"
PLG_SYSTEM_MOKOSUITEBOOKING_BUSINESS_NAME="Business Name"
PLG_SYSTEM_MOKOSUITEBOOKING_CURRENCY="Currency"
PLG_SYSTEM_MOKOSUITEBOOKING_TIMEZONE="Timezone"
PLG_SYSTEM_MOKOSUITEBOOKING_TIME_SLOT_MINUTES="Time Slot (Minutes)"
PLG_SYSTEM_MOKOSUITEBOOKING_FIELDSET_BOOKING="Booking"
PLG_SYSTEM_MOKOSUITEBOOKING_MAX_ADVANCE_DAYS="Max Advance Booking (Days)"
PLG_SYSTEM_MOKOSUITEBOOKING_CANCELLATION_WINDOW="Cancellation Window (Hours)"
PLG_SYSTEM_MOKOSUITEBOOKING_AUTO_CONFIRM="Auto-Confirm"
PLG_SYSTEM_MOKOSUITEBOOKING_ALLOW_WALK_INS="Allow Walk-Ins"
PLG_SYSTEM_MOKOSUITEBOOKING_FIELDSET_NOTIFICATIONS="Notifications"
PLG_SYSTEM_MOKOSUITEBOOKING_CONFIRMATION_EMAIL="Confirmation Email"
PLG_SYSTEM_MOKOSUITEBOOKING_REMINDER_HOURS="Reminder (Hours Before)"
PLG_SYSTEM_MOKOSUITEBOOKING_NOSHOW_THRESHOLD="No-Show Threshold (Minutes)"
PLG_SYSTEM_MOKOSUITEBOOKING_FIELDSET_DISPLAY="Display"
PLG_SYSTEM_MOKOSUITEBOOKING_CALENDAR_START="Calendar Start Hour"
PLG_SYSTEM_MOKOSUITEBOOKING_CALENDAR_END="Calendar End Hour"
PLG_SYSTEM_MOKOSUITEBOOKING_SLOTS_PER_PAGE="Slots Per Page"
@@ -1,4 +1,2 @@
; Copyright (C) 2026 Moko Consulting <hello@mokoconsulting.tech>
; SPDX-License-Identifier: GPL-3.0-or-later
PLG_SYSTEM_MOKOSUITEBOOKING="System - MokoSuite Booking"
PLG_SYSTEM_MOKOSUITEBOOKING_DESC="Appointment booking helpers and schema"
PLG_SYSTEM_MOKOSUITEBOOKING="System - MokoSuiteBooking"
PLG_SYSTEM_MOKOSUITEBOOKING_DESCRIPTION="MokoSuiteBooking system plugin — schema and configuration management"
@@ -1,59 +1,53 @@
<?xml version="1.0" encoding="utf-8"?>
<extension type="plugin" group="system" method="upgrade">
<name>System - MokoSuite Booking</name>
<element>mokosuitebooking</element>
<author>Moko Consulting</author>
<name>plg_system_mokosuitebooking</name>
<version>06.00.00</version>
<creationDate>2026-06-27</creationDate>
<copyright>Copyright (C) 2026 Moko Consulting. All rights reserved.</copyright>
<license>GPL-3.0-or-later</license>
<author>Moko Consulting</author>
<authorEmail>hello@mokoconsulting.tech</authorEmail>
<authorUrl>https://mokoconsulting.tech</authorUrl>
<version>06.00.00</version>
<php_minimum>8.3</php_minimum>
<description>PLG_SYSTEM_MOKOSUITEBOOKING_DESC</description>
<copyright>Copyright (C) 2026 Moko Consulting</copyright>
<license>GPL-3.0-or-later</license>
<description>PLG_SYSTEM_MOKOSUITEBOOKING_DESCRIPTION</description>
<namespace path="src">Moko\Plugin\System\MokoSuiteBooking</namespace>
<files>
<folder plugin="mokosuitebooking">services</folder>
<folder>src</folder>
<folder>services</folder>
<folder>language</folder>
<folder>sql</folder>
</files>
<languages folder="language">
<language tag="en-GB">en-GB/plg_system_mokosuitebooking.ini</language>
<language tag="en-GB">en-GB/plg_system_mokosuitebooking.sys.ini</language>
</languages>
<install><sql><file driver="mysql" charset="utf8">sql/install.mysql.sql</file></sql></install>
<uninstall><sql><file driver="mysql" charset="utf8">sql/uninstall.mysql.sql</file></sql></uninstall>
<install>
<sql><file driver="mysql" charset="utf8">sql/install.mysql.sql</file></sql>
</install>
<uninstall>
<sql><file driver="mysql" charset="utf8">sql/uninstall.mysql.sql</file></sql>
</uninstall>
<config>
<fields name="params">
<fieldset name="basic" label="Booking Defaults">
<field name="timezone" type="timezone" default="America/New_York" label="Default Timezone" />
<field name="slot_duration" type="number" default="30" label="Default Slot Duration (min)" />
<field name="default_currency" type="text" default="USD" label="Default Currency" />
<fieldset name="basic" label="PLG_SYSTEM_MOKOSUITEBOOKING_FIELDSET_BASIC">
<field name="business_name" type="text" label="PLG_SYSTEM_MOKOSUITEBOOKING_BUSINESS_NAME" default="" />
<field name="currency" type="text" label="PLG_SYSTEM_MOKOSUITEBOOKING_CURRENCY" default="USD" />
<field name="timezone" type="timezone" label="PLG_SYSTEM_MOKOSUITEBOOKING_TIMEZONE" default="America/New_York" />
<field name="time_slot_minutes" type="number" label="PLG_SYSTEM_MOKOSUITEBOOKING_TIME_SLOT_MINUTES" default="30" min="5" max="120" step="5" />
</fieldset>
<fieldset name="booking" label="Booking Rules">
<field name="advance_booking_days" type="number" default="30" label="Max Advance Booking (days)" />
<field name="cancellation_window_hours" type="number" default="24" label="Cancellation Window (hours)" />
<field name="auto_confirm" type="radio" default="1" label="Auto-Confirm Bookings" class="btn-group btn-group-yesno">
<option value="1">JYES</option>
<option value="0">JNO</option>
</field>
<fieldset name="booking" label="PLG_SYSTEM_MOKOSUITEBOOKING_FIELDSET_BOOKING">
<field name="max_advance_days" type="number" label="PLG_SYSTEM_MOKOSUITEBOOKING_MAX_ADVANCE_DAYS" default="90" min="1" max="365" />
<field name="cancellation_window_hours" type="number" label="PLG_SYSTEM_MOKOSUITEBOOKING_CANCELLATION_WINDOW" default="24" min="0" max="168" />
<field name="auto_confirm" type="radio" label="PLG_SYSTEM_MOKOSUITEBOOKING_AUTO_CONFIRM" default="0" class="btn-group"><option value="0">JNO</option><option value="1">JYES</option></field>
<field name="allow_walk_ins" type="radio" label="PLG_SYSTEM_MOKOSUITEBOOKING_ALLOW_WALK_INS" default="1" class="btn-group"><option value="0">JNO</option><option value="1">JYES</option></field>
</fieldset>
<fieldset name="notifications" label="Notifications">
<field name="reminder_hours" type="number" default="24" label="Reminder Before (hours)" />
<field name="no_show_policy" type="list" default="none" label="No-Show Policy">
<option value="none">None</option>
<option value="flag">Flag Only</option>
<option value="fee">Apply Fee</option>
</field>
<fieldset name="notifications" label="PLG_SYSTEM_MOKOSUITEBOOKING_FIELDSET_NOTIFICATIONS">
<field name="confirmation_email" type="radio" label="PLG_SYSTEM_MOKOSUITEBOOKING_CONFIRMATION_EMAIL" default="1" class="btn-group"><option value="0">JNO</option><option value="1">JYES</option></field>
<field name="reminder_hours_before" type="number" label="PLG_SYSTEM_MOKOSUITEBOOKING_REMINDER_HOURS" default="24" min="0" max="72" />
<field name="noshow_threshold_minutes" type="number" label="PLG_SYSTEM_MOKOSUITEBOOKING_NOSHOW_THRESHOLD" default="15" min="5" max="60" />
</fieldset>
<fieldset name="display" label="Display">
<field name="calendar_default_view" type="list" default="week" label="Default Calendar View">
<option value="day">Day</option>
<option value="week">Week</option>
<option value="month">Month</option>
</field>
<fieldset name="display" label="PLG_SYSTEM_MOKOSUITEBOOKING_FIELDSET_DISPLAY">
<field name="calendar_start_hour" type="number" label="PLG_SYSTEM_MOKOSUITEBOOKING_CALENDAR_START" default="8" min="0" max="12" />
<field name="calendar_end_hour" type="number" label="PLG_SYSTEM_MOKOSUITEBOOKING_CALENDAR_END" default="18" min="12" max="23" />
<field name="slots_per_page" type="number" label="PLG_SYSTEM_MOKOSUITEBOOKING_SLOTS_PER_PAGE" default="20" min="5" max="50" />
</fieldset>
</fields>
</config>
</extension>
</extension>
@@ -15,13 +15,19 @@ use Joomla\DI\ServiceProviderInterface;
use Joomla\Event\DispatcherInterface;
use Moko\Plugin\System\MokoSuiteBooking\Extension\Booking;
return new class implements ServiceProviderInterface {
public function register(Container $container): void {
$container->set(PluginInterface::class, function (Container $container) {
$dispatcher = $container->get(DispatcherInterface::class);
$plugin = new Booking($dispatcher, (array) PluginHelper::getPlugin('system', 'mokosuitebooking'));
$plugin->setApplication(\Joomla\CMS\Factory::getApplication());
return $plugin;
});
return new class implements ServiceProviderInterface
{
public function register(Container $container): void
{
$container->set(
PluginInterface::class,
function (Container $container) {
$dispatcher = $container->get(DispatcherInterface::class);
$plugin = new Booking($dispatcher, (array) PluginHelper::getPlugin('system', 'mokosuitebooking'));
$plugin->setApplication(\Joomla\CMS\Factory::getApplication());
return $plugin;
}
);
}
};
};
@@ -1,37 +1,12 @@
--
-- MokoSuite Booking Tables
--
CREATE TABLE IF NOT EXISTS `#__mokosuitebooking_locations` (
`id` INT UNSIGNED NOT NULL AUTO_INCREMENT,
`name` VARCHAR(255) NOT NULL,
`address` VARCHAR(500) NOT NULL DEFAULT '',
`city` VARCHAR(100) NOT NULL DEFAULT '',
`state` VARCHAR(100) NOT NULL DEFAULT '',
`postal_code` VARCHAR(20) NOT NULL DEFAULT '',
`country` VARCHAR(100) NOT NULL DEFAULT '',
`timezone` VARCHAR(50) NOT NULL DEFAULT 'America/New_York',
`phone` VARCHAR(50) NOT NULL DEFAULT '',
`email` VARCHAR(255) NOT NULL DEFAULT '',
`photo` VARCHAR(500) NOT NULL DEFAULT '',
`notes` TEXT,
`published` TINYINT NOT NULL DEFAULT 1,
`ordering` INT NOT NULL DEFAULT 0,
`created` DATETIME NOT NULL,
`created_by` INT NOT NULL DEFAULT 0,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
CREATE TABLE IF NOT EXISTS `#__mokosuitebooking_services` (
`id` INT UNSIGNED NOT NULL AUTO_INCREMENT,
`name` VARCHAR(255) NOT NULL,
`description` TEXT,
`category` VARCHAR(100) NOT NULL DEFAULT '',
`duration_minutes` SMALLINT UNSIGNED NOT NULL DEFAULT 30,
`duration_minutes` SMALLINT UNSIGNED NOT NULL DEFAULT 60,
`buffer_minutes` SMALLINT UNSIGNED NOT NULL DEFAULT 0,
`price` DECIMAL(10,2) NOT NULL DEFAULT 0.00,
`currency` VARCHAR(3) NOT NULL DEFAULT 'USD',
`max_attendees` SMALLINT UNSIGNED NOT NULL DEFAULT 1,
`max_participants` TINYINT UNSIGNED NOT NULL DEFAULT 1,
`requires_deposit` TINYINT NOT NULL DEFAULT 0,
`deposit_amount` DECIMAL(10,2) NOT NULL DEFAULT 0.00,
`color` VARCHAR(7) NOT NULL DEFAULT '#3788d8',
@@ -39,7 +14,6 @@ CREATE TABLE IF NOT EXISTS `#__mokosuitebooking_services` (
`published` TINYINT NOT NULL DEFAULT 1,
`ordering` INT NOT NULL DEFAULT 0,
`created` DATETIME NOT NULL,
`created_by` INT NOT NULL DEFAULT 0,
PRIMARY KEY (`id`),
KEY `idx_category` (`category`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
@@ -47,22 +21,27 @@ CREATE TABLE IF NOT EXISTS `#__mokosuitebooking_services` (
CREATE TABLE IF NOT EXISTS `#__mokosuitebooking_staff` (
`id` INT UNSIGNED NOT NULL AUTO_INCREMENT,
`contact_id` INT DEFAULT NULL,
`user_id` INT DEFAULT NULL,
`display_name` VARCHAR(255) NOT NULL,
`title` VARCHAR(255) NOT NULL DEFAULT '',
`name` VARCHAR(255) NOT NULL,
`email` VARCHAR(255) NOT NULL DEFAULT '',
`phone` VARCHAR(50) NOT NULL DEFAULT '',
`title` VARCHAR(100) NOT NULL DEFAULT '',
`bio` TEXT,
`photo` VARCHAR(500) NOT NULL DEFAULT '',
`color` VARCHAR(7) NOT NULL DEFAULT '#3788d8',
`services_json` JSON DEFAULT NULL,
`locations_json` JSON DEFAULT NULL,
`max_daily_bookings` TINYINT UNSIGNED NOT NULL DEFAULT 20,
`rating` DECIMAL(3,2) NOT NULL DEFAULT 5.00,
`total_bookings` INT UNSIGNED NOT NULL DEFAULT 0,
`published` TINYINT NOT NULL DEFAULT 1,
`ordering` INT NOT NULL DEFAULT 0,
`created` DATETIME NOT NULL,
PRIMARY KEY (`id`),
KEY `idx_contact` (`contact_id`),
KEY `idx_user` (`user_id`)
KEY `idx_contact` (`contact_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
CREATE TABLE IF NOT EXISTS `#__mokosuitebooking_staff_services` (
`staff_id` INT UNSIGNED NOT NULL,
`service_id` INT UNSIGNED NOT NULL,
PRIMARY KEY (`staff_id`, `service_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
CREATE TABLE IF NOT EXISTS `#__mokosuitebooking_schedules` (
@@ -72,92 +51,100 @@ CREATE TABLE IF NOT EXISTS `#__mokosuitebooking_schedules` (
`day_of_week` TINYINT UNSIGNED NOT NULL,
`start_time` TIME NOT NULL,
`end_time` TIME NOT NULL,
`effective_from` DATE DEFAULT NULL,
`effective_until` DATE DEFAULT NULL,
`published` TINYINT NOT NULL DEFAULT 1,
`is_recurring` TINYINT NOT NULL DEFAULT 1,
`specific_date` DATE DEFAULT NULL,
`override_type` ENUM('available','unavailable') DEFAULT NULL,
`created` DATETIME NOT NULL,
PRIMARY KEY (`id`),
KEY `idx_staff` (`staff_id`),
KEY `idx_location` (`location_id`),
KEY `idx_day` (`day_of_week`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
CREATE TABLE IF NOT EXISTS `#__mokosuitebooking_availability_overrides` (
`id` INT UNSIGNED NOT NULL AUTO_INCREMENT,
`staff_id` INT UNSIGNED NOT NULL,
`override_date` DATE NOT NULL,
`available` TINYINT NOT NULL DEFAULT 0,
`start_time` TIME DEFAULT NULL,
`end_time` TIME DEFAULT NULL,
`reason` VARCHAR(255) NOT NULL DEFAULT '',
`created` DATETIME NOT NULL,
PRIMARY KEY (`id`),
KEY `idx_staff_date` (`staff_id`, `override_date`)
KEY `idx_day` (`day_of_week`),
KEY `idx_date` (`specific_date`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
CREATE TABLE IF NOT EXISTS `#__mokosuitebooking_bookings` (
`id` INT UNSIGNED NOT NULL AUTO_INCREMENT,
`booking_ref` VARCHAR(20) NOT NULL,
`contact_id` INT DEFAULT NULL,
`service_id` INT UNSIGNED NOT NULL,
`staff_id` INT UNSIGNED DEFAULT NULL,
`location_id` INT UNSIGNED DEFAULT NULL,
`customer_contact_id` INT DEFAULT NULL,
`customer_name` VARCHAR(255) NOT NULL,
`customer_email` VARCHAR(255) NOT NULL DEFAULT '',
`customer_phone` VARCHAR(50) NOT NULL DEFAULT '',
`status` ENUM('pending','confirmed','checked_in','in_progress','completed','cancelled','no_show') NOT NULL DEFAULT 'pending',
`booking_date` DATE NOT NULL,
`start_time` TIME NOT NULL,
`end_time` TIME NOT NULL,
`status` ENUM('pending','confirmed','in_progress','completed','cancelled','no_show') NOT NULL DEFAULT 'pending',
`total_price` DECIMAL(10,2) NOT NULL DEFAULT 0.00,
`participants` TINYINT UNSIGNED NOT NULL DEFAULT 1,
`price` DECIMAL(10,2) NOT NULL DEFAULT 0.00,
`deposit_paid` DECIMAL(10,2) NOT NULL DEFAULT 0.00,
`payment_status` ENUM('unpaid','partial','paid','refunded') NOT NULL DEFAULT 'unpaid',
`payment_status` ENUM('pending','deposit_paid','paid','refunded') NOT NULL DEFAULT 'pending',
`source` ENUM('admin','online','phone','walk_in') NOT NULL DEFAULT 'online',
`notes` TEXT,
`internal_notes` TEXT,
`source` ENUM('admin','website','api','walk_in') NOT NULL DEFAULT 'admin',
`cancelled_at` DATETIME DEFAULT NULL,
`cancellation_reason` VARCHAR(500) NOT NULL DEFAULT '',
`customer_notes` TEXT,
`reminder_sent` TINYINT NOT NULL DEFAULT 0,
`created` DATETIME NOT NULL,
`created_by` INT NOT NULL DEFAULT 0,
`modified` DATETIME DEFAULT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `uk_ref` (`booking_ref`),
KEY `idx_contact` (`contact_id`),
UNIQUE KEY `idx_ref` (`booking_ref`),
KEY `idx_service` (`service_id`),
KEY `idx_staff` (`staff_id`),
KEY `idx_location` (`location_id`),
KEY `idx_customer` (`customer_contact_id`),
KEY `idx_status` (`status`),
KEY `idx_date` (`booking_date`),
KEY `idx_status` (`status`)
KEY `idx_datetime` (`booking_date`, `start_time`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
CREATE TABLE IF NOT EXISTS `#__mokosuitebooking_booking_services` (
CREATE TABLE IF NOT EXISTS `#__mokosuitebooking_locations` (
`id` INT UNSIGNED NOT NULL AUTO_INCREMENT,
`booking_id` INT UNSIGNED NOT NULL,
`service_id` INT UNSIGNED NOT NULL,
`staff_id` INT UNSIGNED DEFAULT NULL,
`price` DECIMAL(10,2) NOT NULL DEFAULT 0.00,
`duration_minutes` SMALLINT UNSIGNED NOT NULL DEFAULT 30,
PRIMARY KEY (`id`),
KEY `idx_booking` (`booking_id`),
KEY `idx_service` (`service_id`)
`name` VARCHAR(255) NOT NULL,
`address` VARCHAR(500) NOT NULL DEFAULT '',
`city` VARCHAR(100) NOT NULL DEFAULT '',
`state` VARCHAR(100) NOT NULL DEFAULT '',
`postal_code` VARCHAR(20) NOT NULL DEFAULT '',
`phone` VARCHAR(50) NOT NULL DEFAULT '',
`email` VARCHAR(255) NOT NULL DEFAULT '',
`timezone` VARCHAR(50) NOT NULL DEFAULT 'America/New_York',
`published` TINYINT NOT NULL DEFAULT 1,
`ordering` INT NOT NULL DEFAULT 0,
`created` DATETIME NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
CREATE TABLE IF NOT EXISTS `#__mokosuitebooking_waitlist` (
`id` INT UNSIGNED NOT NULL AUTO_INCREMENT,
`contact_id` INT DEFAULT NULL,
`service_id` INT UNSIGNED NOT NULL,
`staff_id` INT UNSIGNED DEFAULT NULL,
`location_id` INT UNSIGNED DEFAULT NULL,
`customer_contact_id` INT DEFAULT NULL,
`customer_name` VARCHAR(255) NOT NULL,
`customer_email` VARCHAR(255) NOT NULL DEFAULT '',
`customer_phone` VARCHAR(50) NOT NULL DEFAULT '',
`preferred_date_start` DATE DEFAULT NULL,
`preferred_date_end` DATE DEFAULT NULL,
`preferred_time_start` TIME DEFAULT NULL,
`preferred_time_end` TIME DEFAULT NULL,
`status` ENUM('waiting','notified','booked','expired','cancelled') NOT NULL DEFAULT 'waiting',
`notified_at` DATETIME DEFAULT NULL,
`customer_email` VARCHAR(255) NOT NULL DEFAULT '',
`preferred_date` DATE DEFAULT NULL,
`preferred_time` TIME DEFAULT NULL,
`status` ENUM('waiting','offered','booked','expired','cancelled') NOT NULL DEFAULT 'waiting',
`position` INT UNSIGNED NOT NULL DEFAULT 0,
`notes` TEXT,
`created` DATETIME NOT NULL,
PRIMARY KEY (`id`),
KEY `idx_service` (`service_id`),
KEY `idx_customer` (`customer_contact_id`),
KEY `idx_status` (`status`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
CREATE TABLE IF NOT EXISTS `#__mokosuitebooking_booking_history` (
`id` INT UNSIGNED NOT NULL AUTO_INCREMENT,
`booking_id` INT UNSIGNED NOT NULL,
`action` ENUM('created','confirmed','rescheduled','cancelled','completed','no_show','reminder_sent') NOT NULL,
`old_date` DATE DEFAULT NULL,
`old_time` TIME DEFAULT NULL,
`new_date` DATE DEFAULT NULL,
`new_time` TIME DEFAULT NULL,
`note` TEXT,
`created` DATETIME NOT NULL,
`created_by` INT NOT NULL DEFAULT 0,
PRIMARY KEY (`id`),
KEY `idx_booking` (`booking_id`),
KEY `idx_action` (`action`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
@@ -1,12 +1,8 @@
--
-- MokoSuite Booking — Uninstall
--
DROP TABLE IF EXISTS `#__mokosuitebooking_booking_history`;
DROP TABLE IF EXISTS `#__mokosuitebooking_waitlist`;
DROP TABLE IF EXISTS `#__mokosuitebooking_booking_services`;
DROP TABLE IF EXISTS `#__mokosuitebooking_locations`;
DROP TABLE IF EXISTS `#__mokosuitebooking_bookings`;
DROP TABLE IF EXISTS `#__mokosuitebooking_availability_overrides`;
DROP TABLE IF EXISTS `#__mokosuitebooking_schedules`;
DROP TABLE IF EXISTS `#__mokosuitebooking_staff_services`;
DROP TABLE IF EXISTS `#__mokosuitebooking_staff`;
DROP TABLE IF EXISTS `#__mokosuitebooking_services`;
DROP TABLE IF EXISTS `#__mokosuitebooking_locations`;
@@ -13,10 +13,10 @@ defined('_JEXEC') or die;
use Joomla\CMS\Plugin\CMSPlugin;
use Joomla\Event\SubscriberInterface;
class Booking extends CMSPlugin implements SubscriberInterface
final class Booking extends CMSPlugin implements SubscriberInterface
{
public static function getSubscribedEvents(): array
{
return [];
}
}
}
@@ -1,15 +1,17 @@
<?xml version="1.0"?>
<?xml version="1.0" encoding="utf-8"?>
<extension type="plugin" group="webservices" method="upgrade">
<name>Web Services - MokoSuite Booking</name>
<element>mokosuitebooking</element>
<author>Moko Consulting</author>
<authorEmail>hello@mokoconsulting.tech</authorEmail>
<authorUrl>https://mokoconsulting.tech</authorUrl>
<creationDate>2026-06-27</creationDate>
<copyright>Copyright (C) 2026 Moko Consulting.</copyright>
<version>06.00.00</version>
<license>GPL-3.0-or-later</license>
<description>REST API routes for MokoSuite Booking operations</description>
<namespace path="src">Moko\Plugin\WebServices\MokoSuiteBooking</namespace>
<files><folder>src</folder><folder>services</folder></files>
</extension>
<name>plg_webservices_mokosuitebooking</name>
<version>06.00.00</version>
<creationDate>2026-06-27</creationDate>
<author>Moko Consulting</author>
<authorEmail>hello@mokoconsulting.tech</authorEmail>
<authorUrl>https://mokoconsulting.tech</authorUrl>
<copyright>Copyright (C) 2026 Moko Consulting</copyright>
<license>GPL-3.0-or-later</license>
<description>PLG_WEBSERVICES_MOKOSUITEBOOKING_DESCRIPTION</description>
<namespace path="src">Moko\Plugin\Webservices\MokoSuiteBooking</namespace>
<files>
<folder plugin="mokosuitebooking">services</folder>
<folder>src</folder>
</files>
</extension>
@@ -13,13 +13,21 @@ use Joomla\CMS\Plugin\PluginHelper;
use Joomla\DI\Container;
use Joomla\DI\ServiceProviderInterface;
use Joomla\Event\DispatcherInterface;
use Moko\Plugin\WebServices\MokoSuiteBooking\Extension\MokoSuiteBooking;
use Moko\Plugin\Webservices\MokoSuiteBooking\Extension\MokoSuiteBooking;
return new class implements ServiceProviderInterface {
public function register(Container $container): void {
$container->set(PluginInterface::class, function (Container $container) {
$dispatcher = $container->get(DispatcherInterface::class);
return new MokoSuiteBooking($dispatcher, (array) PluginHelper::getPlugin('webservices', 'mokosuitebooking'));
});
return new class implements ServiceProviderInterface
{
public function register(Container $container): void
{
$container->set(
PluginInterface::class,
function (Container $container) {
$dispatcher = $container->get(DispatcherInterface::class);
$plugin = new MokoSuiteBooking($dispatcher, (array) PluginHelper::getPlugin('webservices', 'mokosuitebooking'));
$plugin->setApplication(\Joomla\CMS\Factory::getApplication());
return $plugin;
}
);
}
};
};
@@ -6,7 +6,7 @@
* Authored-by: Moko Consulting
*/
namespace Moko\Plugin\WebServices\MokoSuiteBooking\Extension;
namespace Moko\Plugin\Webservices\MokoSuiteBooking\Extension;
defined('_JEXEC') or die;
@@ -14,7 +14,7 @@ use Joomla\CMS\Plugin\CMSPlugin;
use Joomla\CMS\Router\ApiRouter;
use Joomla\Event\SubscriberInterface;
class MokoSuiteBooking extends CMSPlugin implements SubscriberInterface
final class MokoSuiteBooking extends CMSPlugin implements SubscriberInterface
{
public static function getSubscribedEvents(): array
{
@@ -23,21 +23,8 @@ class MokoSuiteBooking extends CMSPlugin implements SubscriberInterface
];
}
public function onBeforeApiRoute($event): void
public function onBeforeApiRoute(&$router): void
{
$router = $event->getArgument('router');
$routes = [
'services', 'staff', 'bookings', 'schedules',
'locations', 'availability', 'waitlist',
];
foreach ($routes as $route) {
$router->createCRUDRoutes(
"v1/booking/{$route}",
$route,
['component' => 'com_mokosuitebooking']
);
}
// Route registrations will be added during development
}
}
}
+9 -12
View File
@@ -1,24 +1,21 @@
<?xml version="1.0" encoding="utf-8"?>
<extension type="package" method="upgrade">
<name>Package - MokoSuite Booking</name>
<name>pkg_mokosuitebooking</name>
<packagename>mokosuitebooking</packagename>
<version>06.00.00</version>
<creationDate>2026-06-27</creationDate>
<author>Moko Consulting</author>
<authorEmail>hello@mokoconsulting.tech</authorEmail>
<authorUrl>https://mokoconsulting.tech</authorUrl>
<copyright>Copyright (C) 2026 Moko Consulting. All rights reserved.</copyright>
<license>GNU General Public License version 3 or later; see LICENSE</license>
<copyright>Copyright (C) 2026 Moko Consulting</copyright>
<license>GPL-3.0-or-later</license>
<description>Appointment and resource booking for service businesses</description>
<php_minimum>8.3</php_minimum>
<dlid prefix="dlid=" suffix=""/>
<blockChildUninstall>true</blockChildUninstall>
<files folder="packages">
<file type="plugin" id="plg_system_mokosuitebooking" group="system">plg_system_mokosuitebooking.zip</file>
<file type="component" id="com_mokosuitebooking">com_mokosuitebooking.zip</file>
<file type="plugin" id="plg_webservices_mokosuitebooking" group="webservices">plg_webservices_mokosuitebooking.zip</file>
<files>
<file type="plugin" id="mokosuitebooking" group="system">packages/plg_system_mokosuitebooking</file>
<file type="component" id="com_mokosuitebooking">packages/com_mokosuitebooking</file>
<file type="plugin" id="mokosuitebooking" group="webservices">packages/plg_webservices_mokosuitebooking</file>
</files>
<updateservers>
<server type="extension" priority="1" name="Package - MokoSuite Booking">https://git.mokoconsulting.tech/MokoConsulting/MokoSuiteBooking/updates.xml</server>
<server type="extension" name="MokoSuiteBooking Updates">https://git.mokoconsulting.tech/MokoConsulting/MokoSuiteBooking/updates.xml</server>
</updateservers>
</extension>
</extension>
@@ -1,26 +0,0 @@
; Copyright (C) 2026 Moko Consulting <hello@mokoconsulting.tech>
; SPDX-License-Identifier: GPL-3.0-or-later
; Authored-by: Moko Consulting
PLG_SYSTEM_MOKOSUITEBOOKING="System - MokoSuiteBooking"
PLG_SYSTEM_MOKOSUITEBOOKING_DESCRIPTION="MokoSuiteBooking system plugin for appointment and resource booking."
PLG_SYSTEM_MOKOSUITEBOOKING_FIELDSET_BASIC="Basic Settings"
PLG_SYSTEM_MOKOSUITEBOOKING_FIELD_BUSINESS_NAME="Business Name"
PLG_SYSTEM_MOKOSUITEBOOKING_FIELD_TIMEZONE="Timezone"
PLG_SYSTEM_MOKOSUITEBOOKING_FIELD_SLOT_DURATION="Slot Duration (minutes)"
PLG_SYSTEM_MOKOSUITEBOOKING_FIELDSET_BOOKING="Booking Settings"
PLG_SYSTEM_MOKOSUITEBOOKING_FIELD_MAX_ADVANCE_DAYS="Max Advance Booking Days"
PLG_SYSTEM_MOKOSUITEBOOKING_FIELD_CANCELLATION_WINDOW="Cancellation Window (hours)"
PLG_SYSTEM_MOKOSUITEBOOKING_FIELD_CANCELLATION_WINDOW_DESC="Minimum hours before appointment to allow cancellation."
PLG_SYSTEM_MOKOSUITEBOOKING_FIELD_REQUIRE_DEPOSIT="Require Deposit"
PLG_SYSTEM_MOKOSUITEBOOKING_FIELDSET_NOTIFICATIONS="Notifications"
PLG_SYSTEM_MOKOSUITEBOOKING_FIELD_SEND_CONFIRMATION="Send Confirmation Email"
PLG_SYSTEM_MOKOSUITEBOOKING_FIELD_SEND_REMINDER="Send Reminder Email"
PLG_SYSTEM_MOKOSUITEBOOKING_FIELD_REMINDER_HOURS="Reminder Hours Before"
PLG_SYSTEM_MOKOSUITEBOOKING_FIELDSET_DISPLAY="Display"
PLG_SYSTEM_MOKOSUITEBOOKING_FIELD_SHOW_PRICES="Show Prices"
PLG_SYSTEM_MOKOSUITEBOOKING_FIELD_SHOW_DURATION="Show Duration"
@@ -1,6 +0,0 @@
; Copyright (C) 2026 Moko Consulting <hello@mokoconsulting.tech>
; SPDX-License-Identifier: GPL-3.0-or-later
; Authored-by: Moko Consulting
PLG_SYSTEM_MOKOSUITEBOOKING="System - MokoSuiteBooking"
PLG_SYSTEM_MOKOSUITEBOOKING_DESCRIPTION="MokoSuiteBooking system plugin for appointment and resource booking."
@@ -1,139 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright (C) 2026 Moko Consulting <hello@mokoconsulting.tech>
SPDX-License-Identifier: GPL-3.0-or-later
Authored-by: Moko Consulting
-->
<extension type="plugin" group="system" method="upgrade">
<name>plg_system_mokosuitebooking</name>
<version>0.0.1</version>
<creationDate>2026-06-27</creationDate>
<author>Moko Consulting</author>
<authorEmail>hello@mokoconsulting.tech</authorEmail>
<authorUrl>https://mokoconsulting.tech</authorUrl>
<copyright>Copyright (C) 2026 Moko Consulting</copyright>
<license>GPL-3.0-or-later</license>
<description>PLG_SYSTEM_MOKOSUITEBOOKING_DESCRIPTION</description>
<namespace path="src">Moko\Plugin\System\MokoSuiteBooking</namespace>
<files>
<folder>services</folder>
<folder>src</folder>
</files>
<languages folder="language">
<language tag="en-GB">en-GB/plg_system_mokosuitebooking.ini</language>
<language tag="en-GB">en-GB/plg_system_mokosuitebooking.sys.ini</language>
</languages>
<install>
<sql>
<file driver="mysql" charset="utf8">sql/install.mysql.sql</file>
</sql>
</install>
<uninstall>
<sql>
<file driver="mysql" charset="utf8">sql/uninstall.mysql.sql</file>
</sql>
</uninstall>
<config>
<fields name="params">
<fieldset name="basic" label="PLG_SYSTEM_MOKOSUITEBOOKING_FIELDSET_BASIC">
<field
name="business_name"
type="text"
label="PLG_SYSTEM_MOKOSUITEBOOKING_FIELD_BUSINESS_NAME"
default=""
/>
<field
name="timezone"
type="timezone"
label="PLG_SYSTEM_MOKOSUITEBOOKING_FIELD_TIMEZONE"
default="America/New_York"
/>
<field
name="slot_duration"
type="number"
label="PLG_SYSTEM_MOKOSUITEBOOKING_FIELD_SLOT_DURATION"
default="30"
min="5"
max="480"
/>
</fieldset>
<fieldset name="booking" label="PLG_SYSTEM_MOKOSUITEBOOKING_FIELDSET_BOOKING">
<field
name="max_advance_days"
type="number"
label="PLG_SYSTEM_MOKOSUITEBOOKING_FIELD_MAX_ADVANCE_DAYS"
default="90"
min="1"
/>
<field
name="cancellation_window"
type="number"
label="PLG_SYSTEM_MOKOSUITEBOOKING_FIELD_CANCELLATION_WINDOW"
description="PLG_SYSTEM_MOKOSUITEBOOKING_FIELD_CANCELLATION_WINDOW_DESC"
default="24"
min="0"
/>
<field
name="require_deposit"
type="radio"
label="PLG_SYSTEM_MOKOSUITEBOOKING_FIELD_REQUIRE_DEPOSIT"
default="0"
class="btn-group btn-group-yesno">
<option value="0">JNO</option>
<option value="1">JYES</option>
</field>
</fieldset>
<fieldset name="notifications" label="PLG_SYSTEM_MOKOSUITEBOOKING_FIELDSET_NOTIFICATIONS">
<field
name="send_confirmation"
type="radio"
label="PLG_SYSTEM_MOKOSUITEBOOKING_FIELD_SEND_CONFIRMATION"
default="1"
class="btn-group btn-group-yesno">
<option value="0">JNO</option>
<option value="1">JYES</option>
</field>
<field
name="send_reminder"
type="radio"
label="PLG_SYSTEM_MOKOSUITEBOOKING_FIELD_SEND_REMINDER"
default="1"
class="btn-group btn-group-yesno">
<option value="0">JNO</option>
<option value="1">JYES</option>
</field>
<field
name="reminder_hours"
type="number"
label="PLG_SYSTEM_MOKOSUITEBOOKING_FIELD_REMINDER_HOURS"
default="24"
min="1"
/>
</fieldset>
<fieldset name="display" label="PLG_SYSTEM_MOKOSUITEBOOKING_FIELDSET_DISPLAY">
<field
name="show_prices"
type="radio"
label="PLG_SYSTEM_MOKOSUITEBOOKING_FIELD_SHOW_PRICES"
default="1"
class="btn-group btn-group-yesno">
<option value="0">JNO</option>
<option value="1">JYES</option>
</field>
<field
name="show_duration"
type="radio"
label="PLG_SYSTEM_MOKOSUITEBOOKING_FIELD_SHOW_DURATION"
default="1"
class="btn-group btn-group-yesno">
<option value="0">JNO</option>
<option value="1">JYES</option>
</field>
</fieldset>
</fields>
</config>
</extension>
@@ -1,35 +0,0 @@
<?php
/**
* @copyright Copyright (C) 2026 Moko Consulting <hello@mokoconsulting.tech>
* @license GPL-3.0-or-later
*/
defined('_JEXEC') or die;
use Joomla\CMS\Extension\PluginInterface;
use Joomla\CMS\Factory;
use Joomla\CMS\Plugin\PluginHelper;
use Joomla\DI\Container;
use Joomla\DI\ServiceProviderInterface;
use Joomla\Event\DispatcherInterface;
use Moko\Plugin\System\MokoSuiteBooking\Extension\Booking;
return new class () implements ServiceProviderInterface {
public function register(Container $container): void
{
$container->set(
PluginInterface::class,
function (Container $container) {
$dispatcher = $container->get(DispatcherInterface::class);
$plugin = new Booking(
$dispatcher,
(array) PluginHelper::getPlugin('system', 'mokosuitebooking')
);
$plugin->setApplication(Factory::getApplication());
return $plugin;
}
);
}
};
@@ -1,138 +0,0 @@
-- Copyright (C) 2026 Moko Consulting <hello@mokoconsulting.tech>
-- SPDX-License-Identifier: GPL-3.0-or-later
-- Authored-by: Moko Consulting
CREATE TABLE IF NOT EXISTS `#__mokosuitebooking_locations` (
`id` INT UNSIGNED NOT NULL AUTO_INCREMENT,
`name` VARCHAR(255) NOT NULL,
`address` VARCHAR(500) NOT NULL DEFAULT '',
`phone` VARCHAR(50) NOT NULL DEFAULT '',
`email` VARCHAR(255) NOT NULL DEFAULT '',
`timezone` VARCHAR(50) NOT NULL DEFAULT 'America/New_York',
`operating_hours` JSON DEFAULT NULL,
`published` TINYINT NOT NULL DEFAULT 1,
`ordering` INT NOT NULL DEFAULT 0,
`created` DATETIME NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
CREATE TABLE IF NOT EXISTS `#__mokosuitebooking_staff` (
`id` INT UNSIGNED NOT NULL AUTO_INCREMENT,
`contact_id` INT DEFAULT NULL,
`name` VARCHAR(255) NOT NULL,
`email` VARCHAR(255) NOT NULL DEFAULT '',
`phone` VARCHAR(50) NOT NULL DEFAULT '',
`title` VARCHAR(255) NOT NULL DEFAULT '',
`bio` TEXT,
`photo` VARCHAR(500) NOT NULL DEFAULT '',
`color` VARCHAR(7) NOT NULL DEFAULT '#3788d8',
`location_id` INT UNSIGNED DEFAULT NULL,
`published` TINYINT NOT NULL DEFAULT 1,
`ordering` INT NOT NULL DEFAULT 0,
`created` DATETIME NOT NULL,
PRIMARY KEY (`id`),
KEY `idx_contact` (`contact_id`),
KEY `idx_location` (`location_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
CREATE TABLE IF NOT EXISTS `#__mokosuitebooking_services` (
`id` INT UNSIGNED NOT NULL AUTO_INCREMENT,
`name` VARCHAR(255) NOT NULL,
`description` TEXT,
`category` VARCHAR(100) NOT NULL DEFAULT '',
`duration_minutes` SMALLINT UNSIGNED NOT NULL DEFAULT 60,
`buffer_before` SMALLINT UNSIGNED NOT NULL DEFAULT 0,
`buffer_after` SMALLINT UNSIGNED NOT NULL DEFAULT 0,
`price` DECIMAL(10,2) NOT NULL DEFAULT 0.00,
`deposit_required` DECIMAL(10,2) NOT NULL DEFAULT 0.00,
`max_participants` SMALLINT UNSIGNED NOT NULL DEFAULT 1,
`color` VARCHAR(7) NOT NULL DEFAULT '#3788d8',
`published` TINYINT NOT NULL DEFAULT 1,
`ordering` INT NOT NULL DEFAULT 0,
`created` DATETIME NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
CREATE TABLE IF NOT EXISTS `#__mokosuitebooking_schedules` (
`id` INT UNSIGNED NOT NULL AUTO_INCREMENT,
`staff_id` INT UNSIGNED NOT NULL,
`day_of_week` TINYINT UNSIGNED NOT NULL,
`start_time` TIME NOT NULL,
`end_time` TIME NOT NULL,
`location_id` INT UNSIGNED DEFAULT NULL,
`effective_from` DATE DEFAULT NULL,
`effective_to` DATE DEFAULT NULL,
`published` TINYINT NOT NULL DEFAULT 1,
PRIMARY KEY (`id`),
KEY `idx_staff` (`staff_id`),
KEY `idx_day` (`day_of_week`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
CREATE TABLE IF NOT EXISTS `#__mokosuitebooking_availability_overrides` (
`id` INT UNSIGNED NOT NULL AUTO_INCREMENT,
`staff_id` INT UNSIGNED NOT NULL,
`override_date` DATE NOT NULL,
`available` TINYINT NOT NULL DEFAULT 0,
`start_time` TIME DEFAULT NULL,
`end_time` TIME DEFAULT NULL,
`reason` VARCHAR(255) NOT NULL DEFAULT '',
`created` DATETIME NOT NULL,
PRIMARY KEY (`id`),
KEY `idx_staff` (`staff_id`),
KEY `idx_date` (`override_date`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
CREATE TABLE IF NOT EXISTS `#__mokosuitebooking_bookings` (
`id` INT UNSIGNED NOT NULL AUTO_INCREMENT,
`booking_ref` VARCHAR(20) NOT NULL,
`client_contact_id` INT DEFAULT NULL,
`client_name` VARCHAR(255) NOT NULL,
`client_email` VARCHAR(255) NOT NULL DEFAULT '',
`client_phone` VARCHAR(50) NOT NULL DEFAULT '',
`staff_id` INT UNSIGNED DEFAULT NULL,
`location_id` INT UNSIGNED DEFAULT NULL,
`status` ENUM('pending','confirmed','in_progress','completed','cancelled','no_show') NOT NULL DEFAULT 'pending',
`booking_date` DATE NOT NULL,
`start_time` TIME NOT NULL,
`end_time` TIME NOT NULL,
`total_price` DECIMAL(10,2) NOT NULL DEFAULT 0.00,
`deposit_paid` DECIMAL(10,2) NOT NULL DEFAULT 0.00,
`payment_status` ENUM('pending','partial','paid','refunded') NOT NULL DEFAULT 'pending',
`source` ENUM('admin','online','phone','walkin') NOT NULL DEFAULT 'admin',
`notes` TEXT,
`reminder_sent` TINYINT NOT NULL DEFAULT 0,
`created` DATETIME NOT NULL,
`created_by` INT NOT NULL DEFAULT 0,
PRIMARY KEY (`id`),
UNIQUE KEY `idx_ref` (`booking_ref`),
KEY `idx_client` (`client_contact_id`),
KEY `idx_staff` (`staff_id`),
KEY `idx_status` (`status`),
KEY `idx_date` (`booking_date`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
CREATE TABLE IF NOT EXISTS `#__mokosuitebooking_booking_services` (
`id` INT UNSIGNED NOT NULL AUTO_INCREMENT,
`booking_id` INT UNSIGNED NOT NULL,
`service_id` INT UNSIGNED NOT NULL,
`price` DECIMAL(10,2) NOT NULL DEFAULT 0.00,
`duration_minutes` SMALLINT UNSIGNED NOT NULL DEFAULT 60,
PRIMARY KEY (`id`),
KEY `idx_booking` (`booking_id`),
KEY `idx_service` (`service_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
CREATE TABLE IF NOT EXISTS `#__mokosuitebooking_waitlist` (
`id` INT UNSIGNED NOT NULL AUTO_INCREMENT,
`client_contact_id` INT DEFAULT NULL,
`client_name` VARCHAR(255) NOT NULL,
`client_email` VARCHAR(255) NOT NULL DEFAULT '',
`service_id` INT UNSIGNED DEFAULT NULL,
`staff_id` INT UNSIGNED DEFAULT NULL,
`preferred_date` DATE DEFAULT NULL,
`status` ENUM('waiting','notified','booked','expired','cancelled') NOT NULL DEFAULT 'waiting',
`notes` TEXT,
`created` DATETIME NOT NULL,
PRIMARY KEY (`id`),
KEY `idx_status` (`status`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
@@ -1,12 +0,0 @@
-- Copyright (C) 2026 Moko Consulting <hello@mokoconsulting.tech>
-- SPDX-License-Identifier: GPL-3.0-or-later
-- Authored-by: Moko Consulting
DROP TABLE IF EXISTS `#__mokosuitebooking_waitlist`;
DROP TABLE IF EXISTS `#__mokosuitebooking_booking_services`;
DROP TABLE IF EXISTS `#__mokosuitebooking_bookings`;
DROP TABLE IF EXISTS `#__mokosuitebooking_availability_overrides`;
DROP TABLE IF EXISTS `#__mokosuitebooking_schedules`;
DROP TABLE IF EXISTS `#__mokosuitebooking_services`;
DROP TABLE IF EXISTS `#__mokosuitebooking_staff`;
DROP TABLE IF EXISTS `#__mokosuitebooking_locations`;
@@ -1,23 +0,0 @@
<?php
/**
* @copyright Copyright (C) 2026 Moko Consulting <hello@mokoconsulting.tech>
* @license GPL-3.0-or-later
*/
namespace Moko\Plugin\System\MokoSuiteBooking\Extension;
defined('_JEXEC') or die;
use Joomla\CMS\Plugin\CMSPlugin;
use Joomla\Event\DispatcherInterface;
use Psr\Container\ContainerInterface;
final class Booking extends CMSPlugin
{
protected $autoloadLanguage = true;
public function boot(ContainerInterface $container): void
{
}
}
@@ -1,6 +0,0 @@
; Copyright (C) 2026 Moko Consulting <hello@mokoconsulting.tech>
; SPDX-License-Identifier: GPL-3.0-or-later
; Authored-by: Moko Consulting
PLG_WEBSERVICES_MOKOSUITEBOOKING="Web Services - MokoSuiteBooking"
PLG_WEBSERVICES_MOKOSUITEBOOKING_DESCRIPTION="MokoSuiteBooking web services plugin for REST API access."
@@ -1,6 +0,0 @@
; Copyright (C) 2026 Moko Consulting <hello@mokoconsulting.tech>
; SPDX-License-Identifier: GPL-3.0-or-later
; Authored-by: Moko Consulting
PLG_WEBSERVICES_MOKOSUITEBOOKING="Web Services - MokoSuiteBooking"
PLG_WEBSERVICES_MOKOSUITEBOOKING_DESCRIPTION="MokoSuiteBooking web services plugin for REST API access."
@@ -1,28 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright (C) 2026 Moko Consulting <hello@mokoconsulting.tech>
SPDX-License-Identifier: GPL-3.0-or-later
Authored-by: Moko Consulting
-->
<extension type="plugin" group="webservices" method="upgrade">
<name>plg_webservices_mokosuitebooking</name>
<version>0.0.1</version>
<creationDate>2026-06-27</creationDate>
<author>Moko Consulting</author>
<authorEmail>hello@mokoconsulting.tech</authorEmail>
<authorUrl>https://mokoconsulting.tech</authorUrl>
<copyright>Copyright (C) 2026 Moko Consulting</copyright>
<license>GPL-3.0-or-later</license>
<description>PLG_WEBSERVICES_MOKOSUITEBOOKING_DESCRIPTION</description>
<namespace path="src">Moko\Plugin\WebServices\MokoSuiteBooking</namespace>
<files>
<folder>services</folder>
<folder>src</folder>
</files>
<languages folder="language">
<language tag="en-GB">en-GB/plg_webservices_mokosuitebooking.ini</language>
<language tag="en-GB">en-GB/plg_webservices_mokosuitebooking.sys.ini</language>
</languages>
</extension>
@@ -1,35 +0,0 @@
<?php
/**
* @copyright Copyright (C) 2026 Moko Consulting <hello@mokoconsulting.tech>
* @license GPL-3.0-or-later
*/
defined('_JEXEC') or die;
use Joomla\CMS\Extension\PluginInterface;
use Joomla\CMS\Factory;
use Joomla\CMS\Plugin\PluginHelper;
use Joomla\DI\Container;
use Joomla\DI\ServiceProviderInterface;
use Joomla\Event\DispatcherInterface;
use Moko\Plugin\WebServices\MokoSuiteBooking\Extension\MokoSuiteBooking;
return new class () implements ServiceProviderInterface {
public function register(Container $container): void
{
$container->set(
PluginInterface::class,
function (Container $container) {
$dispatcher = $container->get(DispatcherInterface::class);
$plugin = new MokoSuiteBooking(
$dispatcher,
(array) PluginHelper::getPlugin('webservices', 'mokosuitebooking')
);
$plugin->setApplication(Factory::getApplication());
return $plugin;
}
);
}
};
@@ -1,46 +0,0 @@
<?php
/**
* @copyright Copyright (C) 2026 Moko Consulting <hello@mokoconsulting.tech>
* @license GPL-3.0-or-later
*/
namespace Moko\Plugin\WebServices\MokoSuiteBooking\Extension;
defined('_JEXEC') or die;
use Joomla\CMS\Plugin\CMSPlugin;
use Joomla\CMS\Router\ApiRouter;
use Joomla\Event\SubscriberInterface;
final class MokoSuiteBooking extends CMSPlugin implements SubscriberInterface
{
public static function getSubscribedEvents(): array
{
return [
'onBeforeApiRoute' => 'onBeforeApiRoute',
];
}
public function onBeforeApiRoute(&$router): void
{
$routes = [
'bookings' => 'bookingbookings',
'services' => 'bookingservices',
'staff' => 'bookingstaff',
'schedules' => 'bookingschedules',
'locations' => 'bookinglocations',
'waitlist' => 'bookingwaitlist',
];
$defaults = ['component' => 'com_mokosuitebooking', 'public' => false];
foreach ($routes as $pattern => $controller) {
$router->createCRUDRoutes(
'v1/mokosuitebooking/' . $pattern,
$controller,
$defaults
);
}
}
}