diff --git a/application/controllers/Business_settings.php b/application/controllers/Business_settings.php index d303e7d4..98682ba7 100644 --- a/application/controllers/Business_settings.php +++ b/application/controllers/Business_settings.php @@ -54,15 +54,16 @@ class Business_settings extends EA_Controller { $user_id = session('user_id'); - $role_slug = session('role_slug'); + script_vars([ + 'business_settings' => $this->settings_model->get(), + 'first_weekday' => setting('first_weekday'), + 'time_format' => setting('time_format'), + ]); html_vars([ 'page_title' => lang('settings'), 'active_menu' => PRIV_SYSTEM_SETTINGS, 'user_display_name' => $this->accounts->get_user_display_name($user_id), - 'timezones' => $this->timezones->to_array(), - 'privileges' => $this->roles_model->get_permissions_by_slug($role_slug), - 'system_settings' => $this->settings_model->get(), ]); $this->load->view('pages/business_settings', html_vars()); @@ -80,7 +81,7 @@ class Business_settings extends EA_Controller { throw new Exception('You do not have the required permissions for this task.'); } - $settings = json_decode(request('settings', FALSE), TRUE); + $settings = request('business_settings', []); foreach ($settings as $setting) { @@ -101,4 +102,33 @@ class Business_settings extends EA_Controller { json_exception($e); } } + + /** + * Apply global working plan to all providers. + */ + public function apply_global_working_plan() + { + try + { + if (cannot('edit', PRIV_SYSTEM_SETTINGS)) + { + throw new Exception('You do not have the required permissions for this task.'); + } + + $working_plan = request('working_plan'); + + $providers = $this->providers_model->get(); + + foreach ($providers as $provider) + { + $this->providers_model->set_setting($provider['id'], 'working_plan', $working_plan); + } + + response(); + } + catch (Throwable $e) + { + json_exception($e); + } + } } diff --git a/application/views/pages/business_settings.php b/application/views/pages/business_settings.php index c951afc8..2468e083 100755 --- a/application/views/pages/business_settings.php +++ b/application/views/pages/business_settings.php @@ -1,46 +1,37 @@ - - -
+
-
-
- - - - - - +
+
+ +
+ + + + + + + -
-

- +
- - - - - + + + + +
@@ -52,21 +43,6 @@
-
- -

-
- - -
- -
-
-
-

@@ -82,7 +58,7 @@
- +
@@ -93,10 +69,25 @@
-
-
-
-
+ +

