diff --git a/src/application/views/backend/services.php b/src/application/views/backend/services.php index 1b5a990f..e18a7365 100644 --- a/src/application/views/backend/services.php +++ b/src/application/views/backend/services.php @@ -1,3 +1,9 @@ + + + + diff --git a/src/assets/js/backend_categories_helper.js b/src/assets/js/backend_categories_helper.js new file mode 100644 index 00000000..e3f54c93 --- /dev/null +++ b/src/assets/js/backend_categories_helper.js @@ -0,0 +1,346 @@ +/* ---------------------------------------------------------------------------- + * Easy!Appointments - Open Source Web Scheduler + * + * @package EasyAppointments + * @author A.Tselegidis + * @copyright Copyright (c) 2013 - 2016, Alex Tselegidis + * @license http://opensource.org/licenses/GPL-3.0 - GPLv3 + * @link http://easyappointments.org + * @since v1.0.0 + * ---------------------------------------------------------------------------- */ + + /** + * This class contains the core method implementations that belong to the categories tab + * of the backend services page. + * + * @class CategoriesHelper + */ +(function() { + + 'use strict'; + + function CategoriesHelper() { + this.filterResults = {}; + }; + + /** + * Binds the default event handlers of the categories tab. + */ + CategoriesHelper.prototype.bindEventHandlers = function() { + var instance = this; + + /** + * Event: Filter Categories Cancel Button "Click" + */ + $('#filter-categories .clear').click(function() { + $('#filter-categories .key').val(''); + instance.filter(''); + instance.resetForm(); + }); + + /** + * Event: Filter Categories Form "Submit" + */ + $('#filter-categories form').submit(function(event) { + var key = $('#filter-categories .key').val(); + $('.selected-row').removeClass('selected-row'); + instance.resetForm(); + instance.filter(key); + return false; + }); + + /** + * Event: Filter Categories Row "Click" + * + * Displays the selected row data on the right side of the page. + */ + $(document).on('click', '.category-row', function() { + if ($('#filter-categories .filter').prop('disabled')) { + $('#filter-categories .results').css('color', '#AAA'); + return; // exit because we are on edit mode + } + + var categoryId = $(this).attr('data-id'); + var category = {}; + $.each(instance.filterResults, function(index, item) { + if (item.id === categoryId) { + category = item; + return false; + } + }); + + instance.display(category); + $('#filter-categories .selected-row').removeClass('selected-row'); + $(this).addClass('selected-row'); + $('#edit-category, #delete-category').prop('disabled', false); + }); + + /** + * Event: Add Category Button "Click" + */ + $('#add-category').click(function() { + instance.resetForm(); + $('#categories .add-edit-delete-group').hide(); + $('#categories .save-cancel-group').show(); + $('#categories .details').find('input, textarea').prop('readonly', false); + $('#filter-categories button').prop('disabled', true); + $('#filter-categories .results').css('color', '#AAA'); + }); + + /** + * Event: Edit Category Button "Click" + */ + $('#edit-category').click(function() { + $('#categories .add-edit-delete-group').hide(); + $('#categories .save-cancel-group').show(); + $('#categories .details').find('input, textarea').prop('readonly', false); + + $('#filter-categories button').prop('disabled', true); + $('#filter-categories .results').css('color', '#AAA'); + }); + + /** + * Event: Delete Category Button "Click" + */ + $('#delete-category').click(function() { + var categoryId = $('#category-id').val(); + + var messageBtns = {}; + messageBtns[EALang['delete']] = function() { + instance.delete(categoryId); + $('#message_box').dialog('close'); + }; + messageBtns[EALang['cancel']] = function() { + $('#message_box').dialog('close'); + }; + + GeneralFunctions.displayMessageBox(EALang['delete_category'], + EALang['delete_record_prompt'], messageBtns); + }); + + /** + * Event: Categories Save Button "Click" + */ + $('#save-category').click(function() { + var category = { + 'name': $('#category-name').val(), + 'description': $('#category-description').val() + }; + + if ($('#category-id').val() !== '') { + category.id = $('#category-id').val(); + } + + if (!instance.validate(category)) { + return; + } + + instance.save(category); + }); + + /** + * Event: Cancel Category Button "Click" + */ + $('#cancel-category').click(function() { + var id = $('#category-id').val(); + instance.resetForm(); + if (id !== '') { + instance.select(id, true); + } + }); + }; + + /** + * Filter service categories records. + * + * @param {string} key This key string is used to filter the category records. + * @param {numeric} selectId (OPTIONAL = undefined) If set then after the filter + * operation the record with the given id will be selected (but not displayed). + * @param {bool} display (OPTIONAL = false) If true then the selected record will + * be displayed on the form. + */ + CategoriesHelper.prototype.filter = function(key, selectId, display) { + var postUrl = GlobalVariables.baseUrl + '/index.php/backend_api/ajax_filter_service_categories', + postData = { + 'csrfToken': GlobalVariables.csrfToken, + 'key': key + }; + + $.post(postUrl, postData, function(response) { + if (!GeneralFunctions.handleAjaxExceptions(response)) { + return; + } + + this.filterResults = response; + + $('#filter-categories .results').data('jsp').destroy(); + $('#filter-categories .results').html(''); + $.each(response, function(index, category) { + var html = this.getFilterHtml(category); + $('#filter-categories .results').append(html); + }.bind(this)); + $('#filter-categories .results').jScrollPane({ mouseWheelSpeed: 70 }); + + if (response.length === 0) { + $('#filter-categories .results').html('' + EALang['no_records_found'] + ''); + } + + if (selectId !== undefined) { + this.select(selectId, display); + } + + }.bind(this), 'json').fail(GeneralFunctions.ajaxFailureHandler); + }; + + /** + * Save a category record to the database (via ajax post). + * + * @param {object} category Contains the category data. + */ + CategoriesHelper.prototype.save = function(category) { + var postUrl = GlobalVariables.baseUrl + '/index.php/backend_api/ajax_save_service_category', + postData = { + 'csrfToken': GlobalVariables.csrfToken, + 'category': JSON.stringify(category) + }; + + $.post(postUrl, postData, function(response) { + if (!GeneralFunctions.handleAjaxExceptions(response)) { + return; + } + + Backend.displayNotification(EALang['service_category_saved']); + this.resetForm(); + $('#filter-categories .key').val(''); + this.filter('', response.id, true); + BackendServices.updateAvailableCategories(); + }. bind(this), 'json').fail(GeneralFunctions.ajaxFailureHandler); + }; + + /** + * Delete category record. + * + * @param {int} id Record id to be deleted. + */ + CategoriesHelper.prototype.delete = function(id) { + var postUrl = GlobalVariables.baseUrl + '/index.php/backend_api/ajax_delete_service_category', + postData = { + 'csrfToken': GlobalVariables.csrfToken, + 'category_id': id + }; + + $.post(postUrl, postData, function(response) { + if (!GeneralFunctions.handleAjaxExceptions(response)) { + return; + } + + Backend.displayNotification(EALang['service_category_deleted']); + + this.resetForm(); + this.filter($('#filter-categories .key').val()); + BackendServices.updateAvailableCategories(); + }.bind(this), 'json').fail(GeneralFunctions.ajaxFailureHandler); + }; + + /** + * Display a category record on the form. + * + * @param {object} category Contains the category data. + */ + CategoriesHelper.prototype.display = function(category) { + $('#category-id').val(category.id); + $('#category-name').val(category.name); + $('#category-description').val(category.description); + }; + + /** + * Validate category data before save (insert or update). + * + * @param {object} category Contains the category data. + */ + CategoriesHelper.prototype.validate = function(category) { + $('#categories .details').find('input, textarea').css('border', ''); + + try { + var missingRequired = false; + + $('#categories .required').each(function() { + if ($(this).val() === '' || $(this).val() === undefined) { + $(this).css('border', '2px solid red'); + missingRequired = true; + } + }); + + if (missingRequired) { + throw EALang['fields_are_required']; + } + + return true; + } catch(exc) { + return false; + } + }; + + /** + * Bring the category form back to its initial state. + */ + CategoriesHelper.prototype.resetForm = function() { + $('#categories .add-edit-delete-group').show(); + $('#categories .save-cancel-group').hide(); + $('#categories .details').find('input, textarea').val(''); + $('#categories .details').find('input, textarea').prop('readonly', true); + $('#edit-category, #delete-category').prop('disabled', true); + + $('#filter-categories .selected-row').removeClass('selected-row'); + $('#filter-categories .results').css('color', ''); + $('#filter-categories button').prop('disabled', false); + }; + + /** + * Get the filter results row html code. + * + * @param {object} category Contains the category data. + * @return {string} Returns the record html code. + */ + CategoriesHelper.prototype.getFilterHtml = function(category) { + var html = + '
' + + '' + category.name + '' + + '

'; + + return html; + }; + + /** + * Select a specific record from the current filter results. If the category id does not exist + * in the list then no record will be selected. + * + * @param {numeric} id The record id to be selected from the filter results. + * @param {bool} display (OPTIONAL = false) If true then the method will display the record + * on the form. + */ + CategoriesHelper.prototype.select = function(id, display) { + display = display || false; + + $('#filter-categories .selected-row').removeClass('selected-row'); + + $('#filter-categories .category-row').each(function() { + if ($(this).attr('data-id') === id) { + $(this).addClass('selected-row'); + return false; + } + }); + + if (display) { + $.each(this.filterResults, function(index, category) { + if (category.id === id) { + this.display(category); + $('#edit-category, #delete-category').prop('disabled', false); + return false; + } + }.bind(this)); + } + }; + + window.CategoriesHelper = CategoriesHelper; +})(); diff --git a/src/assets/js/backend_services.js b/src/assets/js/backend_services.js index 819dc1ed..c6b90ed5 100644 --- a/src/assets/js/backend_services.js +++ b/src/assets/js/backend_services.js @@ -9,18 +9,23 @@ * @since v1.0.0 * ---------------------------------------------------------------------------- */ +window.BackendServices = window.BackendServices || {}; + /** * This namespace handles the js functionality of the backend services page. * - * @namespace BackendServices + * @module BackendServices */ -var BackendServices = { +(function(exports) { + + 'use strict'; + /** * Contains the basic record methods for the page. * * @type ServicesHelper|CategoriesHelper */ - helper: {}, + var helper; /** * Default initialize method of the page. @@ -28,8 +33,8 @@ var BackendServices = { * @param {bool} bindEventHandlers (OPTIONAL) Determines whether to bind the * default event handlers (default: true). */ - initialize: function(bindEventHandlers) { - if (bindEventHandlers === undefined) bindEventHandlers = true; + exports.initialize = function(bindEventHandlers) { + bindEventHandlers = bindEventHandlers || true; // Fill available service categories listbox. $.each(GlobalVariables.categories, function(index, category) { @@ -39,26 +44,28 @@ var BackendServices = { $('#service-category').append(new Option('- ' + EALang['no_category'] + ' -', null)).val('null'); $('#service-duration').spinner({ - 'min': 0, - 'disabled': true //default + min: 0, + disabled: true // default }); // Instantiate helper object (service helper by default). - BackendServices.helper = new ServicesHelper(); - BackendServices.helper.resetForm(); - BackendServices.helper.filter(''); + helper = new ServicesHelper(); + helper.resetForm(); + helper.filter(''); $('#filter-services .results').jScrollPane(); $('#filter-categories .results').jScrollPane(); - if (bindEventHandlers) BackendServices.bindEventHandlers(); - }, + if (bindEventHandlers) { + _bindEventHandlers(); + } + }; /** * Binds the default event handlers of the backend services page. Do not use this method * if you include the "BackendServices" namespace on another page. */ - bindEventHandlers: function() { + function _bindEventHandlers() { /** * Event: Page Tab Button "Click" * @@ -71,36 +78,40 @@ var BackendServices = { if ($(this).hasClass('services-tab')) { // display services tab $('#services').show(); - BackendServices.helper = new ServicesHelper(); + helper = new ServicesHelper(); } else if ($(this).hasClass('categories-tab')) { // display categories tab $('#categories').show(); - BackendServices.helper = new CategoriesHelper(); + helper = new CategoriesHelper(); } - BackendServices.helper.resetForm(); - BackendServices.helper.filter(''); + helper.resetForm(); + helper.filter(''); $('.filter-key').val(''); Backend.placeFooterToBottom(); }); - ServicesHelper.prototype.bindEventHandlers(); - CategoriesHelper.prototype.bindEventHandlers(); + helper.bindEventHandlers(); - }, + // @todo Bind and unbind the events dynamically on tab click. + var tmpHelper = new CategoriesHelper(); + tmpHelper.bindEventHandlers(); + } /** * Update the service category listbox. Use this method every time a change is made * to the service categories db table. */ - updateAvailableCategories: function() { - var postUrl = GlobalVariables.baseUrl + '/index.php/backend_api/ajax_filter_service_categories'; - var postData = { - 'csrfToken': GlobalVariables.csrfToken, - 'key': '' - }; + exports.updateAvailableCategories = function() { + var postUrl = GlobalVariables.baseUrl + '/index.php/backend_api/ajax_filter_service_categories', + postData = { + csrfToken: GlobalVariables.csrfToken, + key: '' + }; $.post(postUrl, postData, function(response) { - if (!GeneralFunctions.handleAjaxExceptions(response)) return; + if (!GeneralFunctions.handleAjaxExceptions(response)) { + return; + } GlobalVariables.categories = response; var $select = $('#service-category'); @@ -112,663 +123,5 @@ var BackendServices = { $select.append(new Option('- ' + EALang['no_category'] + ' -', null)).val('null'); }, 'json').fail(GeneralFunctions.ajaxFailureHandler); } -}; -/** - * This class contains the methods that will be used by the "Services" tab of the page. - * @class ServicesHelper - */ -var ServicesHelper = function() { - this.filterResults = {}; -}; - -ServicesHelper.prototype.bindEventHandlers = function() { - /** - * Event: Filter Services Form "Submit" - */ - $('#filter-services form').submit(function(event) { - var key = $('#filter-services .key').val(); - $('#filter-services .selected-row').removeClass('selected-row'); - BackendServices.helper.resetForm(); - BackendServices.helper.filter(key); - return false; - }); - - /** - * Event: Filter Service Cancel Button "Click" - */ - $('#filter-services .clear').click(function() { - $('#filter-services .key').val(''); - BackendServices.helper.filter(''); - BackendServices.helper.resetForm(); - }); - - /** - * Event: Filter Service Row "Click" - * - * Display the selected service data to the user. - */ - $(document).on('click', '.service-row', function() { - if ($('#filter-services .filter').prop('disabled')) { - $('#filter-services .results').css('color', '#AAA'); - return; // exit because we are on edit mode - } - - var serviceId = $(this).attr('data-id'); - var service = {}; - $.each(BackendServices.helper.filterResults, function(index, item) { - if (item.id === serviceId) { - service = item; - return false; - } - }); - - BackendServices.helper.display(service); - $('#filter-services .selected-row').removeClass('selected-row'); - $(this).addClass('selected-row'); - $('#edit-service, #delete-service').prop('disabled', false); - }); - - /** - * Event: Add New Service Button "Click" - */ - $('#add-service').click(function() { - BackendServices.helper.resetForm(); - $('#services .add-edit-delete-group').hide(); - $('#services .save-cancel-group').show(); - $('#services .details').find('input, textarea').prop('readonly', false); - $('#services .details').find('select').prop('disabled', false); - $('#service-duration').spinner('enable'); - - $('#filter-services button').prop('disabled', true); - $('#filter-services .results').css('color', '#AAA'); - }); - - /** - * Event: Cancel Service Button "Click" - * - * Cancel add or edit of a service record. - */ - $('#cancel-service').click(function() { - var id = $('#service-id').val(); - BackendServices.helper.resetForm(); - if (id != '') { - BackendServices.helper.select(id, true); - } - }); - - /** - * Event: Save Service Button "Click" - */ - $('#save-service').click(function() { - var service = { - 'name': $('#service-name').val(), - 'duration': $('#service-duration').val(), - 'price': $('#service-price').val(), - 'currency': $('#service-currency').val(), - 'description': $('#service-description').val() - }; - - if ($('#service-category').val() !== 'null') { - service.id_service_categories = $('#service-category').val(); - } else { - service.id_service_categories = null; - } - - if ($('#service-id').val() !== '') { - service.id = $('#service-id').val(); - } - - if (!BackendServices.helper.validate(service)) return; - - BackendServices.helper.save(service); - }); - - /** - * Event: Edit Service Button "Click" - */ - $('#edit-service').click(function() { - $('#services .add-edit-delete-group').hide(); - $('#services .save-cancel-group').show(); - $('#services .details').find('input, textarea').prop('readonly', false); - $('#services .details select').prop('disabled', false); - $('#service-duration').spinner('enable'); - - $('#filter-services button').prop('disabled', true); - $('#filter-services .results').css('color', '#AAA'); - }); - - /** - * Event: Delete Service Button "Click" - */ - $('#delete-service').click(function() { - var serviceId = $('#service-id').val(); - - var messageBtns = {}; - messageBtns[EALang['delete']] = function() { - BackendServices.helper.delete(serviceId); - $('#message_box').dialog('close'); - }; - - messageBtns[EALang['cancel']] = function() { - $('#message_box').dialog('close'); - }; - - GeneralFunctions.displayMessageBox(EALang['delete_service'], - EALang['delete_record_prompt'], messageBtns); - }); -}; - -/** - * Save service record to database. - * - * @param {object} service Contains the service record data. If an 'id' value is provided - * then the update operation is going to be executed. - */ -ServicesHelper.prototype.save = function(service) { - var postUrl = GlobalVariables.baseUrl + '/index.php/backend_api/ajax_save_service'; - var postData = { - 'csrfToken': GlobalVariables.csrfToken, - 'service': JSON.stringify(service) - }; - - $.post(postUrl, postData, function(response) { - if (!GeneralFunctions.handleAjaxExceptions(response)) return; - - Backend.displayNotification(EALang['service_saved']); - BackendServices.helper.resetForm(); - $('#filter-services .key').val(''); - BackendServices.helper.filter('', response.id, true); - }, 'json').fail(GeneralFunctions.ajaxFailureHandler); -}; - -/** - * Delete a service record from database. - * - * @param {numeric} id Record id to be deleted. - */ -ServicesHelper.prototype.delete = function(id) { - var postUrl = GlobalVariables.baseUrl + '/index.php/backend_api/ajax_delete_service'; - var postData = { - 'csrfToken': GlobalVariables.csrfToken, - 'service_id': id - }; - - $.post(postUrl, postData, function(response) { - if (!GeneralFunctions.handleAjaxExceptions(response)) return; - - Backend.displayNotification(EALang['service_deleted']); - - BackendServices.helper.resetForm(); - BackendServices.helper.filter($('#filter-services .key').val()); - }, 'json').fail(GeneralFunctions.ajaxFailureHandler); -}; - -/** - * Validates a service record. - * - * @param {object} service Contains the service data. - * @returns {bool} Returns the validation result. - */ -ServicesHelper.prototype.validate = function(service) { - $('#services .required').css('border', ''); - - try { - // validate required fields. - var missingRequired = false; - $('#services .required').each(function() { - if ($(this).val() == '' || $(this).val() == undefined) { - $(this).css('border', '2px solid red'); - missingRequired = true; - } - }); - - if (missingRequired) - throw EALang['fields_are_required']; - - - return true; - } catch(exc) { - return false; - } -}; - -/** - * Resets the service tab form back to its initial state. - */ -ServicesHelper.prototype.resetForm = function() { - $('#services .details').find('input, textarea').val(''); - $('#service-category').val('null'); - $('#services .add-edit-delete-group').show(); - $('#services .save-cancel-group').hide(); - $('#edit-service, #delete-service').prop('disabled', true); - $('#services .details').find('input, textarea').prop('readonly', true); - $('#service-category').prop('disabled', true); - $('#service-duration').spinner('disable'); - - $('#filter-services .selected-row').removeClass('selected-row'); - $('#filter-services button').prop('disabled', false); - $('#filter-services .results').css('color', ''); -}; - -/** - * Display a service record into the service form. - * - * @param {object} service Contains the service record data. - */ -ServicesHelper.prototype.display = function(service) { - $('#service-id').val(service.id); - $('#service-name').val(service.name); - $('#service-duration').val(service.duration); - $('#service-price').val(service.price); - $('#service-currency').val(service.currency); - $('#service-description').val(service.description); - - var categoryId = (service.id_service_categories != null) ? service.id_service_categories : 'null'; - $('#service-category').val(categoryId); -}; - -/** - * Filters service records depending a string key. - * - * @param {string} key This is used to filter the service records of the database. - * @param {numeric} selectId (OPTIONAL = undefined) If set then after the filter - * operation the record with this id will be selected (but not displayed). - * @param {bool} display (OPTIONAL = false) If true then the selected record will - * be displayed on the form. - */ -ServicesHelper.prototype.filter = function(key, selectId, display) { - if (display == undefined) display = false; - - var postUrl = GlobalVariables.baseUrl + '/index.php/backend_api/ajax_filter_services'; - var postData = { - 'csrfToken': GlobalVariables.csrfToken, - 'key': key - }; - - $.post(postUrl, postData, function(response) { - if (!GeneralFunctions.handleAjaxExceptions(response)) return; - - BackendServices.helper.filterResults = response; - - $('#filter-services .results').data('jsp').destroy(); - $('#filter-services .results').html(''); - $.each(response, function(index, service) { - var html = ServicesHelper.prototype.getFilterHtml(service); - $('#filter-services .results').append(html); - }); - $('#filter-services .results').jScrollPane({ mouseWheelSpeed: 70 }); - - if (response.length == 0) { - $('#filter-services .results').html('' + EALang['no_records_found'] + ''); - } - - if (selectId != undefined) { - BackendServices.helper.select(selectId, display); - } - }, 'json').fail(GeneralFunctions.ajaxFailureHandler); -}; - -/** - * Get a service row html code that is going to be displayed on the filter results list. - * - * @param {object} service Contains the service record data. - * @returns {string} The html code that represents the record on the filter results list. - */ -ServicesHelper.prototype.getFilterHtml = function(service) { - var html = - '
' + - '' + service.name + '
' + - service.duration + ' min - ' + - service.price + ' ' + service.currency + '
' + - '

'; - - return html; -}; - -/** - * Select a specific record from the current filter results. If the service id does not exist - * in the list then no record will be selected. - * - * @param {numeric} id The record id to be selected from the filter results. - * @param {bool} display (OPTIONAL = false) If true then the method will display the record - * on the form. - */ -ServicesHelper.prototype.select = function(id, display) { - if (display == undefined) display = false; - - $('#filter-services .selected-row').removeClass('selected-row'); - - $('#filter-services .service-row').each(function() { - if ($(this).attr('data-id') == id) { - $(this).addClass('selected-row'); - return false; - } - }); - - if (display) { - $.each(BackendServices.helper.filterResults, function(index, service) { - if (service.id == id) { - BackendServices.helper.display(service); - $('#edit-service, #delete-service').prop('disabled', false); - return false; - } - }); - } -}; - -/** - * This class contains the core method implementations that belong to the categories tab - * of the backend services page. - * - * @class CategoriesHelper - */ -var CategoriesHelper = function() { - this.filterResults = {}; -}; - -/** - * Binds the default event handlers of the categories tab. - */ -CategoriesHelper.prototype.bindEventHandlers = function() { - /** - * Event: Filter Categories Cancel Button "Click" - */ - $('#filter-categories .clear').click(function() { - $('#filter-categories .key').val(''); - BackendServices.helper.filter(''); - BackendServices.helper.resetForm(); - }); - - /** - * Event: Filter Categories Form "Submit" - */ - $('#filter-categories form').submit(function(event) { - var key = $('#filter-categories .key').val(); - $('.selected-row').removeClass('selected-row'); - BackendServices.helper.resetForm(); - BackendServices.helper.filter(key); - return false; - }); - - /** - * Event: Filter Categories Row "Click" - * - * Displays the selected row data on the right side of the page. - */ - $(document).on('click', '.category-row', function() { - if ($('#filter-categories .filter').prop('disabled')) { - $('#filter-categories .results').css('color', '#AAA'); - return; // exit because we are on edit mode - } - - var categoryId = $(this).attr('data-id'); - var category = {}; - $.each(BackendServices.helper.filterResults, function(index, item) { - if (item.id === categoryId) { - category = item; - return false; - } - }); - - BackendServices.helper.display(category); - $('#filter-categories .selected-row').removeClass('selected-row'); - $(this).addClass('selected-row'); - $('#edit-category, #delete-category').prop('disabled', false); - }); - - /** - * Event: Add Category Button "Click" - */ - $('#add-category').click(function() { - BackendServices.helper.resetForm(); - $('#categories .add-edit-delete-group').hide(); - $('#categories .save-cancel-group').show(); - $('#categories .details').find('input, textarea').prop('readonly', false); - $('#filter-categories button').prop('disabled', true); - $('#filter-categories .results').css('color', '#AAA'); - }); - - /** - * Event: Edit Category Button "Click" - */ - $('#edit-category').click(function() { - $('#categories .add-edit-delete-group').hide(); - $('#categories .save-cancel-group').show(); - $('#categories .details').find('input, textarea').prop('readonly', false); - - $('#filter-categories button').prop('disabled', true); - $('#filter-categories .results').css('color', '#AAA'); - }); - - /** - * Event: Delete Category Button "Click" - */ - $('#delete-category').click(function() { - var categoryId = $('#category-id').val(); - - var messageBtns = {}; - messageBtns[EALang['delete']] = function() { - BackendServices.helper.delete(categoryId); - $('#message_box').dialog('close'); - }; - messageBtns[EALang['cancel']] = function() { - $('#message_box').dialog('close'); - }; - - GeneralFunctions.displayMessageBox(EALang['delete_category'], - EALang['delete_record_prompt'], messageBtns); - }); - - /** - * Event: Categories Save Button "Click" - */ - $('#save-category').click(function() { - var category = { - 'name': $('#category-name').val(), - 'description': $('#category-description').val() - }; - - if ($('#category-id').val() !== '') { - category.id = $('#category-id').val(); - } - - if (!BackendServices.helper.validate(category)) return; - - BackendServices.helper.save(category); - }); - - /** - * Event: Cancel Category Button "Click" - */ - $('#cancel-category').click(function() { - var id = $('#category-id').val(); - BackendServices.helper.resetForm(); - if (id != '') { - BackendServices.helper.select(id, true); - } - }); -}; - -/** - * Filter service categories records. - * - * @param {string} key This key string is used to filter the category records. - * @param {numeric} selectId (OPTIONAL = undefined) If set then after the filter - * operation the record with the given id will be selected (but not displayed). - * @param {bool} display (OPTIONAL = false) If true then the selected record will - * be displayed on the form. - */ -CategoriesHelper.prototype.filter = function(key, selectId, display) { - var postUrl = GlobalVariables.baseUrl + '/index.php/backend_api/ajax_filter_service_categories'; - var postData = { - 'csrfToken': GlobalVariables.csrfToken, - 'key': key - }; - - $.post(postUrl, postData, function(response) { - if (!GeneralFunctions.handleAjaxExceptions(response)) return; - - BackendServices.helper.filterResults = response; - - $('#filter-categories .results').data('jsp').destroy(); - $('#filter-categories .results').html(''); - $.each(response, function(index, category) { - var html = BackendServices.helper.getFilterHtml(category); - $('#filter-categories .results').append(html); - }); - $('#filter-categories .results').jScrollPane({ mouseWheelSpeed: 70 }); - - if (response.length == 0) { - $('#filter-categories .results').html('' + EALang['no_records_found'] + ''); - } - - if (selectId != undefined) { - BackendServices.helper.select(selectId, display); - } - - }, 'json').fail(GeneralFunctions.ajaxFailureHandler); -}; - -/** - * Save a category record to the database (via ajax post). - * - * @param {object} category Contains the category data. - */ -CategoriesHelper.prototype.save = function(category) { - var postUrl = GlobalVariables.baseUrl + '/index.php/backend_api/ajax_save_service_category'; - var postData = { - 'csrfToken': GlobalVariables.csrfToken, - 'category': JSON.stringify(category) - }; - - $.post(postUrl, postData, function(response) { - if (!GeneralFunctions.handleAjaxExceptions(response)) return; - - Backend.displayNotification(EALang['service_category_saved']); - BackendServices.helper.resetForm(); - $('#filter-categories .key').val(''); - BackendServices.helper.filter('', response.id, true); - BackendServices.updateAvailableCategories(); - }, 'json').fail(GeneralFunctions.ajaxFailureHandler); -}; - -/** - * Delete category record. - * - * @param {int} id Record id to be deleted. - */ -CategoriesHelper.prototype.delete = function(id) { - var postUrl = GlobalVariables.baseUrl + '/index.php/backend_api/ajax_delete_service_category'; - var postData = { - 'csrfToken': GlobalVariables.csrfToken, - 'category_id': id - }; - - $.post(postUrl, postData, function(response) { - if (!GeneralFunctions.handleAjaxExceptions(response)) return; - - Backend.displayNotification(EALang['service_category_deleted']); - - BackendServices.helper.resetForm(); - BackendServices.helper.filter($('#filter-categories .key').val()); - BackendServices.updateAvailableCategories(); - }, 'json').fail(GeneralFunctions.ajaxFailureHandler); -}; - -/** - * Display a category record on the form. - * - * @param {object} category Contains the category data. - */ -CategoriesHelper.prototype.display = function(category) { - $('#category-id').val(category.id); - $('#category-name').val(category.name); - $('#category-description').val(category.description); -}; - -/** - * Validate category data before save (insert or update). - * - * @param {object} category Contains the category data. - */ -CategoriesHelper.prototype.validate = function(category) { - $('#categories .details').find('input, textarea').css('border', ''); - - try { - var missingRequired = false; - $('#categories .required').each(function() { - if ($(this).val() == '' || $(this).val() == undefined) { - $(this).css('border', '2px solid red'); - missingRequired = true; - } - }); - if (missingRequired) throw EALang['fields_are_required']; - - return true; - - } catch(exc) { - return false; - } -}; - -/** - * Bring the category form back to its initial state. - */ -CategoriesHelper.prototype.resetForm = function() { - $('#categories .add-edit-delete-group').show(); - $('#categories .save-cancel-group').hide(); - $('#categories .details').find('input, textarea').val(''); - $('#categories .details').find('input, textarea').prop('readonly', true); - $('#edit-category, #delete-category').prop('disabled', true); - - $('#filter-categories .selected-row').removeClass('selected-row'); - $('#filter-categories .results').css('color', ''); - $('#filter-categories button').prop('disabled', false); -}; - -/** - * Get the filter results row html code. - * - * @param {object} category Contains the category data. - * @return {string} Returns the record html code. - */ -CategoriesHelper.prototype.getFilterHtml = function(category) { - var html = - '
' + - '' + category.name + '' + - '

'; - - return html; -}; - -/** - * Select a specific record from the current filter results. If the category id does not exist - * in the list then no record will be selected. - * - * @param {numeric} id The record id to be selected from the filter results. - * @param {bool} display (OPTIONAL = false) If true then the method will display the record - * on the form. - */ -CategoriesHelper.prototype.select = function(id, display) { - if (display == undefined) display = false; - - $('#filter-categories .selected-row').removeClass('selected-row'); - - $('#filter-categories .category-row').each(function() { - if ($(this).attr('data-id') == id) { - $(this).addClass('selected-row'); - return false; - } - }); - - if (display) { - $.each(BackendServices.helper.filterResults, function(index, category) { - if (category.id == id) { - BackendServices.helper.display(category); - $('#edit-category, #delete-category').prop('disabled', false); - return false; - } - }); - } -}; +})(window.BackendServices); diff --git a/src/assets/js/backend_services_helper.js b/src/assets/js/backend_services_helper.js new file mode 100644 index 00000000..615c0971 --- /dev/null +++ b/src/assets/js/backend_services_helper.js @@ -0,0 +1,374 @@ +/* ---------------------------------------------------------------------------- + * Easy!Appointments - Open Source Web Scheduler + * + * @package EasyAppointments + * @author A.Tselegidis + * @copyright Copyright (c) 2013 - 2016, Alex Tselegidis + * @license http://opensource.org/licenses/GPL-3.0 - GPLv3 + * @link http://easyappointments.org + * @since v1.0.0 + * ---------------------------------------------------------------------------- */ + + /** + * ServicesHelper + * + * This class contains the methods that will be used by the "Services" tab of the page. + * + * @class ServicesHelper + */ +(function() { + + 'use strict'; + + function ServicesHelper() { + this.filterResults = {}; + }; + + ServicesHelper.prototype.bindEventHandlers = function() { + var instance = this; + + /** + * Event: Filter Services Form "Submit" + */ + $('#filter-services form').submit(function(event) { + var key = $('#filter-services .key').val(); + $('#filter-services .selected-row').removeClass('selected-row'); + instance.resetForm(); + instance.filter(key); + return false; + }); + + /** + * Event: Filter Service Cancel Button "Click" + */ + $('#filter-services .clear').click(function() { + $('#filter-services .key').val(''); + instance.filter(''); + instance.resetForm(); + }); + + /** + * Event: Filter Service Row "Click" + * + * Display the selected service data to the user. + */ + $(document).on('click', '.service-row', function() { + if ($('#filter-services .filter').prop('disabled')) { + $('#filter-services .results').css('color', '#AAA'); + return; // exit because we are on edit mode + } + + var serviceId = $(this).attr('data-id'), + service = {}; + $.each(instance.filterResults, function(index, item) { + if (item.id === serviceId) { + service = item; + return false; + } + }); + + instance.display(service); + $('#filter-services .selected-row').removeClass('selected-row'); + $(this).addClass('selected-row'); + $('#edit-service, #delete-service').prop('disabled', false); + }); + + /** + * Event: Add New Service Button "Click" + */ + $('#add-service').click(function() { + instance.resetForm(); + $('#services .add-edit-delete-group').hide(); + $('#services .save-cancel-group').show(); + $('#services .details').find('input, textarea').prop('readonly', false); + $('#services .details').find('select').prop('disabled', false); + $('#service-duration').spinner('enable'); + + $('#filter-services button').prop('disabled', true); + $('#filter-services .results').css('color', '#AAA'); + }); + + /** + * Event: Cancel Service Button "Click" + * + * Cancel add or edit of a service record. + */ + $('#cancel-service').click(function() { + var id = $('#service-id').val(); + instance.resetForm(); + if (id !== '') { + instance.select(id, true); + } + }); + + /** + * Event: Save Service Button "Click" + */ + $('#save-service').click(function() { + var service = { + name: $('#service-name').val(), + duration: $('#service-duration').val(), + price: $('#service-price').val(), + currency: $('#service-currency').val(), + description: $('#service-description').val() + }; + + if ($('#service-category').val() !== 'null') { + service.id_service_categories = $('#service-category').val(); + } else { + service.id_service_categories = null; + } + + if ($('#service-id').val() !== '') { + service.id = $('#service-id').val(); + } + + if (!instance.validate(service)) { + return; + } + + instance.save(service); + }); + + /** + * Event: Edit Service Button "Click" + */ + $('#edit-service').click(function() { + $('#services .add-edit-delete-group').hide(); + $('#services .save-cancel-group').show(); + $('#services .details').find('input, textarea').prop('readonly', false); + $('#services .details select').prop('disabled', false); + $('#service-duration').spinner('enable'); + + $('#filter-services button').prop('disabled', true); + $('#filter-services .results').css('color', '#AAA'); + }); + + /** + * Event: Delete Service Button "Click" + */ + $('#delete-service').click(function() { + var serviceId = $('#service-id').val(), + messageBtns = {}; + + messageBtns[EALang['delete']] = function() { + instance.delete(serviceId); + $('#message_box').dialog('close'); + }; + + messageBtns[EALang['cancel']] = function() { + $('#message_box').dialog('close'); + }; + + GeneralFunctions.displayMessageBox(EALang['delete_service'], + EALang['delete_record_prompt'], messageBtns); + }); + }; + + /** + * Save service record to database. + * + * @param {object} service Contains the service record data. If an 'id' value is provided + * then the update operation is going to be executed. + */ + ServicesHelper.prototype.save = function(service) { + var postUrl = GlobalVariables.baseUrl + '/index.php/backend_api/ajax_save_service', + postData = { + 'csrfToken': GlobalVariables.csrfToken, + 'service': JSON.stringify(service) + }; + + $.post(postUrl, postData, function(response) { + if (!GeneralFunctions.handleAjaxExceptions(response)) { + return; + } + + Backend.displayNotification(EALang['service_saved']); + this.resetForm(); + $('#filter-services .key').val(''); + this.filter('', response.id, true); + }.bind(this), 'json').fail(GeneralFunctions.ajaxFailureHandler); + }; + + /** + * Delete a service record from database. + * + * @param {numeric} id Record id to be deleted. + */ + ServicesHelper.prototype.delete = function(id) { + var postUrl = GlobalVariables.baseUrl + '/index.php/backend_api/ajax_delete_service', + postData = { + 'csrfToken': GlobalVariables.csrfToken, + 'service_id': id + }; + + $.post(postUrl, postData, function(response) { + if (!GeneralFunctions.handleAjaxExceptions(response)) { + return; + } + + Backend.displayNotification(EALang['service_deleted']); + + this.resetForm(); + this.filter($('#filter-services .key').val()); + }.bind(this), 'json').fail(GeneralFunctions.ajaxFailureHandler); + }; + + /** + * Validates a service record. + * + * @param {object} service Contains the service data. + * @returns {bool} Returns the validation result. + */ + ServicesHelper.prototype.validate = function(service) { + $('#services .required').css('border', ''); + + try { + // validate required fields. + var missingRequired = false; + + $('#services .required').each(function() { + if ($(this).val() == '' || $(this).val() == undefined) { + $(this).css('border', '2px solid red'); + missingRequired = true; + } + }); + + if (missingRequired) { + throw EALang['fields_are_required']; + } + + return true; + } catch(exc) { + return false; + } + }; + + /** + * Resets the service tab form back to its initial state. + */ + ServicesHelper.prototype.resetForm = function() { + $('#services .details').find('input, textarea').val(''); + $('#service-category').val('null'); + $('#services .add-edit-delete-group').show(); + $('#services .save-cancel-group').hide(); + $('#edit-service, #delete-service').prop('disabled', true); + $('#services .details').find('input, textarea').prop('readonly', true); + $('#service-category').prop('disabled', true); + $('#service-duration').spinner('disable'); + + $('#filter-services .selected-row').removeClass('selected-row'); + $('#filter-services button').prop('disabled', false); + $('#filter-services .results').css('color', ''); + }; + + /** + * Display a service record into the service form. + * + * @param {object} service Contains the service record data. + */ + ServicesHelper.prototype.display = function(service) { + $('#service-id').val(service.id); + $('#service-name').val(service.name); + $('#service-duration').val(service.duration); + $('#service-price').val(service.price); + $('#service-currency').val(service.currency); + $('#service-description').val(service.description); + + var categoryId = (service.id_service_categories !== null) ? service.id_service_categories : 'null'; + $('#service-category').val(categoryId); + }; + + /** + * Filters service records depending a string key. + * + * @param {string} key This is used to filter the service records of the database. + * @param {numeric} selectId (OPTIONAL = undefined) If set then after the filter + * operation the record with this id will be selected (but not displayed). + * @param {bool} display (OPTIONAL = false) If true then the selected record will + * be displayed on the form. + */ + ServicesHelper.prototype.filter = function(key, selectId, display) { + display = display || false; + + var postUrl = GlobalVariables.baseUrl + '/index.php/backend_api/ajax_filter_services', + postData = { + 'csrfToken': GlobalVariables.csrfToken, + 'key': key + }; + + $.post(postUrl, postData, function(response) { + if (!GeneralFunctions.handleAjaxExceptions(response)) { + return; + } + + this.filterResults = response; + + $('#filter-services .results').data('jsp').destroy(); + $('#filter-services .results').html(''); + $.each(response, function(index, service) { + var html = ServicesHelper.prototype.getFilterHtml(service); + $('#filter-services .results').append(html); + }); + $('#filter-services .results').jScrollPane({ mouseWheelSpeed: 70 }); + + if (response.length === 0) { + $('#filter-services .results').html('' + EALang['no_records_found'] + ''); + } + + if (selectId !== undefined) { + this.select(selectId, display); + } + }.bind(this), 'json').fail(GeneralFunctions.ajaxFailureHandler); + }; + + /** + * Get a service row html code that is going to be displayed on the filter results list. + * + * @param {object} service Contains the service record data. + * @returns {string} The html code that represents the record on the filter results list. + */ + ServicesHelper.prototype.getFilterHtml = function(service) { + var html = + '
' + + '' + service.name + '
' + + service.duration + ' min - ' + + service.price + ' ' + service.currency + '
' + + '

'; + + return html; + }; + + /** + * Select a specific record from the current filter results. If the service id does not exist + * in the list then no record will be selected. + * + * @param {numeric} id The record id to be selected from the filter results. + * @param {bool} display (OPTIONAL = false) If true then the method will display the record + * on the form. + */ + ServicesHelper.prototype.select = function(id, display) { + display = display || false; + + $('#filter-services .selected-row').removeClass('selected-row'); + + $('#filter-services .service-row').each(function() { + if ($(this).attr('data-id') === id) { + $(this).addClass('selected-row'); + return false; + } + }); + + if (display) { + $.each(this.filterResults, function(index, service) { + if (service.id === id) { + this.display(service); + $('#edit-service, #delete-service').prop('disabled', false); + return false; + } + }.bind(this)); + } + }; + + window.ServicesHelper = ServicesHelper; +})();