Added ajax failure handler to jquery post requests.

This commit is contained in:
Alex Tselegidis 2015-10-08 23:12:59 +02:00
parent daa4d28a6e
commit a24597ba4d
10 changed files with 743 additions and 722 deletions

View file

@ -444,7 +444,7 @@ var BackendCalendar = {
// Refresh calendar event items.
$('#select-filter-item').trigger('change');
}, 'json');
}, 'json').fail(GeneralFunctions.ajaxFailureHandler);
};
messageButtons[EALang['cancel']] = function() {
@ -486,7 +486,7 @@ var BackendCalendar = {
// Refresh calendar event items.
$('#select-filter-item').trigger('change');
}, 'json');
}, 'json').fail(GeneralFunctions.ajaxFailureHandler);
}
});
@ -740,7 +740,7 @@ var BackendCalendar = {
$('#select-google-calendar').modal('show');
}, 'json');
}, 'json').fail(GeneralFunctions.ajaxFailureHandler);
}
}
}, 100);
@ -970,7 +970,7 @@ var BackendCalendar = {
if (!GeneralFunctions.handleAjaxExceptions(response)) return;
Backend.displayNotification(EALang['google_calendar_selected']);
$('#select-google-calendar').modal('hide');
});
}, 'json').fail(GeneralFunctions.ajaxFailureHandler);
});
/**
@ -1038,7 +1038,7 @@ var BackendCalendar = {
};
calendarEvents.push(event);
});
}, 'json').fail(GeneralFunctions.ajaxFailureHandler);
$calendar.fullCalendar('removeEvents');
$calendar.fullCalendar('addEventSource', calendarEvents);
@ -1403,7 +1403,7 @@ var BackendCalendar = {
$.post(postUrl, postData, function(response) {
$('#notification').hide('blind');
revertFunc();
});
}, 'json').fail(GeneralFunctions.ajaxFailureHandler);
};
Backend.displayNotification(EALang['appointment_updated'], [
@ -1459,7 +1459,7 @@ var BackendCalendar = {
$.post(postUrl, postData, function(response) {
$('#notification').hide('blind');
revertFunc();
});
}, 'json').fail(GeneralFunctions.ajaxFailureHandler);
};
Backend.displayNotification(EALang['unavailable_updated'], [
@ -1686,7 +1686,7 @@ var BackendCalendar = {
$.post(postUrl, postData, function(response) {
$('#notification').hide('blind');
revertFunc();
});
}, 'json').fail(GeneralFunctions.ajaxFailureHandler);
};
Backend.displayNotification(EALang['appointment_updated'], [
@ -1751,7 +1751,7 @@ var BackendCalendar = {
$.post(postUrl, postData, function(response) {
$('#notification').hide('blind');
revertFunc();
});
}, 'json').fail(GeneralFunctions.ajaxFailureHandler);
};
Backend.displayNotification(EALang['unavailable_updated'], [
@ -1823,7 +1823,7 @@ var BackendCalendar = {
$('#message_box').append(GeneralFunctions.exceptionsToHtml(response.exceptions));
return;
}
}, 'json');
}, 'json').fail(GeneralFunctions.ajaxFailureHandler);
},
/**

View file

@ -1,52 +1,52 @@
/* ----------------------------------------------------------------------------
* Easy!Appointments - Open Source Web Scheduler
*
*
* @package EasyAppointments
* @author A.Tselegidis <alextselegidis@gmail.com>
* @copyright Copyright (c) 2013 - 2015, Alex Tselegidis
* @license http://opensource.org/licenses/GPL-3.0 - GPLv3
* @license http://opensource.org/licenses/GPL-3.0 - GPLv3
* @link http://easyappointments.org
* @since v1.0.0
* ---------------------------------------------------------------------------- */
/**
* Backend Customers javasript namespace. Contains the main functionality
* of the backend customers page. If you need to use this namespace in a
* Backend Customers javasript namespace. Contains the main functionality
* of the backend customers page. If you need to use this namespace in a
* different page, do not bind the default event handlers during initialization.
*
* @namespace BackendCustomers
*/
var BackendCustomers = {
/**
* The page helper contains methods that implement each record type functionality
* The page helper contains methods that implement each record type functionality
* (for now there is only the CustomersHelper).
*
*
* @type {object{
*/
helper: {},
/**
* This method initializes the backend customers page. If you use this namespace
* in a different page do not use this method.
*
* @param {bool} defaultEventHandlers (OPTIONAL = false) Whether to bind the default
* event handlers or not.
* in a different page do not use this method.
*
* @param {bool} defaultEventHandlers (OPTIONAL = false) Whether to bind the default
* event handlers or not.
*/
initialize: function(defaultEventHandlers) {
if (defaultEventHandlers == undefined) defaultEventHandlers = false;
if (defaultEventHandlers == undefined) defaultEventHandlers = false;
BackendCustomers.helper = new CustomersHelper();
BackendCustomers.helper.resetForm();
BackendCustomers.helper.filter('');
$('#filter-customers .results').jScrollPane();
$('#customer-appointments').jScrollPane();
if (defaultEventHandlers) {
BackendCustomers.bindEventHandlers();
}
},
/**
* Default event handlers declaration for backend customers page.
*/
@ -57,7 +57,7 @@ var BackendCustomers = {
/**
* This class contains the methods that are used in the backend customers page.
*
*
* @class CustomersHelper
*/
var CustomersHelper = function() {
@ -78,7 +78,7 @@ CustomersHelper.prototype.bindEventHandlers = function() {
BackendCustomers.helper.filter(key);
return false;
});
/**
* Event: Filter Customers Clear Button "Click"
*/
@ -86,17 +86,17 @@ CustomersHelper.prototype.bindEventHandlers = function() {
$('#filter-customers .key').val('');
BackendCustomers.helper.filter('');
});
/**
* Event: Customer Row "Click"
*
*
* Display the customer data of the selected row.
*/
$(document).on('click', '.customer-row', function() {
if ($('#filter-customers .filter').prop('disabled')) {
return; // Do nothing when user edits a customer record.
}
var customerId = $(this).attr('data-id');
var customer = {};
$.each(BackendCustomers.helper.filterResults, function(index, item) {
@ -105,7 +105,7 @@ CustomersHelper.prototype.bindEventHandlers = function() {
return false;
}
});
BackendCustomers.helper.display(customer);
$('#filter-customers .selected-row').removeClass('selected-row');
$(this).addClass('selected-row');
@ -114,7 +114,7 @@ CustomersHelper.prototype.bindEventHandlers = function() {
/**
* Event: Appointment Row "Click"
*
*
* Display appointment data of the selected row.
*/
$(document).on('click', '.appointment-row', function() {
@ -194,9 +194,9 @@ CustomersHelper.prototype.bindEventHandlers = function() {
if ($('#customer-id').val() != '') {
customer.id = $('#customer-id').val();
}
if (!BackendCustomers.helper.validate(customer)) return;
BackendCustomers.helper.save(customer);
});
@ -205,9 +205,9 @@ CustomersHelper.prototype.bindEventHandlers = function() {
*/
$('#delete-customer').click(function() {
var customerId = $('#customer-id').val();
var messageBtns = {};
messageBtns[EALang['delete']] = function() {
messageBtns[EALang['delete']] = function() {
BackendCustomers.helper.delete(customerId);
$('#message_box').dialog('close');
};
@ -215,71 +215,71 @@ CustomersHelper.prototype.bindEventHandlers = function() {
$('#message_box').dialog('close');
};
GeneralFunctions.displayMessageBox(EALang['delete_customer'],
GeneralFunctions.displayMessageBox(EALang['delete_customer'],
EALang['delete_record_prompt'], messageBtns);
});
};
/**
* Save a customer record to the database (via ajax post).
*
*
* @param {object} customer Contains the customer data.
*/
CustomersHelper.prototype.save = function(customer) {
var postUrl = GlobalVariables.baseUrl + '/index.php/backend_api/ajax_save_customer';
var postData = {
var postData = {
'csrfToken': GlobalVariables.csrfToken,
'customer': JSON.stringify(customer)
'customer': JSON.stringify(customer)
};
$.post(postUrl, postData, function(response) {
///////////////////////////////////////////////////////////
console.log('Save Customer Response:', response);
///////////////////////////////////////////////////////////
if (!GeneralFunctions.handleAjaxExceptions(response)) return;
Backend.displayNotification(EALang['customer_saved']);
BackendCustomers.helper.resetForm();
$('#filter-customers .key').val('');
BackendCustomers.helper.filter('', response.id, true);
}, 'json');
}, 'json').fail(GeneralFunctions.ajaxFailureHandler);
};
/**
* Delete a customer record from database.
*
* @param {numeric} id Record id to be deleted.
*
* @param {numeric} id Record id to be deleted.
*/
CustomersHelper.prototype.delete = function(id) {
var postUrl = GlobalVariables.baseUrl + '/index.php/backend_api/ajax_delete_customer';
var postData = {
var postData = {
'csrfToken': GlobalVariables.csrfToken,
'customer_id': id
'customer_id': id
};
$.post(postUrl, postData, function(response) {
////////////////////////////////////////////////////
//console.log('Delete customer response:', response);
////////////////////////////////////////////////////
if (!GeneralFunctions.handleAjaxExceptions(response)) return;
Backend.displayNotification(EALang['customer_deleted']);
BackendCustomers.helper.resetForm();
BackendCustomers.helper.filter($('#filter-customers .key').val());
}, 'json');
}, 'json').fail(GeneralFunctions.ajaxFailureHandler);
};
/**
* Validate customer data before save (insert or update).
*
*
* @param {object} customer Contains the customer data.
*/
CustomersHelper.prototype.validate = function(customer) {
$('#form-message').hide();
$('.required').css('border', '');
try {
// Validate required fields.
var missingRequired = false;
@ -311,18 +311,18 @@ CustomersHelper.prototype.validate = function(customer) {
* Bring the customer form back to its initial state.
*/
CustomersHelper.prototype.resetForm = function() {
$('.details').find('input, textarea').val('');
$('.details').find('input, textarea').prop('readonly', true);
$('.details').find('input, textarea').val('');
$('.details').find('input, textarea').prop('readonly', true);
$('#customer-appointments').html('');
$('#appointment-details').html('');
$('#edit-customer, #delete-customer').prop('disabled', true);
$('#add-edit-delete-group').show();
$('#save-cancel-group').hide();
$('.details .required').css('border', '');
$('.details #form-message').hide();
$('#filter-customers button').prop('disabled', false);
$('#filter-customers .selected-row').removeClass('selected-row');
$('#filter-customers .results').css('color', '');
@ -330,7 +330,7 @@ CustomersHelper.prototype.resetForm = function() {
/**
* Display a customer record into the form.
*
*
* @param {object} customer Contains the customer record data.
*/
CustomersHelper.prototype.display = function(customer) {
@ -349,109 +349,109 @@ CustomersHelper.prototype.display = function(customer) {
$.each(customer.appointments, function(index, appointment) {
var start = Date.parse(appointment.start_datetime).toString('dd/MM/yyyy HH:mm');
var end = Date.parse(appointment.end_datetime).toString('dd/MM/yyyy HH:mm');
var html =
'<div class="appointment-row" data-id="' + appointment.id + '">' +
var html =
'<div class="appointment-row" data-id="' + appointment.id + '">' +
start + ' - ' + end + '<br>' +
appointment.service.name + ', ' +
appointment.service.name + ', ' +
appointment.provider.first_name + ' ' + appointment.provider.last_name +
'</div>';
'</div>';
$('#customer-appointments').append(html);
});
$('#customer-appointments').jScrollPane({ mouseWheelSpeed: 70 });
$('#appointment-details').empty();
};
/**
* Filter customer records.
*
*
* @param {string} key This key string is used to filter the customer records.
* @param {numeric} selectId (OPTIONAL = undefined) If set then after the filter
* @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.
*/
CustomersHelper.prototype.filter = function(key, selectId, display) {
if (display == undefined) display = false;
var postUrl = GlobalVariables.baseUrl + '/index.php/backend_api/ajax_filter_customers';
var postData = {
var postData = {
'csrfToken': GlobalVariables.csrfToken,
'key': key
'key': key
};
$.post(postUrl, postData, function(response) {
///////////////////////////////////////////////////////
console.log('Filter Customers Response:', response);
///////////////////////////////////////////////////////
if (!GeneralFunctions.handleAjaxExceptions(response)) return;
BackendCustomers.helper.filterResults = response;
$('#filter-customers .results').data('jsp').destroy();
$('#filter-customers .results').data('jsp').destroy();
$('#filter-customers .results').html('');
$.each(response, function(index, customer) {
var html = BackendCustomers.helper.getFilterHtml(customer);
$('#filter-customers .results').append(html);
});
$('#filter-customers .results').jScrollPane({ mouseWheelSpeed: 70 });
if (response.length == 0) {
$('#filter-customers .results').html('<em>' + EALang['no_records_found'] + '</em>');
}
if (selectId != undefined) {
BackendCustomers.helper.select(selectId, display);
}
}, 'json');
}, 'json').fail(GeneralFunctions.ajaxFailureHandler);
};
/**
* Get the filter results row html code.
*
*
* @param {object} customer Contains the customer data.
* @return {string} Returns the record html code.
*/
CustomersHelper.prototype.getFilterHtml = function(customer) {
var name = customer.first_name + ' ' + customer.last_name;
var info = customer.email;
info = (customer.phone_number != '' && customer.phone_number != null)
var info = customer.email;
info = (customer.phone_number != '' && customer.phone_number != null)
? info + ', ' + customer.phone_number : info;
var html =
var html =
'<div class="customer-row" data-id="' + customer.id + '">' +
'<strong>' +
name +
'</strong><br>' +
'<strong>' +
name +
'</strong><br>' +
info +
'</div><hr>';
return html;
};
/**
* Select a specific record from the current filter results. If the customer id does not exist
* in the list then no record will be selected.
*
* Select a specific record from the current filter results. If the customer 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.
*/
CustomersHelper.prototype.select = function(id, display) {
if (display == undefined) display = false;
$('#filter-customers .selected-row').removeClass('selected-row');
$('#filter-customers .customer-row').each(function() {
if ($(this).attr('data-id') == id) {
$(this).addClass('selected-row');
return false;
}
});
if (display) {
if (display) {
$.each(BackendCustomers.helper.filterResults, function(index, customer) {
if (customer.id == id) {
BackendCustomers.helper.display(customer);
@ -460,23 +460,23 @@ CustomersHelper.prototype.select = function(id, display) {
}
});
}
};
};
/**
* Display appointment details on customers backend page.
*
*
* @param {object} appointment Appointment data
*/
CustomersHelper.prototype.displayAppointment = function(appointment) {
var start = Date.parse(appointment.start_datetime).toString('dd/MM/yyyy HH:mm');
var end = Date.parse(appointment.end_datetime).toString('dd/MM/yyyy HH:mm');
var html =
'<div>' +
'<strong>' + appointment.service.name + '</strong><br>' +
var html =
'<div>' +
'<strong>' + appointment.service.name + '</strong><br>' +
appointment.provider.first_name + ' ' + appointment.provider.last_name + '<br>' +
start + ' - ' + end + '<br>' +
'</div>';
$('#appointment-details').html(html);
};
};

View file

@ -1,59 +1,59 @@
/* ----------------------------------------------------------------------------
* Easy!Appointments - Open Source Web Scheduler
*
*
* @package EasyAppointments
* @author A.Tselegidis <alextselegidis@gmail.com>
* @copyright Copyright (c) 2013 - 2015, Alex Tselegidis
* @license http://opensource.org/licenses/GPL-3.0 - GPLv3
* @license http://opensource.org/licenses/GPL-3.0 - GPLv3
* @link http://easyappointments.org
* @since v1.0.0
* ---------------------------------------------------------------------------- */
/**
* This namespace handles the js functionality of the backend services page.
*
*
* @namespace BackendServices
*/
var BackendServices = {
/**
* Contains the basic record methods for the page.
*
*
* @type ServicesHelper|CategoriesHelper
*/
helper: {},
/**
* Default initialize method of the page.
*
* @param {bool} bindEventHandlers (OPTIONAL) Determines whether to bind the
*
* @param {bool} bindEventHandlers (OPTIONAL) Determines whether to bind the
* default event handlers (default: true).
*/
initialize: function(bindEventHandlers) {
if (bindEventHandlers === undefined) bindEventHandlers = true;
// Fill available service categories listbox.
$.each(GlobalVariables.categories, function(index, category) {
var option = new Option(category.name, category.id);
$('#service-category').append(option);
});
$('#service-category').append(new Option('- ' + EALang['no_category'] + ' -', null)).val('null');
$('#service-duration').spinner({
'min': 0,
'disabled': true //default
});
// Instantiate helper object (service helper by default).
BackendServices.helper = new ServicesHelper();
BackendServices.helper.resetForm();
BackendServices.helper.filter('');
$('#filter-services .results').jScrollPane();
$('#filter-categories .results').jScrollPane();
if (bindEventHandlers) BackendServices.bindEventHandlers();
if (bindEventHandlers) BackendServices.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.
@ -61,14 +61,14 @@ var BackendServices = {
bindEventHandlers: function() {
/**
* Event: Page Tab Button "Click"
*
*
* Changes the displayed tab.
*/
$('.tab').click(function() {
$(this).parent().find('.active').removeClass('active');
$(this).addClass('active');
$('.tab-content').hide();
if ($(this).hasClass('services-tab')) { // display services tab
$('#services').show();
BackendServices.helper = new ServicesHelper();
@ -76,36 +76,36 @@ var BackendServices = {
$('#categories').show();
BackendServices.helper = new CategoriesHelper();
}
BackendServices.helper.resetForm();
BackendServices.helper.filter('');
$('.filter-key').val('');
Backend.placeFooterToBottom();
});
ServicesHelper.prototype.bindEventHandlers();
CategoriesHelper.prototype.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 = {
var postData = {
'csrfToken': GlobalVariables.csrfToken,
'key': ''
'key': ''
};
$.post(postUrl, postData, function(response) {
///////////////////////////////////////////////////////////////
console.log('Update Available Categories Response:', response);
///////////////////////////////////////////////////////////////
if (!GeneralFunctions.handleAjaxExceptions(response)) return;
GlobalVariables.categories = response;
var $select = $('#service-category');
$select.empty();
@ -114,7 +114,7 @@ var BackendServices = {
$select.append(option);
});
$select.append(new Option('- ' + EALang['no_category'] + ' -', null)).val('null');
}, 'json');
}, 'json').fail(GeneralFunctions.ajaxFailureHandler);
}
};
@ -148,7 +148,7 @@ ServicesHelper.prototype.bindEventHandlers = function() {
/**
* Event: Filter Service Row "Click"
*
*
* Display the selected service data to the user.
*/
$(document).on('click', '.service-row', function() {
@ -157,7 +157,7 @@ ServicesHelper.prototype.bindEventHandlers = function() {
return; // exit because we are on edit mode
}
var serviceId = $(this).attr('data-id');
var serviceId = $(this).attr('data-id');
var service = {};
$.each(BackendServices.helper.filterResults, function(index, item) {
if (item.id === serviceId) {
@ -189,7 +189,7 @@ ServicesHelper.prototype.bindEventHandlers = function() {
/**
* Event: Cancel Service Button "Click"
*
*
* Cancel add or edit of a service record.
*/
$('#cancel-service').click(function() {
@ -257,14 +257,14 @@ ServicesHelper.prototype.bindEventHandlers = function() {
$('#message_box').dialog('close');
};
GeneralFunctions.displayMessageBox(EALang['delete_service'],
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.
*/
@ -272,61 +272,61 @@ ServicesHelper.prototype.save = function(service) {
////////////////////////////////////////////////
//console.log('Service data to save:', service);
////////////////////////////////////////////////
var postUrl = GlobalVariables.baseUrl + '/index.php/backend_api/ajax_save_service';
var postData = {
var postData = {
'csrfToken': GlobalVariables.csrfToken,
'service': JSON.stringify(service)
'service': JSON.stringify(service)
};
$.post(postUrl, postData, function(response) {
//////////////////////////////////////////////////
//console.log('Save Service Response:', 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');
}, 'json').fail(GeneralFunctions.ajaxFailureHandler);
};
/**
* Delete a service record from database.
*
* @param {numeric} id Record id to be deleted.
*
* @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 = {
var postData = {
'csrfToken': GlobalVariables.csrfToken,
'service_id': id
'service_id': id
};
$.post(postUrl, postData, function(response) {
////////////////////////////////////////////////////
//console.log('Delete service response:', response);
////////////////////////////////////////////////////
if (!GeneralFunctions.handleAjaxExceptions(response)) return;
Backend.displayNotification(EALang['service_deleted']);
BackendServices.helper.resetForm();
BackendServices.helper.filter($('#filter-services .key').val());
}, 'json');
}, '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;
@ -336,11 +336,11 @@ ServicesHelper.prototype.validate = function(service) {
missingRequired = true;
}
});
if (missingRequired)
if (missingRequired)
throw EALang['fields_are_required'];
return true;
} catch(exc) {
return false;
@ -348,7 +348,7 @@ ServicesHelper.prototype.validate = function(service) {
};
/**
* Resets the service tab form back to its initial state.
* Resets the service tab form back to its initial state.
*/
ServicesHelper.prototype.resetForm = function() {
$('#services .details').find('input, textarea').val('');
@ -359,7 +359,7 @@ ServicesHelper.prototype.resetForm = function() {
$('#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', '');
@ -367,7 +367,7 @@ ServicesHelper.prototype.resetForm = function() {
/**
* Display a service record into the service form.
*
*
* @param {object} service Contains the service record data.
*/
ServicesHelper.prototype.display = function(service) {
@ -377,67 +377,67 @@ ServicesHelper.prototype.display = function(service) {
$('#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
* @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
* @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 = {
var postData = {
'csrfToken': GlobalVariables.csrfToken,
'key': key
'key': key
};
$.post(postUrl, postData, function(response) {
/////////////////////////////////////////////////////
//console.log('Filter services response:', 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('<em>' + EALang['no_records_found'] + '</em>');
}
if (selectId != undefined) {
BackendServices.helper.select(selectId, display);
}
}, 'json');
}, '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 =
'<div class="service-row" data-id="' + service.id + '">' +
'<div class="service-row" data-id="' + service.id + '">' +
'<strong>' + service.name + '</strong><br>' +
service.duration + ' min - ' +
service.duration + ' min - ' +
service.price + ' ' + service.currency + '<br>' +
'</div><hr>';
@ -445,26 +445,26 @@ ServicesHelper.prototype.getFilterHtml = function(service) {
};
/**
* 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.
*
* 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) {
if (display) {
$.each(BackendServices.helper.filterResults, function(index, service) {
if (service.id == id) {
BackendServices.helper.display(service);
@ -478,7 +478,7 @@ ServicesHelper.prototype.select = function(id, display) {
/**
* This class contains the core method implementations that belong to the categories tab
* of the backend services page.
*
*
* @class CategoriesHelper
*/
var CategoriesHelper = function() {
@ -507,10 +507,10 @@ CategoriesHelper.prototype.bindEventHandlers = function() {
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() {
@ -533,7 +533,7 @@ CategoriesHelper.prototype.bindEventHandlers = function() {
$(this).addClass('selected-row');
$('#edit-category, #delete-category').prop('disabled', false);
});
/**
* Event: Add Category Button "Click"
*/
@ -545,7 +545,7 @@ CategoriesHelper.prototype.bindEventHandlers = function() {
$('#filter-categories button').prop('disabled', true);
$('#filter-categories .results').css('color', '#AAA');
});
/**
* Event: Edit Category Button "Click"
*/
@ -557,7 +557,7 @@ CategoriesHelper.prototype.bindEventHandlers = function() {
$('#filter-categories button').prop('disabled', true);
$('#filter-categories .results').css('color', '#AAA');
});
/**
* Event: Delete Category Button "Click"
*/
@ -573,10 +573,10 @@ CategoriesHelper.prototype.bindEventHandlers = function() {
$('#message_box').dialog('close');
};
GeneralFunctions.displayMessageBox(EALang['delete_category'],
GeneralFunctions.displayMessageBox(EALang['delete_category'],
EALang['delete_record_prompt'], messageBtns);
});
/**
* Event: Categories Save Button "Click"
*/
@ -594,7 +594,7 @@ CategoriesHelper.prototype.bindEventHandlers = function() {
BackendServices.helper.save(category);
});
/**
* Event: Cancel Category Button "Click"
*/
@ -609,29 +609,29 @@ CategoriesHelper.prototype.bindEventHandlers = function() {
/**
* 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
* @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 = {
var postData = {
'csrfToken': GlobalVariables.csrfToken,
'key': key
'key': key
};
$.post(postUrl, postData, function(response) {
///////////////////////////////////////////////////////
console.log('Filter Categories Response:', 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) {
@ -639,75 +639,75 @@ CategoriesHelper.prototype.filter = function(key, selectId, display) {
$('#filter-categories .results').append(html);
});
$('#filter-categories .results').jScrollPane({ mouseWheelSpeed: 70 });
if (response.length == 0) {
$('#filter-categories .results').html('<em>' + EALang['no_records_found'] + '</em>');
}
if (selectId != undefined) {
BackendServices.helper.select(selectId, display);
}
}, 'json');
}, '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 = {
var postData = {
'csrfToken': GlobalVariables.csrfToken,
'category': JSON.stringify(category)
'category': JSON.stringify(category)
};
$.post(postUrl, postData, function(response) {
///////////////////////////////////////////////////////////
console.log('Save Service Category Response:', 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');
}, '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 = {
var postData = {
'csrfToken': GlobalVariables.csrfToken,
'category_id': id
'category_id': id
};
$.post(postUrl, postData, function(response) {
////////////////////////////////////////////////////
console.log('Delete category response:', 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');
}, 'json').fail(GeneralFunctions.ajaxFailureHandler);
};
/**
* Display a category record on the form.
*
*
* @param {object} category Contains the category data.
*/
CategoriesHelper.prototype.display = function(category) {
@ -718,12 +718,12 @@ CategoriesHelper.prototype.display = function(category) {
/**
* 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() {
@ -733,9 +733,9 @@ CategoriesHelper.prototype.validate = function(category) {
}
});
if (missingRequired) throw EALang['fields_are_required'];
return true;
} catch(exc) {
console.log('Category Record Validation Exc:', exc);
return false;
@ -751,7 +751,7 @@ CategoriesHelper.prototype.resetForm = function() {
$('#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);
@ -759,13 +759,13 @@ CategoriesHelper.prototype.resetForm = function() {
/**
* 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) {
CategoriesHelper.prototype.getFilterHtml = function(category) {
var html =
'<div class="category-row" data-id="' + category.id + '">' +
'<div class="category-row" data-id="' + category.id + '">' +
'<strong>' + category.name + '</strong>' +
'</div><hr>';
@ -773,26 +773,26 @@ CategoriesHelper.prototype.getFilterHtml = function(category) {
};
/**
* 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.
*
* 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) {
if (display) {
$.each(BackendServices.helper.filterResults, function(index, category) {
if (category.id == id) {
BackendServices.helper.display(category);
@ -801,4 +801,4 @@ CategoriesHelper.prototype.select = function(id, display) {
}
});
}
};
};

View file

@ -1,70 +1,70 @@
/* ----------------------------------------------------------------------------
* Easy!Appointments - Open Source Web Scheduler
*
*
* @package EasyAppointments
* @author A.Tselegidis <alextselegidis@gmail.com>
* @copyright Copyright (c) 2013 - 2015, Alex Tselegidis
* @license http://opensource.org/licenses/GPL-3.0 - GPLv3
* @license http://opensource.org/licenses/GPL-3.0 - GPLv3
* @link http://easyappointments.org
* @since v1.0.0
* ---------------------------------------------------------------------------- */
/**
* Contains the functionality of the backend settings page. Can either work for
* 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).
*
*
* @namespace BackendSettings
*/
var BackendSettings = {
SETTINGS_SYSTEM: 'SETTINGS_SYSTEM',
SETTINGS_USER: 'SETTINGS_USER',
/**
* Use this WorkingPlan class instance to perform actions on the page's working plan
* tables.
*/
wp: {},
/**
* Tab settings object.
*
*
* @type {object}
*/
settings: {},
/**
* Initialize Page
*
*
* @param {bool} bindEventHandlers (OPTIONAL)Determines whether to bind the default event
* handlers (default = true).
* @returns {undefined}
*/
initialize: function(bindEventHandlers) {
if (bindEventHandlers == undefined) bindEventHandlers = true;
// Apply setting values from database.
$.each(GlobalVariables.settings.system, function(index, setting) {
$('input[data-field="' + setting.name + '"]').val(setting.value);
});
var workingPlan = {};
$.each(GlobalVariables.settings.system, function(index, setting) {
if (setting.name == 'company_working_plan') {
workingPlan = $.parseJSON(setting.value);
workingPlan = $.parseJSON(setting.value);
return false;
}
});
BackendSettings.wp = new WorkingPlan();
BackendSettings.wp.setup(workingPlan);
BackendSettings.wp.timepickers(false);
// Book Advance Timeout Spinner
$('#book-advance-timeout').spinner({
'min': 0
});
// Load user settings into form
$('#user-id').val(GlobalVariables.settings.user.id);
$('#first-name').val(GlobalVariables.settings.user.first_name);
@ -77,87 +77,87 @@ var BackendSettings = {
$('#state').val(GlobalVariables.settings.user.state);
$('#zip-code').val(GlobalVariables.settings.user.zip_code);
$('#notes').val(GlobalVariables.settings.user.notes);
$('#username').val(GlobalVariables.settings.user.settings.username);
$('#password, #retype-password').val('');
if (GlobalVariables.settings.user.settings.notifications == true) {
if (GlobalVariables.settings.user.settings.notifications == true) {
$('#user-notifications').addClass('active');
} else {
$('#user-notifications').removeClass('active');
}
// Set default settings helper.
BackendSettings.settings = new SystemSettings();
if (bindEventHandlers) {
BackendSettings.bindEventHandlers();
$('#settings-page .nav li').first().addClass('active');
$('#settings-page .nav li').first().find('a').trigger('click');
}
// Apply Privileges
if (GlobalVariables.user.privileges.system_settings.edit == false) {
$('#general, #business-logic').find('select, input, textarea').prop('readonly', true);
$('#general, #business-logic').find('button').prop('disabled', true);
}
if (GlobalVariables.user.privileges.user_settings.edit == false) {
$('#user').find('select, input, textarea').prop('readonly', true);
$('#user').find('button').prop('disabled', true);
}
Backend.placeFooterToBottom();
},
/**
* Bind the backend/settings default event handlers. This method depends on the
* 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.
*/
bindEventHandlers: function() {
BackendSettings.wp.bindEventHandlers();
/**
* Event: Tab "Click"
*
*
* Change the visible tab contents.
*/
$('.tab').click(function() {
// Bootstrap has a bug with toggle buttons. Their toggle state is lost when the
// button is hidden or shown. Show before anything else we need to store the toggle
// button is hidden or shown. Show before anything else we need to store the toggle
// and apply it whenever the user tab is clicked..
var areNotificationsActive = $('#user-notifications').hasClass('active');
$(this).parent().find('.active').removeClass('active');
$(this).addClass('active');
$('.tab-content').hide();
if ($(this).hasClass('general-tab')) {
if ($(this).hasClass('general-tab')) {
$('#general').show();
BackendSettings.settings = new SystemSettings();
} else if ($(this).hasClass('business-logic-tab')) {
} else if ($(this).hasClass('business-logic-tab')) {
$('#business-logic').show();
BackendSettings.settings = new SystemSettings();
} else if ($(this).hasClass('user-tab')) {
$('#user').show();
BackendSettings.settings = new UserSettings();
// Apply toggle state to user notifications button.
if (areNotificationsActive) {
$('#user-notifications').addClass('active');
} else {
$('#user-notifications').removeClass('active');
$('#user-notifications').removeClass('active');
}
} else if ($(this).hasClass('about-tab')) {
$('#about').show();
}
Backend.placeFooterToBottom();
});
/**
* Event: Save Settings Button "Click"
*
*
* Store the setting changes into the database.
*/
$('.save-settings').click(function() {
@ -167,25 +167,25 @@ var BackendSettings = {
//console.log('Settings To Save: ', settings);
//////////////////////////////////////////////
});
/**
* Event: Username "Focusout"
*
* When the user leaves the username input field we will need to check if the username
* Event: Username "Focusout"
*
* When the user leaves the username input field we will need to check if the username
* is not taken by another record in the system. Usernames must be unique.
*/
$('#username').focusout(function() {
var $input = $(this);
if ($input.prop('readonly') == true || $input.val() == '') return;
var postUrl = GlobalVariables.baseUrl + '/index.php/backend_api/ajax_validate_username';
var postData = {
var postData = {
'csrfToken': GlobalVariables.csrfToken,
'username': $input.val(),
'username': $input.val(),
'user_id': $input.parents().eq(2).find('#user-id').val()
};
$.post(postUrl, postData, function(response) {
///////////////////////////////////////////////////////
//console.log('Validate Username Response:', response);
@ -199,7 +199,7 @@ var BackendSettings = {
$input.css('border', '');
$input.attr('already-exists', 'false');
}
}, 'json');
}, 'json').fail(GeneralFunctions.ajaxFailureHandler);
});
}
};
@ -211,9 +211,9 @@ var BackendSettings = {
var SystemSettings = function() {};
/**
* Save the system settings. This method is run after changes are detected on the
* 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.
*/
SystemSettings.prototype.save = function(settings) {
@ -223,37 +223,37 @@ SystemSettings.prototype.save = function(settings) {
'settings': JSON.stringify(settings),
'type': BackendSettings.SETTINGS_SYSTEM
};
$.post(postUrl, postData, function(response) {
///////////////////////////////////////////////////////////
console.log('Save General Settings Response:', response);
///////////////////////////////////////////////////////////
if (!GeneralFunctions.handleAjaxExceptions(response)) return;
Backend.displayNotification(EALang['settings_saved']);
// Update the logo title on the header.
$('#header-logo span').text($('#company-name').val());
// We need to refresh the working plan.
var workingPlan = BackendSettings.wp.get();
$('.breaks').empty();
BackendSettings.wp.setup(workingPlan);
BackendSettings.wp.timepickers(false);
}, 'json');
}, 'json').fail(GeneralFunctions.ajaxFailureHandler);
};
/**
* Prepare the system settings array. This method uses the DOM elements of the
* 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.
*
*
* @returns {array} Returns the system settings array.
*/
SystemSettings.prototype.get = function() {
var settings = [];
// General Settings Tab
$('#general input').each(function() {
settings.push({
@ -261,30 +261,30 @@ SystemSettings.prototype.get = function() {
'value': $(this).val()
});
});
// Business Logic Tab
settings.push({
'name': 'company_working_plan',
'value': JSON.stringify(BackendSettings.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
* Validate the settings data. If the validation fails then display a
* message to the user.
*
*
* @returns {bool} Returns the validation result.
*/
SystemSettings.prototype.validate = function() {
$('#general .required').css('border', '');
try {
// Validate required fields.
var missingRequired = false;
@ -297,13 +297,13 @@ SystemSettings.prototype.validate = function() {
if (missingRequired) {
throw EALang['fields_are_required'];
}
// Validate company email address.
if (!GeneralFunctions.validateEmail($('#company-email').val())) {
$('#company-email').css('border', '2px solid red');
throw EALang['invalid_email'];
}
return true;
} catch(exc) {
Backend.displayNotification(exc);
@ -319,7 +319,7 @@ var UserSettings = function() {};
/**
* Get the settings data for the user settings.
*
*
* @returns {object} Returns the user settings array.
*/
UserSettings.prototype.get = function() {
@ -340,17 +340,17 @@ UserSettings.prototype.get = function() {
'notifications': $('#user-notifications').hasClass('active')
}
};
if ($('#password').val() != '') {
user.settings.password = $('#password').val();
}
return user;
};
/**
* Store the user settings into the database.
*
*
* @param {array} settings Contains the user settings.
*/
UserSettings.prototype.save = function(settings) {
@ -358,32 +358,32 @@ UserSettings.prototype.save = function(settings) {
Backend.displayNotification(EALang['user_settings_are_invalid']);
return; // Validation failed, do not procceed.
}
var postUrl = GlobalVariables.baseUrl + '/index.php/backend_api/ajax_save_settings';
var postData = {
'csrfToken': GlobalVariables.csrfToken,
'type': BackendSettings.SETTINGS_USER,
'settings': JSON.stringify(settings)
};
$.post(postUrl, postData, function(response) {
//////////////////////////////////////////////////////////
console.log('Save User Settings Response: ', response);
//////////////////////////////////////////////////////////
if (!GeneralFunctions.handleAjaxExceptions(response)) return;
Backend.displayNotification(EALang['settings_saved']);
// Update footer greetings.
$('#footer-user-display-name').text('Hello, ' + $('#first-name').val() + ' ' + $('#last-name').val() + '!');
}, 'json');
}, 'json').fail(GeneralFunctions.ajaxFailureHandler);
};
/**
* Validate the settings data. If the validation fails then display a
* Validate the settings data. If the validation fails then display a
* message to the user.
*
*
* @returns {bool} Returns the validation result.
*/
UserSettings.prototype.validate = function() {
@ -402,24 +402,24 @@ UserSettings.prototype.validate = function() {
if (missingRequired) {
throw EALang['fields_are_required'];
}
// Validate passwords (if provided).
if ($('#password').val() != $('#retype-password').val()) {
$('#password, #retype-password').css('border', '2px solid red');
throw EALang['passwords_mismatch'];
}
// Validate user email.
if (!GeneralFunctions.validateEmail($('#email').val())) {
$('#email').css('border', '2px solid red');
throw EALang['invalid_email'];
}
if ($('#username').attr('already-exists') === 'true') {
$('#username').css('border', '2px solid red');
throw EALang['username_already_exists'];
}
return true;
} catch(exc) {
Backend.displayNotification(exc);

View file

@ -1,90 +1,90 @@
/* ----------------------------------------------------------------------------
* Easy!Appointments - Open Source Web Scheduler
*
*
* @package EasyAppointments
* @author A.Tselegidis <alextselegidis@gmail.com>
* @copyright Copyright (c) 2013 - 2015, Alex Tselegidis
* @license http://opensource.org/licenses/GPL-3.0 - GPLv3
* @license http://opensource.org/licenses/GPL-3.0 - GPLv3
* @link http://easyappointments.org
* @since v1.0.0
* ---------------------------------------------------------------------------- */
/**
* This namespace handles the js functionality of the users backend page. It uses three other
* classes (defined below) in order to handle the admin, provider and secretary record types.
*
* classes (defined below) in order to handle the admin, provider and secretary record types.
*
* @namespace BackendUsers
*/
var BackendUsers = {
MIN_PASSWORD_LENGTH: 7,
MIN_PASSWORD_LENGTH: 7,
/**
* Contains the current tab record methods for the page.
*
*
* @type AdminsHelper|ProvidersHelper|SecretariesHelper
*/
helper: {},
/**
* Use this class instance for performing actions on the working plan.
*
*
* @type {object}
*/
wp: {},
/**
* Initialize the backend users page.
*
* @param {bool} defaultEventHandlers (OPTIONAL) Whether to bind the default event handlers
*
* @param {bool} defaultEventHandlers (OPTIONAL) Whether to bind the default event handlers
* (default: true).
*/
initialize: function(defaultEventHandlers) {
if (defaultEventHandlers == undefined) defaultEventHandlers = true;
// Initialize jScrollPane Scrollbars
$('#filter-admins .results').jScrollPane();
$('#filter-providers .results').jScrollPane();
$('#filter-secretaries .results').jScrollPane();
// Instanciate default helper object (admin).
BackendUsers.helper = new AdminsHelper();
BackendUsers.helper.resetForm();
BackendUsers.helper.filter('');
BackendUsers.wp = new WorkingPlan();
BackendUsers.wp.bindEventHandlers();
// Fill the services and providers list boxes.
var html = '<div class="col-md-12">';
$.each(GlobalVariables.services, function(index, service) {
html +=
html +=
'<div class="checkbox">' +
'<label class="checkbox">' +
'<input type="checkbox" data-id="' + service.id + '" />' +
service.name +
service.name +
'</label>' +
'</div>';
});
html += '</div>';
$('#provider-services').html(html);
$('#provider-services').jScrollPane({ mouseWheelSpeed: 70 });
var html = '<div class="col-md-12">';
$.each(GlobalVariables.providers, function(index, provider) {
html +=
html +=
'<div class="checkbox">' +
'<label class="checkbox">' +
'<input type="checkbox" data-id="' + provider.id + '" />' +
provider.first_name + ' ' + provider.last_name +
provider.first_name + ' ' + provider.last_name +
'</label>' +
'</div>';
});
html += '</div>';
$('#secretary-providers').html(html);
$('#secretary-providers').jScrollPane({ mouseWheelSpeed: 70 });
$('#reset-working-plan').qtip({
position: {
my: 'top center',
@ -94,26 +94,26 @@ var BackendUsers = {
classes: 'qtip-green qtip-shadow custom-qtip'
}
});
// Bind event handlers.
if (defaultEventHandlers) BackendUsers.bindEventHandlers();
},
/**
* Binds the defauly backend users event handlers. Do not use this method on a different
* Binds the defauly backend users event handlers. Do not use this method on a different
* page because it needs the backend users page DOM.
*/
bindEventHandlers: function() {
/**
* Event: Page Tab Button "Click"
*
*
* Changes the displayed tab.
*/
$('.tab').click(function() {
$(this).parent().find('.active').removeClass('active');
$(this).addClass('active');
$('.tab-content').hide();
if ($(this).hasClass('admins-tab')) { // display admins tab
$('#admins').show();
BackendUsers.helper = new AdminsHelper();
@ -125,68 +125,68 @@ var BackendUsers = {
} else if ($(this).hasClass('secretaries-tab')) { // display secretaries tab
$('#secretaries').show();
BackendUsers.helper = new SecretariesHelper();
// Update the list with the all the available providers.
var postUrl = GlobalVariables.baseUrl + '/index.php/backend_api/ajax_filter_providers';
var postData = {
var postData = {
'csrfToken': GlobalVariables.csrfToken,
'key': ''
'key': ''
};
$.post(postUrl, postData, function(response) {
//////////////////////////////////////////////////////////
//console.log('Get all db providers response:', response);
//////////////////////////////////////////////////////////
if (!GeneralFunctions.handleAjaxExceptions(response)) return;
GlobalVariables.providers = response;
$('#secretary-providers').data('jsp').destroy();
var html = '<div class="col-md-12">';
$.each(GlobalVariables.providers, function(index, provider) {
html +=
html +=
'<div class="checkbox">' +
'<label class="checkbox">' +
'<input type="checkbox" data-id="' + provider.id + '" />' +
provider.first_name + ' ' + provider.last_name +
provider.first_name + ' ' + provider.last_name +
'</label>' +
'</div>';
});
html += '</div>';
$('#secretary-providers').html(html);
$('#secretary-providers input[type="checkbox"]').prop('disabled', true);
$('#secretary-providers').jScrollPane({ mouseWheelSpeed: 70 });
}, 'json');
}, 'json').fail(GeneralFunctions.ajaxFailureHandler);
}
BackendUsers.helper.resetForm();
BackendUsers.helper.filter('');
$('.filter-key').val('');
});
/**
* Event: Admin, Provider, Secretary Username "Focusout"
*
* When the user leaves the username input field we will need to check if the username
* Event: Admin, Provider, Secretary Username "Focusout"
*
* When the user leaves the username input field we will need to check if the username
* is not taken by another record in the system. Usernames must be unique.
*/
$('#admin-username, #provider-username, #secretary-username').focusout(function() {
var $input = $(this);
if ($input.prop('readonly') == true || $input.val() == '') {
return;
}
var postUrl = GlobalVariables.baseUrl + '/index.php/backend_api/ajax_validate_username';
var postData = {
'csrfToken': GlobalVariables.csrfToken,
'username': $input.val(),
'csrfToken': GlobalVariables.csrfToken,
'username': $input.val(),
'user_id': $input.parents().eq(2).find('.record-id').val()
};
$.post(postUrl, postData, function(response) {
///////////////////////////////////////////////////////
console.log('Validate Username Response:', response);
@ -204,21 +204,21 @@ var BackendUsers = {
$input.parents().eq(3).find('.form-message').hide();
}
}
}, 'json');
}, 'json').fail(GeneralFunctions.ajaxFailureHandler);
});
// ------------------------------------------------------------------------
AdminsHelper.prototype.bindEventHandlers();
// ------------------------------------------------------------------------
ProvidersHelper.prototype.bindEventHandlers();
// ------------------------------------------------------------------------
SecretariesHelper.prototype.bindEventHandlers();
// ------------------------------------------------------------------------
}
};
};

View file

@ -1,19 +1,19 @@
/* ----------------------------------------------------------------------------
* Easy!Appointments - Open Source Web Scheduler
*
*
* @package EasyAppointments
* @author A.Tselegidis <alextselegidis@gmail.com>
* @copyright Copyright (c) 2013 - 2015, Alex Tselegidis
* @license http://opensource.org/licenses/GPL-3.0 - GPLv3
* @license http://opensource.org/licenses/GPL-3.0 - GPLv3
* @link http://easyappointments.org
* @since v1.0.0
* ---------------------------------------------------------------------------- */
/**
* This class contains the Admins helper class declaration, along with the "Admins" tab
* This class contains the Admins helper class declaration, along with the "Admins" tab
* event handlers. By deviding the backend/users tab functionality into separate files
* it is easier to maintain the code.
*
*
* @class AdminsHelper
*/
var AdminsHelper = function() {
@ -26,7 +26,7 @@ var AdminsHelper = function() {
AdminsHelper.prototype.bindEventHandlers = function() {
/**
* Event: Filter Admins Form "Sumbit"
*
*
* Filter the admin records with the given key string.
*/
$('#filter-admins form').submit(function(event) {
@ -36,7 +36,7 @@ AdminsHelper.prototype.bindEventHandlers = function() {
BackendUsers.helper.filter(key);
return false;
});
/**
* Event: Clear Filter Results Button "Click"
*/
@ -47,7 +47,7 @@ AdminsHelper.prototype.bindEventHandlers = function() {
/**
* Event: Filter Admin Row "Click"
*
*
* Display the selected admin data to the user.
*/
$(document).on('click', '.admin-row', function() {
@ -64,7 +64,7 @@ AdminsHelper.prototype.bindEventHandlers = function() {
return false;
}
});
BackendUsers.helper.display(admin);
$('#filter-admins .selected-row').removeClass('selected-row');
$(this).addClass('selected-row');
@ -94,7 +94,7 @@ AdminsHelper.prototype.bindEventHandlers = function() {
$('#admins .details').find('input, textarea').prop('readonly', false);
$('#admin-password, #admin-password-confirm').removeClass('required');
$('#admin-notifications').prop('disabled', false);
$('#filter-admins .filter').prop('disabled', true);
$('#filter-admins .results').css('color', '#AAA');
});
@ -114,7 +114,7 @@ AdminsHelper.prototype.bindEventHandlers = function() {
$('#message_box').dialog('close');
};
GeneralFunctions.displayMessageBox(EALang['delete_admin'],
GeneralFunctions.displayMessageBox(EALang['delete_admin'],
EALang['delete_record_prompt'], messageBtns);
});
@ -134,7 +134,7 @@ AdminsHelper.prototype.bindEventHandlers = function() {
'zip_code': $('#admin-zip-code').val(),
'notes': $('#admin-notes').val(),
'settings': {
'username': $('#admin-username').val(),
'username': $('#admin-username').val(),
'notifications': $('#admin-notifications').hasClass('active')
}
};
@ -156,7 +156,7 @@ AdminsHelper.prototype.bindEventHandlers = function() {
/**
* Event: Cancel Admin Button "Click"
*
*
* Cancel add or edit of an admin record.
*/
$('#cancel-admin').click(function() {
@ -170,7 +170,7 @@ AdminsHelper.prototype.bindEventHandlers = function() {
/**
* Save admin record to database.
*
*
* @param {object} admin Contains the admin record data. If an 'id' value is provided
* then the update operation is going to be executed.
*/
@ -178,13 +178,13 @@ AdminsHelper.prototype.save = function(admin) {
////////////////////////////////////////////
//console.log('Admin data to save:', admin);
////////////////////////////////////////////
var postUrl = GlobalVariables.baseUrl + '/index.php/backend_api/ajax_save_admin';
var postData = {
var postData = {
'csrfToken': GlobalVariables.csrfToken,
'admin': JSON.stringify(admin)
'admin': JSON.stringify(admin)
};
$.post(postUrl, postData, function(response) {
////////////////////////////////////////////////
//console.log('Save Admin Response:', response);
@ -193,22 +193,22 @@ AdminsHelper.prototype.save = function(admin) {
Backend.displayNotification(EALang['admin_saved']);
BackendUsers.helper.resetForm();
$('#filter-admins .key').val('');
BackendUsers.helper.filter('', response.id, true);
}, 'json');
BackendUsers.helper.filter('', response.id, true);
}, 'json').fail(GeneralFunctions.ajaxFailureHandler);
};
/**
* Delete an admin record from database.
*
* @param {int} id Record id to be deleted.
*
* @param {int} id Record id to be deleted.
*/
AdminsHelper.prototype.delete = function(id) {
var postUrl = GlobalVariables.baseUrl + '/index.php/backend_api/ajax_delete_admin';
var postData = {
var postData = {
'csrfToken': GlobalVariables.csrfToken,
'admin_id': id
'admin_id': id
};
$.post(postUrl, postData, function(response) {
//////////////////////////////////////////////////
//console.log('Delete admin response:', response);
@ -217,19 +217,19 @@ AdminsHelper.prototype.delete = function(id) {
Backend.displayNotification(EALang['admin_deleted']);
BackendUsers.helper.resetForm();
BackendUsers.helper.filter($('#filter-admins .key').val());
}, 'json');
}, 'json').fail(GeneralFunctions.ajaxFailureHandler);
};
/**
* Validates an admin record.
*
*
* @param {object} admin Contains the admin data to be validated.
* @returns {bool} Returns the validation result.
*/
AdminsHelper.prototype.validate = function(admin) {
$('#admins .required').css('border', '');
$('#admin-password, #admin-password-confirm').css('border', '');
try {
// Validate required fields.
var missingRequired = false;
@ -242,32 +242,32 @@ AdminsHelper.prototype.validate = function(admin) {
if (missingRequired) {
throw 'Fields with * are required.';
}
// Validate passwords.
if ($('#admin-password').val() != $('#admin-password-confirm').val()) {
$('#admin-password, #admin-password-confirm').css('border', '2px solid red');
throw EALang['passwords_mismatch'];
}
if ($('#admin-password').val().length < BackendUsers.MIN_PASSWORD_LENGTH
&& $('#admin-password').val() != '') {
$('#admin-password, #admin-password-confirm').css('border', '2px solid red');
throw EALang['password_length_notice'].replace('$number', BackendUsers.MIN_PASSWORD_LENGTH);
}
// Validate user email.
if (!GeneralFunctions.validateEmail($('#admin-email').val())) {
$('#admin-email').css('border', '2px solid red');
throw EALang['invalid_email'];
}
// Check if username exists
if ($('#admin-username').attr('already-exists') == 'true') {
$('#admin-username').css('border', '2px solid red');
throw EALang['username_already_exists'];
}
}
return true;
} catch(exc) {
$('#admins .form-message').text(exc);
@ -277,20 +277,20 @@ AdminsHelper.prototype.validate = function(admin) {
};
/**
* Resets the admin form back to its initial state.
* Resets the admin form back to its initial state.
*/
AdminsHelper.prototype.resetForm = function() {
$('#admins .add-edit-delete-group').show();
$('#admins .save-cancel-group').hide();
$('#admins .details').find('input, textarea').prop('readonly', true);
$('#admins .form-message').hide();
$('#admins .form-message').hide();
$('#admin-notifications').prop('disabled', true);
$('#admins .required').css('border', '');
$('#admin-password, #admin-password-confirm').css('border', '');
$('#admins .details').find('input, textarea').val('');
$('#admin-notifications').removeClass('active');
$('#edit-admin, #delete-admin').prop('disabled', true);
$('#filter-admins .selected-row').removeClass('selected-row');
$('#filter-admins button').prop('disabled', false);
$('#filter-admins .results').css('color', '');
@ -298,7 +298,7 @@ AdminsHelper.prototype.resetForm = function() {
/**
* Display a admin record into the admin form.
*
*
* @param {object} admin Contains the admin record data.
*/
AdminsHelper.prototype.display = function(admin) {
@ -313,7 +313,7 @@ AdminsHelper.prototype.display = function(admin) {
$('#admin-state').val(admin.state);
$('#admin-zip-code').val(admin.zip_code);
$('#admin-notes').val(admin.notes);
$('#admin-username').val(admin.settings.username);
if (admin.settings.notifications == true) {
$('#admin-notifications').addClass('active');
@ -324,31 +324,31 @@ AdminsHelper.prototype.display = function(admin) {
/**
* Filters admin records depending a key string.
*
*
* @param {string} key This string is used to filter the admin records of the database.
* @param {numeric} selectId (OPTIONAL = undefined) This record id will be selected when
* @param {numeric} selectId (OPTIONAL = undefined) This record id will be selected when
* the filter operation is finished.
* @param {bool} display (OPTIONAL = false) If true the selected record data are going
* to be displayed on the details column (requires a selected record though).
*/
AdminsHelper.prototype.filter = function(key, selectId, display) {
if (display == undefined) display = false;
var postUrl = GlobalVariables.baseUrl + '/index.php/backend_api/ajax_filter_admins';
var postData = {
var postData = {
'csrfToken': GlobalVariables.csrfToken,
'key': key
'key': key
};
$.post(postUrl, postData, function(response) {
///////////////////////////////////////////////////
//console.log('Filter admins response:', response);
///////////////////////////////////////////////////
if (!GeneralFunctions.handleAjaxExceptions(response)) return;
BackendUsers.helper.filterResults = response;
$('#filter-admins .results').data('jsp').destroy();
$('#filter-admins .results').html('');
$.each(response, function(index, admin) {
@ -356,61 +356,61 @@ AdminsHelper.prototype.filter = function(key, selectId, display) {
$('#filter-admins .results').append(html);
});
$('#filter-admins .results').jScrollPane({ mouseWheelSpeed: 70 });
if (response.length == 0) {
$('#filter-admins .results').html('<em>' + EALang['no_records_found'] + '</em>')
}
if (selectId != undefined) {
BackendUsers.helper.select(selectId, display);
}
}, 'json');
}, 'json').fail(GeneralFunctions.ajaxFailureHandler);
};
/**
* Get an admin row html code that is going to be displayed on the filter results list.
*
*
* @param {object} admin Contains the admin record data.
* @returns {string} The html code that represents the record on the filter results list.
*/
AdminsHelper.prototype.getFilterHtml = function(admin) {
var name = admin.first_name + ' ' + admin.last_name;
var info = admin.email;
info = (admin.mobile_number != '' && admin.mobile_number != null)
info = (admin.mobile_number != '' && admin.mobile_number != null)
? info + ', ' + admin.mobile_number : info;
info = (admin.phone_number != '' && admin.phone_number != null)
info = (admin.phone_number != '' && admin.phone_number != null)
? info + ', ' + admin.phone_number : info;
var html =
'<div class="admin-row" data-id="' + admin.id + '">' +
'<div class="admin-row" data-id="' + admin.id + '">' +
'<strong>' + name + '</strong><br>' +
info + '<br>' +
info + '<br>' +
'</div><hr>';
return html;
};
/**
* Select a specific record from the current filter results. If the admin id does not exist
* in the list then no record will be selected.
*
* Select a specific record from the current filter results. If the admin 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.
*/
AdminsHelper.prototype.select = function(id, display) {
if (display == undefined) display = false;
$('#filter-admins .selected-row').removeClass('selected-row');
$('.admin-row').each(function() {
if ($(this).attr('data-id') == id) {
$(this).addClass('selected-row');
return false;
}
});
if (display) {
if (display) {
$.each(BackendUsers.helper.filterResults, function(index, admin) {
if (admin.id == id) {
BackendUsers.helper.display(admin);

View file

@ -1,19 +1,19 @@
/* ----------------------------------------------------------------------------
* Easy!Appointments - Open Source Web Scheduler
*
*
* @package EasyAppointments
* @author A.Tselegidis <alextselegidis@gmail.com>
* @copyright Copyright (c) 2013 - 2015, Alex Tselegidis
* @license http://opensource.org/licenses/GPL-3.0 - GPLv3
* @license http://opensource.org/licenses/GPL-3.0 - GPLv3
* @link http://easyappointments.org
* @since v1.0.0
* ---------------------------------------------------------------------------- */
/**
* This class contains the Providers helper class declaration, along with the "Providers" tab
* This class contains the Providers helper class declaration, along with the "Providers" tab
* event handlers. By deviding the backend/users tab functionality into separate files
* it is easier to maintain the code.
*
*
* @class ProvidersHelper
*/
var ProvidersHelper = function() {
@ -26,7 +26,7 @@ var ProvidersHelper = function() {
ProvidersHelper.prototype.bindEventHandlers = function() {
/**
* Event: Filter Providers Form "Submit"
*
*
* Filter the provider records with the given key string.
*/
$('#filter-providers form').submit(function(event) {
@ -47,7 +47,7 @@ ProvidersHelper.prototype.bindEventHandlers = function() {
/**
* Event: Filter Provider Row "Click"
*
*
* Display the selected provider data to the user.
*/
$(document).on('click', '.provider-row', function() {
@ -55,7 +55,7 @@ ProvidersHelper.prototype.bindEventHandlers = function() {
$('#filter-providers .results').css('color', '#AAA');
return; // Exit because we are currently on edit mode.
}
var providerId = $(this).attr('data-id');
var provider = {};
$.each(BackendUsers.helper.filterResults, function(index, item) {
@ -64,7 +64,7 @@ ProvidersHelper.prototype.bindEventHandlers = function() {
return false;
}
});
BackendUsers.helper.display(provider);
$('#filter-providers .selected-row').removeClass('selected-row');
$(this).addClass('selected-row');
@ -124,7 +124,7 @@ ProvidersHelper.prototype.bindEventHandlers = function() {
$('#message_box').dialog('close');
};
GeneralFunctions.displayMessageBox(EALang['delete_provider'],
GeneralFunctions.displayMessageBox(EALang['delete_provider'],
EALang['delete_record_prompt'], messageBtns);
});
@ -144,7 +144,7 @@ ProvidersHelper.prototype.bindEventHandlers = function() {
'zip_code': $('#provider-zip-code').val(),
'notes': $('#provider-notes').val(),
'settings': {
'username': $('#provider-username').val(),
'username': $('#provider-username').val(),
'working_plan': JSON.stringify(BackendUsers.wp.get()),
'notifications': $('#provider-notifications').hasClass('active')
}
@ -175,7 +175,7 @@ ProvidersHelper.prototype.bindEventHandlers = function() {
/**
* Event: Cancel Provider Button "Click"
*
*
* Cancel add or edit of an provider record.
*/
$('#cancel-provider').click(function() {
@ -207,7 +207,7 @@ ProvidersHelper.prototype.bindEventHandlers = function() {
$('.working-plan-view').show('fade');
});
});
/**
* Event: Reset Working Plan Button "Click".
*/
@ -221,7 +221,7 @@ ProvidersHelper.prototype.bindEventHandlers = function() {
/**
* Save provider record to database.
*
*
* @param {object} provider Contains the admin record data. If an 'id' value is provided
* then the update operation is going to be executed.
*/
@ -229,13 +229,13 @@ ProvidersHelper.prototype.save = function(provider) {
//////////////////////////////////////////////////
//console.log('Provider data to save:', provider);
//////////////////////////////////////////////////
var postUrl = GlobalVariables.baseUrl + '/index.php/backend_api/ajax_save_provider';
var postData = {
var postData = {
'csrfToken': GlobalVariables.csrfToken,
'provider': JSON.stringify(provider)
'provider': JSON.stringify(provider)
};
$.post(postUrl, postData, function(response) {
///////////////////////////////////////////////////
//console.log('Save Provider Response:', response);
@ -244,22 +244,22 @@ ProvidersHelper.prototype.save = function(provider) {
Backend.displayNotification(EALang['provider_saved']);
BackendUsers.helper.resetForm();
$('#filter-providers .key').val('');
BackendUsers.helper.filter('', response.id, true);
}, 'json');
BackendUsers.helper.filter('', response.id, true);
}, 'json').fail(GeneralFunctions.ajaxFailureHandler);
};
/**
* Delete a provider record from database.
*
* @param {numeric} id Record id to be deleted.
*
* @param {numeric} id Record id to be deleted.
*/
ProvidersHelper.prototype.delete = function(id) {
var postUrl = GlobalVariables.baseUrl + '/index.php/backend_api/ajax_delete_provider';
var postData = {
var postData = {
'csrfToken': GlobalVariables.csrfToken,
'provider_id': id
'provider_id': id
};
$.post(postUrl, postData, function(response) {
/////////////////////////////////////////////////////
//console.log('Delete provider response:', response);
@ -268,19 +268,19 @@ ProvidersHelper.prototype.delete = function(id) {
Backend.displayNotification(EALang['provider_deleted']);
BackendUsers.helper.resetForm();
BackendUsers.helper.filter($('#filter-providers .key').val());
}, 'json');
}, 'json').fail(GeneralFunctions.ajaxFailureHandler);
};
/**
* Validates a provider record.
*
*
* @param {object} provider Contains the admin data to be validated.
* @returns {bool} Returns the validation result.
*/
ProvidersHelper.prototype.validate = function(provider) {
$('#providers .required').css('border', '');
$('#provider-password, #provider-password-confirm').css('border', '');
try {
// Validate required fields.
var missingRequired = false;
@ -293,31 +293,31 @@ ProvidersHelper.prototype.validate = function(provider) {
if (missingRequired) {
throw EALang['fields_are_required'];
}
// Validate passwords.
if ($('#provider-password').val() != $('#provider-password-confirm').val()) {
$('#provider-password, #provider-password-confirm').css('border', '2px solid red');
throw EALang['passwords_mismatch'];
}
if ($('#provider-password').val().length < BackendUsers.MIN_PASSWORD_LENGTH
&& $('#provider-password').val() != '') {
$('#provider-password, #provider-password-confirm').css('border', '2px solid red');
throw EALang['password_length_notice'].replace('$number', BackendUsers.MIN_PASSWORD_LENGTH);
}
// Validate user email.
if (!GeneralFunctions.validateEmail($('#provider-email').val())) {
$('#provider-email').css('border', '2px solid red');
throw EALang['invalid_email'];
}
// Check if username exists
if ($('#provider-username').attr('already-exists') == 'true') {
$('#provider-username').css('border', '2px solid red');
throw EALang['username_already_exists'];
}
}
return true;
} catch(exc) {
$('#providers .form-message').text(exc);
@ -327,17 +327,17 @@ ProvidersHelper.prototype.validate = function(provider) {
};
/**
* Resets the admin tab form back to its initial state.
* Resets the admin tab form back to its initial state.
*/
ProvidersHelper.prototype.resetForm = function() {
$('#filter-providers .selected-row').removeClass('selected-row');
$('#filter-providers button').prop('disabled', false);
$('#filter-providers .results').css('color', '');
$('#providers .add-edit-delete-group').show();
$('#providers .save-cancel-group').hide();
$('#providers .details').find('input, textarea').prop('readonly', true);
$('#providers .form-message').hide();
$('#providers .form-message').hide();
$('#provider-notifications').removeClass('active');
$('#provider-notifications').prop('disabled', true);
$('#provider-services input[type="checkbox"]').prop('disabled', true);
@ -359,7 +359,7 @@ ProvidersHelper.prototype.resetForm = function() {
/**
* Display a provider record into the admin form.
*
*
* @param {object} provider Contains the provider record data.
*/
ProvidersHelper.prototype.display = function(provider) {
@ -374,14 +374,14 @@ ProvidersHelper.prototype.display = function(provider) {
$('#provider-state').val(provider.state);
$('#provider-zip-code').val(provider.zip_code);
$('#provider-notes').val(provider.notes);
$('#provider-username').val(provider.settings.username);
if (provider.settings.notifications == true) {
$('#provider-notifications').addClass('active');
} else {
$('#provider-notifications').removeClass('active');
}
$('#provider-services input[type="checkbox"]').prop('checked', false);
$.each(provider.services, function(index, serviceId) {
$('#provider-services input[type="checkbox"]').each(function() {
@ -390,7 +390,7 @@ ProvidersHelper.prototype.display = function(provider) {
}
});
});
// Display working plan
$('#providers .breaks tbody').empty();
var workingPlan = $.parseJSON(provider.settings.working_plan);
@ -400,32 +400,32 @@ ProvidersHelper.prototype.display = function(provider) {
/**
* Filters provider records depending a string key.
*
*
* @param {string} key This is used to filter the provider records of the database.
* @param {numeric} selectId (OPTIONAL = undefined) If set, when the function is complete
* a result row can be set as selected.
* @param {bool} display (OPTIONAL = false) If true then the selected record will be also
* a result row can be set as selected.
* @param {bool} display (OPTIONAL = false) If true then the selected record will be also
* displayed.
*/
ProvidersHelper.prototype.filter = function(key, selectId, display) {
if (display == undefined) display = false;
var postUrl = GlobalVariables.baseUrl + '/index.php/backend_api/ajax_filter_providers';
var postData = {
var postData = {
'csrfToken': GlobalVariables.csrfToken,
'key': key
'key': key
};
$.post(postUrl, postData, function(response) {
//////////////////////////////////////////////////////
//console.log('Filter providers response:', response);
//////////////////////////////////////////////////////
if (!GeneralFunctions.handleAjaxExceptions(response)) return;
BackendUsers.helper.filterResults = response;
$('#filter-providers .results').data('jsp').destroy;
$('#filter-providers .results').html('');
$.each(response, function(index, provider) {
@ -433,20 +433,20 @@ ProvidersHelper.prototype.filter = function(key, selectId, display) {
$('#filter-providers .results').append(html);
});
$('#filter-providers .results').jScrollPane({ mouseWheelSpeed: 70 });
if (response.length == 0) {
$('#filter-providers .results').html('<em>' + EALang['no_records_found'] + '</em>')
}
if (selectId != undefined) {
BackendUsers.helper.select(selectId, display);
}
}, 'json');
}, 'json').fail(GeneralFunctions.ajaxFailureHandler);
};
/**
* Get an provider row html code that is going to be displayed on the filter results list.
*
*
* @param {object} provider Contains the provider record data.
* @returns {string} The html code that represents the record on the filter results list.
*/
@ -456,12 +456,12 @@ ProvidersHelper.prototype.getFilterHtml = function(provider) {
info = (provider.mobile_number != '' && provider.mobile_number != null)
? info + ', ' + provider.mobile_number : info;
info = (provider.phone_number != '' && provider.phone_number != null)
? info + ', ' + provider.phone_number : info;
? info + ', ' + provider.phone_number : info;
var html =
'<div class="provider-row" data-id="' + provider.id + '">' +
'<div class="provider-row" data-id="' + provider.id + '">' +
'<strong>' + name + '</strong><br>' +
info + '<br>' +
info + '<br>' +
'</div><hr>';
return html;
@ -469,7 +469,7 @@ ProvidersHelper.prototype.getFilterHtml = function(provider) {
/**
* Initialize the editable functionality to the break day table cells.
*
*
* @param {object} $selector The cells to be initialized.
*/
ProvidersHelper.prototype.editableBreakDay = function($selector) {
@ -507,9 +507,9 @@ ProvidersHelper.prototype.editableBreakDay = function($selector) {
/**
* Initialize the editable functionality to the break time table cells.
*
*
* @param {object} $selector The cells to be initialized.
*/
*/
ProvidersHelper.prototype.editableBreakTime = function($selector) {
$selector.editable(function(value, settings) {
// Do not return the value because the user needs to press the "Save" button.
@ -531,13 +531,13 @@ ProvidersHelper.prototype.editableBreakTime = function($selector) {
/**
* Select and display a providers filter result on the form.
*
*
* @param {numeric} id Record id to be selected.
* @param {bool} display (OPTIONAL = false) If true the record will be displayed on the form.
*/
ProvidersHelper.prototype.select = function(id, display) {
if (display == undefined) display = false;
// Select record in filter results.
$('#filter-providers .provider-row').each(function() {
if ($(this).attr('data-id') == id) {
@ -545,7 +545,7 @@ ProvidersHelper.prototype.select = function(id, display) {
return false;
}
});
// Display record in form (if display = true).
if (display) {
$.each(BackendUsers.helper.filterResults, function(index, provider) {
@ -556,4 +556,4 @@ ProvidersHelper.prototype.select = function(id, display) {
}
});
}
};
};

View file

@ -1,19 +1,19 @@
/* ----------------------------------------------------------------------------
* Easy!Appointments - Open Source Web Scheduler
*
*
* @package EasyAppointments
* @author A.Tselegidis <alextselegidis@gmail.com>
* @copyright Copyright (c) 2013 - 2015, Alex Tselegidis
* @license http://opensource.org/licenses/GPL-3.0 - GPLv3
* @license http://opensource.org/licenses/GPL-3.0 - GPLv3
* @link http://easyappointments.org
* @since v1.0.0
* ---------------------------------------------------------------------------- */
/**
* This class contains the Secretaries helper class declaration, along with the "Secretaries"
* This class contains the Secretaries helper class declaration, along with the "Secretaries"
* tab event handlers. By deviding the backend/users tab functionality into separate files
* it is easier to maintain the code.
*
*
* @class SecretariesHelper
*/
var SecretariesHelper = function() {
@ -26,7 +26,7 @@ var SecretariesHelper = function() {
SecretariesHelper.prototype.bindEventHandlers = function() {
/**
* Event: Filter Secretaries Form "Submit"
*
*
* Filter the secretary records with the given key string.
*/
$('#filter-secretaries form').submit(function(event) {
@ -47,7 +47,7 @@ SecretariesHelper.prototype.bindEventHandlers = function() {
/**
* Event: Filter Secretary Row "Click"
*
*
* Display the selected secretary data to the user.
*/
$(document).on('click', '.secretary-row', function() {
@ -56,7 +56,7 @@ SecretariesHelper.prototype.bindEventHandlers = function() {
return; // exit because we are currently on edit mode
}
var secretaryId = $(this).attr('data-id');
var secretaryId = $(this).attr('data-id');
var secretary = {};
$.each(BackendUsers.helper.filterResults, function(index, item) {
if (item.id === secretaryId) {
@ -64,7 +64,7 @@ SecretariesHelper.prototype.bindEventHandlers = function() {
return false;
}
});
BackendUsers.helper.display(secretary);
$('#filter-secretaries .selected-row').removeClass('selected-row');
$(this).addClass('selected-row');
@ -78,7 +78,7 @@ SecretariesHelper.prototype.bindEventHandlers = function() {
BackendUsers.helper.resetForm();
$('#filter-secretaries button').prop('disabled', true);
$('#filter-secretaries .results').css('color', '#AAA');
$('#secretaries .add-edit-delete-group').hide();
$('#secretaries .save-cancel-group').show();
$('#secretaries .details').find('input, textarea').prop('readonly', false);
@ -93,7 +93,7 @@ SecretariesHelper.prototype.bindEventHandlers = function() {
$('#edit-secretary').click(function() {
$('#filter-secretaries button').prop('disabled', true);
$('#filter-secretaries .results').css('color', '#AAA');
$('#secretaries .add-edit-delete-group').hide();
$('#secretaries .save-cancel-group').show();
$('#secretaries .details').find('input, textarea').prop('readonly', false);
@ -117,7 +117,7 @@ SecretariesHelper.prototype.bindEventHandlers = function() {
$('#message_box').dialog('close');
};
GeneralFunctions.displayMessageBox(EALang['delete_secretary'],
GeneralFunctions.displayMessageBox(EALang['delete_secretary'],
EALang['delete_record_prompt'], messageBtns);
});
@ -137,7 +137,7 @@ SecretariesHelper.prototype.bindEventHandlers = function() {
'zip_code': $('#secretary-zip-code').val(),
'notes': $('#secretary-notes').val(),
'settings': {
'username': $('#secretary-username').val(),
'username': $('#secretary-username').val(),
'notifications': $('#secretary-notifications').hasClass('active')
}
};
@ -167,7 +167,7 @@ SecretariesHelper.prototype.bindEventHandlers = function() {
/**
* Event: Cancel Secretary Button "Click"
*
*
* Cancel add or edit of an secretary record.
*/
$('#cancel-secretary').click(function() {
@ -181,7 +181,7 @@ SecretariesHelper.prototype.bindEventHandlers = function() {
/**
* Save secretary record to database.
*
*
* @param {object} secretary Contains the admin record data. If an 'id' value is provided
* then the update operation is going to be executed.
*/
@ -189,13 +189,13 @@ SecretariesHelper.prototype.save = function(secretary) {
////////////////////////////////////////////////////
//console.log('Secretary data to save:', secretary);
////////////////////////////////////////////////////
var postUrl = GlobalVariables.baseUrl + '/index.php/backend_api/ajax_save_secretary';
var postData = {
var postData = {
'csrfToken': GlobalVariables.csrfToken,
'secretary': JSON.stringify(secretary)
'secretary': JSON.stringify(secretary)
};
$.post(postUrl, postData, function(response) {
////////////////////////////////////////////////////
//console.log('Save Secretary Response:', response);
@ -205,21 +205,21 @@ SecretariesHelper.prototype.save = function(secretary) {
BackendUsers.helper.resetForm();
$('#filter-secretaries .key').val('');
BackendUsers.helper.filter('', response.id, true);
}, 'json');
}, 'json').fail(GeneralFunctions.ajaxFailureHandler);
};
/**
* Delete a secretary record from database.
*
* @param {int} id Record id to be deleted.
*
* @param {int} id Record id to be deleted.
*/
SecretariesHelper.prototype.delete = function(id) {
var postUrl = GlobalVariables.baseUrl + '/index.php/backend_api/ajax_delete_secretary';
var postData = {
var postData = {
'csrfToken': GlobalVariables.csrfToken,
'secretary_id': id
'secretary_id': id
};
$.post(postUrl, postData, function(response) {
//////////////////////////////////////////////////////
//console.log('Delete secretary response:', response);
@ -228,19 +228,19 @@ SecretariesHelper.prototype.delete = function(id) {
Backend.displayNotification(EALang['secretary_deleted']);
BackendUsers.helper.resetForm();
BackendUsers.helper.filter($('#filter-secretaries .key').val());
}, 'json');
}, 'json').fail(GeneralFunctions.ajaxFailureHandler);
};
/**
* Validates a secretary record.
*
*
* @param {object} secretary Contains the admin data to be validated.
* @returns {bool} Returns the validation result.
*/
SecretariesHelper.prototype.validate = function(secretary) {
$('#secretaries .required').css('border', '');
$('#secretary-password, #secretary-password-confirm').css('border', '');
try {
// Validate required fields.
var missingRequired = false;
@ -253,32 +253,32 @@ SecretariesHelper.prototype.validate = function(secretary) {
if (missingRequired) {
throw 'Fields with * are required.';
}
// Validate passwords.
if ($('#secretary-password').val() != $('#secretary-password-confirm').val()) {
$('#secretary-password, #secretary-password-confirm').css('border', '2px solid red');
throw 'Passwords mismatch!';
}
if ($('#secretary-password').val().length < BackendUsers.MIN_PASSWORD_LENGTH
&& $('#secretary-password').val() != '') {
$('#secretary-password, #secretary-password-confirm').css('border', '2px solid red');
throw 'Password must be at least ' + BackendUsers.MIN_PASSWORD_LENGTH
throw 'Password must be at least ' + BackendUsers.MIN_PASSWORD_LENGTH
+ ' characters long.';
}
// Validate user email.
if (!GeneralFunctions.validateEmail($('#secretary-email').val())) {
$('#secretary-email').css('border', '2px solid red');
throw 'Invalid email address!';
}
// Check if username exists
if ($('#secretary-username').attr('already-exists') == 'true') {
$('#secretary-username').css('border', '2px solid red');
throw 'Username already exists.';
}
}
return true;
} catch(exc) {
$('#secretaries .form-message').text(exc);
@ -288,7 +288,7 @@ SecretariesHelper.prototype.validate = function(secretary) {
};
/**
* Resets the admin tab form back to its initial state.
* Resets the admin tab form back to its initial state.
*/
SecretariesHelper.prototype.resetForm = function() {
$('#secretaries .details').find('input, textarea').val('');
@ -296,14 +296,14 @@ SecretariesHelper.prototype.resetForm = function() {
$('#secretaries .save-cancel-group').hide();
$('#edit-secretary, #delete-secretary').prop('disabled', true);
$('#secretaries .details').find('input, textarea').prop('readonly', true);
$('#secretaries .form-message').hide();
$('#secretaries .form-message').hide();
$('#secretary-notifications').removeClass('active');
$('#secretary-notifications').prop('disabled', true);
$('#secretary-providers input[type="checkbox"]').prop('checked', false);
$('#secretary-providers input[type="checkbox"]').prop('disabled', true);
$('#secretaries .required').css('border', '');
$('#secretary-password, #secretary-password-confirm').css('border', '');
$('#filter-secretaries .selected-row').removeClass('selected-row');
$('#filter-secretaries button').prop('disabled', false);
$('#filter-secretaries .results').css('color', '');
@ -311,7 +311,7 @@ SecretariesHelper.prototype.resetForm = function() {
/**
* Display a secretary record into the admin form.
*
*
* @param {object} secretary Contains the secretary record data.
*/
SecretariesHelper.prototype.display = function(secretary) {
@ -326,14 +326,14 @@ SecretariesHelper.prototype.display = function(secretary) {
$('#secretary-state').val(secretary.state);
$('#secretary-zip-code').val(secretary.zip_code);
$('#secretary-notes').val(secretary.notes);
$('#secretary-username').val(secretary.settings.username);
if (secretary.settings.notifications == true) {
$('#secretary-notifications').addClass('active');
} else {
$('#secretary-notifications').removeClass('active');
}
$('#secretary-providers input[type="checkbox"]').prop('checked', false);
$.each(secretary.providers, function(index, providerId) {
$('#secretary-providers input[type="checkbox"]').each(function() {
@ -346,30 +346,30 @@ SecretariesHelper.prototype.display = function(secretary) {
/**
* Filters secretary records depending a string key.
*
*
* @param {string} key This is used to filter the secretary records of the database.
* @param {numeric} selectId (OPTIONAL = undefined) If provided then the given id will be
* @param {numeric} selectId (OPTIONAL = undefined) If provided then the given id will be
* selected in the filter results (only selected, not displayed).
* @param {bool} display (OPTIONAL = false)
*/
SecretariesHelper.prototype.filter = function(key, selectId, display) {
if (display == undefined) display = false;
var postUrl = GlobalVariables.baseUrl + '/index.php/backend_api/ajax_filter_secretaries';
var postData = {
var postData = {
'csrfToken': GlobalVariables.csrfToken,
'key': key
'key': key
};
$.post(postUrl, postData, function(response) {
////////////////////////////////////////////////////////
//console.log('Filter secretaries response:', response);
////////////////////////////////////////////////////////
if (!GeneralFunctions.handleAjaxExceptions(response)) return;
BackendUsers.helper.filterResults = response;
$('#filter-secretaries .results').data('jsp').destroy();
$('#filter-secretaries .results').html('');
$.each(response, function(index, secretary) {
@ -377,20 +377,20 @@ SecretariesHelper.prototype.filter = function(key, selectId, display) {
$('#filter-secretaries .results').append(html);
});
$('#filter-secretaries .results').jScrollPane({ mouseWheelSpeed: 70 });
if (response.length == 0) {
$('#filter-secretaries .results').html('<em>' + EALang['no_records_found'] + '</em>')
}
if (selectId != undefined) {
BackendUsers.helper.select(selectId, display);
}
}, 'json');
}, 'json').fail(GeneralFunctions.ajaxFailureHandler);
};
/**
* Get an secretary row html code that is going to be displayed on the filter results list.
*
*
* @param {object} secretary Contains the secretary record data.
* @returns {string} The html code that represents the record on the filter results list.
*/
@ -400,38 +400,38 @@ SecretariesHelper.prototype.getFilterHtml = function(secretary) {
info = (secretary.mobile_number != '' && secretary.mobile_number != null)
? info + ', ' + secretary.mobile_number : info;
info = (secretary.phone_number != '' && secretary.phone_number != null)
? info + ', ' + secretary.phone_number : info;
? info + ', ' + secretary.phone_number : info;
var html =
'<div class="secretary-row" data-id="' + secretary.id + '">' +
'<div class="secretary-row" data-id="' + secretary.id + '">' +
'<strong>' + name + '</strong><br>' +
info + '<br>' +
info + '<br>' +
'</div><hr>';
return html;
};
/**
* Select a specific record from the current filter results. If the secretary id does not exist
* in the list then no record will be selected.
*
* Select a specific record from the current filter results. If the secretary 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.
*/
SecretariesHelper.prototype.select = function(id, display) {
if (display == undefined) display = false;
$('#filter-secretaries .selected-row').removeClass('selected-row');
$('#filter-secretaries .secretary-row').each(function() {
if ($(this).attr('data-id') == id) {
$(this).addClass('selected-row');
return false;
}
});
if (display) {
if (display) {
$.each(BackendUsers.helper.filterResults, function(index, admin) {
if (admin.id == id) {
BackendUsers.helper.display(admin);
@ -440,4 +440,4 @@ SecretariesHelper.prototype.select = function(id, display) {
}
});
}
};
};

View file

@ -1,48 +1,48 @@
/* ----------------------------------------------------------------------------
* Easy!Appointments - Open Source Web Scheduler
*
*
* @package EasyAppointments
* @author A.Tselegidis <alextselegidis@gmail.com>
* @copyright Copyright (c) 2013 - 2015, Alex Tselegidis
* @license http://opensource.org/licenses/GPL-3.0 - GPLv3
* @license http://opensource.org/licenses/GPL-3.0 - GPLv3
* @link http://easyappointments.org
* @since v1.0.0
* ---------------------------------------------------------------------------- */
/**
* This namespace contains functions that implement the book appointment page
* functionality. Once the initialize() method is called the page is fully
* This namespace contains functions that implement the book appointment page
* functionality. Once the initialize() method is called the page is fully
* functional and can serve the appointment booking process.
*
*
* @namespace FrontendBook
*/
var FrontendBook = {
/**
* Determines the functionality of the page.
*
*
* @type {bool}
*/
manageMode: false,
manageMode: false,
/**
* This method initializes the book appointment page.
*
* @param {bool} bindEventHandlers (OPTIONAL) Determines whether the default
*
* @param {bool} bindEventHandlers (OPTIONAL) Determines whether the default
* event handlers will be binded to the dom elements.
* @param {bool} manageMode (OPTIONAL) Determines whether the customer is going
* @param {bool} manageMode (OPTIONAL) Determines whether the customer is going
* to make changes to an existing appointment rather than booking a new one.
*/
initialize: function(bindEventHandlers, manageMode) {
if (bindEventHandlers === undefined) {
bindEventHandlers = true; // Default Value
}
if (manageMode === undefined) {
manageMode = false; // Default Value
}
FrontendBook.manageMode = manageMode;
// Initialize page's components (tooltips, datepickers etc).
$('.book-step').qtip({
position: {
@ -53,20 +53,20 @@ var FrontendBook = {
classes: 'qtip-green qtip-shadow custom-qtip'
}
});
$('#select-date').datepicker({
dateFormat: 'dd-mm-yy',
firstDay: 1, // Monday
minDate: 0,
defaultDate: Date.today(),
dayNames: [EALang['sunday'], EALang['monday'], EALang['tuesday'], EALang['wednesday'], EALang['thursday'], EALang['friday'], EALang['saturday']],
dayNamesShort: [EALang['sunday'].substr(0,3), EALang['monday'].substr(0,3),
EALang['tuesday'].substr(0,3), EALang['wednesday'].substr(0,3),
dayNamesShort: [EALang['sunday'].substr(0,3), EALang['monday'].substr(0,3),
EALang['tuesday'].substr(0,3), EALang['wednesday'].substr(0,3),
EALang['thursday'].substr(0,3), EALang['friday'].substr(0,3),
EALang['saturday'].substr(0,3)],
dayNamesMin: [EALang['sunday'].substr(0,2), EALang['monday'].substr(0,2),
EALang['tuesday'].substr(0,2), EALang['wednesday'].substr(0,2),
dayNamesMin: [EALang['sunday'].substr(0,2), EALang['monday'].substr(0,2),
EALang['tuesday'].substr(0,2), EALang['wednesday'].substr(0,2),
EALang['thursday'].substr(0,2), EALang['friday'].substr(0,2),
EALang['saturday'].substr(0,2)],
monthNames: [EALang['january'], EALang['february'], EALang['march'], EALang['april'],
@ -76,20 +76,20 @@ var FrontendBook = {
nextText: EALang['next'],
currentText: EALang['now'],
closeText: EALang['close'],
onSelect: function(dateText, instance) {
FrontendBook.getAvailableHours(dateText);
FrontendBook.updateConfirmFrame();
}
});
// Bind the event handlers (might not be necessary every time
// we use this class).
if (bindEventHandlers) {
FrontendBook.bindEventHandlers();
}
// If the manage mode is true, the appointments data should be
// loaded by default.
if (FrontendBook.manageMode) {
@ -99,15 +99,15 @@ var FrontendBook = {
$('#select-service').trigger('change'); // Load the available hours.
}
},
/**
* This method binds the necessary event handlers for the book
* This method binds the necessary event handlers for the book
* appointments page.
*/
bindEventHandlers: function() {
/**
* Event: Selected Provider "Changed"
*
*
* Whenever the provider changes the available appointment
* date - time periods must be updated.
*/
@ -115,12 +115,12 @@ var FrontendBook = {
FrontendBook.getAvailableHours(Date.today().toString('dd-MM-yyyy'));
FrontendBook.updateConfirmFrame();
});
/**
* Event: Selected Service "Changed"
*
* When the user clicks on a service, its available providers should
* become visible.
*
* When the user clicks on a service, its available providers should
* become visible.
*/
$('#select-service').change(function() {
var currServiceId = $('#select-service').val();
@ -129,10 +129,10 @@ var FrontendBook = {
$.each(GlobalVariables.availableProviders, function(indexProvider, provider) {
$.each(provider['services'], function(indexService, serviceId) {
// If the current provider is able to provide the selected service,
// add him to the listbox.
if (serviceId == currServiceId) {
var optionHtml = '<option value="' + provider['id'] + '">'
+ provider['first_name'] + ' ' + provider['last_name']
// add him to the listbox.
if (serviceId == currServiceId) {
var optionHtml = '<option value="' + provider['id'] + '">'
+ provider['first_name'] + ' ' + provider['last_name']
+ '</option>';
$('#select-provider').append(optionHtml);
}
@ -143,30 +143,30 @@ var FrontendBook = {
FrontendBook.updateConfirmFrame();
FrontendBook.updateServiceDescription($('#select-service').val(), $('#service-description'));
});
/**
* Event: Next Step Button "Clicked"
*
* This handler is triggered every time the user pressed the
* "next" button on the book wizard. Some special tasks might
*
* This handler is triggered every time the user pressed the
* "next" button on the book wizard. Some special tasks might
* be perfomed, depending the current wizard step.
*/
$('.button-next').click(function() {
// If we are on the 2nd tab then the user should have an appointment hour
// If we are on the 2nd tab then the user should have an appointment hour
// selected.
if ($(this).attr('data-step_index') === '2') {
if ($('.selected-hour').length == 0) {
if ($('#select-hour-prompt').length == 0) {
$('#available-hours').append('<br><br>'
+ '<span id="select-hour-prompt" class="text-danger">'
+ EALang['appointment_hour_missing']
+ EALang['appointment_hour_missing']
+ '</span>');
}
return;
}
}
// If we are on the 3rd tab then we will need to validate the user's
// If we are on the 3rd tab then we will need to validate the user's
// input before proceeding to the next step.
if ($(this).attr('data-step_index') === '3') {
if (!FrontendBook.validateCustomerForm()) {
@ -175,11 +175,11 @@ var FrontendBook = {
FrontendBook.updateConfirmFrame();
}
}
// Display the next step tab (uses jquery animation effect).
var nextTabIndex = parseInt($(this).attr('data-step_index')) + 1;
$(this).parents().eq(1).hide('fade', function() {
$(this).parents().eq(1).hide('fade', function() {
$('.active-step').removeClass('active-step');
$('#step-' + nextTabIndex).addClass('active-step');
$('#wizard-frame-' + nextTabIndex).show('fade');
@ -188,14 +188,14 @@ var FrontendBook = {
/**
* Event: Back Step Button "Clicked"
*
* This handler is triggered every time the user pressed the
*
* This handler is triggered every time the user pressed the
* "back" button on the book wizard.
*/
$('.button-back').click(function() {
var prevTabIndex = parseInt($(this).attr('data-step_index')) - 1;
$(this).parents().eq(1).hide('fade', function() {
$(this).parents().eq(1).hide('fade', function() {
$('.active-step').removeClass('active-step');
$('#step-' + prevTabIndex).addClass('active-step');
$('#wizard-frame-' + prevTabIndex).show('fade');
@ -204,7 +204,7 @@ var FrontendBook = {
/**
* Event: Available Hour "Click"
*
*
* Triggered whenever the user clicks on an available hour
* for his appointment.
*/
@ -213,14 +213,14 @@ var FrontendBook = {
$(this).addClass('selected-hour');
FrontendBook.updateConfirmFrame();
});
if (FrontendBook.manageMode) {
/**
* Event: Cancel Appointment Button "Click"
*
*
* When the user clicks the "Cancel" button this form is going to
* be submitted. We need the user to confirm this action because
* once the appointment is cancelled, it will be delete from the
* once the appointment is cancelled, it will be delete from the
* database.
*/
$('#cancel-appointment').click(function(event) {
@ -233,48 +233,48 @@ var FrontendBook = {
$('#cancel-appointment-form textarea').val($('#cancel-reason').val());
$('#cancel-appointment-form').submit();
};
dialogButtons[EALang['cancel']] = function() {
$('#message_box').dialog('close');
};
GeneralFunctions.displayMessageBox(EALang['cancel_appointment_title'],
GeneralFunctions.displayMessageBox(EALang['cancel_appointment_title'],
EALang['write_appointment_removal_reason'], dialogButtons);
$('#message_box').append('<textarea id="cancel-reason" rows="3"></textarea>');
$('#cancel-reason').css('width', '100%');
return false;
});
}
/**
* Event: Book Appointment Form "Submit"
*
*
* Before the form is submitted to the server we need to make sure that
* in the meantime the selected appointment date/time wasn't reserved by
* another customer or event.
* another customer or event.
*/
$('#book-appointment-submit').click(function(event) {
var formData = jQuery.parseJSON($('input[name="post_data"]').val());
var postData = {
'csrfToken': GlobalVariables.csrfToken,
'id_users_provider': formData['appointment']['id_users_provider'],
'id_services': formData['appointment']['id_services'],
'start_datetime': formData['appointment']['start_datetime'],
};
if (GlobalVariables.manageMode) {
postData.exclude_appointment_id = GlobalVariables.appointmentData.id;
}
var postUrl = GlobalVariables.baseUrl + '/index.php/appointments/ajax_check_datetime_availability';
$.post(postUrl, postData, function(response) {
////////////////////////////////////////////////////////////////////////
console.log('Check Date/Time Availability Post Response :', response);
////////////////////////////////////////////////////////////////////////
if (response.exceptions) {
response.exceptions = GeneralFunctions.parseExceptions(response.exceptions);
GeneralFunctions.displayMessageBox('Unexpected Issues', 'Unfortunately '
@ -282,8 +282,8 @@ var FrontendBook = {
+ 'The following issues occurred:');
$('#message_box').append(GeneralFunctions.exceptionsToHtml(response.exceptions));
return false;
}
}
if (response === true) {
$('#book-appointment-form').submit();
} else {
@ -292,34 +292,37 @@ var FrontendBook = {
+ 'another hour.');
FrontendBook.getAvailableHours($('#select-date').val());
}
}, 'json');
}, 'json').fail(GeneralFunctions.ajaxFailureHandler);
});
},
/**
* This function makes an ajax call and returns the available
* This function makes an ajax call and returns the available
* hours for the selected service, provider and date.
*
*
* @param {string} selDate The selected date of which the available
* hours we need to receive.
*/
getAvailableHours: function(selDate) {
$('#available-hours').empty();
// Find the selected service duration (it is going to
// Find the selected service duration (it is going to
// be send within the "postData" object).
var selServiceDuration = 15; // Default value of duration (in minutes).
$.each(GlobalVariables.availableServices, function(index, service) {
if (service['id'] == $('#select-service').val()) {
selServiceDuration = service['duration'];
selServiceDuration = service['duration'];
}
});
// If the manage mode is true then the appointment's start
// If the manage mode is true then the appointment's start
// date should return as available too.
var appointmentId = (FrontendBook.manageMode)
var appointmentId = (FrontendBook.manageMode)
? GlobalVariables.appointmentData['id'] : undefined;
// Make ajax post request and get the available hours.
var postUrl = GlobalVariables.baseUrl + '/index.php/appointments/ajax_get_available_hours';
var postData = {
'csrfToken': GlobalVariables.csrfToken,
'service_id': $('#select-service').val(),
@ -330,17 +333,15 @@ var FrontendBook = {
'appointment_id': appointmentId
};
// Make ajax post request and get the available hours.
var ajaxurl = GlobalVariables.baseUrl + '/index.php/appointments/ajax_get_available_hours';
$.post(ajaxurl, postData, function(response) {
$.post(postUrl, postData, function(response) {
///////////////////////////////////////////////////////////////
console.log('Get Available Hours JSON Response:', response);
///////////////////////////////////////////////////////////////
if (!GeneralFunctions.handleAjaxExceptions(response)) return;
// The response contains the available hours for the selected provider and
// service. Fill the available hours div with response data.
// service. Fill the available hours div with response data.
if (response.length > 0) {
var currColumn = 1;
$('#available-hours').html('<div style="width:50px; float:left;"></div>');
@ -369,22 +370,22 @@ var FrontendBook = {
}
FrontendBook.updateConfirmFrame();
} else {
$('#available-hours').text(EALang['no_available_hours']);
}
}, 'json');
}, 'json').fail(GeneralFunctions.ajaxFailureHandler);
},
/**
* This function validates the customer's data input. The user cannot contiue
* without passing all the validation checks.
*
*
* @return {bool} Returns the validation result.
*/
validateCustomerForm: function() {
$('#wizard-frame-3 input').css('border', '');
try {
// Validate required fields.
var missingRequiredField = false;
@ -398,14 +399,14 @@ var FrontendBook = {
if (missingRequiredField) {
throw EALang['fields_are_required'];
}
// Validate email address.
if (!GeneralFunctions.validateEmail($('#email').val())) {
$('#email').parents('.form-group').addClass('has-error');
// $('#email').css('border', '2px solid red');
throw EALang['invalid_email'];
}
return true;
} catch(exc) {
$('#form-message').text(exc);
@ -415,7 +416,7 @@ var FrontendBook = {
/**
* Every time this function is executed, it updates the confirmation
* page with the latest customer settigns and input for the appointment
* page with the latest customer settigns and input for the appointment
* booking.
*/
updateConfirmFrame: function() {
@ -436,36 +437,36 @@ var FrontendBook = {
});
$('#appointment-details').html(
'<h4>' + $('#select-service option:selected').text() + '</h4>' +
'<p>'
+ '<strong class="text-primary">'
'<h4>' + $('#select-service option:selected').text() + '</h4>' +
'<p>'
+ '<strong class="text-primary">'
+ $('#select-provider option:selected').text() + '<br>'
+ selectedDate + ' ' + $('.selected-hour').text()
+ selectedDate + ' ' + $('.selected-hour').text()
+ servicePrice + ' ' + serviceCurrency
+ '</strong>' +
+ '</strong>' +
'</p>'
);
// Customer Details
$('#customer-details').html(
'<h4>' + $('#first-name').val() + ' ' + $('#last-name').val() + '</h4>' +
'<p>' +
EALang['phone'] + ': ' + $('#phone-number').val() +
'<br/>' +
EALang['email'] + ': ' + $('#email').val() +
'<br/>' +
EALang['address'] + ': ' + $('#address').val() +
'<br/>' +
EALang['city'] + ': ' + $('#city').val() +
'<br/>' +
EALang['zip_code'] + ': ' + $('#zip-code').val() +
'<h4>' + $('#first-name').val() + ' ' + $('#last-name').val() + '</h4>' +
'<p>' +
EALang['phone'] + ': ' + $('#phone-number').val() +
'<br/>' +
EALang['email'] + ': ' + $('#email').val() +
'<br/>' +
EALang['address'] + ': ' + $('#address').val() +
'<br/>' +
EALang['city'] + ': ' + $('#city').val() +
'<br/>' +
EALang['zip_code'] + ': ' + $('#zip-code').val() +
'</p>'
);
// Update appointment form data for submission to server when the user confirms
// the appointment.
var postData = new Object();
postData['customer'] = {
'last_name': $('#last-name').val(),
'first_name': $('#first-name').val(),
@ -475,9 +476,9 @@ var FrontendBook = {
'city': $('#city').val(),
'zip_code': $('#zip-code').val()
};
postData['appointment'] = {
'start_datetime': $('#select-date').datepicker('getDate').toString('yyyy-MM-dd')
'start_datetime': $('#select-date').datepicker('getDate').toString('yyyy-MM-dd')
+ ' ' + $('.selected-hour').text() + ':00',
'end_datetime': FrontendBook.calcEndDatetime(),
'notes': $('#notes').val(),
@ -485,9 +486,9 @@ var FrontendBook = {
'id_users_provider': $('#select-provider').val(),
'id_services': $('#select-service').val()
};
postData['manage_mode'] = FrontendBook.manageMode;
if (FrontendBook.manageMode) {
postData['appointment']['id'] = GlobalVariables.appointmentData['id'];
postData['customer']['id'] = GlobalVariables.customerData['id'];
@ -495,43 +496,43 @@ var FrontendBook = {
$('input[name="csrfToken"]').val(GlobalVariables.csrfToken);
$('input[name="post_data"]').val(JSON.stringify(postData));
},
/**
* This method calculates the end datetime of the current appointment.
/**
* This method calculates the end datetime of the current appointment.
* End datetime is depending on the service and start datetime fieldss.
*
*
* @return {string} Returns the end datetime in string format.
*/
calcEndDatetime: function() {
// Find selected service duration.
// Find selected service duration.
var selServiceDuration = undefined;
$.each(GlobalVariables.availableServices, function(index, service) {
if (service.id == $('#select-service').val()) {
selServiceDuration = service.duration;
return false; // Stop searching ...
return false; // Stop searching ...
}
});
// Add the duration to the start datetime.
var startDatetime = $('#select-date').datepicker('getDate').toString('dd-MM-yyyy')
var startDatetime = $('#select-date').datepicker('getDate').toString('dd-MM-yyyy')
+ ' ' + $('.selected-hour').text();
startDatetime = Date.parseExact(startDatetime, 'dd-MM-yyyy HH:mm');
var endDatetime = undefined;
if (selServiceDuration !== undefined && startDatetime !== null) {
endDatetime = startDatetime.add({ 'minutes' : parseInt(selServiceDuration) });
} else {
endDatetime = new Date();
}
return endDatetime.toString('yyyy-MM-dd HH:mm:ss');
},
/**
* This method applies the appointment's data to the wizard so
* This method applies the appointment's data to the wizard so
* that the user can start making changes on an existing record.
*
*
* @param {object} appointment Selected appointment's data.
* @param {object} provider Selected provider's data.
* @param {object} customer Selected customer's data.
@ -542,12 +543,12 @@ var FrontendBook = {
// Select Service & Provider
$('#select-service').val(appointment['id_services']).trigger('change');
$('#select-provider').val(appointment['id_users_provider']);
// Set Appointment Date
$('#select-date').datepicker('setDate',
$('#select-date').datepicker('setDate',
Date.parseExact(appointment['start_datetime'], 'yyyy-MM-dd HH:mm:ss'));
FrontendBook.getAvailableHours($('#select-date').val());
// Apply Customer's Data
$('#last-name').val(customer['last_name']);
$('#first-name').val(customer['first_name']);
@ -556,62 +557,62 @@ var FrontendBook = {
$('#address').val(customer['address']);
$('#city').val(customer['city']);
$('#zip-code').val(customer['zip_code']);
var appointmentNotes = (appointment['notes'] !== null)
var appointmentNotes = (appointment['notes'] !== null)
? appointment['notes'] : '';
$('#notes').val(appointmentNotes);
FrontendBook.updateConfirmFrame();
return true;
} catch(exc) {
console.log(exc); // log exception
return false;
}
},
/**
* This method updates a div's html content with a brief description of the
* user selected service (only if available in db). This is usefull for the
* This method updates a div's html content with a brief description of the
* user selected service (only if available in db). This is usefull for the
* customers upon selecting the correct service.
*
*
* @param {int} serviceId The selected service record id.
* @param {object} $div The destination div jquery object (e.g. provide $('#div-id')
* @param {object} $div The destination div jquery object (e.g. provide $('#div-id')
* object as value).
*/
updateServiceDescription: function(serviceId, $div) {
var html = '';
var html = '';
$.each(GlobalVariables.availableServices, function(index, service) {
if (service.id == serviceId) { // Just found the service.
html = '<strong>' + service.name + ' </strong>';
if (service.description != '' && service.description != null) {
html += '<br>' + service.description + '<br>';
}
if (service.duration != '' && service.duration != null) {
html += '[' + EALang['duration'] + ' ' + service.duration
html += '[' + EALang['duration'] + ' ' + service.duration
+ ' ' + EALang['minutes'] + '] ';
}
if (service.price != '' && service.price != null) {
html += '[' + EALang['price'] + ' ' + service.price + ' ' + service.currency + ']';
}
}
html += '<br>';
return false;
}
});
$div.html(html);
if (html != '') {
$div.show();
} else {
$div.hide();
}
}
};
};

View file

@ -331,7 +331,27 @@ var GeneralFunctions = {
if (!GeneralFunctions.handleAjaxExceptions(response)) return;
document.location.reload(true);
}, 'json');
}, 'json').fail(GeneralFunctions.ajaxFailureHandler);
});
},
/**
* Use this method for common error handling between
*
* @param {object} jqxhr
* @param {string} textStatus
* @param {object} errorThrown
*/
ajaxFailureHandler: function(jqxhr, textStatus, errorThrown) {
var exceptions = [
{
message: 'AJAX Error: ' + textStatus
}
];
console.log('AJAX Failure Handler:', jqxhr, textStatus, errorThrown);
GeneralFunctions.displayMessageBox(GeneralFunctions.EXCEPTIONS_TITLE,
GeneralFunctions.EXCEPTIONS_MESSAGE);
$('#message_box').append(GeneralFunctions.exceptionsToHtml(exceptions));
}
};