+ +
+ + +
+ + + +
+
+ + +
+
@@ -104,35 +95,12 @@ - - - - + + + + diff --git a/assets/css/layouts/backend_layout.scss b/assets/css/layouts/backend_layout.scss index 52e632ed..5128f850 100644 --- a/assets/css/layouts/backend_layout.scss +++ b/assets/css/layouts/backend_layout.scss @@ -835,14 +835,6 @@ body .form-horizontal .controls { max-width: 1024px; } -#settings-page .working-plan-wrapper { - max-width: 600px; -} - -#settings-page .breaks-wrapper { - max-width: 500px; -} - #settings-page .personal-info-wrapper { max-width: 450px; margin-bottom: 20px; diff --git a/assets/js/http/business_settings_http_client.js b/assets/js/http/business_settings_http_client.js new file mode 100644 index 00000000..7513504e --- /dev/null +++ b/assets/js/http/business_settings_http_client.js @@ -0,0 +1,53 @@ +/* ---------------------------------------------------------------------------- + * Easy!Appointments - Open Source Web Scheduler + * + * @package EasyAppointments + * @author A.Tselegidis + * @copyright Copyright (c) Alex Tselegidis + * @license https://opensource.org/licenses/GPL-3.0 - GPLv3 + * @link https://easyappointments.org + * @since v1.5.0 + * ---------------------------------------------------------------------------- */ + +App.Http.BusinessSettings = (function () { + /** + * Save business settings. + * + * @param {Object} businessSettings + * + * @return {Object} + */ + function save(businessSettings) { + const url = App.Utils.Url.siteUrl('business_settings/save'); + + const data = { + csrf_token: App.Vars.csrf_token, + business_settings: businessSettings + }; + + return $.post(url, data); + } + + /** + * Apply global working plan. + * + * @param {Object} workingPlan + * + * @return {Object} + */ + function applyGlobalWorkingPlan(workingPlan) { + const url = App.Utils.Url.siteUrl('business_settings/apply_global_working_plan'); + + const data = { + csrf_token: App.Vars.csrf_token, + working_plan: JSON.stringify(workingPlan) + }; + + return $.post(url, data); + } + + return { + save, + applyGlobalWorkingPlan + }; +})(); diff --git a/assets/js/pages/backend_settings_business_logic.js b/assets/js/pages/backend_settings_business_logic.js deleted file mode 100644 index d02ccb32..00000000 --- a/assets/js/pages/backend_settings_business_logic.js +++ /dev/null @@ -1,141 +0,0 @@ -/* ---------------------------------------------------------------------------- - * Easy!Appointments - Open Source Web Scheduler - * - * @package EasyAppointments - * @author A.Tselegidis - * @copyright Copyright (c) Alex Tselegidis - * @license https://opensource.org/licenses/GPL-3.0 - GPLv3 - * @link https://easyappointments.org - * @since v1.0.0 - * ---------------------------------------------------------------------------- */ - -window.BackendSettingsBusinessLogic = window.BackendSettingsBusinessLogic || {}; - -/** - * Backend Settings - * - * Contains the functionality of the backend settings page. Can either work for system or user settings, - * but the actions allowed to the user are restricted to his role (only admin has full privileges). - * - * @module BackendSettingsBusinessLogic - */ -(function (exports) { - 'use strict'; - - // Constants - exports.SETTINGS_SYSTEM = 'SETTINGS_SYSTEM'; - - /** - * Use this WorkingPlan class instance to perform actions on the page's working plan tables. - * - * @type {WorkingPlan} - */ - exports.wp = {}; - - /** - * Tab settings object. - * - * @type {Object} - */ - var settings = {}; - - /** - * Initialize Page - * - * @param {bool} defaultEventHandlers Optional (true), determines whether to bind the default event handlers. - */ - exports.initialize = function (defaultEventHandlers) { - defaultEventHandlers = defaultEventHandlers || true; - - // Apply setting values from database. - var workingPlan = {}; - - GlobalVariables.settings.system.forEach(function (setting) { - $('input[data-field="' + setting.name + '"]').val(setting.value); - $('select[data-field="' + setting.name + '"]').val(setting.value); - - if (setting.name === 'company_working_plan') { - workingPlan = $.parseJSON(setting.value); - } - }); - - exports.wp = new WorkingPlan(); - exports.wp.setup(workingPlan); - exports.wp.timepickers(false); - - // Set default settings helper. - settings = new SystemSettingsBusinessLogicHelper(); - - if (defaultEventHandlers) { - bindEventHandlers(); - var $link = $('#settings-page .nav li').not('.d-none').first().find('a'); - $link.tab('show'); - } - - // Apply Privileges - if (GlobalVariables.user.privileges.system_settings.edit === false) { - $('#business-logic').find('select, input, textarea').prop('readonly', true); - $('#business-logic').find('button').prop('disabled', true); - } - - Backend.placeFooterToBottom(); - }; - - /** - * Bind the backend/settings default event handlers. - * - * This method depends on the backend/settings html, so do not use this method on a different page. - */ - function bindEventHandlers() { - exports.wp.bindEventHandlers(); - - /** - * Event: Save Settings Button "Click" - * - * Store the setting changes into the database. - */ - $('.save-settings').on('click', function () { - var data = settings.get(); - settings.save(data); - }); - - /** - * Event: Apply Global Working Plan - */ - $('#apply-global-working-plan').on('click', function () { - var buttons = [ - { - text: App.Lang.cancel, - click: function () { - $('#message-box').dialog('close'); - } - }, - { - text: 'OK', - click: function () { - var url = GlobalVariables.baseUrl + '/index.php/backend_api/ajax_apply_global_working_plan'; - - var data = { - csrf_token: GlobalVariables.csrfToken, - working_plan: JSON.stringify(exports.wp.get()) - }; - - $.post(url, data) - .done(function () { - Backend.displayNotification(App.Lang.working_plans_got_updated); - }) - .always(function () { - $('#message-box').dialog('close'); - }); - } - } - ]; - - GeneralFunctions.displayMessageBox( - App.Lang.working_plan, - App.Lang.overwrite_existing_working_plans, - buttons - ); - }); - } -})(window.BackendSettingsBusinessLogic); diff --git a/assets/js/pages/backend_settings_business_logic_helper.js b/assets/js/pages/backend_settings_business_logic_helper.js deleted file mode 100644 index 8a566228..00000000 --- a/assets/js/pages/backend_settings_business_logic_helper.js +++ /dev/null @@ -1,123 +0,0 @@ -/* ---------------------------------------------------------------------------- - * Easy!Appointments - Open Source Web Scheduler - * - * @package EasyAppointments - * @author A.Tselegidis - * @copyright Copyright (c) Alex Tselegidis - * @license https://opensource.org/licenses/GPL-3.0 - GPLv3 - * @link https://easyappointments.org - * @since v1.0.0 - * ---------------------------------------------------------------------------- */ - -(function () { - 'use strict'; - - /** - * "System Settings" Tab Helper Class - * - * @class SystemSettingsBusinessLogicHelper - */ - var SystemSettingsBusinessLogicHelper = function () {}; - - /** - * Save the system settings. - * - * This method is run after changes are detected on the tab input fields. - * - * @param {Array} settings Contains the system settings data. - */ - SystemSettingsBusinessLogicHelper.prototype.save = function (settings) { - if (!this.validate()) { - return; // Validation failed, do not proceed. - } - - var url = GlobalVariables.baseUrl + '/index.php/backend_api/ajax_save_settings'; - - var data = { - csrf_token: GlobalVariables.csrfToken, - settings: JSON.stringify(settings), - type: BackendSettingsBusinessLogic.SETTINGS_SYSTEM - }; - - $.post(url, data).done(function () { - Backend.displayNotification(App.Lang.settings_saved); - - // Update the logo title on the header. - $('#header-logo span').text($('#company-name').val()); - - // Update book_advance_timeout preview - var totalMinutes = $('#book-advance-timeout').val(); - var hours = Math.floor(totalMinutes / 60); - var minutes = totalMinutes % 60; - $('#book-advance-timeout-helper').text( - App.Lang.book_advance_timeout_hint.replace( - '{$limit}', - ('0' + hours).slice(-2) + ':' + ('0' + minutes).slice(-2) - ) - ); - - // We need to refresh the working plan. - var workingPlan = BackendSettingsBusinessLogic.wp.get(); - BackendSettingsBusinessLogic.wp.setup(workingPlan); - BackendSettingsBusinessLogic.wp.timepickers(false); - }); - }; - - /** - * Prepare the system settings array. - * - * This method uses the DOM elements of the backend/settings page, so it can't be used in another page. - * - * @return {Array} Returns the system settings array. - */ - SystemSettingsBusinessLogicHelper.prototype.get = function () { - var settings = []; - - // Business Logic Tab - - settings.push({ - name: 'company_working_plan', - value: JSON.stringify(BackendSettingsBusinessLogic.wp.get()) - }); - - settings.push({ - name: 'book_advance_timeout', - value: $('#book-advance-timeout').val() - }); - - return settings; - }; - - /** - * Validate the settings data. - * - * If the validation fails then display a message to the user. - * - * @return {Boolean} Returns the validation result. - */ - SystemSettingsBusinessLogicHelper.prototype.validate = function () { - $('#business-logic .is-invalid').removeClass('is-invalid'); - - try { - // Validate required fields. - var missingRequired = false; - $('#business-logic .required').each(function (index, requiredField) { - if (!$(requiredField).val()) { - $(requiredField).addClass('is-invalid'); - missingRequired = true; - } - }); - - if (missingRequired) { - throw new Error(App.Lang.fields_are_required); - } - - return true; - } catch (error) { - Backend.displayNotification(error.message); - return false; - } - }; - - window.SystemSettingsBusinessLogicHelper = SystemSettingsBusinessLogicHelper; -})(); diff --git a/assets/js/pages/business_settings.js b/assets/js/pages/business_settings.js new file mode 100644 index 00000000..0108f140 --- /dev/null +++ b/assets/js/pages/business_settings.js @@ -0,0 +1,159 @@ +/* ---------------------------------------------------------------------------- + * Easy!Appointments - Open Source Web Scheduler + * + * @package EasyAppointments + * @author A.Tselegidis + * @copyright Copyright (c) Alex Tselegidis + * @license https://opensource.org/licenses/GPL-3.0 - GPLv3 + * @link https://easyappointments.org + * @since v1.5.0 + * ---------------------------------------------------------------------------- */ + +/** + * Business Settings + * + * Contains the functionality of the business settings page. + */ +App.Pages.BusinessSettings = (function () { + const $saveSettings = $('#save-settings'); + const $applyGlobalWorkingPlan = $('#apply-global-working-plan'); + + let workingPlanManager = null; + + /** + * Check if the form has invalid values. + * + * @return {Boolean} + */ + function isInvalid() { + try { + $('#business-settings .is-invalid').removeClass('is-invalid'); + + // Validate required fields. + + let missingRequiredFields = false; + + $('#business-settings .required').each((index, requiredField) => { + const $requiredField = $(requiredField); + + if (!$requiredField.val()) { + $requiredField.addClass('is-invalid'); + missingRequiredFields = true; + } + }); + + if (missingRequiredFields) { + throw new Error(App.Lang.fields_are_required); + } + + return false; + } catch (error) { + Backend.displayNotification(error.message); + return true; + } + } + + function serialize(businessSettings) { + businessSettings.forEach((businessSetting) => { + $('[data-field="' + businessSetting.name + '"]').val(businessSetting.value); + }); + } + + function deserialize() { + const businessSettings = []; + + $('[data-field]').each((index, field) => { + const $field = $(field); + + businessSettings.push({ + name: $field.data('field'), + value: $field.val() + }); + }); + + const workingPlan = workingPlanManager.get(); + + businessSettings.push({ + name: 'company_working_plan', + value: JSON.stringify(workingPlan) + }); + + return businessSettings; + } + + /** + * Save the account information. + */ + function onSaveSettingsClick() { + if (isInvalid()) { + Backend.displayNotification(App.Lang.settings_are_invalid); + + return; + } + + const businessSettings = deserialize(); + + App.Http.BusinessSettings.save(businessSettings).done(() => { + Backend.displayNotification(App.Lang.settings_saved); + }); + } + + /** + * Save the global working plan information. + */ + function onApplyGlobalWorkingPlan() { + var buttons = [ + { + text: App.Lang.cancel, + click: function () { + $('#message-box').dialog('close'); + } + }, + { + text: 'OK', + click: function () { + const workingPlan = workingPlanManager.get(); + + App.Http.BusinessSettings.applyGlobalWorkingPlan(workingPlan) + .done(() => { + Backend.displayNotification(App.Lang.working_plans_got_updated); + }) + .always(function () { + $('#message-box').dialog('close'); + }); + } + } + ]; + + GeneralFunctions.displayMessageBox(App.Lang.working_plan, App.Lang.overwrite_existing_working_plans, buttons); + } + + function init() { + const businessSettings = App.Vars.business_settings; + + serialize(businessSettings); + + let workingPlan = {}; + + App.Vars.business_settings.forEach((generalSetting) => { + if (generalSetting.name === 'company_working_plan') { + workingPlan = JSON.parse(generalSetting.value); + } + }); + + workingPlanManager = new WorkingPlan(); + workingPlanManager.setup(workingPlan); + workingPlanManager.timepickers(false); + workingPlanManager.bindEventHandlers(); + + $saveSettings.on('click', onSaveSettingsClick); + + $applyGlobalWorkingPlan.on('click', onApplyGlobalWorkingPlan); + + Backend.placeFooterToBottom(); + } + + document.addEventListener('DOMContentLoaded', init); + + return {}; +})(); diff --git a/assets/js/utils/working_plan.js b/assets/js/utils/working_plan.js index bbb7a4b8..346174fc 100755 --- a/assets/js/utils/working_plan.js +++ b/assets/js/utils/working_plan.js @@ -44,14 +44,14 @@ * @param {Object} workingPlan Contains the working hours and breaks for each day of the week. */ WorkingPlan.prototype.setup = function (workingPlan) { - var weekDayId = GeneralFunctions.getWeekDayId(GlobalVariables.firstWeekday); + var weekDayId = GeneralFunctions.getWeekDayId(App.Vars.first_weekday); var workingPlanSorted = GeneralFunctions.sortWeekDictionary(workingPlan, weekDayId); $('.working-plan tbody').empty(); $('.breaks tbody').empty(); // Build working plan day list starting with the first weekday as set in the General settings - var timeFormat = GlobalVariables.timeFormat === 'regular' ? 'h:mm a' : 'HH:mm'; + var timeFormat = App.Vars.time_format === 'regular' ? 'h:mm a' : 'HH:mm'; $.each( workingPlanSorted, @@ -292,7 +292,7 @@ * @param {Object} workingPlanException Contains exception information. */ WorkingPlan.prototype.renderWorkingPlanExceptionRow = function (date, workingPlanException) { - var timeFormat = GlobalVariables.timeFormat === 'regular' ? 'h:mm a' : 'HH:mm'; + var timeFormat = App.Vars.time_format === 'regular' ? 'h:mm a' : 'HH:mm'; return $('', { 'data': { @@ -302,7 +302,7 @@ 'html': [ $('', { 'class': 'working-plan-exception-date', - 'text': GeneralFunctions.formatDate(date, GlobalVariables.dateFormat, false) + 'text': GeneralFunctions.formatDate(date, App.Vars.dateFormat, false) }), $('', { 'class': 'working-plan-exception--start', @@ -378,7 +378,7 @@ $('.add-break').on( 'click', function () { - var timeFormat = GlobalVariables.timeFormat === 'regular' ? 'h:mm a' : 'HH:mm'; + var timeFormat = App.Vars.time_format === 'regular' ? 'h:mm a' : 'HH:mm'; var $newBreak = $('', { 'html': [ @@ -470,7 +470,7 @@ .parent() .find('.break-start input, .break-end input') .timepicker({ - timeFormat: GlobalVariables.timeFormat === 'regular' ? 'h:mm tt' : 'HH:mm', + timeFormat: App.Vars.time_format === 'regular' ? 'h:mm tt' : 'HH:mm', currentText: App.Lang.now, closeText: App.Lang.close, timeOnlyTitle: App.Lang.select_time, @@ -542,7 +542,7 @@ $modifiedRow.find('.break-end input').val( startMoment .add(1, 'hour') - .format(GlobalVariables.timeFormat === 'regular' ? 'h:mm a' : 'HH:mm') + .format(App.Vars.time_format === 'regular' ? 'h:mm a' : 'HH:mm') .toLowerCase() ); } @@ -650,12 +650,11 @@ workingPlan[id].breaks.push({ start: moment( start, - GlobalVariables.timeFormat === 'regular' ? 'h:mm a' : 'HH:mm' + App.Vars.time_format === 'regular' ? 'h:mm a' : 'HH:mm' ).format('HH:mm'), - end: moment( - end, - GlobalVariables.timeFormat === 'regular' ? 'h:mm a' : 'HH:mm' - ).format('HH:mm') + end: moment(end, App.Vars.time_format === 'regular' ? 'h:mm a' : 'HH:mm').format( + 'HH:mm' + ) }); } }.bind(this) @@ -703,7 +702,7 @@ if (disabled === false) { // Set timepickers where needed. $('.working-plan input:text').timepicker({ - timeFormat: GlobalVariables.timeFormat === 'regular' ? 'h:mm tt' : 'HH:mm', + timeFormat: App.Vars.time_format === 'regular' ? 'h:mm tt' : 'HH:mm', currentText: App.Lang.now, closeText: App.Lang.close, timeOnlyTitle: App.Lang.select_time, @@ -725,7 +724,7 @@ .val( startMoment .add(1, 'hour') - .format(GlobalVariables.timeFormat === 'regular' ? 'h:mm a' : 'HH:mm') + .format(App.Vars.time_format === 'regular' ? 'h:mm a' : 'HH:mm') .toLowerCase() ); }