/* ---------------------------------------------------------------------------- * Easy!Appointments - Open Source Web Scheduler * * @package EasyAppointments * @author A.Tselegidis * @copyright Copyright (c) 2013 - 2016, Alex Tselegidis * @license https://opensource.org/licenses/GPL-3.0 - GPLv3 * @link https://easyappointments.org * @since v1.2.0 * ---------------------------------------------------------------------------- */ /** * Working plan utility. * * This module implements the functionality of table calendar view. * * Old Name: BackendCalendarTableView */ App.Utils.CalendarTableView = (function () { let $filterProvider; let $filterService; let lastFocusedEventData; /** * Bind the event handlers. */ function bindEventHandlers() { const $calendarToolbar = $('#calendar-toolbar'); const $calendar = $('#calendar'); $calendar.on('click', '.calendar-header .btn.previous', () => { const dayInterval = $('#select-filter-item').val(); const currentDate = $('.select-date').datepicker('getDate'); const startDate = moment(currentDate).subtract(1, 'days'); const endDate = startDate.clone().add(dayInterval - 1, 'days'); $('.select-date').datepicker('setDate', startDate.toDate()); createView(startDate.toDate(), endDate.toDate()); }); $calendar.on('click', '.calendar-header .btn.next', () => { const dayInterval = $('#select-filter-item').val(); const currentDate = $('.select-date').datepicker('getDate'); const startDate = moment(currentDate).add(1, 'days'); const endDate = startDate.clone().add(dayInterval - 1, 'days'); $('.select-date').datepicker('setDate', startDate.toDate()); createView(startDate.toDate(), endDate.toDate()); }); $calendarToolbar.on('change', '#select-filter-item', () => { const dayInterval = $('#select-filter-item').val(); const currentDate = $('.select-date').datepicker('getDate'); const startDate = moment(currentDate); const endDate = startDate.clone().add(dayInterval - 1, 'days'); createView(startDate.toDate(), endDate.toDate()); }); $calendarToolbar.on('click', '#reload-appointments', () => { // Remove all the events from the tables. $('.calendar-view .event').remove(); // Fetch the events and place them in the existing HTML format. const dayInterval = $('#select-filter-item').val(); const currentDate = $('.select-date').datepicker('getDate'); const startDateMoment = moment(currentDate); const startDate = startDateMoment.toDate(); const endDateMoment = startDateMoment.clone().add(dayInterval - 1, 'days'); const endDate = endDateMoment.toDate(); getCalendarEvents(startDate, endDate).done((response) => { const currentDate = startDate; while (currentDate <= endDate) { $('.calendar-view .date-column').each((index, dateColumn) => { const $dateColumn = $(dateColumn); const date = new Date($dateColumn.data('date')); if (currentDate.getTime() !== date.getTime()) { return true; } $dateColumn .find('.date-column-title') .text(App.Utils.Date.format(date, App.Vars.date_format, App.Vars.time_format)); $dateColumn.find('.provider-column').each(function (index, providerColumn) { const $providerColumn = $(providerColumn); const provider = $providerColumn.data('provider'); $providerColumn.find('.calendar-wrapper').fullCalendar('removeEvents'); createNonWorkingHours( $providerColumn.find('.calendar-wrapper'), $providerColumn.data('provider') ); // Add the appointments to the column. createAppointments($providerColumn, response.appointments); // Add the unavailability events to the column. createUnavailabilityEvents($providerColumn, response.unavailability_events); // Add the provider breaks to the column. const workingPlan = JSON.parse(provider.settings.working_plan); const day = moment(date).format('dddd').toLowerCase(); if (workingPlan[day]) { const breaks = workingPlan[day].breaks; createBreaks($providerColumn, breaks); } }); }); currentDate.add({days: 1}); } // setCalendarViewSize(); Backend.placeFooterToBottom(); }); }); /** * Event: On Window Resize */ $(window).on('resize', () => { setCalendarViewSize(); }); /** * Event: Popover Close Button "Click" * * Hides the open popover element. */ $calendar.on('click', '.close-popover', (event) => { $(event.target).parents('.popover').popover('dispose'); }); /** * Event: Popover Edit Button "Click" * * Enables the edit dialog of the selected table event. */ $calendar.on('click', '.edit-popover', (event) => { $(event.target).parents('.popover').popover('dispose'); let $dialog; 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 = () => { Backend.displayNotification(App.Lang.working_plan_exception_saved); const workingPlanExceptions = JSON.parse(provider.settings.working_plan_exceptions) || {}; workingPlanExceptions[date] = workingPlanException; for (const index in GlobalVariables.availableProviders) { const availableProvider = GlobalVariables.availableProviders[index]; if (Number(availableProvider.id) === Number(provider.id)) { availableProvider.settings.working_plan_exceptions = JSON.stringify(workingPlanExceptions); break; } } $('#select-filter-item').trigger('change'); // Update the calendar. }; App.Http.Calendar.saveWorkingPlanException( date, workingPlanException, provider.id, successCallback, null ); } ); } else if (lastFocusedEventData.data.is_unavailable === '0') { const appointment = lastFocusedEventData.data; $dialog = $('#appointments-modal'); BackendCalendarAppointmentsModal.resetAppointmentDialog(); // Apply appointment data and show modal dialog. $dialog.find('.modal-header h3').text(App.Lang.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. startMoment = moment(appointment.start_datetime); $dialog.find('#start-datetime').datetimepicker('setDate', startMoment); endMoment = moment(appointment.end_datetime); $dialog.find('#end-datetime').datetimepicker('setDate', endMoment); const 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-location').val(appointment.location); $dialog.find('#appointment-notes').val(appointment.notes); $dialog.find('#customer-notes').val(customer.notes); $dialog.modal('show'); } else { const unavailable = lastFocusedEventData.data; // Replace string date values with actual date objects. unavailable.start_datetime = lastFocusedEventData.start.format('YYYY-MM-DD HH:mm:ss'); startMoment = moment(unavailable.start_datetime); unavailable.end_datetime = lastFocusedEventData.end.format('YYYY-MM-DD HH:mm:ss'); endMoment = moment(unavailable.end_datetime); $dialog = $('#unavailabilities-modal'); BackendCalendarUnavailabilityEventsModal.resetUnavailableDialog(); // Apply unavailable data to dialog. $dialog.find('.modal-header h3').text('Edit Unavailable Period'); $dialog.find('#unavailable-start').datetimepicker('setDate', startMoment); $dialog.find('#unavailable-id').val(unavailable.id); $dialog.find('#unavailable-provider').val(unavailable.id_users_provider); $dialog.find('#unavailable-end').datetimepicker('setDate', endMoment); $dialog.find('#unavailable-notes').val(unavailable.notes); $dialog.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. */ $calendar.on('click', '.delete-popover', (event) => { $(event.target).parents('.popover').popover('dispose'); // Hide the popover. let url; let data; // If id_role parameter exists the popover is an working plan exception. if (lastFocusedEventData.data.hasOwnProperty('id_roles')) { // Do not display confirmation prompt. url = App.Utils.Url.siteUrl + '/index.php/backend_api/ajax_delete_working_plan_exception'; data = { csrf_token: App.Vars.csrf_token, working_plan_exception: lastFocusedEventData.start.format('YYYY-MM-DD'), provider_id: lastFocusedEventData.data.id }; $.post(url, data).done(() => { $('#message-box').dialog('close'); const workingPlanExceptions = JSON.parse( lastFocusedEventData.data.settings.working_plan_exceptions ); delete workingPlanExceptions[lastFocusedEventData.start.format('YYYY-MM-DD')]; lastFocusedEventData.data.settings.working_plan_exceptions = JSON.stringify(workingPlanExceptions); // Refresh calendar event items. $('#select-filter-item').trigger('change'); }); } else if (lastFocusedEventData.data.is_unavailable === '0') { const buttons = [ { text: App.Lang.cancel, click: function () { $('#message-box').dialog('close'); } }, { text: 'OK', click: () => { url = App.Utils.Url.siteUrl('backend_api/ajax_delete_appointment'); data = { csrf_token: App.Vars.csrf_token, appointment_id: lastFocusedEventData.data.id, delete_reason: $('#delete-reason').val() }; $.post(url, data).done(() => { $('#message-box').dialog('close'); // Refresh calendar event items. $('#select-filter-item').trigger('change'); }); } } ]; App.Utils.Message.show( App.Lang.delete_appointment_title, App.Lang.write_appointment_removal_reason, buttons ); $('