/* ---------------------------------------------------------------------------- * Easy!Appointments - Online Appointment Scheduler * * @package EasyAppointments * @author A.Tselegidis * @copyright Copyright (c) Alex Tselegidis * @license https://opensource.org/licenses/GPL-3.0 - GPLv3 * @link https://easyappointments.org * @since v1.5.0 * ---------------------------------------------------------------------------- */ /** * Default calendar view utility. * * This module implements the functionality of the default calendar view. * * Old Name: BackendCalendarDefaultView */ App.Utils.CalendarDefaultView = (function () { const $calendarPage = $('#calendar-page'); const $reloadAppointments = $('#reload-appointments'); const $calendar = $('#calendar'); const $selectFilterItem = $('#select-filter-item'); const $appointmentsModal = $('#appointments-modal'); const $unavailabilitiesModal = $('#unavailabilities-modal'); const $header = $('#header'); const $footer = $('#footer'); const $notification = $('#notification'); const $calendarToolbar = $('#calendar-toolbar'); const FILTER_TYPE_PROVIDER = 'provider'; const FILTER_TYPE_SERVICE = 'service'; let lastFocusedEventData; // Contains event data for later use. /** * Add the utility event listeners. */ function addEventListeners() { /** * Event: Reload Button "Click" * * When the user clicks the reload button, the calendar items need to be refreshed. */ $reloadAppointments.on('click', () => { const calendarView = $calendar.fullCalendar('getView'); refreshCalendarAppointments( $calendar, $selectFilterItem.val(), $selectFilterItem.find('option:selected').attr('type'), calendarView.start, calendarView.end ); }); /** * Event: Popover Close Button "Click" * * Hides the open popover element. */ $calendarPage.on('click', '.close-popover', (event) => { $(event.target).parents('.popover').popover('dispose'); }); /** * Event: Popover Edit Button "Click" * * Enables the edit dialog of the selected calendar event. * * @param {jQuery.Event} event */ $calendarPage.on('click', '.edit-popover', (event) => { const $target = $(event.target); $target.closest('.popover').popover('dispose'); let startMoment; let endMoment; if (lastFocusedEventData.data.workingPlanException) { const date = lastFocusedEventData.data.date; const workingPlanException = lastFocusedEventData.data.workingPlanException; const provider = lastFocusedEventData.data.provider; App.Components.WorkingPlanExceptionsModal.edit(date, workingPlanException).done( (date, workingPlanException) => { const successCallback = () => { App.Layouts.Backend.displayNotification(lang('working_plan_exception_saved')); const workingPlanExceptions = JSON.parse(provider.settings.working_plan_exceptions) || {}; workingPlanExceptions[date] = workingPlanException; for (const index in vars('available_providers')) { const availableProvider = vars('available_providers')[index]; if (Number(availableProvider.id) === Number(provider.id)) { availableProvider.settings.working_plan_exceptions = JSON.stringify(workingPlanExceptions); break; } } $selectFilterItem.trigger('change'); // Update the calendar. }; App.Http.Calendar.saveWorkingPlanException( date, workingPlanException, provider.id, successCallback, null ); } ); } else if (!lastFocusedEventData.data.is_unavailability) { const appointment = lastFocusedEventData.data; App.Components.AppointmentsModal.resetModal(); // Apply appointment data and show modal dialog. $appointmentsModal.find('.modal-header h3').text(lang('edit_appointment_title')); $appointmentsModal.find('#appointment-id').val(appointment.id); $appointmentsModal.find('#select-service').val(appointment.id_services).trigger('change'); $appointmentsModal.find('#select-provider').val(appointment.id_users_provider); // Set the start and end datetime of the appointment. startMoment = moment(appointment.start_datetime); $appointmentsModal.find('#start-datetime').datetimepicker('setDate', startMoment.toDate()); endMoment = moment(appointment.end_datetime); $appointmentsModal.find('#end-datetime').datetimepicker('setDate', endMoment.toDate()); const customer = appointment.customer; $appointmentsModal.find('#customer-id').val(appointment.id_users_customer); $appointmentsModal.find('#first-name').val(customer.first_name); $appointmentsModal.find('#last-name').val(customer.last_name); $appointmentsModal.find('#email').val(customer.email); $appointmentsModal.find('#phone-number').val(customer.phone_number); $appointmentsModal.find('#address').val(customer.address); $appointmentsModal.find('#city').val(customer.city); $appointmentsModal.find('#zip-code').val(customer.zip_code); $appointmentsModal.find('#appointment-location').val(appointment.location); $appointmentsModal.find('#appointment-notes').val(appointment.notes); $appointmentsModal.find('#customer-notes').val(customer.notes); $appointmentsModal.modal('show'); } else { const unavailability = lastFocusedEventData.data; // Replace string date values with actual date objects. unavailability.start_datetime = lastFocusedEventData.start.format('YYYY-MM-DD HH:mm:ss'); startMoment = moment(unavailability.start_datetime); unavailability.end_datetime = lastFocusedEventData.end.format('YYYY-MM-DD HH:mm:ss'); endMoment = moment(unavailability.end_datetime); App.Components.UnavailabilitiesModal.resetModal(); // Apply unavailability data to dialog. $unavailabilitiesModal.find('.modal-header h3').text('Edit Unavailability Period'); $unavailabilitiesModal.find('#unavailability-start').datetimepicker('setDate', startMoment.toDate()); $unavailabilitiesModal.find('#unavailability-id').val(unavailability.id); $unavailabilitiesModal.find('#unavailability-provider').val(unavailability.id_users_provider); $unavailabilitiesModal.find('#unavailability-end').datetimepicker('setDate', endMoment.toDate()); $unavailabilitiesModal.find('#unavailability-notes').val(unavailability.notes); $unavailabilitiesModal.modal('show'); } }); /** * Event: Popover Delete Button "Click" * * Displays a prompt on whether the user wants the appointment to be deleted. If he confirms the * deletion then an AJAX call is made to the server and deletes the appointment from the database. * * @param {jQuery.Event} event */ $calendarPage.on('click', '.delete-popover', (event) => { const $target = $(event.target); $target.parents('.popover').popover('dispose'); if (lastFocusedEventData.data.workingPlanException) { const providerId = $selectFilterItem.val(); const provider = vars('available_providers').find( (availableProvider) => Number(availableProvider.id) === Number(providerId) ); if (!provider) { throw new Error('Provider could not be found: ' + providerId); } const successCallback = () => { App.Layouts.Backend.displayNotification(lang('working_plan_exception_deleted')); const workingPlanExceptions = JSON.parse(provider.settings.working_plan_exceptions) || {}; delete workingPlanExceptions[date]; for (const index in vars('available_providers')) { const availableProvider = vars('available_providers')[index]; if (Number(availableProvider.id) === Number(providerId)) { availableProvider.settings.working_plan_exceptions = JSON.stringify(workingPlanExceptions); break; } } $selectFilterItem.trigger('change'); // Update the calendar. }; const date = lastFocusedEventData.start.format('YYYY-MM-DD'); App.Http.Calendar.deleteWorkingPlanException(date, providerId, successCallback); } else if (!lastFocusedEventData.data.is_unavailability) { const buttons = [ { text: lang('cancel'), click: () => { $('#message-box').dialog('close'); } }, { text: 'OK', click: () => { const appointmentId = lastFocusedEventData.data.id; const deleteReason = $('#delete-reason').val(); App.Http.Calendar.deleteAppointment(appointmentId, deleteReason).done(() => { $('#message-box').dialog('close'); // Refresh calendar event items. $selectFilterItem.trigger('change'); }); } } ]; App.Utils.Message.show( lang('delete_appointment_title'), lang('write_appointment_removal_reason'), buttons ); $('