diff --git a/src/assets/js/backend_calendar.js b/src/assets/js/backend_calendar.js
index b711e911..8a685ce2 100644
--- a/src/assets/js/backend_calendar.js
+++ b/src/assets/js/backend_calendar.js
@@ -22,932 +22,6 @@ window.BackendCalendar = window.BackendCalendar || {};
'use strict';
- // Variables
- var lastFocusedEventData; // Contains event data for later use.
-
- /**
- * Bind Event Handlers
- *
- * This method binds the default event handlers for the backend calendar page. If you do not need the
- * default handlers then initialize the page by setting the "defaultEventHandlers" argument to "false".
- */
- function _bindEventHandlers() {
-
- var $calendarPage = $('#calendar-page');
-
- /**
- * Event: Reload Button "Click"
- *
- * When the user clicks the reload button an the calendar items need to be refreshed.
- */
- $('#reload-appointments').click(function() {
- $('#select-filter-item').trigger('change');
- });
-
- /**
- * Event: Popover Close Button "Click"
- *
- * Hides the open popover element.
- */
- $calendarPage.on('click', '.close-popover', function() {
- $(this).parents().eq(2).remove();
- });
-
- /**
- * Event: Popover Edit Button "Click"
- *
- * Enables the edit dialog of the selected calendar event.
- */
- $calendarPage.on('click', '.edit-popover', function() {
- $(this).parents().eq(2).remove(); // Hide the popover
-
- var $dialog;
-
- if (lastFocusedEventData.data.is_unavailable == false) {
- var appointment = lastFocusedEventData.data;
- $dialog = $('#manage-appointment');
-
- _resetAppointmentDialog();
-
- // Apply appointment data and show modal dialog.
- $dialog.find('.modal-header h3').text(EALang['edit_appointment_title']);
- $dialog.find('#appointment-id').val(appointment['id']);
- $dialog.find('#select-service').val(appointment['id_services']).trigger('change');
- $dialog.find('#select-provider').val(appointment['id_users_provider']);
-
- // Set the start and end datetime of the appointment.
- var startDatetime = Date.parseExact(appointment['start_datetime'],
- 'yyyy-MM-dd HH:mm:ss');
- $dialog.find('#start-datetime').datetimepicker('setDate', startDatetime);
-
- var endDatetime = Date.parseExact(appointment['end_datetime'],
- 'yyyy-MM-dd HH:mm:ss');
- $dialog.find('#end-datetime').datetimepicker('setDate', endDatetime);
-
- var customer = appointment['customer'];
- $dialog.find('#customer-id').val(appointment['id_users_customer']);
- $dialog.find('#first-name').val(customer['first_name']);
- $dialog.find('#last-name').val(customer['last_name']);
- $dialog.find('#email').val(customer['email']);
- $dialog.find('#phone-number').val(customer['phone_number']);
- $dialog.find('#address').val(customer['address']);
- $dialog.find('#city').val(customer['city']);
- $dialog.find('#zip-code').val(customer['zip_code']);
- $dialog.find('#appointment-notes').val(appointment['notes']);
- $dialog.find('#customer-notes').val(customer['notes']);
- } else {
- var unavailable = lastFocusedEventData.data;
-
- // Replace string date values with actual date objects.
- unavailable.start_datetime = GeneralFunctions.clone(lastFocusedEventData.start);
- unavailable.end_datetime = GeneralFunctions.clone(lastFocusedEventData.end);
-
- $dialog = $('#manage-unavailable');
- _resetUnavailableDialog();
-
- // Apply unvailable data to dialog.
- $dialog.find('.modal-header h3').text('Edit Unavailable Period');
- $dialog.find('#unavailable-start').datetimepicker('setDate', unavailable.start_datetime);
- $dialog.find('#unavailable-id').val(unavailable.id);
- $dialog.find('#unavailable-end').datetimepicker('setDate', unavailable.end_datetime);
- $dialog.find('#unavailable-notes').val(unavailable.notes);
- }
-
- // :: DISPLAY EDIT DIALOG
- $dialog.modal('show');
- });
-
- /**
- * Event: Popover Delete Button "Click"
- *
- * Displays a prompt on whether the user wants the appoinmtent to be deleted. If he confirms the
- * deletion then an ajax call is made to the server and deletes the appointment from the database.
- */
- $calendarPage.on('click', '.delete-popover', function() {
- $(this).parents().eq(2).remove(); // Hide the popover
-
- if (lastFocusedEventData.data.is_unavailable == false) {
- var messageButtons = {};
- messageButtons['OK'] = function() {
- var postUrl = GlobalVariables.baseUrl + '/index.php/backend_api/ajax_delete_appointment';
-
- var postData = {
- 'csrfToken': GlobalVariables.csrfToken,
- 'appointment_id' : lastFocusedEventData.data['id'],
- 'delete_reason': $('#delete-reason').val()
- };
-
- $.post(postUrl, postData, function(response) {
- $('#message_box').dialog('close');
-
- if (response.exceptions) {
- response.exceptions = GeneralFunctions.parseExceptions(response.exceptions);
- GeneralFunctions.displayMessageBox(GeneralFunctions.EXCEPTIONS_TITLE,
- GeneralFunctions.EXCEPTIONS_MESSAGE);
- $('#message_box').append(GeneralFunctions.exceptionsToHtml(response.exceptions));
- return;
- }
-
- if (response.warnings) {
- response.warnings = GeneralFunctions.parseExceptions(response.warnings);
- GeneralFunctions.displayMessageBox(GeneralFunctions.WARNINGS_TITLE,
- GeneralFunctions.WARNINGS_MESSAGE);
- $('#message_box').append(GeneralFunctions.exceptionsToHtml(response.warnings));
- }
-
- // Refresh calendar event items.
- $('#select-filter-item').trigger('change');
- }, 'json').fail(GeneralFunctions.ajaxFailureHandler);
- };
-
- messageButtons[EALang['cancel']] = function() {
- $('#message_box').dialog('close');
- };
-
- GeneralFunctions.displayMessageBox(EALang['delete_appointment_title'],
- EALang['write_appointment_removal_reason'], messageButtons);
-
- $('#message_box').append('');
- $('#delete-reason').css('width', '100%');
- } else {
- // Do not display confirmation promt.
- var postUrl = GlobalVariables.baseUrl + '/index.php/backend_api/ajax_delete_unavailable';
- var postData = {
- csrfToken: GlobalVariables.csrfToken,
- unavailable_id : lastFocusedEventData.data.id
- };
-
- $.post(postUrl, postData, function(response) {
- $('#message_box').dialog('close');
-
- if (response.exceptions) {
- response.exceptions = GeneralFunctions.parseExceptions(response.exceptions);
- GeneralFunctions.displayMessageBox(GeneralFunctions.EXCEPTIONS_TITLE, GeneralFunctions.EXCEPTIONS_MESSAGE);
- $('#message_box').append(GeneralFunctions.exceptionsToHtml(response.exceptions));
- return;
- }
-
- if (response.warnings) {
- response.warnings = GeneralFunctions.parseExceptions(response.warnings);
- GeneralFunctions.displayMessageBox(GeneralFunctions.WARNINGS_TITLE, GeneralFunctions.WARNINGS_MESSAGE);
- $('#message_box').append(GeneralFunctions.exceptionsToHtml(response.warnings));
- }
-
- // Refresh calendar event items.
- $('#select-filter-item').trigger('change');
- }, 'json').fail(GeneralFunctions.ajaxFailureHandler);
- }
- });
-
- /**
- * Event: Manage Appointments Dialog Cancel Button "Click"
- *
- * Closes the dialog without saving any changes to the database.
- */
- $('#manage-appointment #cancel-appointment').click(function() {
- $('#manage-appointment').modal('hide');
- });
-
- /**
- * Event: Manage Appointments Dialog Save Button "Click"
- *
- * Stores the appointment changes or inserts a new appointment depending the dialog mode.
- */
- $('#manage-appointment #save-appointment').click(function() {
- // Before doing anything the appointment data need to be validated.
- if (!_validateAppointmentForm()) {
- return;
- }
-
- // Prepare appointment data for AJAX request.
- var $dialog = $('#manage-appointment');
-
- // ID must exist on the object in order for the model to update the record and not to perform
- // an insert operation.
-
- var startDatetime = $dialog.find('#start-datetime')
- .datepicker('getDate').toString('yyyy-MM-dd HH:mm:ss');
- var endDatetime = $dialog.find('#end-datetime')
- .datepicker('getDate').toString('yyyy-MM-dd HH:mm:ss');
-
- var appointment = {
- id_services: $dialog.find('#select-service').val(),
- id_users_provider: $dialog.find('#select-provider').val(),
- start_datetime: startDatetime,
- end_datetime: endDatetime,
- notes: $dialog.find('#appointment-notes').val(),
- is_unavailable: false
- };
-
- if ($dialog.find('#appointment-id').val() !== '') {
- // Set the id value, only if we are editing an appointment.
- appointment['id'] = $dialog.find('#appointment-id').val();
- }
-
- var customer = {
- first_name: $dialog.find('#first-name').val(),
- last_name: $dialog.find('#last-name').val(),
- email: $dialog.find('#email').val(),
- phone_number: $dialog.find('#phone-number').val(),
- address: $dialog.find('#address').val(),
- city: $dialog.find('#city').val(),
- zip_code: $dialog.find('#zip-code').val(),
- notes: $dialog.find('#customer-notes').val()
- };
-
- if ($dialog.find('#customer-id').val() !== '') {
- // Set the id value, only if we are editing an appointment.
- customer['id'] = $dialog.find('#customer-id').val();
- appointment['id_users_customer'] = customer['id'];
- }
-
- // Define success callback.
- var successCallback = function(response) {
- if (!GeneralFunctions.handleAjaxExceptions(response)) {
- $dialog.find('.modal-message').text(EALang['unexpected_issues_occurred']);
- $dialog.find('.modal-message').addClass('alert-danger').removeClass('hidden');
- return false;
- }
-
- // Display success message to the user.
- $dialog.find('.modal-message').text(EALang['appointment_saved']);
- $dialog.find('.modal-message').addClass('alert-success').removeClass('alert-danger hidden');
- $dialog.find('.modal-body').scrollTop(0);
-
- // Close the modal dialog and refresh the calendar appointments after one second.
- setTimeout(function() {
- $dialog.find('.alert').addClass('hidden');
- $dialog.modal('hide');
- $('#select-filter-item').trigger('change');
- }, 2000);
- };
-
- // Define error callback.
- var errorCallback = function() {
- $dialog.find('.modal-message').text(EALang['server_communication_error']);
- $dialog.find('.modal-message').addClass('alert-danger').removeClass('hidden');
- $dialog.find('.modal-body').scrollTop(0);
- };
-
- // Save appointment data.
- _saveAppointment(appointment, customer, successCallback, errorCallback);
- });
-
- /**
- * Event: Manage Unavailable Dialog Save Button "Click"
- *
- * Stores the unavailable period changes or inserts a new record.
- */
- $('#manage-unavailable #save-unavailable').click(function() {
- var $dialog = $('#manage-unavailable');
- var start = $dialog.find('#unavailable-start').datetimepicker('getDate');
- var end = $dialog.find('#unavailable-end').datetimepicker('getDate');
-
- if (start > end) {
- // Start time is after end time - display message to user.
- $dialog.find('.modal-message')
- .text(EALang['start_date_before_end_error'])
- .addClass('alert-danger')
- .removeClass('hidden');
- return;
- }
-
- // Unavailable period records go to the appointments table.
- var unavailable = {
- start_datetime: start.toString('yyyy-MM-dd HH:mm'),
- end_datetime: end.toString('yyyy-MM-dd HH:mm'),
- notes: $dialog.find('#unavailable-notes').val(),
- id_users_provider: $('#select-filter-item').val() // curr provider
- };
-
- if ($dialog.find('#unavailable-id').val() !== '') {
- // Set the id value, only if we are editing an appointment.
- unavailable.id = $dialog.find('#unavailable-id').val();
- }
-
- var successCallback = function(response) {
- if (response.exceptions) {
- response.exceptions = GeneralFunctions.parseExceptions(response.exceptions);
- GeneralFunctions.displayMessageBox(GeneralFunctions.EXCEPTIONS_TITLE,
- GeneralFunctions.EXCEPTIONS_MESSAGE);
- $('#message_box').append(GeneralFunctions.exceptionsToHtml(response.exceptions));
-
- $dialog.find('.modal-message')
- .text(EALang['unexpected_issues_occurred'])
- .addClass('alert-danger')
- .removeClass('hidden');
-
- return;
- }
-
- if (response.warnings) {
- response.warnings = GeneralFunctions.parseExceptions(response.warnings);
- GeneralFunctions.displayMessageBox(GeneralFunctions.WARNINGS_TITLE,
- GeneralFunctions.WARNINGS_MESSAGE);
- $('#message_box').append(GeneralFunctions.exceptionsToHtml(response.warnings));
- }
-
- // Display success message to the user.
- $dialog.find('.modal-message')
- .text(EALang['unavailable_saved'])
- .addClass('alert-success')
- .removeClass('alert-danger hidden');
-
- // Close the modal dialog and refresh the calendar appointments after one second.
- setTimeout(function() {
- $dialog.find('.alert').addClass('hidden');
- $dialog.modal('hide');
- $('#select-filter-item').trigger('change');
- }, 2000);
- };
-
- var errorCallback = function(jqXHR, textStatus, errorThrown) {
- GeneralFunctions.displayMessageBox('Communication Error', 'Unfortunately ' +
- 'the operation could not complete due to server communication errors.');
-
- $dialog.find('.modal-message').txt(EALang['service_communication_error']);
- $dialog.find('.modal-message').addClass('alert-danger').removeClass('hidden');
- };
-
- _saveUnavailable(unavailable, successCallback, errorCallback);
- });
-
- /**
- * Event: Manage Unavailable Dialog Cancel Button "Click"
- *
- * Closes the dialog without saveing any changes to the database.
- */
- $('#manage-unavailable #cancel-unavailable').click(function() {
- $('#manage-unavailable').modal('hide');
- });
-
-
-
- /**
- * Event: Insert Appointment Button "Click"
- *
- * When the user presses this button, the manage appointment dialog opens and lets the user to
- * create a new appointment.
- */
- $('#insert-appointment').click(function() {
- _resetAppointmentDialog();
- var $dialog = $('#manage-appointment');
-
- // Set the selected filter item and find the next appointment time as the default modal values.
- if ($('#select-filter-item option:selected').attr('type') == 'provider') {
- var $providerOption = $dialog.find('#select-provider option[value="'
- + $('#select-filter-item').val() + '"]');
- if ($providerOption.length === 0) { // Change the services until you find the correct.
- $.each($dialog.find('#select-service option'), function() {
- $(this).prop('selected', true).parent().change();
- if ($providerOption.length > 0)
- return false;
- });
- }
- $providerOption.prop('selected', true);
- } else {
- $dialog.find('#select-service option[value="'
- + $('#select-filter-item').val() + '"]').prop('selected', true);
- }
-
- var serviceDuration = 0;
- $.each(GlobalVariables.availableServices, function(index, service) {
- if (service['id'] == $dialog.find('#select-service').val()) {
- serviceDuration = service['duration'];
- return false; // exit loop
- }
- });
-
- var start = new Date();
- var currentMin = parseInt(start.toString('mm'));
-
- if (currentMin > 0 && currentMin < 15) {
- start.set({ 'minute': 15 });
- } else if (currentMin > 15 && currentMin < 30) {
- start.set({ 'minute': 30 });
- } else if (currentMin > 30 && currentMin < 45) {
- start.set({ 'minute': 45 });
- } else {
- start.addHours(1).set({ 'minute': 0 });
- }
-
- $dialog.find('#start-datetime').val(GeneralFunctions.formatDate(start, GlobalVariables.dateFormat, true));
- $dialog.find('#end-datetime').val(GeneralFunctions.formatDate(start.addMinutes(serviceDuration),
- GlobalVariables.dateFormat, true));
-
- // Display modal form.
- $dialog.find('.modal-header h3').text(EALang['new_appointment_title']);
- $dialog.modal('show');
- });
-
- /**
- * Event : Insert Unavailable Time Period Button "Click"
- *
- * When the user clicks this button a popup dialog appears and the use can set a time period where
- * he cannot accept any appointments.
- */
- $('#insert-unavailable').click(function() {
- _resetUnavailableDialog();
- var $dialog = $('#manage-unavailable');
-
- // Set the default datetime values.
- var start = new Date();
- var currentMin = parseInt(start.toString('mm'));
-
- if (currentMin > 0 && currentMin < 15) {
- start.set({ 'minute': 15 });
- } else if (currentMin > 15 && currentMin < 30) {
- start.set({ 'minute': 30 });
- } else if (currentMin > 30 && currentMin < 45) {
- start.set({ 'minute': 45 });
- } else {
- start.addHours(1).set({ 'minute': 0 });
- }
-
- $dialog.find('#unavailable-start').val(GeneralFunctions.formatDate(start, GlobalVariables.dateFormat, true));
- $dialog.find('#unavailable-end').val(GeneralFunctions.formatDate(start.addHours(1), GlobalVariables.dateFormat, true));
- $dialog.find('.modal-header h3').text(EALang['new_unavailable_title']);
- $dialog.modal('show');
- });
-
- /**
- * Event: Pick Existing Customer Button "Click"
- */
- $('#select-customer').click(function() {
- var $list = $('#existing-customers-list');
-
- if (!$list.is(':visible')) {
- $(this).text(EALang['hide']);
- $list.empty();
- $list.slideDown('slow');
- $('#filter-existing-customers').fadeIn('slow');
- $('#filter-existing-customers').val('');
- $.each(GlobalVariables.customers, function(index, c) {
- $list.append('
'
- + c.first_name + ' ' + c.last_name + '
');
- });
- } else {
- $list.slideUp('slow');
- $('#filter-existing-customers').fadeOut('slow');
- $(this).text(EALang['select']);
- }
- });
-
- /**
- * Event: Select Existing Customer From List "Click"
- */
- $calendarPage.on('click', '#existing-customers-list div', function() {
- var id = $(this).attr('data-id');
-
- $.each(GlobalVariables.customers, function(index, c) {
- if (c.id == id) {
- $('#customer-id').val(c.id);
- $('#first-name').val(c.first_name);
- $('#last-name').val(c.last_name);
- $('#email').val(c.email);
- $('#phone-number').val(c.phone_number);
- $('#address').val(c.address);
- $('#city').val(c.city);
- $('#zip-code').val(c.zip_code);
- $('#customer-notes').val(c.notes);
- return false;
- }
- });
-
- $('#select-customer').trigger('click'); // hide list
- });
-
- /**
- * Event: Filter Existing Customers "Change"
- */
- $('#filter-existing-customers').keyup(function() {
- var key = $(this).val().toLowerCase();
- var $list = $('#existing-customers-list');
- var postUrl = GlobalVariables.baseUrl + '/index.php/backend_api/ajax_filter_customers';
- var postData = {
- csrfToken: GlobalVariables.csrfToken,
- key: key
- };
-
- // Try to get the updated customer list.
- $.ajax({
- type: 'POST',
- url: postUrl,
- data: postData,
- dataType: 'json',
- timeout: 1000,
- global: false,
- success: function(response) {
- $list.empty();
- $.each(response, function(index, c) {
- $list.append(''
- + c.first_name + ' ' + c.last_name + '
');
-
- // Verify if this customer is on the old customer list.
- var result = $.grep(GlobalVariables.customers,
- function(e){ return e.id == c.id; });
-
- // Add it to the customer list.
- if(result.length == 0){
- GlobalVariables.customers.push(c);
- }
- });
- },
- error: function(jqXHR, textStatus, errorThrown) {
- // If there is any error on the request, search by the local client database.
- $list.empty();
- $.each(GlobalVariables.customers, function(index, c) {
- if (c.first_name.toLowerCase().indexOf(key) != -1
- || c.last_name.toLowerCase().indexOf(key) != -1
- || c.email.toLowerCase().indexOf(key) != -1
- || c.phone_number.toLowerCase().indexOf(key) != -1
- || c.address.toLowerCase().indexOf(key) != -1
- || c.city.toLowerCase().indexOf(key) != -1
- || c.zip_code.toLowerCase().indexOf(key) != -1
- || c.notes.toLowerCase().indexOf(key) != -1) {
- $list.append(''
- + c.first_name + ' ' + c.last_name + '
');
- }
- });
- }
- });
- });
-
- /**
- * Event: Selected Service "Change"
- *
- * When the user clicks on a service, its available providers should become visible. Also we need to
- * update the start and end time of the appointment.
- */
- $('#select-service').change(function() {
- var sid = $('#select-service').val();
- $('#select-provider').empty();
-
- // Automatically update the service duration.
- $.each(GlobalVariables.availableServices, function(indexService, service) {
- if (service.id == sid) {
- var start = $('#start-datetime').datepicker('getDate');
- $('#end-datetime').datepicker('setDate', new Date(start.getTime() + service.duration * 60000));
- return false; // break loop
- }
- });
-
- // Update the providers select box.
- $.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 == sid) {
- var optionHtml = '';
- $('#select-provider').append(optionHtml);
- }
- });
- });
- });
-
- /**
- * Event: Enter New Customer Button "Click"
- */
- $('#new-customer').click(function() {
- $('#manage-appointment').find('#customer-id, #first-name, #last-name, #email, '
- + '#phone-number, #address, #city, #zip-code, #customer-notes').val('');
- });
- }
-
- /**
- * Save Appointment
- *
- * This method stores the changes of an already registered appointment into the database, via an ajax call.
- *
- * @param {Object} appointment Contain the new appointment data. The ID of the appointment MUST be
- * already included. The rest values must follow the database structure.
- * @param {Object} customer Optional, contains the customer data.
- * @param {Function} successCallback Optional, if defined, this function is going to be executed on post success.
- * @param {Function} errorCallback Optional, if defined, this function is going to be executed on post failure.
- */
- function _saveAppointment(appointment, customer, successCallback, errorCallback) {
- var postUrl = GlobalVariables.baseUrl + '/index.php/backend_api/ajax_save_appointment';
- var postData = {
- csrfToken: GlobalVariables.csrfToken,
- appointment_data: JSON.stringify(appointment)
- };
-
- if (customer !== undefined) {
- postData['customer_data'] = JSON.stringify(customer);
- }
-
- $.ajax({
- url: postUrl,
- type: 'POST',
- data: postData,
- dataType: 'json'
- })
- .done(function(response) {
- if (successCallback !== undefined) {
- successCallback(response);
- }
- })
- .fail(function(jqXHR, textStatus, errorThrown) {
- if (errorCallback !== undefined) {
- errorCallback();
- }
- });
- }
-
- /**
- * Save unavailable period to database.
- *
- * @param {Object} unavailable Containts the unavailable period data.
- * @param {Function} successCallback The ajax success callback function.
- * @param {Function} errorCallback The ajax failure callback function.
- */
- function _saveUnavailable(unavailable, successCallback, errorCallback) {
- var postUrl = GlobalVariables.baseUrl + '/index.php/backend_api/ajax_save_unavailable';
- var postData = {
- csrfToken: GlobalVariables.csrfToken,
- unavailable: JSON.stringify(unavailable)
- };
-
- $.ajax({
- type: 'POST',
- url: postUrl,
- data: postData,
- success: successCallback,
- error: errorCallback
- });
- }
-
- /**
- * Reset Apppointment Dialog
- *
- * This method resets the manage appointment dialog modal to its initial state. After that you can make
- * any modification might be necessary in order to bring the dialog to the desired state.
- */
- function _resetAppointmentDialog() {
- var $dialog = $('#manage-appointment');
-
- // Empty form fields.
- $dialog.find('input, textarea').val('');
- $dialog.find('.modal-message').fadeOut();
-
- // Prepare service and provider select boxes.
- $dialog.find('#select-service').val(
- $dialog.find('#select-service').eq(0).attr('value'));
-
- // Fill the providers listbox with providers that can serve the appointment's
- // service and then select the user's provider.
- $dialog.find('#select-provider').empty();
- $.each(GlobalVariables.availableProviders, function(index, provider) {
- var canProvideService = false;
-
- $.each(provider['services'], function(index, serviceId) {
- if (serviceId == $dialog.find('#select-service').val()) {
- canProvideService = true;
- return false;
- }
- });
-
- if (canProvideService) { // Add the provider to the listbox.
- var option = new Option(provider['first_name']
- + ' ' + provider['last_name'], provider['id']);
- $dialog.find('#select-provider').append(option);
- }
- });
-
- // Close existing customers-filter frame.
- $('#existing-customers-list').slideUp('slow');
- $('#filter-existing-customers').fadeOut('slow');
- $('#select-customer').text(EALang['select']);
-
- // Setup start and datetimepickers.
- // Get the selected service duration. It will be needed in order to calculate the appointment end datetime.
- var serviceDuration = 0;
- $.each(GlobalVariables.availableServices, function(index, service) {
- if (service['id'] == $dialog.find('#select-service').val()) {
- serviceDuration = service['duration'];
- return false;
- }
- });
-
- var startDatetime = new Date().addMinutes(GlobalVariables.bookAdvanceTimeout);
- var endDatetime = new Date().addMinutes(GlobalVariables.bookAdvanceTimeout).addMinutes(serviceDuration);
- var dateFormat;
-
- switch(GlobalVariables.dateFormat) {
- case 'DMY':
- dateFormat = 'dd/mm/yy';
- break;
- case 'MDY':
- dateFormat = 'mm/dd/yy';
- break;
- case 'YMD':
- dateFormat = 'yy/mm/dd';
- break;
- default:
- throw new Error('Invalid GlobalVariables.dateFormat value.');
- }
-
- $dialog.find('#start-datetime').datetimepicker({
- dateFormat: dateFormat,
-
- // Translation
- 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),
- 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),
- EALang['thursday'].substr(0,2), EALang['friday'].substr(0,2),
- EALang['saturday'].substr(0,2)],
- monthNames: [EALang['january'], EALang['february'], EALang['march'], EALang['april'],
- EALang['may'], EALang['june'], EALang['july'], EALang['august'], EALang['september'],
- EALang['october'], EALang['november'], EALang['december']],
- prevText: EALang['previous'],
- nextText: EALang['next'],
- currentText: EALang['now'],
- closeText: EALang['close'],
- timeOnlyTitle: EALang['select_time'],
- timeText: EALang['time'],
- hourText: EALang['hour'],
- minuteText: EALang['minutes'],
- firstDay: 1
- });
- $dialog.find('#start-datetime').datepicker('setDate', startDatetime);
-
- $dialog.find('#end-datetime').datetimepicker({
- dateFormat: dateFormat,
-
- // Translation
- 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),
- 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),
- EALang['thursday'].substr(0,2), EALang['friday'].substr(0,2),
- EALang['saturday'].substr(0,2)],
- monthNames: [EALang['january'], EALang['february'], EALang['march'], EALang['april'],
- EALang['may'], EALang['june'], EALang['july'], EALang['august'], EALang['september'],
- EALang['october'], EALang['november'], EALang['december']],
- prevText: EALang['previous'],
- nextText: EALang['next'],
- currentText: EALang['now'],
- closeText: EALang['close'],
- timeOnlyTitle: EALang['select_time'],
- timeText: EALang['time'],
- hourText: EALang['hour'],
- minuteText: EALang['minutes'],
- firstDay: 1
- });
- $dialog.find('#end-datetime').datepicker('setDate', endDatetime);
- }
-
- /**
- * Validate the manage appointment dialog data. Validation checks need to
- * run every time the data are going to be saved.
- *
- * @returns {Boolean} Returns the validation result.
- */
- function _validateAppointmentForm() {
- var $dialog = $('#manage-appointment');
-
- // Reset previous validation css formating.
- $dialog.find('.form-group').removeClass('has-error');
- $dialog.find('.modal-message').addClass('hidden');
-
- try {
- // Check required fields.
- var missingRequiredField = false;
-
- $dialog.find('.required').each(function() {
- if ($(this).val() == '' || $(this).val() == null) {
- $(this).parents('.form-group').addClass('has-error');
- missingRequiredField = true;
- }
- });
-
- if (missingRequiredField) {
- throw EALang['fields_are_required'];
- }
-
- // Check email address.
- if (!GeneralFunctions.validateEmail($dialog.find('#email').val())) {
- $dialog.find('#email').parents('.form-group').eq(1).addClass('has-error');
- throw EALang['invalid_email'];
- }
-
- // Check appointment start and end time.
- var start = $('#start-datetime').datepicker('getDate');
- var end = $('#end-datetime').datepicker('getDate');
- if (start > end) {
- $dialog.find('#start-datetime').parents('.form-group').addClass('has-error');
- $dialog.find('#end-datetime').parents('.form-group').addClass('has-error');
- throw EALang['start_date_before_end_error'];
- }
-
- return true;
- } catch(exc) {
- $dialog.find('.modal-message').addClass('alert-danger').text(exc).removeClass('hidden');
- return false;
- }
- }
-
- /**
- * Reset unavailable dialog form.
- *
- * Reset the "#manage-unavailable" dialog. Use this method to bring the dialog to the initial state
- * before it becomes visible to the user.
- */
- function _resetUnavailableDialog() {
- var $dialog = $('#manage-unavailable');
-
- $dialog.find('#unavailable-id').val('');
-
- // Set default time values
- var start = GeneralFunctions.formatDate(new Date(), GlobalVariables.dateFormat, true);
- var end = GeneralFunctions.formatDate(new Date().addHours(1), GlobalVariables.dateFormat, true);
- var dateFormat;
-
- switch(GlobalVariables.dateFormat) {
- case 'DMY':
- dateFormat = 'dd/mm/yy';
- break;
- case 'MDY':
- dateFormat = 'mm/dd/yy';
- break;
- case 'YMD':
- dateFormat = 'yy/mm/dd';
- break;
- }
-
-
- $dialog.find('#unavailable-start').datetimepicker({
- dateFormat: dateFormat,
-
- // Translation
- 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),
- 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),
- EALang['thursday'].substr(0,2), EALang['friday'].substr(0,2),
- EALang['saturday'].substr(0,2)],
- monthNames: [EALang['january'], EALang['february'], EALang['march'], EALang['april'],
- EALang['may'], EALang['june'], EALang['july'], EALang['august'], EALang['september'],
- EALang['october'], EALang['november'], EALang['december']],
- prevText: EALang['previous'],
- nextText: EALang['next'],
- currentText: EALang['now'],
- closeText: EALang['close'],
- timeOnlyTitle: EALang['select_time'],
- timeText: EALang['time'],
- hourText: EALang['hour'],
- minuteText: EALang['minutes'],
- firstDay: 1
- });
- $dialog.find('#unavailable-start').val(start);
-
- $dialog.find('#unavailable-end').datetimepicker({
- dateFormat: dateFormat,
-
- // Translation
- 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),
- 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),
- EALang['thursday'].substr(0,2), EALang['friday'].substr(0,2),
- EALang['saturday'].substr(0,2)],
- monthNames: [EALang['january'], EALang['february'], EALang['march'], EALang['april'],
- EALang['may'], EALang['june'], EALang['july'], EALang['august'], EALang['september'],
- EALang['october'], EALang['november'], EALang['december']],
- prevText: EALang['previous'],
- nextText: EALang['next'],
- currentText: EALang['now'],
- closeText: EALang['close'],
- timeOnlyTitle: EALang['select_time'],
- timeText: EALang['time'],
- hourText: EALang['hour'],
- minuteText: EALang['minutes'],
- firstDay: 1
- });
- $dialog.find('#unavailable-end').val(end);
-
- // Clear the unavailable notes field.
- $dialog.find('#unavailable-notes').val('');
- }
-
/**
* Initialize Module
*
@@ -965,8 +39,8 @@ window.BackendCalendar = window.BackendCalendar || {};
}
BackendCalendarGoogleSync.initialize();
-
- _bindEventHandlers(); // General event handling.
+ BackendCalendarAppointmentsModal.initialize();
+ BackendCalendarUnavailabilitiesModal.initialize();
};
})(window.BackendCalendar);
diff --git a/src/assets/js/backend_calendar_api.js b/src/assets/js/backend_calendar_api.js
new file mode 100644
index 00000000..4a089118
--- /dev/null
+++ b/src/assets/js/backend_calendar_api.js
@@ -0,0 +1,88 @@
+/* ----------------------------------------------------------------------------
+ * Easy!Appointments - Open Source Web Scheduler
+ *
+ * @package EasyAppointments
+ * @author A.Tselegidis
+ * @copyright Copyright (c) 2013 - 2016, Alex Tselegidis
+ * @license http://opensource.org/licenses/GPL-3.0 - GPLv3
+ * @link http://easyappointments.org
+ * @since v1.2.0
+ * ---------------------------------------------------------------------------- */
+
+/**
+ * Backend Calendar API
+ *
+ * This module implements the AJAX requests for the calendar page.
+ *
+ * @module BackendCalendarApi
+ */
+window.BackendCalendarApi = window.BackendCalendarApi || {};
+
+(function(exports) {
+
+ 'use strict';
+
+ /**
+ * Save Appointment
+ *
+ * This method stores the changes of an already registered appointment into the database, via an ajax call.
+ *
+ * @param {Object} appointment Contain the new appointment data. The ID of the appointment MUST be
+ * already included. The rest values must follow the database structure.
+ * @param {Object} customer Optional, contains the customer data.
+ * @param {Function} successCallback Optional, if defined, this function is going to be executed on post success.
+ * @param {Function} errorCallback Optional, if defined, this function is going to be executed on post failure.
+ */
+ exports.saveAppointment = function(appointment, customer, successCallback, errorCallback) {
+ var postUrl = GlobalVariables.baseUrl + '/index.php/backend_api/ajax_save_appointment';
+ var postData = {
+ csrfToken: GlobalVariables.csrfToken,
+ appointment_data: JSON.stringify(appointment)
+ };
+
+ if (customer !== undefined) {
+ postData['customer_data'] = JSON.stringify(customer);
+ }
+
+ $.ajax({
+ url: postUrl,
+ type: 'POST',
+ data: postData,
+ dataType: 'json'
+ })
+ .done(function(response) {
+ if (successCallback !== undefined) {
+ successCallback(response);
+ }
+ })
+ .fail(function(jqXHR, textStatus, errorThrown) {
+ if (errorCallback !== undefined) {
+ errorCallback();
+ }
+ });
+ };
+
+ /**
+ * Save unavailable period to database.
+ *
+ * @param {Object} unavailable Containts the unavailable period data.
+ * @param {Function} successCallback The ajax success callback function.
+ * @param {Function} errorCallback The ajax failure callback function.
+ */
+ exports.saveUnavailable = function(unavailable, successCallback, errorCallback) {
+ var postUrl = GlobalVariables.baseUrl + '/index.php/backend_api/ajax_save_unavailable';
+ var postData = {
+ csrfToken: GlobalVariables.csrfToken,
+ unavailable: JSON.stringify(unavailable)
+ };
+
+ $.ajax({
+ type: 'POST',
+ url: postUrl,
+ data: postData,
+ success: successCallback,
+ error: errorCallback
+ });
+ };
+
+})(window.BackendCalendarApi);
diff --git a/src/assets/js/backend_calendar_appointments_modal.js b/src/assets/js/backend_calendar_appointments_modal.js
new file mode 100644
index 00000000..1af9bf5a
--- /dev/null
+++ b/src/assets/js/backend_calendar_appointments_modal.js
@@ -0,0 +1,505 @@
+/* ----------------------------------------------------------------------------
+ * Easy!Appointments - Open Source Web Scheduler
+ *
+ * @package EasyAppointments
+ * @author A.Tselegidis
+ * @copyright Copyright (c) 2013 - 2016, Alex Tselegidis
+ * @license http://opensource.org/licenses/GPL-3.0 - GPLv3
+ * @link http://easyappointments.org
+ * @since v1.2.0
+ * ---------------------------------------------------------------------------- */
+
+/**
+ * Backend Calendar Appointments Modal
+ *
+ * This module implements the appointments modal functionality.
+ *
+ * @module BackendCalendarAppointmentsModal
+ */
+window.BackendCalendarAppointmentsModal = window.BackendCalendarAppointmentsModal || {};
+
+(function(exports) {
+
+ 'use strict';
+
+ function _bindEventHandlers() {
+ /**
+ * Event: Manage Appointments Dialog Cancel Button "Click"
+ *
+ * Closes the dialog without saving any changes to the database.
+ */
+ $('#manage-appointment #cancel-appointment').click(function() {
+ $('#manage-appointment').modal('hide');
+ });
+
+ /**
+ * Event: Manage Appointments Dialog Save Button "Click"
+ *
+ * Stores the appointment changes or inserts a new appointment depending the dialog mode.
+ */
+ $('#manage-appointment #save-appointment').click(function() {
+ // Before doing anything the appointment data need to be validated.
+ if (!_validateAppointmentForm()) {
+ return;
+ }
+
+ // Prepare appointment data for AJAX request.
+ var $dialog = $('#manage-appointment');
+
+ // ID must exist on the object in order for the model to update the record and not to perform
+ // an insert operation.
+
+ var startDatetime = $dialog.find('#start-datetime')
+ .datepicker('getDate').toString('yyyy-MM-dd HH:mm:ss');
+ var endDatetime = $dialog.find('#end-datetime')
+ .datepicker('getDate').toString('yyyy-MM-dd HH:mm:ss');
+
+ var appointment = {
+ id_services: $dialog.find('#select-service').val(),
+ id_users_provider: $dialog.find('#select-provider').val(),
+ start_datetime: startDatetime,
+ end_datetime: endDatetime,
+ notes: $dialog.find('#appointment-notes').val(),
+ is_unavailable: false
+ };
+
+ if ($dialog.find('#appointment-id').val() !== '') {
+ // Set the id value, only if we are editing an appointment.
+ appointment['id'] = $dialog.find('#appointment-id').val();
+ }
+
+ var customer = {
+ first_name: $dialog.find('#first-name').val(),
+ last_name: $dialog.find('#last-name').val(),
+ email: $dialog.find('#email').val(),
+ phone_number: $dialog.find('#phone-number').val(),
+ address: $dialog.find('#address').val(),
+ city: $dialog.find('#city').val(),
+ zip_code: $dialog.find('#zip-code').val(),
+ notes: $dialog.find('#customer-notes').val()
+ };
+
+ if ($dialog.find('#customer-id').val() !== '') {
+ // Set the id value, only if we are editing an appointment.
+ customer['id'] = $dialog.find('#customer-id').val();
+ appointment['id_users_customer'] = customer['id'];
+ }
+
+ // Define success callback.
+ var successCallback = function(response) {
+ if (!GeneralFunctions.handleAjaxExceptions(response)) {
+ $dialog.find('.modal-message').text(EALang['unexpected_issues_occurred']);
+ $dialog.find('.modal-message').addClass('alert-danger').removeClass('hidden');
+ return false;
+ }
+
+ // Display success message to the user.
+ $dialog.find('.modal-message').text(EALang['appointment_saved']);
+ $dialog.find('.modal-message').addClass('alert-success').removeClass('alert-danger hidden');
+ $dialog.find('.modal-body').scrollTop(0);
+
+ // Close the modal dialog and refresh the calendar appointments after one second.
+ setTimeout(function() {
+ $dialog.find('.alert').addClass('hidden');
+ $dialog.modal('hide');
+ $('#select-filter-item').trigger('change');
+ }, 2000);
+ };
+
+ // Define error callback.
+ var errorCallback = function() {
+ $dialog.find('.modal-message').text(EALang['server_communication_error']);
+ $dialog.find('.modal-message').addClass('alert-danger').removeClass('hidden');
+ $dialog.find('.modal-body').scrollTop(0);
+ };
+
+ // Save appointment data.
+ BackendCalendarApi.saveAppointment(appointment, customer, successCallback, errorCallback);
+ });
+
+ /**
+ * Event: Insert Appointment Button "Click"
+ *
+ * When the user presses this button, the manage appointment dialog opens and lets the user to
+ * create a new appointment.
+ */
+ $('#insert-appointment').click(function() {
+ _resetAppointmentDialog();
+ var $dialog = $('#manage-appointment');
+
+ // Set the selected filter item and find the next appointment time as the default modal values.
+ if ($('#select-filter-item option:selected').attr('type') == 'provider') {
+ var $providerOption = $dialog.find('#select-provider option[value="'
+ + $('#select-filter-item').val() + '"]');
+ if ($providerOption.length === 0) { // Change the services until you find the correct.
+ $.each($dialog.find('#select-service option'), function() {
+ $(this).prop('selected', true).parent().change();
+ if ($providerOption.length > 0)
+ return false;
+ });
+ }
+ $providerOption.prop('selected', true);
+ } else {
+ $dialog.find('#select-service option[value="'
+ + $('#select-filter-item').val() + '"]').prop('selected', true);
+ }
+
+ var serviceDuration = 0;
+ $.each(GlobalVariables.availableServices, function(index, service) {
+ if (service['id'] == $dialog.find('#select-service').val()) {
+ serviceDuration = service['duration'];
+ return false; // exit loop
+ }
+ });
+
+ var start = new Date();
+ var currentMin = parseInt(start.toString('mm'));
+
+ if (currentMin > 0 && currentMin < 15) {
+ start.set({ 'minute': 15 });
+ } else if (currentMin > 15 && currentMin < 30) {
+ start.set({ 'minute': 30 });
+ } else if (currentMin > 30 && currentMin < 45) {
+ start.set({ 'minute': 45 });
+ } else {
+ start.addHours(1).set({ 'minute': 0 });
+ }
+
+ $dialog.find('#start-datetime').val(GeneralFunctions.formatDate(start, GlobalVariables.dateFormat, true));
+ $dialog.find('#end-datetime').val(GeneralFunctions.formatDate(start.addMinutes(serviceDuration),
+ GlobalVariables.dateFormat, true));
+
+ // Display modal form.
+ $dialog.find('.modal-header h3').text(EALang['new_appointment_title']);
+ $dialog.modal('show');
+ });
+
+ /**
+ * Event: Pick Existing Customer Button "Click"
+ */
+ $('#select-customer').click(function() {
+ var $list = $('#existing-customers-list');
+
+ if (!$list.is(':visible')) {
+ $(this).text(EALang['hide']);
+ $list.empty();
+ $list.slideDown('slow');
+ $('#filter-existing-customers').fadeIn('slow');
+ $('#filter-existing-customers').val('');
+ $.each(GlobalVariables.customers, function(index, c) {
+ $list.append(''
+ + c.first_name + ' ' + c.last_name + '
');
+ });
+ } else {
+ $list.slideUp('slow');
+ $('#filter-existing-customers').fadeOut('slow');
+ $(this).text(EALang['select']);
+ }
+ });
+
+ /**
+ * Event: Select Existing Customer From List "Click"
+ */
+ $('#manage-appointment').on('click', '#existing-customers-list div', function() {
+ var id = $(this).attr('data-id');
+
+ $.each(GlobalVariables.customers, function(index, c) {
+ if (c.id == id) {
+ $('#customer-id').val(c.id);
+ $('#first-name').val(c.first_name);
+ $('#last-name').val(c.last_name);
+ $('#email').val(c.email);
+ $('#phone-number').val(c.phone_number);
+ $('#address').val(c.address);
+ $('#city').val(c.city);
+ $('#zip-code').val(c.zip_code);
+ $('#customer-notes').val(c.notes);
+ return false;
+ }
+ });
+
+ $('#select-customer').trigger('click'); // hide list
+ });
+
+ /**
+ * Event: Filter Existing Customers "Change"
+ */
+ $('#filter-existing-customers').keyup(function() {
+ var key = $(this).val().toLowerCase();
+ var $list = $('#existing-customers-list');
+ var postUrl = GlobalVariables.baseUrl + '/index.php/backend_api/ajax_filter_customers';
+ var postData = {
+ csrfToken: GlobalVariables.csrfToken,
+ key: key
+ };
+
+ // Try to get the updated customer list.
+ $.ajax({
+ type: 'POST',
+ url: postUrl,
+ data: postData,
+ dataType: 'json',
+ timeout: 1000,
+ global: false,
+ success: function(response) {
+ $list.empty();
+ $.each(response, function(index, c) {
+ $list.append(''
+ + c.first_name + ' ' + c.last_name + '
');
+
+ // Verify if this customer is on the old customer list.
+ var result = $.grep(GlobalVariables.customers,
+ function(e){ return e.id == c.id; });
+
+ // Add it to the customer list.
+ if(result.length == 0){
+ GlobalVariables.customers.push(c);
+ }
+ });
+ },
+ error: function(jqXHR, textStatus, errorThrown) {
+ // If there is any error on the request, search by the local client database.
+ $list.empty();
+ $.each(GlobalVariables.customers, function(index, c) {
+ if (c.first_name.toLowerCase().indexOf(key) != -1
+ || c.last_name.toLowerCase().indexOf(key) != -1
+ || c.email.toLowerCase().indexOf(key) != -1
+ || c.phone_number.toLowerCase().indexOf(key) != -1
+ || c.address.toLowerCase().indexOf(key) != -1
+ || c.city.toLowerCase().indexOf(key) != -1
+ || c.zip_code.toLowerCase().indexOf(key) != -1
+ || c.notes.toLowerCase().indexOf(key) != -1) {
+ $list.append(''
+ + c.first_name + ' ' + c.last_name + '
');
+ }
+ });
+ }
+ });
+ });
+
+ /**
+ * Event: Selected Service "Change"
+ *
+ * When the user clicks on a service, its available providers should become visible. Also we need to
+ * update the start and end time of the appointment.
+ */
+ $('#select-service').change(function() {
+ var sid = $('#select-service').val();
+ $('#select-provider').empty();
+
+ // Automatically update the service duration.
+ $.each(GlobalVariables.availableServices, function(indexService, service) {
+ if (service.id == sid) {
+ var start = $('#start-datetime').datepicker('getDate');
+ $('#end-datetime').datepicker('setDate', new Date(start.getTime() + service.duration * 60000));
+ return false; // break loop
+ }
+ });
+
+ // Update the providers select box.
+ $.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 == sid) {
+ var optionHtml = '';
+ $('#select-provider').append(optionHtml);
+ }
+ });
+ });
+ });
+
+ /**
+ * Event: Enter New Customer Button "Click"
+ */
+ $('#new-customer').click(function() {
+ $('#manage-appointment').find('#customer-id, #first-name, #last-name, #email, '
+ + '#phone-number, #address, #city, #zip-code, #customer-notes').val('');
+ });
+ }
+
+ /**
+ * Reset Apppointment Dialog
+ *
+ * This method resets the manage appointment dialog modal to its initial state. After that you can make
+ * any modification might be necessary in order to bring the dialog to the desired state.
+ */
+ function _resetAppointmentDialog() {
+ var $dialog = $('#manage-appointment');
+
+ // Empty form fields.
+ $dialog.find('input, textarea').val('');
+ $dialog.find('.modal-message').fadeOut();
+
+ // Prepare service and provider select boxes.
+ $dialog.find('#select-service').val(
+ $dialog.find('#select-service').eq(0).attr('value'));
+
+ // Fill the providers listbox with providers that can serve the appointment's
+ // service and then select the user's provider.
+ $dialog.find('#select-provider').empty();
+ $.each(GlobalVariables.availableProviders, function(index, provider) {
+ var canProvideService = false;
+
+ $.each(provider['services'], function(index, serviceId) {
+ if (serviceId == $dialog.find('#select-service').val()) {
+ canProvideService = true;
+ return false;
+ }
+ });
+
+ if (canProvideService) { // Add the provider to the listbox.
+ var option = new Option(provider['first_name']
+ + ' ' + provider['last_name'], provider['id']);
+ $dialog.find('#select-provider').append(option);
+ }
+ });
+
+ // Close existing customers-filter frame.
+ $('#existing-customers-list').slideUp('slow');
+ $('#filter-existing-customers').fadeOut('slow');
+ $('#select-customer').text(EALang['select']);
+
+ // Setup start and datetimepickers.
+ // Get the selected service duration. It will be needed in order to calculate the appointment end datetime.
+ var serviceDuration = 0;
+ $.each(GlobalVariables.availableServices, function(index, service) {
+ if (service['id'] == $dialog.find('#select-service').val()) {
+ serviceDuration = service['duration'];
+ return false;
+ }
+ });
+
+ var startDatetime = new Date().addMinutes(GlobalVariables.bookAdvanceTimeout);
+ var endDatetime = new Date().addMinutes(GlobalVariables.bookAdvanceTimeout).addMinutes(serviceDuration);
+ var dateFormat;
+
+ switch(GlobalVariables.dateFormat) {
+ case 'DMY':
+ dateFormat = 'dd/mm/yy';
+ break;
+ case 'MDY':
+ dateFormat = 'mm/dd/yy';
+ break;
+ case 'YMD':
+ dateFormat = 'yy/mm/dd';
+ break;
+ default:
+ throw new Error('Invalid GlobalVariables.dateFormat value.');
+ }
+
+ $dialog.find('#start-datetime').datetimepicker({
+ dateFormat: dateFormat,
+
+ // Translation
+ 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),
+ 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),
+ EALang['thursday'].substr(0,2), EALang['friday'].substr(0,2),
+ EALang['saturday'].substr(0,2)],
+ monthNames: [EALang['january'], EALang['february'], EALang['march'], EALang['april'],
+ EALang['may'], EALang['june'], EALang['july'], EALang['august'], EALang['september'],
+ EALang['october'], EALang['november'], EALang['december']],
+ prevText: EALang['previous'],
+ nextText: EALang['next'],
+ currentText: EALang['now'],
+ closeText: EALang['close'],
+ timeOnlyTitle: EALang['select_time'],
+ timeText: EALang['time'],
+ hourText: EALang['hour'],
+ minuteText: EALang['minutes'],
+ firstDay: 1
+ });
+ $dialog.find('#start-datetime').datepicker('setDate', startDatetime);
+
+ $dialog.find('#end-datetime').datetimepicker({
+ dateFormat: dateFormat,
+
+ // Translation
+ 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),
+ 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),
+ EALang['thursday'].substr(0,2), EALang['friday'].substr(0,2),
+ EALang['saturday'].substr(0,2)],
+ monthNames: [EALang['january'], EALang['february'], EALang['march'], EALang['april'],
+ EALang['may'], EALang['june'], EALang['july'], EALang['august'], EALang['september'],
+ EALang['october'], EALang['november'], EALang['december']],
+ prevText: EALang['previous'],
+ nextText: EALang['next'],
+ currentText: EALang['now'],
+ closeText: EALang['close'],
+ timeOnlyTitle: EALang['select_time'],
+ timeText: EALang['time'],
+ hourText: EALang['hour'],
+ minuteText: EALang['minutes'],
+ firstDay: 1
+ });
+ $dialog.find('#end-datetime').datepicker('setDate', endDatetime);
+ }
+
+ /**
+ * Validate the manage appointment dialog data. Validation checks need to
+ * run every time the data are going to be saved.
+ *
+ * @returns {Boolean} Returns the validation result.
+ */
+ function _validateAppointmentForm() {
+ var $dialog = $('#manage-appointment');
+
+ // Reset previous validation css formating.
+ $dialog.find('.form-group').removeClass('has-error');
+ $dialog.find('.modal-message').addClass('hidden');
+
+ try {
+ // Check required fields.
+ var missingRequiredField = false;
+
+ $dialog.find('.required').each(function() {
+ if ($(this).val() == '' || $(this).val() == null) {
+ $(this).parents('.form-group').addClass('has-error');
+ missingRequiredField = true;
+ }
+ });
+
+ if (missingRequiredField) {
+ throw EALang['fields_are_required'];
+ }
+
+ // Check email address.
+ if (!GeneralFunctions.validateEmail($dialog.find('#email').val())) {
+ $dialog.find('#email').parents('.form-group').eq(1).addClass('has-error');
+ throw EALang['invalid_email'];
+ }
+
+ // Check appointment start and end time.
+ var start = $('#start-datetime').datepicker('getDate');
+ var end = $('#end-datetime').datepicker('getDate');
+ if (start > end) {
+ $dialog.find('#start-datetime').parents('.form-group').addClass('has-error');
+ $dialog.find('#end-datetime').parents('.form-group').addClass('has-error');
+ throw EALang['start_date_before_end_error'];
+ }
+
+ return true;
+ } catch(exc) {
+ $dialog.find('.modal-message').addClass('alert-danger').text(exc).removeClass('hidden');
+ return false;
+ }
+ }
+
+ exports.initialize = function() {
+ _bindEventHandlers();
+ };
+
+})(window.BackendCalendarAppointmentsModal);
diff --git a/src/assets/js/backend_calendar_default_view.js b/src/assets/js/backend_calendar_default_view.js
index 4594057e..e8e6e99c 100644
--- a/src/assets/js/backend_calendar_default_view.js
+++ b/src/assets/js/backend_calendar_default_view.js
@@ -26,10 +26,178 @@ window.BackendCalendarDefaultView = window.BackendCalendarDefaultView || {};
var FILTER_TYPE_PROVIDER = 'provider';
var FILTER_TYPE_SERVICE = 'service';
+ // Variables
+ var lastFocusedEventData; // Contains event data for later use.
+
/**
* Bind event handlers for the calendar view.
*/
function _bindEventHandlers() {
+ var $calendarPage = $('#calendar-page');
+
+ /**
+ * Event: Reload Button "Click"
+ *
+ * When the user clicks the reload button an the calendar items need to be refreshed.
+ */
+ $('#reload-appointments').click(function() {
+ $('#select-filter-item').trigger('change');
+ });
+
+ /**
+ * Event: Popover Close Button "Click"
+ *
+ * Hides the open popover element.
+ */
+ $calendarPage.on('click', '.close-popover', function() {
+ $(this).parents().eq(2).remove();
+ });
+
+ /**
+ * Event: Popover Edit Button "Click"
+ *
+ * Enables the edit dialog of the selected calendar event.
+ */
+ $calendarPage.on('click', '.edit-popover', function() {
+ $(this).parents().eq(2).remove(); // Hide the popover
+
+ var $dialog;
+
+ if (lastFocusedEventData.data.is_unavailable == false) {
+ var appointment = lastFocusedEventData.data;
+ $dialog = $('#manage-appointment');
+
+ _resetAppointmentDialog();
+
+ // Apply appointment data and show modal dialog.
+ $dialog.find('.modal-header h3').text(EALang['edit_appointment_title']);
+ $dialog.find('#appointment-id').val(appointment['id']);
+ $dialog.find('#select-service').val(appointment['id_services']).trigger('change');
+ $dialog.find('#select-provider').val(appointment['id_users_provider']);
+
+ // Set the start and end datetime of the appointment.
+ var startDatetime = Date.parseExact(appointment['start_datetime'],
+ 'yyyy-MM-dd HH:mm:ss');
+ $dialog.find('#start-datetime').datetimepicker('setDate', startDatetime);
+
+ var endDatetime = Date.parseExact(appointment['end_datetime'],
+ 'yyyy-MM-dd HH:mm:ss');
+ $dialog.find('#end-datetime').datetimepicker('setDate', endDatetime);
+
+ var customer = appointment['customer'];
+ $dialog.find('#customer-id').val(appointment['id_users_customer']);
+ $dialog.find('#first-name').val(customer['first_name']);
+ $dialog.find('#last-name').val(customer['last_name']);
+ $dialog.find('#email').val(customer['email']);
+ $dialog.find('#phone-number').val(customer['phone_number']);
+ $dialog.find('#address').val(customer['address']);
+ $dialog.find('#city').val(customer['city']);
+ $dialog.find('#zip-code').val(customer['zip_code']);
+ $dialog.find('#appointment-notes').val(appointment['notes']);
+ $dialog.find('#customer-notes').val(customer['notes']);
+ } else {
+ var unavailable = lastFocusedEventData.data;
+
+ // Replace string date values with actual date objects.
+ unavailable.start_datetime = GeneralFunctions.clone(lastFocusedEventData.start);
+ unavailable.end_datetime = GeneralFunctions.clone(lastFocusedEventData.end);
+
+ $dialog = $('#manage-unavailable');
+ _resetUnavailableDialog();
+
+ // Apply unvailable data to dialog.
+ $dialog.find('.modal-header h3').text('Edit Unavailable Period');
+ $dialog.find('#unavailable-start').datetimepicker('setDate', unavailable.start_datetime);
+ $dialog.find('#unavailable-id').val(unavailable.id);
+ $dialog.find('#unavailable-end').datetimepicker('setDate', unavailable.end_datetime);
+ $dialog.find('#unavailable-notes').val(unavailable.notes);
+ }
+
+ // :: DISPLAY EDIT DIALOG
+ $dialog.modal('show');
+ });
+
+ /**
+ * Event: Popover Delete Button "Click"
+ *
+ * Displays a prompt on whether the user wants the appoinmtent to be deleted. If he confirms the
+ * deletion then an ajax call is made to the server and deletes the appointment from the database.
+ */
+ $calendarPage.on('click', '.delete-popover', function() {
+ $(this).parents().eq(2).remove(); // Hide the popover
+
+ if (lastFocusedEventData.data.is_unavailable == false) {
+ var messageButtons = {};
+ messageButtons['OK'] = function() {
+ var postUrl = GlobalVariables.baseUrl + '/index.php/backend_api/ajax_delete_appointment';
+ var postData = {
+ csrfToken: GlobalVariables.csrfToken,
+ appointment_id : lastFocusedEventData.data['id'],
+ delete_reason: $('#delete-reason').val()
+ };
+
+ $.post(postUrl, postData, function(response) {
+ $('#message_box').dialog('close');
+
+ if (response.exceptions) {
+ response.exceptions = GeneralFunctions.parseExceptions(response.exceptions);
+ GeneralFunctions.displayMessageBox(GeneralFunctions.EXCEPTIONS_TITLE,
+ GeneralFunctions.EXCEPTIONS_MESSAGE);
+ $('#message_box').append(GeneralFunctions.exceptionsToHtml(response.exceptions));
+ return;
+ }
+
+ if (response.warnings) {
+ response.warnings = GeneralFunctions.parseExceptions(response.warnings);
+ GeneralFunctions.displayMessageBox(GeneralFunctions.WARNINGS_TITLE,
+ GeneralFunctions.WARNINGS_MESSAGE);
+ $('#message_box').append(GeneralFunctions.exceptionsToHtml(response.warnings));
+ }
+
+ // Refresh calendar event items.
+ $('#select-filter-item').trigger('change');
+ }, 'json').fail(GeneralFunctions.ajaxFailureHandler);
+ };
+
+ messageButtons[EALang['cancel']] = function() {
+ $('#message_box').dialog('close');
+ };
+
+ GeneralFunctions.displayMessageBox(EALang['delete_appointment_title'],
+ EALang['write_appointment_removal_reason'], messageButtons);
+
+ $('#message_box').append('');
+ $('#delete-reason').css('width', '100%');
+ } else {
+ // Do not display confirmation promt.
+ var postUrl = GlobalVariables.baseUrl + '/index.php/backend_api/ajax_delete_unavailable';
+ var postData = {
+ csrfToken: GlobalVariables.csrfToken,
+ unavailable_id : lastFocusedEventData.data.id
+ };
+
+ $.post(postUrl, postData, function(response) {
+ $('#message_box').dialog('close');
+
+ if (response.exceptions) {
+ response.exceptions = GeneralFunctions.parseExceptions(response.exceptions);
+ GeneralFunctions.displayMessageBox(GeneralFunctions.EXCEPTIONS_TITLE, GeneralFunctions.EXCEPTIONS_MESSAGE);
+ $('#message_box').append(GeneralFunctions.exceptionsToHtml(response.exceptions));
+ return;
+ }
+
+ if (response.warnings) {
+ response.warnings = GeneralFunctions.parseExceptions(response.warnings);
+ GeneralFunctions.displayMessageBox(GeneralFunctions.WARNINGS_TITLE, GeneralFunctions.WARNINGS_MESSAGE);
+ $('#message_box').append(GeneralFunctions.exceptionsToHtml(response.warnings));
+ }
+
+ // Refresh calendar event items.
+ $('#select-filter-item').trigger('change');
+ }, 'json').fail(GeneralFunctions.ajaxFailureHandler);
+ }
+ });
+
/**
* Event: Calendar Filter Item "Change"
*
@@ -257,7 +425,7 @@ window.BackendCalendarDefaultView = window.BackendCalendarDefaultView || {};
};
// Update appointment data.
- _saveAppointment(appointment, undefined, successCallback, undefined);
+ BackendCalendarApi.saveAppointment(appointment, undefined, successCallback, undefined);
} else {
// Update unvailable time period.
var unavailable = {
@@ -311,7 +479,7 @@ window.BackendCalendarDefaultView = window.BackendCalendarDefaultView || {};
$('#footer').css('position', 'static'); // Footer position fix.
};
- _saveUnavailable(unavailable, successCallback, undefined);
+ BackendCalendarApi.saveUnavailable(unavailable, successCallback, undefined);
}
}
@@ -433,7 +601,7 @@ window.BackendCalendarDefaultView = window.BackendCalendarDefaultView || {};
};
// Update appointment data.
- _saveAppointment(appointment, undefined, successCallback, undefined);
+ BackendCalendarApi.saveAppointment(appointment, undefined, successCallback, undefined);
} else {
// Update unavailable time period.
var unavailable = {
@@ -493,7 +661,7 @@ window.BackendCalendarDefaultView = window.BackendCalendarDefaultView || {};
$('#footer').css('position', 'static'); // Footer position fix.
};
- _saveUnavailable(unavailable, successCallback, undefined);
+ BackendCalendarApi.saveUnavailable(unavailable, successCallback, undefined);
}
}
diff --git a/src/assets/js/backend_calendar_unavailabilities_modal.js b/src/assets/js/backend_calendar_unavailabilities_modal.js
new file mode 100644
index 00000000..eb056a19
--- /dev/null
+++ b/src/assets/js/backend_calendar_unavailabilities_modal.js
@@ -0,0 +1,240 @@
+/* ----------------------------------------------------------------------------
+ * Easy!Appointments - Open Source Web Scheduler
+ *
+ * @package EasyAppointments
+ * @author A.Tselegidis
+ * @copyright Copyright (c) 2013 - 2016, Alex Tselegidis
+ * @license http://opensource.org/licenses/GPL-3.0 - GPLv3
+ * @link http://easyappointments.org
+ * @since v1.2.0
+ * ---------------------------------------------------------------------------- */
+
+/**
+ * Backend Calendar Unavailabilities Modal
+ *
+ * This module implements the unavailabilities modal functionality.
+ *
+ * @module BackendCalendarUnavailabilitiesModal
+ */
+window.BackendCalendarUnavailabilitiesModal = window.BackendCalendarUnavailabilitiesModal || {};
+
+(function(exports) {
+
+ 'use strict';
+
+ function _bindEventHandlers() {
+ /**
+ * Event: Manage Unavailable Dialog Save Button "Click"
+ *
+ * Stores the unavailable period changes or inserts a new record.
+ */
+ $('#manage-unavailable #save-unavailable').click(function() {
+ var $dialog = $('#manage-unavailable');
+ var start = $dialog.find('#unavailable-start').datetimepicker('getDate');
+ var end = $dialog.find('#unavailable-end').datetimepicker('getDate');
+
+ if (start > end) {
+ // Start time is after end time - display message to user.
+ $dialog.find('.modal-message')
+ .text(EALang['start_date_before_end_error'])
+ .addClass('alert-danger')
+ .removeClass('hidden');
+ return;
+ }
+
+ // Unavailable period records go to the appointments table.
+ var unavailable = {
+ start_datetime: start.toString('yyyy-MM-dd HH:mm'),
+ end_datetime: end.toString('yyyy-MM-dd HH:mm'),
+ notes: $dialog.find('#unavailable-notes').val(),
+ id_users_provider: $('#select-filter-item').val() // curr provider
+ };
+
+ if ($dialog.find('#unavailable-id').val() !== '') {
+ // Set the id value, only if we are editing an appointment.
+ unavailable.id = $dialog.find('#unavailable-id').val();
+ }
+
+ var successCallback = function(response) {
+ if (response.exceptions) {
+ response.exceptions = GeneralFunctions.parseExceptions(response.exceptions);
+ GeneralFunctions.displayMessageBox(GeneralFunctions.EXCEPTIONS_TITLE,
+ GeneralFunctions.EXCEPTIONS_MESSAGE);
+ $('#message_box').append(GeneralFunctions.exceptionsToHtml(response.exceptions));
+
+ $dialog.find('.modal-message')
+ .text(EALang['unexpected_issues_occurred'])
+ .addClass('alert-danger')
+ .removeClass('hidden');
+
+ return;
+ }
+
+ if (response.warnings) {
+ response.warnings = GeneralFunctions.parseExceptions(response.warnings);
+ GeneralFunctions.displayMessageBox(GeneralFunctions.WARNINGS_TITLE,
+ GeneralFunctions.WARNINGS_MESSAGE);
+ $('#message_box').append(GeneralFunctions.exceptionsToHtml(response.warnings));
+ }
+
+ // Display success message to the user.
+ $dialog.find('.modal-message')
+ .text(EALang['unavailable_saved'])
+ .addClass('alert-success')
+ .removeClass('alert-danger hidden');
+
+ // Close the modal dialog and refresh the calendar appointments after one second.
+ setTimeout(function() {
+ $dialog.find('.alert').addClass('hidden');
+ $dialog.modal('hide');
+ $('#select-filter-item').trigger('change');
+ }, 2000);
+ };
+
+ var errorCallback = function(jqXHR, textStatus, errorThrown) {
+ GeneralFunctions.displayMessageBox('Communication Error', 'Unfortunately ' +
+ 'the operation could not complete due to server communication errors.');
+
+ $dialog.find('.modal-message').txt(EALang['service_communication_error']);
+ $dialog.find('.modal-message').addClass('alert-danger').removeClass('hidden');
+ };
+
+ BackendCalendarApi.saveUnavailable(unavailable, successCallback, errorCallback);
+ });
+
+ /**
+ * Event: Manage Unavailable Dialog Cancel Button "Click"
+ *
+ * Closes the dialog without saveing any changes to the database.
+ */
+ $('#manage-unavailable #cancel-unavailable').click(function() {
+ $('#manage-unavailable').modal('hide');
+ });
+
+ /**
+ * Event : Insert Unavailable Time Period Button "Click"
+ *
+ * When the user clicks this button a popup dialog appears and the use can set a time period where
+ * he cannot accept any appointments.
+ */
+ $('#insert-unavailable').click(function() {
+ _resetUnavailableDialog();
+ var $dialog = $('#manage-unavailable');
+
+ // Set the default datetime values.
+ var start = new Date();
+ var currentMin = parseInt(start.toString('mm'));
+
+ if (currentMin > 0 && currentMin < 15) {
+ start.set({ 'minute': 15 });
+ } else if (currentMin > 15 && currentMin < 30) {
+ start.set({ 'minute': 30 });
+ } else if (currentMin > 30 && currentMin < 45) {
+ start.set({ 'minute': 45 });
+ } else {
+ start.addHours(1).set({ 'minute': 0 });
+ }
+
+ $dialog.find('#unavailable-start').val(GeneralFunctions.formatDate(start, GlobalVariables.dateFormat, true));
+ $dialog.find('#unavailable-end').val(GeneralFunctions.formatDate(start.addHours(1), GlobalVariables.dateFormat, true));
+ $dialog.find('.modal-header h3').text(EALang['new_unavailable_title']);
+ $dialog.modal('show');
+ });
+ }
+
+ /**
+ * Reset unavailable dialog form.
+ *
+ * Reset the "#manage-unavailable" dialog. Use this method to bring the dialog to the initial state
+ * before it becomes visible to the user.
+ */
+ function _resetUnavailableDialog() {
+ var $dialog = $('#manage-unavailable');
+
+ $dialog.find('#unavailable-id').val('');
+
+ // Set default time values
+ var start = GeneralFunctions.formatDate(new Date(), GlobalVariables.dateFormat, true);
+ var end = GeneralFunctions.formatDate(new Date().addHours(1), GlobalVariables.dateFormat, true);
+ var dateFormat;
+
+ switch(GlobalVariables.dateFormat) {
+ case 'DMY':
+ dateFormat = 'dd/mm/yy';
+ break;
+ case 'MDY':
+ dateFormat = 'mm/dd/yy';
+ break;
+ case 'YMD':
+ dateFormat = 'yy/mm/dd';
+ break;
+ }
+
+
+ $dialog.find('#unavailable-start').datetimepicker({
+ dateFormat: dateFormat,
+
+ // Translation
+ 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),
+ 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),
+ EALang['thursday'].substr(0,2), EALang['friday'].substr(0,2),
+ EALang['saturday'].substr(0,2)],
+ monthNames: [EALang['january'], EALang['february'], EALang['march'], EALang['april'],
+ EALang['may'], EALang['june'], EALang['july'], EALang['august'], EALang['september'],
+ EALang['october'], EALang['november'], EALang['december']],
+ prevText: EALang['previous'],
+ nextText: EALang['next'],
+ currentText: EALang['now'],
+ closeText: EALang['close'],
+ timeOnlyTitle: EALang['select_time'],
+ timeText: EALang['time'],
+ hourText: EALang['hour'],
+ minuteText: EALang['minutes'],
+ firstDay: 1
+ });
+ $dialog.find('#unavailable-start').val(start);
+
+ $dialog.find('#unavailable-end').datetimepicker({
+ dateFormat: dateFormat,
+
+ // Translation
+ 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),
+ 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),
+ EALang['thursday'].substr(0,2), EALang['friday'].substr(0,2),
+ EALang['saturday'].substr(0,2)],
+ monthNames: [EALang['january'], EALang['february'], EALang['march'], EALang['april'],
+ EALang['may'], EALang['june'], EALang['july'], EALang['august'], EALang['september'],
+ EALang['october'], EALang['november'], EALang['december']],
+ prevText: EALang['previous'],
+ nextText: EALang['next'],
+ currentText: EALang['now'],
+ closeText: EALang['close'],
+ timeOnlyTitle: EALang['select_time'],
+ timeText: EALang['time'],
+ hourText: EALang['hour'],
+ minuteText: EALang['minutes'],
+ firstDay: 1
+ });
+ $dialog.find('#unavailable-end').val(end);
+
+ // Clear the unavailable notes field.
+ $dialog.find('#unavailable-notes').val('');
+ }
+
+ exports.initialize = function() {
+ _bindEventHandlers();
+ };
+
+})(window.BackendCalendarUnavailabilitiesModal);