Version Description
Download this release
Release Info
Developer | Ladela |
Plugin | ![]() |
Version | 17.4 |
Comparing to | |
See all releases |
Code changes from version 17.3 to 17.4
- backend/Backend.php +2 -5
- backend/components/dialogs/appointment/delete/templates/delete.php +2 -2
- backend/components/dialogs/appointment/edit/Dialog.php +2 -12
- backend/components/dialogs/appointment/edit/resources/js/ng-appointment.js +6 -3
- backend/components/dialogs/appointment/edit/templates/edit.php +1 -1
- backend/components/dialogs/customer/edit/Dialog.php +4 -12
- backend/components/dialogs/customer/edit/resources/js/ng-customer.js +9 -1
- backend/components/dialogs/sms/Ajax.php +1 -1
- backend/components/dialogs/staff/categories/proxy/Pro.php +15 -0
- backend/components/dialogs/staff/edit/Ajax.php +405 -0
- backend/components/dialogs/staff/edit/Dialog.php +91 -0
- backend/{modules/staff → components/dialogs/staff/edit}/forms/StaffServices.php +2 -2
- backend/components/dialogs/staff/edit/proxy/Pro.php +16 -0
- backend/components/dialogs/staff/edit/proxy/SpecialDays.php +16 -0
- backend/components/dialogs/staff/edit/resources/js/staff-days-off.js +62 -0
- backend/{modules/staff → components/dialogs/staff/edit}/resources/js/staff-details.js +95 -40
- backend/components/dialogs/staff/edit/resources/js/staff-edit-dialog.js +274 -0
- backend/components/dialogs/staff/edit/resources/js/staff-schedule.js +368 -0
- backend/components/dialogs/staff/edit/resources/js/staff-services.js +187 -0
- backend/{modules/staff → components/dialogs/staff/edit}/templates/_break.php +0 -0
- backend/{modules/staff → components/dialogs/staff/edit}/templates/_breaks.php +0 -0
- backend/{modules/staff/templates/_details.php → components/dialogs/staff/edit/templates/details.php} +45 -19
- backend/components/dialogs/staff/edit/templates/dialog.php +28 -0
- backend/components/dialogs/staff/edit/templates/dialog_body.php +53 -0
- backend/{modules/staff → components/dialogs/staff/edit}/templates/holidays.php +1 -1
- backend/{modules/staff → components/dialogs/staff/edit}/templates/schedule.php +1 -1
- backend/{modules/staff → components/dialogs/staff/edit}/templates/services.php +2 -2
- backend/modules/appearance/Page.php +1 -1
- backend/modules/appearance/resources/js/appearance.js +3 -3
- backend/modules/appointments/Ajax.php +104 -67
- backend/modules/appointments/Page.php +2 -25
- backend/modules/appointments/proxy/GroupBooking.php +18 -0
- backend/modules/appointments/proxy/Ratings.php +3 -2
- backend/modules/appointments/resources/js/appointments.js +54 -55
- backend/modules/appointments/templates/index.php +1 -3
- backend/modules/calendar/Page.php +2 -11
- backend/modules/calendar/resources/js/calendar-common.js +5 -5
- backend/modules/dashboard/Page.php +2 -22
- backend/modules/dashboard/resources/js/dashboard.js +19 -19
- backend/modules/payments/Page.php +11 -31
- backend/modules/payments/resources/js/payments.js +27 -27
- backend/modules/services/Ajax.php +4 -3
- backend/modules/services/templates/index.php +0 -1
- backend/modules/settings/Page.php +1 -1
- backend/modules/settings/resources/js/settings.js +2 -1
- backend/modules/sms/Page.php +3 -19
- backend/modules/sms/resources/js/sms.js +22 -22
- backend/modules/staff/Ajax.php +79 -401
- backend/modules/staff/Page.php +14 -66
- backend/modules/staff/forms/StaffMember.php +0 -62
- backend/modules/staff/forms/StaffMemberEdit.php +0 -28
- backend/modules/staff/forms/StaffScheduleItemBreak.php +0 -23
- backend/modules/staff/proxy/Pro.php +0 -2
- backend/modules/staff/proxy/Shared.php +1 -1
- backend/modules/staff/resources/js/staff-days-off.js +0 -52
- backend/modules/staff/resources/js/staff-list.js +253 -0
- backend/modules/staff/resources/js/staff-schedule.js +0 -357
- backend/modules/staff/resources/js/staff-services.js +0 -180
- backend/modules/staff/resources/js/staff.js +0 -486
- backend/modules/staff/templates/_list_item.php +0 -22
- backend/modules/staff/templates/_new.php +0 -44
- backend/modules/staff/templates/edit.php +0 -82
- backend/modules/staff/templates/index.php +55 -99
- backend/resources/bootstrap/css/bootstrap-theme.min.css +1 -1
- backend/resources/images/sprite.png +0 -0
- frontend/modules/booking/ShortCode.php +1 -1
- frontend/modules/booking/proxy/PaypalCheckout.php +15 -0
- frontend/resources/js/bookly.js +38 -35
- frontend/resources/js/bookly.min.js +1 -1
- frontend/resources/js/bookly.min.js.map +1 -1
- frontend/resources/js/src/details_step.js +1 -1
- frontend/resources/js/src/main.js +33 -30
- frontend/resources/js/src/repeat_step.js +2 -2
- frontend/resources/js/src/service_step.js +1 -1
- frontend/resources/js/src/time_step.js +1 -1
- languages/bookly.pot +139 -132
- lib/Installer.php +2 -1
- lib/Plugin.php +1 -0
- lib/Query.php +41 -2
- lib/UserBookingData.php +4 -3
- lib/base/Ajax.php +1 -1
- lib/entities/Staff.php +24 -0
- lib/slots/Finder.php +13 -2
- lib/slots/Generator.php +92 -83
- lib/slots/Range.php +16 -0
- lib/slots/Staff.php +0 -1
- lib/utils/DateTime.php +50 -0
- main.php +1 -1
- readme.txt +2 -2
backend/Backend.php
CHANGED
@@ -71,11 +71,8 @@ abstract class Backend
|
|
71 |
$appearance = __( 'Appearance', 'bookly' );
|
72 |
$settings = __( 'Settings', 'bookly' );
|
73 |
|
74 |
-
|
75 |
-
|
76 |
-
Modules\Dashboard\Page::pageSlug(), function () {
|
77 |
-
Modules\Dashboard\Page::render(); } );
|
78 |
-
}
|
79 |
add_submenu_page( 'bookly-menu', $calendar, $calendar, 'read',
|
80 |
Modules\Calendar\Page::pageSlug(), function () { Modules\Calendar\Page::render(); } );
|
81 |
if ( $current_user->has_cap( 'manage_options' ) || $current_user->has_cap( 'manage_bookly_appointments' ) ) {
|
71 |
$appearance = __( 'Appearance', 'bookly' );
|
72 |
$settings = __( 'Settings', 'bookly' );
|
73 |
|
74 |
+
add_submenu_page( 'bookly-menu', $dashboard, $dashboard, 'manage_options',
|
75 |
+
Modules\Dashboard\Page::pageSlug(), function () {Modules\Dashboard\Page::render();} );
|
|
|
|
|
|
|
76 |
add_submenu_page( 'bookly-menu', $calendar, $calendar, 'read',
|
77 |
Modules\Calendar\Page::pageSlug(), function () { Modules\Calendar\Page::render(); } );
|
78 |
if ( $current_user->has_cap( 'manage_options' ) || $current_user->has_cap( 'manage_bookly_appointments' ) ) {
|
backend/components/dialogs/appointment/delete/templates/delete.php
CHANGED
@@ -21,8 +21,8 @@ use Bookly\Backend\Components\Controls\Buttons;
|
|
21 |
</div>
|
22 |
</div>
|
23 |
<div class="modal-footer">
|
24 |
-
<?php Buttons::
|
25 |
-
<?php Buttons::renderCustom( null, 'btn-default',
|
26 |
</div>
|
27 |
</div>
|
28 |
</div>
|
21 |
</div>
|
22 |
</div>
|
23 |
<div class="modal-footer">
|
24 |
+
<?php Buttons::renderCustom( 'bookly-delete', 'btn-danger', esc_html__( 'Delete', 'bookly' ), array(), '<i class="fa fa-fw fa-trash"></i> {caption}' ) ?>
|
25 |
+
<?php Buttons::renderCustom( null, 'btn-default', esc_html__( 'Cancel', 'bookly' ), array( 'ng-click' => 'closeDialog()', 'data-dismiss' => 'modal' ) ) ?>
|
26 |
</div>
|
27 |
</div>
|
28 |
</div>
|
backend/components/dialogs/appointment/edit/Dialog.php
CHANGED
@@ -14,8 +14,6 @@ class Dialog extends Lib\Base\Component
|
|
14 |
*/
|
15 |
public static function render()
|
16 |
{
|
17 |
-
global $wp_locale;
|
18 |
-
|
19 |
self::enqueueStyles( array(
|
20 |
'backend' => array( 'css/jquery-ui-theme/jquery-ui.min.css', 'css/select2.min.css', 'css/fontawesome-all.min.css' ),
|
21 |
'frontend' => array( 'css/ladda.min.css', ),
|
@@ -39,16 +37,8 @@ class Dialog extends Lib\Base\Component
|
|
39 |
) );
|
40 |
|
41 |
wp_localize_script( 'bookly-ng-appointment.js', 'BooklyL10nAppDialog', array(
|
42 |
-
'csrf_token'
|
43 |
-
'
|
44 |
-
'dateFormat' => Lib\Utils\DateTime::convertFormat( 'date', Lib\Utils\DateTime::FORMAT_JQUERY_DATEPICKER ),
|
45 |
-
'monthNamesShort' => array_values( $wp_locale->month_abbrev ),
|
46 |
-
'monthNames' => array_values( $wp_locale->month ),
|
47 |
-
'dayNamesMin' => array_values( $wp_locale->weekday_abbrev ),
|
48 |
-
'dayNamesShort' => array_values( $wp_locale->weekday_abbrev ),
|
49 |
-
'dayNames' => array_values( $wp_locale->weekday ),
|
50 |
-
'firstDay' => (int) get_option( 'start_of_week' ),
|
51 |
-
),
|
52 |
'cf_per_service' => (int) Lib\Config::customFieldsPerService(),
|
53 |
'no_result_found' => __( 'No result found', 'bookly' ),
|
54 |
'staff_any' => get_option( 'bookly_l10n_option_employee' ),
|
14 |
*/
|
15 |
public static function render()
|
16 |
{
|
|
|
|
|
17 |
self::enqueueStyles( array(
|
18 |
'backend' => array( 'css/jquery-ui-theme/jquery-ui.min.css', 'css/select2.min.css', 'css/fontawesome-all.min.css' ),
|
19 |
'frontend' => array( 'css/ladda.min.css', ),
|
37 |
) );
|
38 |
|
39 |
wp_localize_script( 'bookly-ng-appointment.js', 'BooklyL10nAppDialog', array(
|
40 |
+
'csrf_token' => Lib\Utils\Common::getCsrfToken(),
|
41 |
+
'datePicker' => Lib\Utils\DateTime::datePickerOptions(),
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
42 |
'cf_per_service' => (int) Lib\Config::customFieldsPerService(),
|
43 |
'no_result_found' => __( 'No result found', 'bookly' ),
|
44 |
'staff_any' => get_option( 'bookly_l10n_option_employee' ),
|
backend/components/dialogs/appointment/edit/resources/js/ng-appointment.js
CHANGED
@@ -1158,7 +1158,7 @@
|
|
1158 |
month = m.format('M'),
|
1159 |
day = m.format('DD');
|
1160 |
|
1161 |
-
return BooklyL10nAppDialog.
|
1162 |
};
|
1163 |
$scope.schFormatTime = function(slots, options) {
|
1164 |
for (var i = 0; i < options.length; ++ i) {
|
@@ -1263,7 +1263,7 @@
|
|
1263 |
return item.deleted;
|
1264 |
});
|
1265 |
};
|
1266 |
-
$scope.
|
1267 |
$scope.schViewSeries = function ( customer ) {
|
1268 |
jQuery(document.body).trigger( 'recurring_appointments.series_dialog', [ customer.series_id, function (event) {
|
1269 |
// Switch to the event owner tab.
|
@@ -1274,7 +1274,7 @@
|
|
1274 |
/**
|
1275 |
* Datepicker options.
|
1276 |
*/
|
1277 |
-
$scope.
|
1278 |
});
|
1279 |
|
1280 |
/**
|
@@ -1347,6 +1347,9 @@
|
|
1347 |
* @param function callback
|
1348 |
*/
|
1349 |
var showAppointmentDialog = function (appointment_id, staff_id, start_date, callback) {
|
|
|
|
|
|
|
1350 |
var $dialog = jQuery('#bookly-appointment-dialog');
|
1351 |
var $scope = angular.element($dialog[0]).scope();
|
1352 |
$scope.$apply(function ($scope) {
|
1158 |
month = m.format('M'),
|
1159 |
day = m.format('DD');
|
1160 |
|
1161 |
+
return BooklyL10nAppDialog.datePicker.weekdayShort[weekday] + ', ' + BooklyL10nAppDialog.datePicker.monthNamesShort[month-1] + ' ' + day;
|
1162 |
};
|
1163 |
$scope.schFormatTime = function(slots, options) {
|
1164 |
for (var i = 0; i < options.length; ++ i) {
|
1263 |
return item.deleted;
|
1264 |
});
|
1265 |
};
|
1266 |
+
$scope.schDatePickerOptions = jQuery.extend({}, BooklyL10nAppDialog.datePicker, {dateFormat: 'D, M dd, yy'});
|
1267 |
$scope.schViewSeries = function ( customer ) {
|
1268 |
jQuery(document.body).trigger( 'recurring_appointments.series_dialog', [ customer.series_id, function (event) {
|
1269 |
// Switch to the event owner tab.
|
1274 |
/**
|
1275 |
* Datepicker options.
|
1276 |
*/
|
1277 |
+
$scope.datePickerOptions = BooklyL10nAppDialog.datePicker;
|
1278 |
});
|
1279 |
|
1280 |
/**
|
1347 |
* @param function callback
|
1348 |
*/
|
1349 |
var showAppointmentDialog = function (appointment_id, staff_id, start_date, callback) {
|
1350 |
+
if (jQuery.fn.tooltip.Constructor.VERSION.split('.')[0] === '4') {
|
1351 |
+
jQuery('#bookly-tbs .modal.fade').removeClass('fade');
|
1352 |
+
}
|
1353 |
var $dialog = jQuery('#bookly-appointment-dialog');
|
1354 |
var $scope = angular.element($dialog[0]).scope();
|
1355 |
$scope.$apply(function ($scope) {
|
backend/components/dialogs/appointment/edit/templates/edit.php
CHANGED
@@ -56,7 +56,7 @@ use Bookly\Lib\Entities\CustomerAppointment;
|
|
56 |
<div class="col-sm-4">
|
57 |
<label for="bookly-date"><?php esc_html_e( 'Date', 'bookly' ) ?></label>
|
58 |
<input id="bookly-date" class="form-control" type=text
|
59 |
-
ng-model=form.date ui-date="
|
60 |
ng-change=onDateChange()>
|
61 |
</div>
|
62 |
<div class="col-sm-8">
|
56 |
<div class="col-sm-4">
|
57 |
<label for="bookly-date"><?php esc_html_e( 'Date', 'bookly' ) ?></label>
|
58 |
<input id="bookly-date" class="form-control" type=text
|
59 |
+
ng-model=form.date ui-date="datePickerOptions" autocomplete="off"
|
60 |
ng-change=onDateChange()>
|
61 |
</div>
|
62 |
<div class="col-sm-8">
|
backend/components/dialogs/customer/edit/Dialog.php
CHANGED
@@ -14,8 +14,6 @@ class Dialog extends Lib\Base\Component
|
|
14 |
*/
|
15 |
public static function render()
|
16 |
{
|
17 |
-
global $wp_locale;
|
18 |
-
|
19 |
self::enqueueStyles( array(
|
20 |
'backend' => array( 'css/jquery-ui-theme/jquery-ui.min.css', 'css/select2.min.css', ),
|
21 |
'frontend' => get_option( 'bookly_cst_phone_default_country' ) == 'disabled'
|
@@ -44,16 +42,10 @@ class Dialog extends Lib\Base\Component
|
|
44 |
'utils' => is_rtl() ? '' : plugins_url( 'intlTelInput.utils.js', Lib\Plugin::getDirectory() . '/frontend/resources/js/intlTelInput.utils.js' ),
|
45 |
'country' => get_option( 'bookly_cst_phone_default_country' ),
|
46 |
),
|
47 |
-
'
|
48 |
-
'
|
49 |
-
'
|
50 |
-
|
51 |
-
'dayNamesMin' => array_values( $wp_locale->weekday_abbrev ),
|
52 |
-
'dayNames' => array_values( $wp_locale->weekday ),
|
53 |
-
'firstDay' => (int) get_option( 'start_of_week' ),
|
54 |
-
'yearRange' => sprintf( '%s:%s', date_create()->modify( '-100 years' )->format( 'Y' ), date( 'Y' ) ),
|
55 |
-
'changeYear' => true,
|
56 |
-
),
|
57 |
'infoFields' => (array) Lib\Proxy\CustomerInformation::getFieldsWhichMayHaveData(),
|
58 |
'noResultFound' => __( 'No result found', 'bookly' ),
|
59 |
) );
|
14 |
*/
|
15 |
public static function render()
|
16 |
{
|
|
|
|
|
17 |
self::enqueueStyles( array(
|
18 |
'backend' => array( 'css/jquery-ui-theme/jquery-ui.min.css', 'css/select2.min.css', ),
|
19 |
'frontend' => get_option( 'bookly_cst_phone_default_country' ) == 'disabled'
|
42 |
'utils' => is_rtl() ? '' : plugins_url( 'intlTelInput.utils.js', Lib\Plugin::getDirectory() . '/frontend/resources/js/intlTelInput.utils.js' ),
|
43 |
'country' => get_option( 'bookly_cst_phone_default_country' ),
|
44 |
),
|
45 |
+
'datePicker' => Lib\Utils\DateTime::datePickerOptions( array(
|
46 |
+
'yearRange' => sprintf( '%s:%s', date_create()->modify( '-100 years' )->format( 'Y' ), date( 'Y' ) ),
|
47 |
+
'changeYear' => true,
|
48 |
+
) ),
|
|
|
|
|
|
|
|
|
|
|
|
|
49 |
'infoFields' => (array) Lib\Proxy\CustomerInformation::getFieldsWhichMayHaveData(),
|
50 |
'noResultFound' => __( 'No result found', 'bookly' ),
|
51 |
) );
|
backend/components/dialogs/customer/edit/resources/js/ng-customer.js
CHANGED
@@ -192,7 +192,15 @@
|
|
192 |
/**
|
193 |
* Datepicker options.
|
194 |
*/
|
195 |
-
scope.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
196 |
|
197 |
/**
|
198 |
* Toggle checkbox info field.
|
192 |
/**
|
193 |
* Datepicker options.
|
194 |
*/
|
195 |
+
scope.datePickerOptions = jQuery.extend({
|
196 |
+
beforeShow: function (input, inst) {
|
197 |
+
jQuery(document).off('focusin.bs.modal');
|
198 |
+
},
|
199 |
+
onClose: function () {
|
200 |
+
jQuery(document).on('focusin.bs.modal');
|
201 |
+
},
|
202 |
+
},
|
203 |
+
BooklyL10nCustDialog.datePicker);
|
204 |
|
205 |
/**
|
206 |
* Toggle checkbox info field.
|
backend/components/dialogs/sms/Ajax.php
CHANGED
@@ -42,7 +42,7 @@ class Ajax extends Lib\Base\Ajax
|
|
42 |
$notification->load( self::parameter( 'id' ) );
|
43 |
$data = $notification->getFields();
|
44 |
$data['settings'] = array_merge( Lib\DataHolders\Notification\Settings::getDefault(), json_decode( $data['settings'], true ) );
|
45 |
-
if ( get_user_meta( get_current_user_id(), 'rich_editing', true ) !== 'false' ) {
|
46 |
$data['message'] = wpautop( $data['message'] );
|
47 |
}
|
48 |
|
42 |
$notification->load( self::parameter( 'id' ) );
|
43 |
$data = $notification->getFields();
|
44 |
$data['settings'] = array_merge( Lib\DataHolders\Notification\Settings::getDefault(), json_decode( $data['settings'], true ) );
|
45 |
+
if ( get_user_meta( get_current_user_id(), 'rich_editing', true ) !== 'false' && $notification->getGateway() != 'sms' ) {
|
46 |
$data['message'] = wpautop( $data['message'] );
|
47 |
}
|
48 |
|
backend/components/dialogs/staff/categories/proxy/Pro.php
ADDED
@@ -0,0 +1,15 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
namespace Bookly\Backend\Components\Dialogs\Staff\Categories\Proxy;
|
3 |
+
|
4 |
+
use Bookly\Lib as BooklyLib;
|
5 |
+
|
6 |
+
/**
|
7 |
+
* Class Pro
|
8 |
+
* @package Bookly\Backend\Components\Dialogs\Staff\Categories\Proxy
|
9 |
+
*
|
10 |
+
* @method static void renderDialog()
|
11 |
+
* @method static void renderAdd()
|
12 |
+
*/
|
13 |
+
abstract class Pro extends BooklyLib\Base\Proxy
|
14 |
+
{
|
15 |
+
}
|
backend/components/dialogs/staff/edit/Ajax.php
ADDED
@@ -0,0 +1,405 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
namespace Bookly\Backend\Components\Dialogs\Staff\Edit;
|
3 |
+
|
4 |
+
use Bookly\Backend\Modules\Staff\Forms\Widgets\TimeChoice;
|
5 |
+
use Bookly\Backend\Modules\Staff\Proxy as StaffProxy;
|
6 |
+
use Bookly\Lib;
|
7 |
+
|
8 |
+
/**
|
9 |
+
* Class Ajax
|
10 |
+
* @package Bookly\Backend\Components\Dialogs\Staff\Edit
|
11 |
+
*/
|
12 |
+
class Ajax extends Lib\Base\Ajax
|
13 |
+
{
|
14 |
+
/** @var Lib\Entities\Staff */
|
15 |
+
protected static $staff;
|
16 |
+
|
17 |
+
/**
|
18 |
+
* @inheritdoc
|
19 |
+
*/
|
20 |
+
protected static function permissions()
|
21 |
+
{
|
22 |
+
$permissions = get_option( 'bookly_gen_allow_staff_edit_profile' ) ? array( '_default' => 'user' ) : array();
|
23 |
+
if ( Lib\Config::staffCabinetActive() ) {
|
24 |
+
$permissions = array( '_default' => 'user' );
|
25 |
+
}
|
26 |
+
|
27 |
+
return $permissions;
|
28 |
+
}
|
29 |
+
|
30 |
+
/**
|
31 |
+
* Get data for staff
|
32 |
+
*/
|
33 |
+
public static function getStaffData()
|
34 |
+
{
|
35 |
+
$data = StaffProxy\Shared::editStaff(
|
36 |
+
array( 'alert' => array( 'error' => array() ), 'tpl' => array() ),
|
37 |
+
self::$staff
|
38 |
+
);
|
39 |
+
$tpl_data = $data['tpl'];
|
40 |
+
|
41 |
+
$users_for_staff = Lib\Utils\Common::isCurrentUserAdmin() ? self::_getUsersForStaff( self::$staff->getId() ) : array();
|
42 |
+
|
43 |
+
$staff_fields = self::$staff->getFields();
|
44 |
+
$src = false;
|
45 |
+
if ( $staff_fields['attachment_id'] ) {
|
46 |
+
$src = wp_get_attachment_image_src( $staff_fields['attachment_id'], 'thumbnail' );
|
47 |
+
}
|
48 |
+
$staff_fields['avatar'] = $src ? $src[0] : null;
|
49 |
+
|
50 |
+
$response = array(
|
51 |
+
'html' => array(
|
52 |
+
'edit' => self::renderTemplate( 'dialog_body', array( 'staff' => self::$staff ), false ),
|
53 |
+
'details' => self::renderTemplate( 'details', array( 'staff' => self::$staff, 'users_for_staff' => $users_for_staff, 'tpl_data' => $tpl_data ), false ),
|
54 |
+
),
|
55 |
+
);
|
56 |
+
if ( self::$staff->getId() ) {
|
57 |
+
$response['holidays'] = self::$staff->getHolidays();
|
58 |
+
$response['html']['services'] = self::_getStaffServices( self::$staff->getId(), null );
|
59 |
+
$response['html']['schedule'] = self::_getStaffSchedule( self::$staff->getId(), null );
|
60 |
+
$response['html']['special_days'] = Proxy\SpecialDays::getStaffSpecialDaysHtml( '', self::$staff->getId() );
|
61 |
+
$response['html']['holidays'] = self::renderTemplate( 'holidays', array( 'holidays' => $response['holidays'] ), false );
|
62 |
+
$response['staff'] = $staff_fields;
|
63 |
+
$response['alert'] = $data['alert'];
|
64 |
+
}
|
65 |
+
|
66 |
+
wp_send_json_success( $response );
|
67 |
+
}
|
68 |
+
|
69 |
+
/**
|
70 |
+
* Update staff from POST request.
|
71 |
+
*/
|
72 |
+
public static function updateStaff()
|
73 |
+
{
|
74 |
+
if ( ! Lib\Utils\Common::isCurrentUserAdmin() ) {
|
75 |
+
// Check permissions to prevent one staff member from updating profile of another staff member.
|
76 |
+
do {
|
77 |
+
if ( self::parameter( 'staff_cabinet' ) && Lib\Config::staffCabinetActive() ) {
|
78 |
+
$allow = true;
|
79 |
+
} else {
|
80 |
+
$allow = get_option( 'bookly_gen_allow_staff_edit_profile' );
|
81 |
+
}
|
82 |
+
if ( $allow ) {
|
83 |
+
unset ( $_POST['wp_user_id'] );
|
84 |
+
break;
|
85 |
+
}
|
86 |
+
do_action( 'admin_page_access_denied' );
|
87 |
+
wp_die( 'Bookly: ' . __( 'You do not have sufficient permissions to access this page.' ) );
|
88 |
+
} while ( 0 );
|
89 |
+
} elseif ( self::parameter( 'id' ) == 0
|
90 |
+
&& ! Lib\Config::proActive()
|
91 |
+
&& Lib\Entities\Staff::query()->count() > 0
|
92 |
+
) {
|
93 |
+
do_action( 'admin_page_access_denied' );
|
94 |
+
wp_die( 'Bookly: ' . __( 'You do not have sufficient permissions to access this page.' ) );
|
95 |
+
}
|
96 |
+
|
97 |
+
$params = self::postParameters();
|
98 |
+
if ( ! $params['category_id'] ) {
|
99 |
+
$params['category_id'] = null;
|
100 |
+
}
|
101 |
+
if ( ! $params['working_time_limit'] ) {
|
102 |
+
$params['working_time_limit'] = null;
|
103 |
+
}
|
104 |
+
|
105 |
+
self::$staff->setFields( $params );
|
106 |
+
|
107 |
+
StaffProxy\Shared::preUpdateStaff( self::$staff, $params );
|
108 |
+
self::$staff->save();
|
109 |
+
StaffProxy\Shared::updateStaff( self::$staff, $params );
|
110 |
+
|
111 |
+
wp_send_json_success();
|
112 |
+
}
|
113 |
+
|
114 |
+
/**
|
115 |
+
* Get staff services
|
116 |
+
*/
|
117 |
+
public static function getStaffServices()
|
118 |
+
{
|
119 |
+
$form = new Forms\StaffServices();
|
120 |
+
$staff_id = self::parameter( 'staff_id' );
|
121 |
+
$location_id = self::parameter( 'location_id' );
|
122 |
+
|
123 |
+
$form->load( $staff_id, $location_id );
|
124 |
+
|
125 |
+
$html = self::_getStaffServices( $staff_id, $location_id );
|
126 |
+
wp_send_json_success( compact( 'html' ) );
|
127 |
+
}
|
128 |
+
|
129 |
+
/**
|
130 |
+
* Update staff services.
|
131 |
+
*/
|
132 |
+
public static function staffServicesUpdate()
|
133 |
+
{
|
134 |
+
$form = new Forms\StaffServices();
|
135 |
+
$form->bind( self::postParameters() );
|
136 |
+
$form->save();
|
137 |
+
|
138 |
+
StaffProxy\Shared::updateStaffServices( self::postParameters() );
|
139 |
+
|
140 |
+
wp_send_json_success();
|
141 |
+
}
|
142 |
+
|
143 |
+
/**
|
144 |
+
* Get staff schedule.
|
145 |
+
*/
|
146 |
+
public static function getStaffSchedule()
|
147 |
+
{
|
148 |
+
$staff_id = self::parameter( 'staff_id' );
|
149 |
+
$location_id = self::parameter( 'location_id' );
|
150 |
+
$html = self::_getStaffSchedule( $staff_id, $location_id );
|
151 |
+
wp_send_json_success( compact( 'html' ) );
|
152 |
+
}
|
153 |
+
|
154 |
+
/**
|
155 |
+
* Update staff holidays.
|
156 |
+
*/
|
157 |
+
public static function staffHolidaysUpdate()
|
158 |
+
{
|
159 |
+
$id = self::parameter( 'id' );
|
160 |
+
$holiday = self::parameter( 'holiday' ) === 'true';
|
161 |
+
$repeat = self::parameter( 'repeat' ) === 'true';
|
162 |
+
$day = self::parameter( 'day', false );
|
163 |
+
if ( self::$staff ) {
|
164 |
+
// Update or delete the event.
|
165 |
+
if ( $id ) {
|
166 |
+
if ( $holiday ) {
|
167 |
+
Lib\Entities\Holiday::query()
|
168 |
+
->update()
|
169 |
+
->set( 'repeat_event', (int) $repeat )
|
170 |
+
->where( 'id', $id )
|
171 |
+
->execute();
|
172 |
+
} else {
|
173 |
+
Lib\Entities\Holiday::query()
|
174 |
+
->delete()
|
175 |
+
->where( 'id', $id )
|
176 |
+
->execute();
|
177 |
+
}
|
178 |
+
} elseif ( $holiday && $day ) {
|
179 |
+
// Add the new event.
|
180 |
+
$holiday = new Lib\Entities\Holiday();
|
181 |
+
$holiday
|
182 |
+
->setDate( $day )
|
183 |
+
->setRepeatEvent( (int) $repeat )
|
184 |
+
->setStaffId( self::$staff->getId() )
|
185 |
+
->save();
|
186 |
+
}
|
187 |
+
// And return refreshed events.
|
188 |
+
echo json_encode( self::$staff->getHolidays() );
|
189 |
+
}
|
190 |
+
exit;
|
191 |
+
}
|
192 |
+
|
193 |
+
/**
|
194 |
+
* Handle staff schedule break.
|
195 |
+
*/
|
196 |
+
public static function staffScheduleHandleBreak()
|
197 |
+
{
|
198 |
+
$start_time = self::parameter( 'start_time' );
|
199 |
+
$end_time = self::parameter( 'end_time' );
|
200 |
+
$working_start = self::parameter( 'working_start' );
|
201 |
+
$working_end = self::parameter( 'working_end' );
|
202 |
+
|
203 |
+
if ( Lib\Utils\DateTime::timeToSeconds( $start_time ) >= Lib\Utils\DateTime::timeToSeconds( $end_time ) ) {
|
204 |
+
wp_send_json_error( array( 'message' => __( 'The start time must be less than the end one', 'bookly' ), ) );
|
205 |
+
}
|
206 |
+
|
207 |
+
$res_schedule = new Lib\Entities\StaffScheduleItem();
|
208 |
+
$res_schedule->load( self::parameter( 'staff_schedule_item_id' ) );
|
209 |
+
|
210 |
+
$break_id = self::parameter( 'break_id', 0 );
|
211 |
+
|
212 |
+
$in_working_time = $working_start <= $start_time && $start_time <= $working_end
|
213 |
+
&& $working_start <= $end_time && $end_time <= $working_end;
|
214 |
+
if ( ! $in_working_time || ! $res_schedule->isBreakIntervalAvailable( $start_time, $end_time, $break_id ) ) {
|
215 |
+
wp_send_json_error( array( 'message' => __( 'The requested interval is not available', 'bookly' ), ) );
|
216 |
+
}
|
217 |
+
|
218 |
+
$formatted_start = Lib\Utils\DateTime::formatTime( Lib\Utils\DateTime::timeToSeconds( $start_time ) );
|
219 |
+
$formatted_end = Lib\Utils\DateTime::formatTime( Lib\Utils\DateTime::timeToSeconds( $end_time ) );
|
220 |
+
$formatted_interval = $formatted_start . ' - ' . $formatted_end;
|
221 |
+
|
222 |
+
if ( $break_id ) {
|
223 |
+
$break = new Lib\Entities\ScheduleItemBreak();
|
224 |
+
$break->load( $break_id );
|
225 |
+
$break->setStartTime( $start_time )
|
226 |
+
->setEndTime( $end_time )
|
227 |
+
->save();
|
228 |
+
|
229 |
+
wp_send_json_success( array( 'interval' => $formatted_interval, ) );
|
230 |
+
} else {
|
231 |
+
$res_schedule_break = new Lib\Entities\ScheduleItemBreak();
|
232 |
+
$res_schedule_break->setFields( self::postParameters() );
|
233 |
+
$res_schedule_break->save();
|
234 |
+
if ( $res_schedule_break ) {
|
235 |
+
$breakStart = new TimeChoice( array( 'use_empty' => false, 'type' => 'break_from' ) );
|
236 |
+
$breakEnd = new TimeChoice( array( 'use_empty' => false, 'type' => 'to' ) );
|
237 |
+
wp_send_json( array(
|
238 |
+
'success' => true,
|
239 |
+
'item_content' => self::renderTemplate( '_break', array(
|
240 |
+
'staff_schedule_item_break_id' => $res_schedule_break->getId(),
|
241 |
+
'formatted_interval' => $formatted_interval,
|
242 |
+
'break_start_choices' => $breakStart->render( '', $start_time, array( 'class' => 'break-start form-control' ) ),
|
243 |
+
'break_end_choices' => $breakEnd->render( '', $end_time, array( 'class' => 'break-end form-control' ) ),
|
244 |
+
), false ),
|
245 |
+
) );
|
246 |
+
} else {
|
247 |
+
wp_send_json_error( array( 'message' => __( 'Error adding the break interval', 'bookly' ), ) );
|
248 |
+
}
|
249 |
+
}
|
250 |
+
}
|
251 |
+
|
252 |
+
/**
|
253 |
+
* Delete staff schedule break.
|
254 |
+
*/
|
255 |
+
public static function deleteStaffScheduleBreak()
|
256 |
+
{
|
257 |
+
$break = new Lib\Entities\ScheduleItemBreak();
|
258 |
+
$break->setId( self::parameter( 'id', 0 ) );
|
259 |
+
$break->delete();
|
260 |
+
|
261 |
+
wp_send_json_success();
|
262 |
+
}
|
263 |
+
|
264 |
+
/**
|
265 |
+
* Get list of users available for particular staff.
|
266 |
+
*
|
267 |
+
* @param integer $staff_id If null then it means new staff
|
268 |
+
* @return array
|
269 |
+
*/
|
270 |
+
private static function _getUsersForStaff( $staff_id = null )
|
271 |
+
{
|
272 |
+
/** @var \wpdb $wpdb */
|
273 |
+
global $wpdb;
|
274 |
+
if ( ! is_multisite() ) {
|
275 |
+
$query = sprintf(
|
276 |
+
'SELECT ID, user_email, display_name FROM ' . $wpdb->users . '
|
277 |
+
WHERE ID NOT IN(SELECT DISTINCT IFNULL( wp_user_id, 0 ) FROM ' . Lib\Entities\Staff::getTableName() . ' %s)
|
278 |
+
ORDER BY display_name',
|
279 |
+
$staff_id !== null
|
280 |
+
? 'WHERE ' . Lib\Entities\Staff::getTableName() . '.id <> ' . (int) $staff_id
|
281 |
+
: ''
|
282 |
+
);
|
283 |
+
$users = $wpdb->get_results( $query );
|
284 |
+
} else {
|
285 |
+
// In Multisite show users only for current blog.
|
286 |
+
$query = Lib\Entities\Staff::query( 's' )->select( 'DISTINCT wp_user_id' )->whereNot( 'wp_user_id', null );
|
287 |
+
if ( $staff_id != null ) {
|
288 |
+
$query->whereNot( 'id', $staff_id );
|
289 |
+
}
|
290 |
+
$exclude_wp_users = array();
|
291 |
+
foreach ( $query->fetchArray() as $staff ) {
|
292 |
+
$exclude_wp_users[] = $staff['wp_user_id'];
|
293 |
+
}
|
294 |
+
$users = array_map(
|
295 |
+
function ( \WP_User $wp_user ) {
|
296 |
+
$obj = new \stdClass();
|
297 |
+
$obj->ID = $wp_user->ID;
|
298 |
+
$obj->user_email = $wp_user->data->user_email;
|
299 |
+
$obj->display_name = $wp_user->data->display_name;
|
300 |
+
|
301 |
+
return $obj;
|
302 |
+
},
|
303 |
+
get_users( array( 'blog_id' => get_current_blog_id(), 'orderby' => 'display_name', 'exclude' => $exclude_wp_users ) )
|
304 |
+
);
|
305 |
+
}
|
306 |
+
|
307 |
+
return $users;
|
308 |
+
}
|
309 |
+
|
310 |
+
/**
|
311 |
+
* @param int $staff_id
|
312 |
+
* @param int|null $location_id
|
313 |
+
* @return string
|
314 |
+
*/
|
315 |
+
private static function _getStaffServices( $staff_id, $location_id )
|
316 |
+
{
|
317 |
+
$form = new Forms\StaffServices();
|
318 |
+
$form->load( $staff_id, $location_id );
|
319 |
+
$services_data = $form->getServicesData();
|
320 |
+
|
321 |
+
return self::renderTemplate( 'services', compact( 'form', 'services_data', 'staff_id', 'location_id' ), false );
|
322 |
+
}
|
323 |
+
|
324 |
+
/**
|
325 |
+
* Get staff schedule.
|
326 |
+
*
|
327 |
+
* @param int $staff_id
|
328 |
+
* @param int|null $location_id
|
329 |
+
* @return string|void
|
330 |
+
*/
|
331 |
+
private static function _getStaffSchedule( $staff_id, $location_id )
|
332 |
+
{
|
333 |
+
$staff = new Lib\Entities\Staff();
|
334 |
+
$staff->load( $staff_id );
|
335 |
+
$schedule_items = $staff->getScheduleItems( $location_id );
|
336 |
+
return self::renderTemplate( 'schedule', compact( 'schedule_items', 'staff_id', 'location_id' ), false );
|
337 |
+
}
|
338 |
+
|
339 |
+
/**
|
340 |
+
* Extend parent method to control access on staff member level.
|
341 |
+
*
|
342 |
+
* @param string $action
|
343 |
+
* @return bool
|
344 |
+
*/
|
345 |
+
protected static function hasAccess( $action )
|
346 |
+
{
|
347 |
+
if ( parent::hasAccess( $action ) ) {
|
348 |
+
self::$staff = new Lib\Entities\Staff();
|
349 |
+
if ( ! Lib\Utils\Common::isCurrentUserAdmin() ) {
|
350 |
+
self::$staff->loadBy( array( 'wp_user_id' => get_current_user_id() ) );
|
351 |
+
switch ( $action ) {
|
352 |
+
case 'getStaffData':
|
353 |
+
case 'updateStaff':
|
354 |
+
return self::$staff->isLoaded();
|
355 |
+
case 'getStaffSchedule':
|
356 |
+
case 'getStaffServices':
|
357 |
+
case 'staffHolidaysUpdate':
|
358 |
+
case 'staffServicesUpdate':
|
359 |
+
return self::$staff->isLoaded()
|
360 |
+
&& ( self::$staff->getId() == self::parameter( 'staff_id' ) );
|
361 |
+
case 'staffScheduleHandleBreak':
|
362 |
+
$res_schedule = new Lib\Entities\StaffScheduleItem();
|
363 |
+
$res_schedule->load( self::parameter( 'staff_schedule_item_id' ) );
|
364 |
+
return self::$staff->isLoaded()
|
365 |
+
&& ( self::$staff->getId() == $res_schedule->getStaffId() );
|
366 |
+
break;
|
367 |
+
case 'deleteStaffScheduleBreak':
|
368 |
+
$break = new Lib\Entities\ScheduleItemBreak();
|
369 |
+
$break->load( self::parameter( 'id' ) );
|
370 |
+
$res_schedule = new Lib\Entities\StaffScheduleItem();
|
371 |
+
$res_schedule->load( $break->getStaffScheduleItemId() );
|
372 |
+
return self::$staff->isLoaded()
|
373 |
+
&& ( self::$staff->getId() == $res_schedule->getStaffId() );
|
374 |
+
break;
|
375 |
+
case 'staffScheduleUpdate':
|
376 |
+
if ( self::hasParameter( 'days' ) ) {
|
377 |
+
foreach ( self::parameter( 'days' ) as $id => $day_index ) {
|
378 |
+
$res_schedule = new Lib\Entities\StaffScheduleItem();
|
379 |
+
$res_schedule->load( $id );
|
380 |
+
$staff = new Lib\Entities\Staff();
|
381 |
+
$staff->load( $res_schedule->getStaffId() );
|
382 |
+
if ( $staff->getWpUserId() != get_current_user_id() ) {
|
383 |
+
return false;
|
384 |
+
}
|
385 |
+
}
|
386 |
+
}
|
387 |
+
return true;
|
388 |
+
break;
|
389 |
+
default:
|
390 |
+
return false;
|
391 |
+
}
|
392 |
+
} else {
|
393 |
+
if ( in_array( $action, array( 'getStaffData', 'updateStaff' ) ) ) {
|
394 |
+
self::$staff->load( self::parameter( 'id' ) );
|
395 |
+
} elseif ( in_array( $action, array( 'staffHolidaysUpdate' ) ) ) {
|
396 |
+
self::$staff->load( self::parameter( 'staff_id' ) );
|
397 |
+
}
|
398 |
+
}
|
399 |
+
|
400 |
+
return true;
|
401 |
+
}
|
402 |
+
|
403 |
+
return false;
|
404 |
+
}
|
405 |
+
}
|
backend/components/dialogs/staff/edit/Dialog.php
ADDED
@@ -0,0 +1,91 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
namespace Bookly\Backend\Components\Dialogs\Staff\Edit;
|
3 |
+
|
4 |
+
use Bookly\Backend\Components\Notices\Limitation;
|
5 |
+
use Bookly\Backend\Components\Dialogs\Staff\Edit\Proxy;
|
6 |
+
use Bookly\Lib;
|
7 |
+
|
8 |
+
/**
|
9 |
+
* Class Dialog
|
10 |
+
* @package Bookly\Backend\Components\Dialogs\Staff\Edit
|
11 |
+
*/
|
12 |
+
class Dialog extends Lib\Base\Component
|
13 |
+
{
|
14 |
+
/**
|
15 |
+
* Render create service dialog.
|
16 |
+
*/
|
17 |
+
public static function render()
|
18 |
+
{
|
19 |
+
/** @var \WP_Locale $wp_locale */
|
20 |
+
global $wp_locale;
|
21 |
+
|
22 |
+
wp_enqueue_media();
|
23 |
+
|
24 |
+
self::enqueueStyles( array(
|
25 |
+
'frontend' => array_merge(
|
26 |
+
array( 'css/ladda.min.css', ),
|
27 |
+
get_option( 'bookly_cst_phone_default_country' ) == 'disabled'
|
28 |
+
? array()
|
29 |
+
: array( 'css/intlTelInput.css' )
|
30 |
+
),
|
31 |
+
'backend' => array( 'css/fontawesome-all.min.css', 'css/select2.min.css' ),
|
32 |
+
) );
|
33 |
+
|
34 |
+
self::enqueueScripts( array(
|
35 |
+
'frontend' => array_merge(
|
36 |
+
array(
|
37 |
+
'js/spin.min.js' => array( 'jquery' ),
|
38 |
+
'js/ladda.min.js' => array( 'jquery' ),
|
39 |
+
),
|
40 |
+
get_option( 'bookly_cst_phone_default_country' ) == 'disabled'
|
41 |
+
? array()
|
42 |
+
: array( 'js/intlTelInput.min.js' => array( 'jquery' ) )
|
43 |
+
),
|
44 |
+
'backend' => array(
|
45 |
+
'js/dropdown.js' => array( 'jquery' ),
|
46 |
+
'js/range_tools.js' => array( 'jquery' ),
|
47 |
+
'js/moment.min.js',
|
48 |
+
'js/select2.full.min.js' => array( 'jquery' ),
|
49 |
+
),
|
50 |
+
'module' => array(
|
51 |
+
'js/staff-details.js' => array( 'jquery' ),
|
52 |
+
'js/staff-services.js' => array( 'bookly-staff-details.js' ),
|
53 |
+
'js/staff-schedule.js' => array( 'bookly-staff-services.js' ),
|
54 |
+
'js/staff-days-off.js' => array( 'bookly-staff-schedule.js' ),
|
55 |
+
'js/staff-edit-dialog.js' => array( 'jquery-ui-sortable', 'jquery-ui-datepicker', 'bookly-range_tools.js', 'bookly-staff-days-off.js' )
|
56 |
+
),
|
57 |
+
) );
|
58 |
+
|
59 |
+
wp_localize_script( 'bookly-staff-edit-dialog.js', 'BooklyStaffEditDialogL10n', array(
|
60 |
+
'csrfToken' => Lib\Utils\Common::getCsrfToken(),
|
61 |
+
'intlTelInput' => array(
|
62 |
+
'enabled' => get_option( 'bookly_cst_phone_default_country' ) != 'disabled',
|
63 |
+
'utils' => is_rtl() ? '' : plugins_url( 'intlTelInput.utils.js', Lib\Plugin::getDirectory() . '/frontend/resources/js/intlTelInput.utils.js' ),
|
64 |
+
'country' => get_option( 'bookly_cst_phone_default_country' ),
|
65 |
+
),
|
66 |
+
'holidays' => array(
|
67 |
+
'loading_img' => plugins_url( 'bookly-responsive-appointment-booking-tool/backend/resources/images/loading.gif' ),
|
68 |
+
'start_of_week' => (int) get_option( 'start_of_week' ),
|
69 |
+
'days' => array_values( $wp_locale->weekday_abbrev ),
|
70 |
+
'months' => array_values( $wp_locale->month ),
|
71 |
+
'close' => __( 'Close', 'bookly' ),
|
72 |
+
'repeat' => __( 'Repeat every year', 'bookly' ),
|
73 |
+
'we_are_not_working' => __( 'We are not working on this day', 'bookly' ),
|
74 |
+
),
|
75 |
+
'services' => array(
|
76 |
+
'capacity_error' => __( 'Min capacity should not be greater than max capacity.', 'bookly' ),
|
77 |
+
),
|
78 |
+
'createStaff' => __( 'Create staff', 'bookly' ),
|
79 |
+
'editStaff' => __( 'Edit staff', 'bookly' ),
|
80 |
+
'areYouSure' => __( 'Are you sure?', 'bookly' ),
|
81 |
+
'settingsSaved' => __( 'Settings saved.', 'bookly' ),
|
82 |
+
'proRequired' => (int) ! Lib\Config::proActive(),
|
83 |
+
'limitation' => Limitation::getHtml(),
|
84 |
+
'activeStaffId' => self::parameter( 'staff_id', 0 )
|
85 |
+
) );
|
86 |
+
|
87 |
+
self::renderTemplate( 'dialog' );
|
88 |
+
|
89 |
+
Proxy\Pro::renderArchivingComponents();
|
90 |
+
}
|
91 |
+
}
|
backend/{modules/staff → components/dialogs/staff/edit}/forms/StaffServices.php
RENAMED
@@ -1,11 +1,11 @@
|
|
1 |
<?php
|
2 |
-
namespace Bookly\Backend\
|
3 |
|
4 |
use Bookly\Lib;
|
5 |
|
6 |
/**
|
7 |
* Class StaffServices
|
8 |
-
* @package Bookly\Backend\
|
9 |
*/
|
10 |
class StaffServices extends Lib\Base\Form
|
11 |
{
|
1 |
<?php
|
2 |
+
namespace Bookly\Backend\Components\Dialogs\Staff\Edit\Forms;
|
3 |
|
4 |
use Bookly\Lib;
|
5 |
|
6 |
/**
|
7 |
* Class StaffServices
|
8 |
+
* @package Bookly\Backend\Components\Dialogs\Staff\Edit\Forms
|
9 |
*/
|
10 |
class StaffServices extends Lib\Base\Form
|
11 |
{
|
backend/components/dialogs/staff/edit/proxy/Pro.php
ADDED
@@ -0,0 +1,16 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
namespace Bookly\Backend\Components\Dialogs\Staff\Edit\Proxy;
|
3 |
+
|
4 |
+
use Bookly\Lib;
|
5 |
+
|
6 |
+
/**
|
7 |
+
* Class Pro
|
8 |
+
*
|
9 |
+
* @package Bookly\Backend\Components\Dialogs\Staff\Edit\Proxy
|
10 |
+
*
|
11 |
+
* @method static string renderArchivingComponents()
|
12 |
+
*/
|
13 |
+
abstract class Pro extends Lib\Base\Proxy
|
14 |
+
{
|
15 |
+
|
16 |
+
}
|
backend/components/dialogs/staff/edit/proxy/SpecialDays.php
ADDED
@@ -0,0 +1,16 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
namespace Bookly\Backend\Components\Dialogs\Staff\Edit\Proxy;
|
3 |
+
|
4 |
+
use Bookly\Lib;
|
5 |
+
|
6 |
+
/**
|
7 |
+
* Class SpecialDays
|
8 |
+
*
|
9 |
+
* @package Bookly\Backend\Components\Dialogs\Staff\Edit\Proxy
|
10 |
+
*
|
11 |
+
* @method static string getStaffSpecialDaysHtml( string $default, int $staff_id )
|
12 |
+
*/
|
13 |
+
abstract class SpecialDays extends Lib\Base\Proxy
|
14 |
+
{
|
15 |
+
|
16 |
+
}
|
backend/components/dialogs/staff/edit/resources/js/staff-days-off.js
ADDED
@@ -0,0 +1,62 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
jQuery(function ($) {
|
2 |
+
|
3 |
+
var DaysOff = function($container, options) {
|
4 |
+
var obj = this;
|
5 |
+
jQuery.extend(obj.options, options);
|
6 |
+
|
7 |
+
if (!$container.children().length) {
|
8 |
+
$container.html('<div class="bookly-loading"></div>');
|
9 |
+
$.ajax({
|
10 |
+
url: ajaxurl,
|
11 |
+
data: {action: 'bookly_staff_holidays', id: obj.options.staff_id, csrf_token: obj.options.csrf_token},
|
12 |
+
xhrFields: {withCredentials: true},
|
13 |
+
crossDomain: 'withCredentials' in new XMLHttpRequest(),
|
14 |
+
success: function (response) {
|
15 |
+
$container.html(response.data.html);
|
16 |
+
init($container, obj);
|
17 |
+
}
|
18 |
+
});
|
19 |
+
} else {
|
20 |
+
init($container, obj);
|
21 |
+
}
|
22 |
+
};
|
23 |
+
|
24 |
+
function init($container, obj) {
|
25 |
+
if ($container.data('init') != true) {
|
26 |
+
var d = new Date();
|
27 |
+
$('.bookly-js-holidays').jCal({
|
28 |
+
day: new Date(d.getFullYear(), 0, 1),
|
29 |
+
days: 1,
|
30 |
+
showMonths: 12,
|
31 |
+
scrollSpeed: 350,
|
32 |
+
action: 'bookly_staff_holidays_update',
|
33 |
+
csrf_token: obj.options.csrf_token,
|
34 |
+
staff_id: obj.options.staff_id,
|
35 |
+
events: obj.options.l10n.holidays,
|
36 |
+
dayOffset: parseInt(obj.options.l10n.firstDay),
|
37 |
+
loadingImg: obj.options.l10n.loading_img,
|
38 |
+
dow: obj.options.l10n.days,
|
39 |
+
ml: obj.options.l10n.months,
|
40 |
+
we_are_not_working: obj.options.l10n.we_are_not_working,
|
41 |
+
repeat: obj.options.l10n.repeat,
|
42 |
+
close: obj.options.l10n.close
|
43 |
+
});
|
44 |
+
|
45 |
+
$('.bookly-js-jCalBtn', $container).on('click', function (e) {
|
46 |
+
e.preventDefault();
|
47 |
+
var trigger = $(this).data('trigger');
|
48 |
+
$('.bookly-js-holidays', $container).find($(trigger)).trigger('click');
|
49 |
+
});
|
50 |
+
|
51 |
+
$container.data('init', true);
|
52 |
+
}
|
53 |
+
}
|
54 |
+
|
55 |
+
DaysOff.prototype.options = {
|
56 |
+
staff_id : -1,
|
57 |
+
csrf_token: '',
|
58 |
+
l10n: {}
|
59 |
+
};
|
60 |
+
|
61 |
+
window.BooklyStaffDaysOff = DaysOff;
|
62 |
+
});
|
backend/{modules/staff → components/dialogs/staff/edit}/resources/js/staff-details.js
RENAMED
@@ -60,23 +60,98 @@ jQuery(function ($) {
|
|
60 |
|
61 |
$staffLocations.booklyDropdown();
|
62 |
|
63 |
-
|
64 |
-
|
65 |
-
|
66 |
-
|
67 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
68 |
|
69 |
-
|
70 |
-
|
71 |
-
|
72 |
-
|
73 |
-
|
74 |
-
|
|
|
|
|
|
|
|
|
|
|
75 |
e.preventDefault();
|
76 |
-
|
77 |
-
|
78 |
-
|
79 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
80 |
$unsaved_changes_save.on('click', function () {
|
81 |
var ladda = Ladda.create(this);
|
82 |
ladda.start();
|
@@ -84,7 +159,7 @@ jQuery(function ($) {
|
|
84 |
if (response.success) {
|
85 |
window.location.href = $unsaved_changes.data('url');
|
86 |
} else {
|
87 |
-
obj.options.
|
88 |
}
|
89 |
ladda.stop();
|
90 |
});
|
@@ -93,34 +168,12 @@ jQuery(function ($) {
|
|
93 |
window.location.href = $unsaved_changes.data('url');
|
94 |
});
|
95 |
|
96 |
-
// Save staff member details.
|
97 |
-
$('#bookly-details-save', $container).on('click', function (e) {
|
98 |
-
e.preventDefault();
|
99 |
-
var ladda = Ladda.create(this);
|
100 |
-
ladda.start();
|
101 |
-
// for BooklyPro listener in archive.js
|
102 |
-
// When button disabled, listeners don't process
|
103 |
-
$(this).removeAttr('disabled');
|
104 |
-
save(function (response) {
|
105 |
-
if (response.success) {
|
106 |
-
obj.options.booklyAlert({success: [obj.options.l10n.saved]});
|
107 |
-
$('[bookly-js-staff-name-' + obj.options.get_details.id + ']').text($('#bookly-full-name', $form).val());
|
108 |
-
if (typeof obj.options.renderWpUsers === 'function') {
|
109 |
-
obj.options.renderWpUsers(response.data.wp_users);
|
110 |
-
}
|
111 |
-
} else {
|
112 |
-
obj.options.booklyAlert({error: [response.data.error]});
|
113 |
-
}
|
114 |
-
ladda.stop();
|
115 |
-
});
|
116 |
-
});
|
117 |
-
|
118 |
function save(callback) {
|
119 |
var data = $form.serializeArray(),
|
120 |
$staff_phone = $('#bookly-phone', $form),
|
121 |
phone;
|
122 |
try {
|
123 |
-
phone =
|
124 |
if (phone == '') {
|
125 |
phone = $staff_phone.val();
|
126 |
}
|
@@ -155,7 +208,9 @@ jQuery(function ($) {
|
|
155 |
csrf_token: ''
|
156 |
},
|
157 |
l10n : {},
|
158 |
-
|
|
|
|
|
159 |
};
|
160 |
|
161 |
window.BooklyStaffDetails = Details;
|
60 |
|
61 |
$staffLocations.booklyDropdown();
|
62 |
|
63 |
+
$container
|
64 |
+
.on('change', 'select,input,textarea', function () {
|
65 |
+
has_changes = true;
|
66 |
+
})
|
67 |
+
.on('click', '.bookly-js-google-calendar-row a', function (e) {
|
68 |
+
var url = $(this).attr('href');
|
69 |
+
if (has_changes) {
|
70 |
+
e.preventDefault();
|
71 |
+
$unsaved_changes.modal('show');
|
72 |
+
$unsaved_changes.data('url', url);
|
73 |
+
}
|
74 |
+
})
|
75 |
+
.on('click', '.bookly-js-outlook-calendar-row a', function (e) {
|
76 |
+
var url = $(this).attr('href');
|
77 |
+
if (has_changes) {
|
78 |
+
e.preventDefault();
|
79 |
+
$unsaved_changes.modal('show');
|
80 |
+
$unsaved_changes.data('url', url);
|
81 |
+
}
|
82 |
+
})
|
83 |
+
.on('change', '[name=google_disconnect]', function () {
|
84 |
+
has_changes = true;
|
85 |
+
$('.bookly-js-google-calendars-list', $container).toggle(!this.checked);
|
86 |
+
}).on('change', '[name=outlook_disconnect]', function () {
|
87 |
+
has_changes = true;
|
88 |
+
$('.bookly-js-outlook-calendars-list', $container).toggle(!this.checked);
|
89 |
+
})
|
90 |
+
.on('click', '.bookly-pretty-indicator', function (e) {
|
91 |
+
e.preventDefault();
|
92 |
+
e.stopPropagation();
|
93 |
+
var frame = wp.media({
|
94 |
+
library: {type: 'image'},
|
95 |
+
multiple: false
|
96 |
+
});
|
97 |
+
frame
|
98 |
+
.on('select', function () {
|
99 |
+
var selection = frame.state().get('selection').toJSON(),
|
100 |
+
img_src;
|
101 |
+
if (selection.length) {
|
102 |
+
if (selection[0].sizes['thumbnail'] !== undefined) {
|
103 |
+
img_src = selection[0].sizes['thumbnail'].url;
|
104 |
+
} else {
|
105 |
+
img_src = selection[0].url;
|
106 |
+
}
|
107 |
+
$container.find('[name=attachment_id]').val(selection[0].id).trigger('change');
|
108 |
+
$('#bookly-js-staff-avatar').find('.bookly-js-image').css({'background-image': 'url(' + img_src + ')', 'background-size': 'cover'});
|
109 |
+
$('.bookly-thumb-delete').show();
|
110 |
+
$(this).hide();
|
111 |
+
has_changes = true;
|
112 |
+
}
|
113 |
+
})
|
114 |
+
.on('close', function(){
|
115 |
+
$('body').addClass('modal-open');
|
116 |
+
});
|
117 |
|
118 |
+
frame.open();
|
119 |
+
})
|
120 |
+
// Delete staff avatar
|
121 |
+
.on('click', '.bookly-thumb-delete', function () {
|
122 |
+
var $thumb = $(this).parents('.bookly-js-image');
|
123 |
+
$thumb.attr('style', '');
|
124 |
+
$container.find('[name=attachment_id]').val('').trigger('change');
|
125 |
+
has_changes = true;
|
126 |
+
})
|
127 |
+
// Save staff member details.
|
128 |
+
.on('click', '#bookly-details-save', function (e) {
|
129 |
e.preventDefault();
|
130 |
+
var ladda = Ladda.create(this);
|
131 |
+
ladda.start();
|
132 |
+
// for BooklyPro listener in archive.js
|
133 |
+
// When button disabled, listeners don't process
|
134 |
+
$(this).removeAttr('disabled');
|
135 |
+
|
136 |
+
save(function (response) {
|
137 |
+
if (response.success) {
|
138 |
+
obj.options.savingStatus({success: [obj.options.l10n.saved]});
|
139 |
+
$('[bookly-js-staff-name-' + obj.options.get_details.id + ']').text($('#bookly-full-name', $form).val());
|
140 |
+
if (typeof obj.options.renderWpUsers === 'function') {
|
141 |
+
obj.options.renderWpUsers(response.data.wp_users);
|
142 |
+
}
|
143 |
+
} else {
|
144 |
+
obj.options.savingStatus({error: [response.data.error]});
|
145 |
+
}
|
146 |
+
ladda.stop();
|
147 |
+
});
|
148 |
+
})
|
149 |
+
.on('click', 'button:reset', function () {
|
150 |
+
setTimeout(function () {
|
151 |
+
$staffLocations.booklyDropdown('reset');
|
152 |
+
}, 0);
|
153 |
+
});
|
154 |
+
|
155 |
$unsaved_changes_save.on('click', function () {
|
156 |
var ladda = Ladda.create(this);
|
157 |
ladda.start();
|
159 |
if (response.success) {
|
160 |
window.location.href = $unsaved_changes.data('url');
|
161 |
} else {
|
162 |
+
obj.options.savingStatus({error: [response.data.error]});
|
163 |
}
|
164 |
ladda.stop();
|
165 |
});
|
168 |
window.location.href = $unsaved_changes.data('url');
|
169 |
});
|
170 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
171 |
function save(callback) {
|
172 |
var data = $form.serializeArray(),
|
173 |
$staff_phone = $('#bookly-phone', $form),
|
174 |
phone;
|
175 |
try {
|
176 |
+
phone = obj.options.intlTelInput.enabled ? $staff_phone.intlTelInput('getNumber') : $staff_phone.val();
|
177 |
if (phone == '') {
|
178 |
phone = $staff_phone.val();
|
179 |
}
|
208 |
csrf_token: ''
|
209 |
},
|
210 |
l10n : {},
|
211 |
+
savingStatus : function (data) {
|
212 |
+
$(document.body).trigger('staff_edit.save', [data]);
|
213 |
+
}
|
214 |
};
|
215 |
|
216 |
window.BooklyStaffDetails = Details;
|
backend/components/dialogs/staff/edit/resources/js/staff-edit-dialog.js
ADDED
@@ -0,0 +1,274 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
jQuery(function ($) {
|
2 |
+
'use strict';
|
3 |
+
|
4 |
+
let $staffList = $('#staff-list'),
|
5 |
+
$modal = $('#bookly-staff-edit-modal'),
|
6 |
+
$modalBody = $('.modal-body', $modal),
|
7 |
+
$modalTitle = $('.modal-title', $modal),
|
8 |
+
$modalFooter = $('.modal-footer ', $modal),
|
9 |
+
$saveBtn = $('.bookly-js-save', $modalFooter),
|
10 |
+
$archiveBtn = $('.bookly-js-staff-archive', $modalFooter),
|
11 |
+
$validateErrors = $('.bookly-js-errors', $modalFooter),
|
12 |
+
$deleteCascadeModal = $('.bookly-js-delete-cascade-confirm'),
|
13 |
+
$staffCount = $('.bookly-js-staff-count'),
|
14 |
+
staff_id,
|
15 |
+
holidays
|
16 |
+
;
|
17 |
+
|
18 |
+
$staffList
|
19 |
+
.on('click', '[data-action="edit"]', function () {
|
20 |
+
let data = $staffList.DataTable().row($(this).closest('td')).data();
|
21 |
+
staff_id = data.id;
|
22 |
+
editStaff(staff_id);
|
23 |
+
});
|
24 |
+
|
25 |
+
$('#bookly-js-new-staff')
|
26 |
+
.on('click', function () {
|
27 |
+
if (BooklyStaffEditDialogL10n.proRequired == '1' && $staffCount.html() > 0) {
|
28 |
+
booklyAlert({error: [BooklyStaffEditDialogL10n.limitation]});
|
29 |
+
return false;
|
30 |
+
} else {
|
31 |
+
staff_id = 0;
|
32 |
+
editStaff(staff_id);
|
33 |
+
}
|
34 |
+
});
|
35 |
+
|
36 |
+
if (BooklyStaffEditDialogL10n.activeStaffId != '0') {
|
37 |
+
staff_id = BooklyStaffEditDialogL10n.activeStaffId;
|
38 |
+
editStaff(staff_id);
|
39 |
+
}
|
40 |
+
|
41 |
+
function editStaff(staff_id) {
|
42 |
+
$modalTitle.html(staff_id ? BooklyStaffEditDialogL10n.editStaff : BooklyStaffEditDialogL10n.createStaff);
|
43 |
+
$('#bookly-staff-delete', $modalFooter).toggle(staff_id != 0);
|
44 |
+
|
45 |
+
$modalFooter.hide();
|
46 |
+
$validateErrors.html('');
|
47 |
+
$saveBtn.prop('disabled', false);
|
48 |
+
$modalBody.html('<div class="bookly-loading"></div>');
|
49 |
+
$modal.modal();
|
50 |
+
$.get(ajaxurl, {action: 'bookly_get_staff_data', id: staff_id, csrf_token: BooklyStaffEditDialogL10n.csrfToken}, function (response) {
|
51 |
+
$modalBody.html(response.data.html.edit);
|
52 |
+
booklyAlert(response.data.alert);
|
53 |
+
$modalFooter.show();
|
54 |
+
holidays = response.data.holidays;
|
55 |
+
let $details_container = $('#bookly-details-container', $modalBody),
|
56 |
+
$services_container = $('#bookly-services-container', $modalBody),
|
57 |
+
$schedule_container = $('#bookly-schedule-container', $modalBody),
|
58 |
+
$holidays_container = $('#bookly-holidays-container', $modalBody),
|
59 |
+
$special_days_container = $('#bookly-special-days-container', $modalBody)
|
60 |
+
;
|
61 |
+
$details_container.append(response.data.html.details);
|
62 |
+
$services_container.append(response.data.html.services);
|
63 |
+
$schedule_container.append(response.data.html.schedule);
|
64 |
+
$holidays_container.append(response.data.html.holidays);
|
65 |
+
$special_days_container.append(response.data.html.special_days);
|
66 |
+
|
67 |
+
$('.panel-footer', $modalBody).hide();
|
68 |
+
|
69 |
+
new BooklyStaffDetails($details_container, {
|
70 |
+
get_details : {},
|
71 |
+
intlTelInput: BooklyStaffEditDialogL10n.intlTelInput,
|
72 |
+
l10n: BooklyStaffEditDialogL10n
|
73 |
+
});
|
74 |
+
|
75 |
+
$archiveBtn.toggle(staff_id ? response.data.staff.visibility !== 'archive' : false);
|
76 |
+
});
|
77 |
+
}
|
78 |
+
|
79 |
+
/**
|
80 |
+
* Delete staff member.
|
81 |
+
*/
|
82 |
+
$modalFooter
|
83 |
+
.on('click', '#bookly-staff-delete', function (e) {
|
84 |
+
e.preventDefault();
|
85 |
+
|
86 |
+
var ladda = Ladda.create(this),
|
87 |
+
data = {
|
88 |
+
action: 'bookly_remove_staff',
|
89 |
+
'staff_ids[]': staff_id,
|
90 |
+
csrf_token: BooklyStaffEditDialogL10n.csrfToken
|
91 |
+
};
|
92 |
+
ladda.start();
|
93 |
+
|
94 |
+
var delete_staff = function (ajaxurl, data) {
|
95 |
+
$.post(ajaxurl, data, function (response) {
|
96 |
+
ladda.stop();
|
97 |
+
if (!response.success) {
|
98 |
+
switch (response.data.action) {
|
99 |
+
case 'show_modal':
|
100 |
+
$deleteCascadeModal.modal('show');
|
101 |
+
break;
|
102 |
+
case 'confirm':
|
103 |
+
if (confirm(BooklyStaffEditDialogL10n.areYouSure)) {
|
104 |
+
delete_staff(ajaxurl, $.extend(data, {force_delete: true}));
|
105 |
+
}
|
106 |
+
break;
|
107 |
+
}
|
108 |
+
} else {
|
109 |
+
$modal.modal('hide');
|
110 |
+
$staffList.DataTable().ajax.reload();
|
111 |
+
}
|
112 |
+
});
|
113 |
+
};
|
114 |
+
|
115 |
+
delete_staff(ajaxurl, data);
|
116 |
+
});
|
117 |
+
|
118 |
+
$modalBody
|
119 |
+
// Delete staff avatar
|
120 |
+
.on('click', '.bookly-thumb-delete', function () {
|
121 |
+
var $thumb = $(this).parents('.bookly-js-image');
|
122 |
+
$thumb.attr('style', '');
|
123 |
+
$modalBody.find('[name=attachment_id]').val('').trigger('change');
|
124 |
+
})
|
125 |
+
|
126 |
+
// Open details tab
|
127 |
+
.on('click', '#bookly-details-tab', function () {
|
128 |
+
$('.tab-pane > div').hide();
|
129 |
+
$('#bookly-details-container', $modalBody).show();
|
130 |
+
})
|
131 |
+
|
132 |
+
// Open services tab
|
133 |
+
.on('click', '#bookly-services-tab', function () {
|
134 |
+
$('.tab-pane > div').hide();
|
135 |
+
let $container = $('#bookly-services-container', $modalBody);
|
136 |
+
new BooklyStaffServices($container, {
|
137 |
+
get_staff_services: {
|
138 |
+
action: 'bookly_get_staff_services',
|
139 |
+
staff_id: staff_id,
|
140 |
+
csrf_token: BooklyStaffEditDialogL10n.csrfToken
|
141 |
+
},
|
142 |
+
onLoad: function () {
|
143 |
+
$('.panel-footer', $container).hide();
|
144 |
+
$('#bookly-services-save', $container).addClass('bookly-js-save');
|
145 |
+
$(document.body).trigger('staff_edit.validation', ['staff-services', false, '']);
|
146 |
+
},
|
147 |
+
l10n: BooklyStaffEditDialogL10n.services,
|
148 |
+
});
|
149 |
+
|
150 |
+
$('#bookly-services-save', $container).addClass('bookly-js-save');
|
151 |
+
$container.show();
|
152 |
+
})
|
153 |
+
|
154 |
+
// Open special days tab
|
155 |
+
.on('click', '#bookly-special-days-tab', function () {
|
156 |
+
$('.tab-pane > div').hide();
|
157 |
+
let $container = $('#bookly-special-days-container', $modalBody);
|
158 |
+
new BooklyStaffSpecialDays($container, {
|
159 |
+
staff_id: staff_id,
|
160 |
+
csrf_token: BooklyStaffEditDialogL10n.csrfToken,
|
161 |
+
l10n: SpecialDaysL10n
|
162 |
+
});
|
163 |
+
|
164 |
+
$('#bookly-js-special-days-save-days', $container).addClass('bookly-js-save');
|
165 |
+
$container.show();
|
166 |
+
})
|
167 |
+
|
168 |
+
// Open schedule tab
|
169 |
+
.on('click', '#bookly-schedule-tab', function () {
|
170 |
+
$('.tab-pane > div').hide();
|
171 |
+
let $container = $('#bookly-schedule-container', $modalBody);
|
172 |
+
|
173 |
+
new BooklyStaffSchedule($container, {
|
174 |
+
get_staff_schedule: {
|
175 |
+
action: 'bookly_get_staff_schedule',
|
176 |
+
staff_id: staff_id,
|
177 |
+
csrf_token: BooklyStaffEditDialogL10n.csrfToken
|
178 |
+
},
|
179 |
+
onLoad: function () {
|
180 |
+
$('.panel-footer', $container).hide();
|
181 |
+
$('#bookly-schedule-save', $container).addClass('bookly-js-save');
|
182 |
+
},
|
183 |
+
l10n: BooklyL10n
|
184 |
+
});
|
185 |
+
|
186 |
+
$('#bookly-schedule-save', $modalBody).addClass('bookly-js-save');
|
187 |
+
$container.show();
|
188 |
+
})
|
189 |
+
|
190 |
+
// Open holiday tab
|
191 |
+
.on('click', '#bookly-holidays-tab', function () {
|
192 |
+
$('.tab-pane > div').hide();
|
193 |
+
let $container = $('#bookly-holidays-container', $modalBody);
|
194 |
+
|
195 |
+
new BooklyStaffDaysOff($container, {
|
196 |
+
staff_id: staff_id,
|
197 |
+
csrf_token: BooklyStaffEditDialogL10n.csrfToken,
|
198 |
+
l10n: jQuery.extend(BooklyStaffEditDialogL10n.holidays, {holidays: holidays})
|
199 |
+
});
|
200 |
+
|
201 |
+
$container.show();
|
202 |
+
});
|
203 |
+
|
204 |
+
$deleteCascadeModal
|
205 |
+
// Delete
|
206 |
+
.on('click', '.bookly-js-delete', function () {
|
207 |
+
$modalBody.html('<div class="bookly-loading"></div>');
|
208 |
+
ladda = Ladda.create(this);
|
209 |
+
ladda.start();
|
210 |
+
delete_staff(ajaxurl, $.extend(data, {force_delete: true}));
|
211 |
+
$deleteCascadeModal.modal('hide');
|
212 |
+
ladda.stop();
|
213 |
+
})
|
214 |
+
// Edit
|
215 |
+
.on('click', '.bookly-js-edit', function () {
|
216 |
+
ladda = Ladda.create(this);
|
217 |
+
ladda.start();
|
218 |
+
window.location.href = response.data.filter_url;
|
219 |
+
});
|
220 |
+
|
221 |
+
let waitResposes = 0,
|
222 |
+
ladda,
|
223 |
+
success;
|
224 |
+
|
225 |
+
$saveBtn
|
226 |
+
.on('click', function (e) {
|
227 |
+
e.preventDefault();
|
228 |
+
ladda = Ladda.create(this);
|
229 |
+
ladda.start();
|
230 |
+
|
231 |
+
let $buttons = $('.panel-footer', $modalBody);
|
232 |
+
waitResposes = 0;
|
233 |
+
success = true;
|
234 |
+
$buttons
|
235 |
+
.each(function () {
|
236 |
+
let $button = $('.bookly-js-save', this);
|
237 |
+
if ($button.length > 0) {
|
238 |
+
waitResposes++;
|
239 |
+
$button.trigger('click');
|
240 |
+
}
|
241 |
+
});
|
242 |
+
});
|
243 |
+
|
244 |
+
$(document.body)
|
245 |
+
.on('staff_edit.save', {},
|
246 |
+
function (event, result) {
|
247 |
+
if (waitResposes > 0) {
|
248 |
+
if (result.hasOwnProperty('error')){
|
249 |
+
success = false;
|
250 |
+
}
|
251 |
+
waitResposes --;
|
252 |
+
}
|
253 |
+
if (waitResposes <= 0) {
|
254 |
+
$staffList.DataTable().ajax.reload();
|
255 |
+
ladda ? ladda.stop() : null;
|
256 |
+
$modal.modal('hide');
|
257 |
+
booklyAlert({success: [BooklyStaffEditDialogL10n.settingsSaved]})
|
258 |
+
}
|
259 |
+
})
|
260 |
+
.on('staff_edit.validation', {},
|
261 |
+
function (event, tab, has_error, info) {
|
262 |
+
let id = 'tab-' + tab + '-validation',
|
263 |
+
$container = $validateErrors.find('#' + id);
|
264 |
+
if (has_error) {
|
265 |
+
if ($container.length === 0) {
|
266 |
+
$validateErrors.append($('<div/>').attr('id', id).html(info));
|
267 |
+
}
|
268 |
+
} else {
|
269 |
+
$container.remove();
|
270 |
+
}
|
271 |
+
|
272 |
+
$saveBtn.prop('disabled', $('>', $validateErrors).length !== 0);
|
273 |
+
});
|
274 |
+
});
|
backend/components/dialogs/staff/edit/resources/js/staff-schedule.js
ADDED
@@ -0,0 +1,368 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
jQuery(function ($) {
|
2 |
+
var Schedule = function ($container, options) {
|
3 |
+
var obj = this;
|
4 |
+
jQuery.extend(obj.options, options);
|
5 |
+
|
6 |
+
// Loads schedule list
|
7 |
+
if (!$container.children().length) {
|
8 |
+
$container.html('<div class="bookly-loading"></div>');
|
9 |
+
$.ajax({
|
10 |
+
type: 'POST',
|
11 |
+
url: ajaxurl,
|
12 |
+
data: obj.options.get_staff_schedule,
|
13 |
+
dataType: 'json',
|
14 |
+
xhrFields: {withCredentials: true},
|
15 |
+
crossDomain: 'withCredentials' in new XMLHttpRequest(),
|
16 |
+
success: function (response) {
|
17 |
+
// fill in the container
|
18 |
+
$container.html('');
|
19 |
+
$container.append(response.data.html);
|
20 |
+
$container.removeData('init');
|
21 |
+
obj.options.onLoad();
|
22 |
+
init($container, obj);
|
23 |
+
}
|
24 |
+
});
|
25 |
+
} else {
|
26 |
+
init($container, obj);
|
27 |
+
}
|
28 |
+
|
29 |
+
function init($container, obj) {
|
30 |
+
if ($container.data('init') != true) {
|
31 |
+
$container.booklyHelp();
|
32 |
+
|
33 |
+
// init 'add break' functionality
|
34 |
+
$('.bookly-js-toggle-popover:not(.break-interval)', $container).popover({
|
35 |
+
html: true,
|
36 |
+
placement: 'bottom',
|
37 |
+
template: '<div class="popover" role="tooltip"><div class="popover-arrow"></div><h3 class="popover-title"></h3><div class="popover-content"></div></div>',
|
38 |
+
trigger: 'manual',
|
39 |
+
content: function () {
|
40 |
+
return $($(this).data('popover-content')).html()
|
41 |
+
}
|
42 |
+
}).on('click', function () {
|
43 |
+
$(this).popover('toggle');
|
44 |
+
|
45 |
+
var $popover = $(this).next('.popover'),
|
46 |
+
working_start = $popover.closest('.row').find('.working-schedule-start').val(),
|
47 |
+
$break_start = $popover.find('.break-start'),
|
48 |
+
$break_end = $popover.find('.break-end'),
|
49 |
+
working_start_time = working_start.split(':'),
|
50 |
+
working_start_hours = parseInt(working_start_time[0], 10),
|
51 |
+
break_start_hours = working_start_hours + 1;
|
52 |
+
if (break_start_hours < 10) {
|
53 |
+
break_start_hours = '0' + break_start_hours;
|
54 |
+
}
|
55 |
+
var break_end_hours = working_start_hours + 2;
|
56 |
+
if (break_end_hours < 10) {
|
57 |
+
break_end_hours = '0' + break_end_hours;
|
58 |
+
}
|
59 |
+
var break_end_hours_str = break_end_hours + ':' + working_start_time[1] + ':' + working_start_time[2],
|
60 |
+
break_start_hours_str = break_start_hours + ':' + working_start_time[1] + ':' + working_start_time[2];
|
61 |
+
|
62 |
+
$break_start.val(break_start_hours_str);
|
63 |
+
$break_end.val(break_end_hours_str);
|
64 |
+
|
65 |
+
hideInaccessibleBreaks($break_start, $break_end);
|
66 |
+
|
67 |
+
$popover.find('.bookly-popover-close').on('click', function () {
|
68 |
+
$popover.popover('hide');
|
69 |
+
});
|
70 |
+
});
|
71 |
+
|
72 |
+
$container.off()
|
73 |
+
// Save Schedule
|
74 |
+
.on('click', '#bookly-schedule-save', function (e) {
|
75 |
+
e.preventDefault();
|
76 |
+
var ladda = Ladda.create(this);
|
77 |
+
ladda.start();
|
78 |
+
var data = {};
|
79 |
+
$('select.working-schedule-start, select.working-schedule-end, input:hidden', $container).each(function () {
|
80 |
+
data[this.name] = this.value;
|
81 |
+
});
|
82 |
+
data['location_id'] = $('#staff_location_id', $container).val();
|
83 |
+
data['custom_location_settings'] = $('#custom_location_settings', $container).val();
|
84 |
+
data['staff_id'] = options.get_staff_schedule.staff_id;
|
85 |
+
$.post(ajaxurl, $.param(data), function () {
|
86 |
+
ladda.stop();
|
87 |
+
obj.options.savingStatus({success: [obj.options.l10n.saved]});
|
88 |
+
});
|
89 |
+
})
|
90 |
+
// Resets initial schedule values
|
91 |
+
.on('click', '#bookly-schedule-reset', function (e) {
|
92 |
+
e.preventDefault();
|
93 |
+
var ladda = Ladda.create(this);
|
94 |
+
ladda.start();
|
95 |
+
|
96 |
+
$('.working-schedule-start', $container).each(function () {
|
97 |
+
$(this).val($(this).data('default_value'));
|
98 |
+
$(this).trigger('change');
|
99 |
+
});
|
100 |
+
|
101 |
+
$('.working-schedule-end', $container).each(function () {
|
102 |
+
$(this).val($(this).data('default_value'));
|
103 |
+
});
|
104 |
+
|
105 |
+
// reset breaks
|
106 |
+
$.ajax({
|
107 |
+
url: ajaxurl,
|
108 |
+
type: 'POST',
|
109 |
+
data: {action: 'bookly_reset_breaks', breaks: $(this).data('default-breaks'), staff_cabinet: $(this).data('staff-cabinet') || 0, csrf_token: obj.options.l10n.csrfToken},
|
110 |
+
dataType: 'json',
|
111 |
+
success: function (response) {
|
112 |
+
for (var k in response) {
|
113 |
+
var $content = $(response[k]);
|
114 |
+
$('[data-staff_schedule_item_id=' + k + '] .breaks', $container).html($content);
|
115 |
+
$content.find('.bookly-intervals-wrapper .delete-break').on('click', function () {
|
116 |
+
deleteBreak.call(this);
|
117 |
+
});
|
118 |
+
}
|
119 |
+
},
|
120 |
+
complete: function () {
|
121 |
+
ladda.stop();
|
122 |
+
}
|
123 |
+
});
|
124 |
+
})
|
125 |
+
|
126 |
+
.on('click', '.break-interval', function () {
|
127 |
+
var $button = $(this);
|
128 |
+
$('.popover').popover('hide');
|
129 |
+
var break_id = $button.closest('.bookly-intervals-wrapper').data('break_id');
|
130 |
+
$(this).popover({
|
131 |
+
html: true,
|
132 |
+
placement: 'bottom',
|
133 |
+
template: '<div class="popover" role="tooltip"><div class="popover-arrow"></div><h3 class="popover-title"></h3><div class="popover-content"></div></div>',
|
134 |
+
content: function () {
|
135 |
+
return $('.bookly-js-content-break-' + break_id).html();
|
136 |
+
},
|
137 |
+
trigger: 'manual'
|
138 |
+
});
|
139 |
+
|
140 |
+
$(this).popover('toggle');
|
141 |
+
|
142 |
+
var $popover = $(this).next('.popover'),
|
143 |
+
$break_start = $popover.find('.break-start'),
|
144 |
+
$break_end = $popover.find('.break-end');
|
145 |
+
|
146 |
+
if ($button.hasClass('break-interval')) {
|
147 |
+
var interval = $button.html().trim().split(' - ');
|
148 |
+
rangeTools.setVal($break_start, interval[0]);
|
149 |
+
rangeTools.setVal($break_end, interval[1]);
|
150 |
+
}
|
151 |
+
|
152 |
+
hideInaccessibleBreaks($break_start, $break_end, true);
|
153 |
+
|
154 |
+
$popover.find('.bookly-popover-close').on('click', function () {
|
155 |
+
$popover.popover('hide');
|
156 |
+
});
|
157 |
+
})
|
158 |
+
|
159 |
+
.on('click', '.bookly-js-save-break', function (e) {
|
160 |
+
var $table = $(this).closest('.bookly-js-schedule-form'),
|
161 |
+
$row = $table.parents('.staff-schedule-item-row').first(),
|
162 |
+
data = {
|
163 |
+
action: 'bookly_staff_schedule_handle_break',
|
164 |
+
staff_schedule_item_id: $row.data('staff_schedule_item_id'),
|
165 |
+
start_time: $table.find('.break-start > option:selected').val(),
|
166 |
+
end_time: $table.find('.break-end > option:selected').val(),
|
167 |
+
working_end: $row.find('.working-schedule-end > option:selected').val(),
|
168 |
+
working_start: $row.find('.working-schedule-start > option:selected').val(),
|
169 |
+
csrf_token: obj.options.l10n.csrfToken
|
170 |
+
},
|
171 |
+
$break_interval_wrapper = $table.parents('.bookly-intervals-wrapper').first(),
|
172 |
+
ladda = Ladda.create(e.currentTarget);
|
173 |
+
ladda.start();
|
174 |
+
|
175 |
+
if ($break_interval_wrapper.data('break_id')) {
|
176 |
+
data['break_id'] = $break_interval_wrapper.data('break_id');
|
177 |
+
}
|
178 |
+
$.ajax({
|
179 |
+
url : ajaxurl,
|
180 |
+
type: 'POST',
|
181 |
+
data: data,
|
182 |
+
dataType: 'json',
|
183 |
+
success: function (response) {
|
184 |
+
if (response.success) {
|
185 |
+
if (response['item_content']) {
|
186 |
+
var $new_break_interval_item = $(response['item_content']);
|
187 |
+
$new_break_interval_item
|
188 |
+
.hide()
|
189 |
+
.appendTo($row.find('.breaks-list-content'))
|
190 |
+
.fadeIn('slow');
|
191 |
+
} else if (response.data.interval) {
|
192 |
+
$break_interval_wrapper
|
193 |
+
.find('.break-interval')
|
194 |
+
.text(response.data.interval);
|
195 |
+
}
|
196 |
+
$('.popover').popover('hide');
|
197 |
+
} else {
|
198 |
+
obj.options.savingStatus({error: [response.data.message]});
|
199 |
+
}
|
200 |
+
},
|
201 |
+
complete: function () {
|
202 |
+
ladda.stop();
|
203 |
+
}
|
204 |
+
});
|
205 |
+
|
206 |
+
return false;
|
207 |
+
})
|
208 |
+
|
209 |
+
.on('click', '.bookly-intervals-wrapper .delete-break', function () {
|
210 |
+
deleteBreak.call(this);
|
211 |
+
})
|
212 |
+
|
213 |
+
.on('change', '.break-start', function () {
|
214 |
+
var $start = $(this);
|
215 |
+
var $end = $start.parents('.bookly-flexbox').find('.break-end');
|
216 |
+
hideInaccessibleBreaks($start, $end);
|
217 |
+
})
|
218 |
+
|
219 |
+
.on('change', '.working-schedule-start', function () {
|
220 |
+
var $this = $(this),
|
221 |
+
$end_select = $this.closest('.bookly-flexbox').find('.working-schedule-end'),
|
222 |
+
start_time = $this.val();
|
223 |
+
|
224 |
+
// Hide end time options to keep them within 24 hours after start time.
|
225 |
+
var parts = start_time.split(':');
|
226 |
+
parts[0] = parseInt(parts[0]) + 24;
|
227 |
+
var end_time = parts.join(':');
|
228 |
+
var frag = document.createDocumentFragment();
|
229 |
+
var old_value = $end_select.val();
|
230 |
+
var new_value = null;
|
231 |
+
$('option', $end_select).each(function () {
|
232 |
+
if (this.value <= start_time || this.value > end_time) {
|
233 |
+
var span = document.createElement('span');
|
234 |
+
span.style.display = 'none';
|
235 |
+
span.appendChild(this.cloneNode(true));
|
236 |
+
frag.appendChild(span);
|
237 |
+
} else {
|
238 |
+
frag.appendChild(this.cloneNode(true));
|
239 |
+
if (new_value === null || old_value == this.value) {
|
240 |
+
new_value = this.value;
|
241 |
+
}
|
242 |
+
}
|
243 |
+
});
|
244 |
+
$end_select.empty().append(frag).val(new_value);
|
245 |
+
|
246 |
+
// when the working day is disabled (working start time is set to 'OFF')
|
247 |
+
// hide all the elements inside the row
|
248 |
+
if (!$this.val()) {
|
249 |
+
$this.closest('.row').find('.bookly-hide-on-off').hide();
|
250 |
+
} else {
|
251 |
+
$this.closest('.row').find('.bookly-hide-on-off').show();
|
252 |
+
}
|
253 |
+
})
|
254 |
+
// Change location
|
255 |
+
.on('change', '#staff_location_id', function () {
|
256 |
+
var get_staff_schedule = {
|
257 |
+
action: options.get_staff_schedule.action,
|
258 |
+
staff_id: options.get_staff_schedule.staff_id,
|
259 |
+
csrf_token: options.get_staff_schedule.csrf_token,
|
260 |
+
},
|
261 |
+
staff_location_id = $('#staff_location_id', $container).val();
|
262 |
+
if (staff_location_id != '') {
|
263 |
+
get_staff_schedule['location_id'] = staff_location_id;
|
264 |
+
}
|
265 |
+
$container.html('');
|
266 |
+
new BooklyStaffSchedule($container, {
|
267 |
+
get_staff_schedule: get_staff_schedule,
|
268 |
+
l10n: options.l10n
|
269 |
+
});
|
270 |
+
})
|
271 |
+
// Change default/custom settings for location
|
272 |
+
.on('change', '#custom_location_settings', function () {
|
273 |
+
if ($(this).val() == 1) {
|
274 |
+
$('.panel', $container).show();
|
275 |
+
} else {
|
276 |
+
$('.panel', $container).hide();
|
277 |
+
}
|
278 |
+
})
|
279 |
+
;
|
280 |
+
|
281 |
+
$('#custom_location_settings', $container).trigger('change');
|
282 |
+
$('.working-schedule-start', $container).trigger('change');
|
283 |
+
$('.break-start', $container).trigger('change');
|
284 |
+
$container.data('init', true);
|
285 |
+
}
|
286 |
+
}
|
287 |
+
|
288 |
+
function hideInaccessibleBreaks($start, $end, force_keep_values) {
|
289 |
+
var $row = $start.closest('.row'),
|
290 |
+
$working_start = $row.find('.working-schedule-start'),
|
291 |
+
$working_end = $row.find('.working-schedule-end'),
|
292 |
+
frag1 = document.createDocumentFragment(),
|
293 |
+
frag2 = document.createDocumentFragment(),
|
294 |
+
old_value = $start.val(),
|
295 |
+
new_value = null;
|
296 |
+
|
297 |
+
$('option', $start).each(function () {
|
298 |
+
if ((this.value < $working_start.val() || this.value >= $working_end.val()) && (!force_keep_values || this.value != old_value)) {
|
299 |
+
var span = document.createElement('span');
|
300 |
+
span.style.display = 'none';
|
301 |
+
span.appendChild(this.cloneNode(true));
|
302 |
+
frag1.appendChild(span);
|
303 |
+
} else {
|
304 |
+
frag1.appendChild(this.cloneNode(true));
|
305 |
+
if (new_value === null || old_value == this.value) {
|
306 |
+
new_value = this.value;
|
307 |
+
}
|
308 |
+
}
|
309 |
+
});
|
310 |
+
$start.empty().append(frag1).val(new_value);
|
311 |
+
|
312 |
+
// Hide end time options with value less than in the start time.
|
313 |
+
old_value = $end.val();
|
314 |
+
new_value = null;
|
315 |
+
$('option', $end).each(function () {
|
316 |
+
if ((this.value <= $start.val() || this.value > $working_end.val()) && (!force_keep_values || this.value != old_value)) {
|
317 |
+
var span = document.createElement('span');
|
318 |
+
span.style.display = 'none';
|
319 |
+
span.appendChild(this.cloneNode(true));
|
320 |
+
frag2.appendChild(span);
|
321 |
+
} else {
|
322 |
+
frag2.appendChild(this.cloneNode(true));
|
323 |
+
if (new_value === null || old_value == this.value) {
|
324 |
+
new_value = this.value;
|
325 |
+
}
|
326 |
+
}
|
327 |
+
});
|
328 |
+
$end.empty().append(frag2).val(new_value);
|
329 |
+
}
|
330 |
+
|
331 |
+
function deleteBreak() {
|
332 |
+
var $break_interval_wrapper = $(this).closest('.bookly-intervals-wrapper');
|
333 |
+
if (confirm(obj.options.l10n.are_you_sure)) {
|
334 |
+
var ladda = Ladda.create(this);
|
335 |
+
ladda.start();
|
336 |
+
$.ajax({
|
337 |
+
url: ajaxurl,
|
338 |
+
type: 'POST',
|
339 |
+
data: {action: 'bookly_delete_staff_schedule_break', id: $break_interval_wrapper.data('break_id'), csrf_token: obj.options.l10n.csrfToken},
|
340 |
+
success: function (response) {
|
341 |
+
if (response.success) {
|
342 |
+
$break_interval_wrapper.remove();
|
343 |
+
}
|
344 |
+
},
|
345 |
+
complete: function () {
|
346 |
+
ladda.stop();
|
347 |
+
}
|
348 |
+
});
|
349 |
+
}
|
350 |
+
}
|
351 |
+
};
|
352 |
+
|
353 |
+
Schedule.prototype.options = {
|
354 |
+
get_staff_schedule: {
|
355 |
+
action: 'bookly_get_staff_schedule',
|
356 |
+
staff_id: -1,
|
357 |
+
csrf_token: ''
|
358 |
+
},
|
359 |
+
savingStatus: function (data) {
|
360 |
+
$(document.body).trigger('staff_edit.save', data);
|
361 |
+
},
|
362 |
+
onLoad: function () {},
|
363 |
+
l10n: {}
|
364 |
+
};
|
365 |
+
|
366 |
+
window.BooklyStaffSchedule = Schedule;
|
367 |
+
});
|
368 |
+
|
backend/components/dialogs/staff/edit/resources/js/staff-services.js
ADDED
@@ -0,0 +1,187 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
jQuery(function ($) {
|
2 |
+
|
3 |
+
var Services = function($container, options) {
|
4 |
+
var obj = this;
|
5 |
+
jQuery.extend(obj.options, options);
|
6 |
+
|
7 |
+
// Load services form
|
8 |
+
if (!$container.children().length) {
|
9 |
+
$container.html('<div class="bookly-loading"></div>');
|
10 |
+
$.ajax({
|
11 |
+
type : 'POST',
|
12 |
+
url : ajaxurl,
|
13 |
+
data : obj.options.get_staff_services,
|
14 |
+
dataType : 'json',
|
15 |
+
xhrFields : { withCredentials: true },
|
16 |
+
crossDomain : 'withCredentials' in new XMLHttpRequest(),
|
17 |
+
success : function (response) {
|
18 |
+
$container.html('');
|
19 |
+
$container.append(response.data.html);
|
20 |
+
$container.removeData('init');
|
21 |
+
obj.options.onLoad();
|
22 |
+
init($container, obj);
|
23 |
+
}
|
24 |
+
});
|
25 |
+
} else {
|
26 |
+
init($container, obj);
|
27 |
+
}
|
28 |
+
};
|
29 |
+
|
30 |
+
function init($container, obj) {
|
31 |
+
if ($container.data('init') != true) {
|
32 |
+
let $services_form = $('form', $container);
|
33 |
+
$services_form.booklyHelp();
|
34 |
+
$(document.body).trigger('special_hours.tab_init', [$container, obj.options]);
|
35 |
+
var autoTickCheckboxes = function () {
|
36 |
+
// Handle 'select category' checkbox.
|
37 |
+
$('.bookly-services-category .bookly-category-checkbox').each(function () {
|
38 |
+
$(this).prop(
|
39 |
+
'checked',
|
40 |
+
$('.bookly-category-services .bookly-service-checkbox.bookly-category-' + $(this).data('category-id') + ':not(:checked)').length == 0
|
41 |
+
);
|
42 |
+
});
|
43 |
+
// Handle 'select all services' checkbox.
|
44 |
+
$('#bookly-check-all-entities').prop(
|
45 |
+
'checked',
|
46 |
+
$('.bookly-service-checkbox:not(:checked)').length == 0
|
47 |
+
);
|
48 |
+
};
|
49 |
+
var checkCapacityError = function ($form_group) {
|
50 |
+
if (parseInt($form_group.find('.bookly-js-capacity-min').val()) > parseInt($form_group.find('.bookly-js-capacity-max').val())) {
|
51 |
+
$form_group.addClass('has-error');
|
52 |
+
} else {
|
53 |
+
$form_group.removeClass('has-error');
|
54 |
+
}
|
55 |
+
let has_errors = $('.bookly-js-capacity-form-group.has-error', $container).length != 0;
|
56 |
+
|
57 |
+
if (has_errors) {
|
58 |
+
$services_form.find('.bookly-js-services-error').html(obj.options.l10n.capacity_error);
|
59 |
+
$services_form.find('#bookly-services-save').prop('disabled', true);
|
60 |
+
} else {
|
61 |
+
$services_form.find('.bookly-js-services-error').html('');
|
62 |
+
$services_form.find('#bookly-services-save').prop('disabled', false);
|
63 |
+
}
|
64 |
+
obj.options.validation(has_errors, obj.options.l10n.capacity_error);
|
65 |
+
};
|
66 |
+
|
67 |
+
$services_form
|
68 |
+
// Select all services related to chosen category
|
69 |
+
.on('click', '.bookly-category-checkbox', function () {
|
70 |
+
$('.bookly-category-services .bookly-category-' + $(this).data('category-id')).prop('checked', $(this).is(':checked')).change();
|
71 |
+
autoTickCheckboxes();
|
72 |
+
})
|
73 |
+
// Check and uncheck all services
|
74 |
+
.on('click', '#bookly-check-all-entities', function () {
|
75 |
+
$('.bookly-service-checkbox', $services_form).prop('checked', $(this).is(':checked')).change();
|
76 |
+
$('.bookly-category-checkbox').prop('checked', $(this).is(':checked'));
|
77 |
+
})
|
78 |
+
// Select service
|
79 |
+
.on('click', '.bookly-service-checkbox', function () {
|
80 |
+
autoTickCheckboxes();
|
81 |
+
})
|
82 |
+
// Save services
|
83 |
+
.on('click', '#bookly-services-save', function (e) {
|
84 |
+
e.preventDefault();
|
85 |
+
var ladda = Ladda.create(this);
|
86 |
+
ladda.start();
|
87 |
+
$.ajax({
|
88 |
+
type : 'POST',
|
89 |
+
url : ajaxurl,
|
90 |
+
data : $services_form.serialize(),
|
91 |
+
dataType : 'json',
|
92 |
+
xhrFields : {withCredentials: true},
|
93 |
+
crossDomain: 'withCredentials' in new XMLHttpRequest(),
|
94 |
+
success : function (response) {
|
95 |
+
ladda.stop();
|
96 |
+
if (response.success) {
|
97 |
+
obj.options.savingStatus({success: [obj.options.l10n.saved]});
|
98 |
+
}
|
99 |
+
}
|
100 |
+
});
|
101 |
+
})
|
102 |
+
// After reset auto tick group checkboxes.
|
103 |
+
.on('click', '#bookly-services-reset', function () {
|
104 |
+
setTimeout(function () {
|
105 |
+
autoTickCheckboxes();
|
106 |
+
$('.bookly-js-capacity-form-group', $services_form).each(function () {
|
107 |
+
checkCapacityError($(this));
|
108 |
+
});
|
109 |
+
$('.bookly-service-checkbox', $services_form).trigger('change');
|
110 |
+
}, 0);
|
111 |
+
})
|
112 |
+
// Change location
|
113 |
+
.on('change', '#staff_location_id', function () {
|
114 |
+
let data = {};
|
115 |
+
if (this.value != '') {
|
116 |
+
data.location_id = this.value;
|
117 |
+
}
|
118 |
+
let get_staff_services = jQuery.extend(data, obj.options.get_staff_services);
|
119 |
+
$container.html('');
|
120 |
+
new BooklyStaffServices($container, {
|
121 |
+
get_staff_services: get_staff_services,
|
122 |
+
l10n : obj.options.l10n,
|
123 |
+
});
|
124 |
+
})
|
125 |
+
// Change default/custom settings for location
|
126 |
+
.on('change', '#custom_location_settings', function () {
|
127 |
+
if ($(this).val() == 1) {
|
128 |
+
$('.panel', $services_form).show();
|
129 |
+
} else {
|
130 |
+
$('.panel', $services_form).hide();
|
131 |
+
}
|
132 |
+
});
|
133 |
+
|
134 |
+
$('.bookly-service-checkbox').on('change', function () {
|
135 |
+
var $this = $(this),
|
136 |
+
$service = $this.closest('li'),
|
137 |
+
$inputs = $service.find('input:not(:checkbox)');
|
138 |
+
|
139 |
+
$inputs.attr('disabled', !$this.is(':checked'));
|
140 |
+
|
141 |
+
// Handle package-service connections
|
142 |
+
if ($(this).is(':checked') && $service.data('service-type') == 'package') {
|
143 |
+
$('li[data-service-type="simple"][data-service-id="' + $service.data('sub-service') + '"] .bookly-service-checkbox', $services_form).prop('checked', true).trigger('change');
|
144 |
+
$('.bookly-js-capacity-min', $service).val($('li[data-service-type="simple"][data-service-id="' + $service.data('sub-service') + '"] .bookly-js-capacity-min', $services_form).val());
|
145 |
+
$('.bookly-js-capacity-max', $service).val($('li[data-service-type="simple"][data-service-id="' + $service.data('sub-service') + '"] .bookly-js-capacity-max', $services_form).val());
|
146 |
+
}
|
147 |
+
if (!$(this).is(':checked') && $service.data('service-type') == 'simple') {
|
148 |
+
$('li[data-service-type="package"][data-sub-service="' + $service.data('service-id') + '"] .bookly-service-checkbox', $services_form).prop('checked', false).trigger('change');
|
149 |
+
}
|
150 |
+
});
|
151 |
+
|
152 |
+
$('.bookly-js-capacity').on('keyup change', function () {
|
153 |
+
var $service = $(this).closest('li');
|
154 |
+
if ($service.data('service-type') == 'simple') {
|
155 |
+
if ($(this).hasClass('bookly-js-capacity-min')) {
|
156 |
+
$('li[data-service-type="package"][data-sub-service="' + $service.data('service-id') + '"] .bookly-js-capacity-min', $services_form).val($(this).val());
|
157 |
+
} else {
|
158 |
+
$('li[data-service-type="package"][data-sub-service="' + $service.data('service-id') + '"] .bookly-js-capacity-max', $services_form).val($(this).val());
|
159 |
+
}
|
160 |
+
}
|
161 |
+
checkCapacityError($(this).closest('.form-group'));
|
162 |
+
});
|
163 |
+
$('#custom_location_settings', $services_form).trigger('change');
|
164 |
+
autoTickCheckboxes();
|
165 |
+
$container.data('init', true);
|
166 |
+
}
|
167 |
+
}
|
168 |
+
|
169 |
+
Services.prototype.options = {
|
170 |
+
get_staff_services: {
|
171 |
+
action : 'bookly_get_staff_services',
|
172 |
+
staff_id: -1,
|
173 |
+
csrf_token: ''
|
174 |
+
},
|
175 |
+
booklyAlert: window.booklyAlert,
|
176 |
+
savingStatus: function (data) {
|
177 |
+
$(document.body).trigger('staff_edit.save', data);
|
178 |
+
},
|
179 |
+
validation: function (has_error, info) {
|
180 |
+
$(document.body).trigger('staff_edit.validation', ['staff-services', has_error, info]);
|
181 |
+
},
|
182 |
+
onLoad: function () {},
|
183 |
+
l10n: {}
|
184 |
+
};
|
185 |
+
|
186 |
+
window.BooklyStaffServices = Services;
|
187 |
+
});
|
backend/{modules/staff → components/dialogs/staff/edit}/templates/_break.php
RENAMED
File without changes
|
backend/{modules/staff → components/dialogs/staff/edit}/templates/_breaks.php
RENAMED
File without changes
|
backend/{modules/staff/templates/_details.php → components/dialogs/staff/edit/templates/details.php}
RENAMED
@@ -7,10 +7,40 @@ use Bookly\Lib\Config;
|
|
7 |
/** @var Bookly\Lib\Entities\Staff $staff */
|
8 |
?>
|
9 |
<form class="bookly-js-staff-details">
|
10 |
-
<div class="
|
11 |
-
<
|
12 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
13 |
</div>
|
|
|
14 |
<?php if ( Common::isCurrentUserAdmin() ) : ?>
|
15 |
<div class="form-group">
|
16 |
<label for="bookly-wp-user"><?php esc_html_e( 'User', 'bookly' ) ?></label>
|
@@ -31,7 +61,7 @@ use Bookly\Lib\Config;
|
|
31 |
<?php endif ?>
|
32 |
|
33 |
<div class="row">
|
34 |
-
<div class="col-sm-
|
35 |
|