From cf6e635aadcd5ab2d912e9780434ae1e5d0b598d Mon Sep 17 00:00:00 2001 From: Alex Tselegidis Date: Thu, 31 Mar 2016 20:08:21 +0200 Subject: [PATCH] Implements #142: Grey out unavailable calendar dates --- src/application/controllers/appointments.php | 61 +++++++++++++++++ src/assets/js/frontend_book.js | 71 +++++++++++++++++++- 2 files changed, 129 insertions(+), 3 deletions(-) diff --git a/src/application/controllers/appointments.php b/src/application/controllers/appointments.php index 356f0d15..3dfa8924 100755 --- a/src/application/controllers/appointments.php +++ b/src/application/controllers/appointments.php @@ -770,6 +770,67 @@ class Appointments extends CI_Controller { return $available_hours; } + + /** + * [AJAX] Get Unavailable Dates + * + * Get an array with the available dates of a specific provider, service and month + * of the year. Provide the "provider_id", "service_id" and "selected_date" as GET + * parameters to the request. The "selected_date" parameter must have the Y-m-d format. + * + * @return string Returns a JSON array with the dates that are unavailable. + */ + public function ajax_get_unavailable_dates() { + try { + $provider_id = $this->input->get('provider_id'); + $service_id = $this->input->get('service_id'); + $selected_date = new DateTime($this->input->get('selected_date')); + $number_of_days = (int)$selected_date->format('t'); + $unavailable_dates = array(); + + // Handle the "Any Provider" case. + if ($provider_id === ANY_PROVIDER) { + $provider_id = $this->search_any_provider($service_id, $this->input->get('selected_date')); + if ($provider_id === NULL) { // No provider is available in the selected date. + for ($i=1; $i<=$number_of_days; $i++) { + $current_date = new DateTime($selected_date->format('Y-m') . '-' . $i); + $unavailable_dates[] = $current_date->format('Y-m-d'); + } + echo json_encode($unavailable_dates); + return; + } + } + + // Get the available time periods for every day of this month. + $this->load->model('services_model'); + $service_duration = (int)$this->services_model->get_value('duration', $service_id); + + for ($i=1; $i<=$number_of_days; $i++) { + $current_date = new DateTime($selected_date->format('Y-m') . '-' . $i); + + if ($current_date < new DateTime()) { // Past dates become immediatelly unavailable. + $unavailable_dates[] = $current_date->format('Y-m-d'); + continue; + } + + $empty_periods = $this->get_provider_available_time_periods($provider_id, + $current_date->format('Y-m-d')); + + $available_hours = $this->calculate_available_hours($empty_periods, $current_date->format('Y-m-d'), + $service_duration); + + if (empty($available_hours)) { + $unavailable_dates[] = $current_date->format('Y-m-d'); + } + } + + echo json_encode($unavailable_dates); + } catch(Exception $exc) { + echo json_encode(array( + 'exceptions' => array(exceptionToJavaScript($exc)) + )); + } + } } /* End of file appointments.php */ diff --git a/src/assets/js/frontend_book.js b/src/assets/js/frontend_book.js index b29d5e65..d442b72b 100644 --- a/src/assets/js/frontend_book.js +++ b/src/assets/js/frontend_book.js @@ -84,6 +84,12 @@ var FrontendBook = { onSelect: function(dateText, instance) { FrontendBook.getAvailableHours(dateText); FrontendBook.updateConfirmFrame(); + }, + + onChangeMonthYear: function(year, month, instance) { + var currentDate = new Date(year, month - 1, 1); + FrontendBook.getUnavailableDates($('#select-provider').val(), $('#select-service').val(), + currentDate.toString('yyyy-MM-dd')); } }); @@ -116,7 +122,8 @@ var FrontendBook = { * date - time periods must be updated. */ $('#select-provider').change(function() { - FrontendBook.getAvailableHours(Date.today().toString('dd-MM-yyyy')); + FrontendBook.getUnavailableDates($(this).val(), $('#select-service').val(), + $('#select-date').datepicker('getDate').toString('yyyy-MM-dd')); FrontendBook.updateConfirmFrame(); }); @@ -148,8 +155,8 @@ var FrontendBook = { $('#select-provider').append(new Option('- ' +EALang['any_provider'] + ' -', 'any-provider')); } - - FrontendBook.getAvailableHours($('#select-date').val()); + FrontendBook.getUnavailableDates($('#select-provider').val(), $(this).val(), + $('#select-date').datepicker('getDate').toString('yyyy-MM-dd')); FrontendBook.updateConfirmFrame(); FrontendBook.updateServiceDescription($('#select-service').val(), $('#service-description')); }); @@ -698,5 +705,63 @@ var FrontendBook = { .always(function() { $layer.remove(); }) + }, + + /** + * Get the unavailable dates of a provider. + * + * This method will fetch the unavailable dates of the selected provider and service and then it will + * select the first available date (if any). It uses the "getAvailableHours" method to fetch the appointment + * hours of the selected date. + * + * @param {int} providerId The selected provider ID. + * @param {int} serviceId The selected service ID. + * @param {string} selectedDateString Y-m-d value of the selected date. + */ + getUnavailableDates: function(providerId, serviceId, selectedDateString) { + var url = GlobalVariables.baseUrl + '/index.php/appointments/ajax_get_unavailable_dates', + data = { + provider_id: providerId, + service_id: serviceId, + selected_date: encodeURIComponent(selectedDateString), + csrfToken: GlobalVariables.csrfToken + }; + + $.ajax({ + url: url, + type: 'GET', + data: data, + dataType: 'json' + }) + .done(function(response) { + // Select first enabled date. + var selectedDate = Date.parse(selectedDateString), + numberOfDays = new Date(selectedDate.getFullYear(), selectedDate.getMonth() + 1, 0).getDate(); + + for (var i=1; i<=numberOfDays; i++) { + var currentDate = new Date(selectedDate.getFullYear(), selectedDate.getMonth(), i); + if ($.inArray(currentDate.toString('yyyy-MM-dd'), response) === -1) { + $('#select-date').datepicker('setDate', currentDate); + FrontendBook.getAvailableHours(currentDate.toString('yyyy-MM-dd')); + break; + } + } + + // If all the days are unavailable then hide the appointments hours. + if (response.length === numberOfDays) { + $('#available-hours').text(EALang['no_available_hours']); + } + + // Apply the new beforeShowDayHandler method to the #select-date datepicker. + var beforeShowDayHandler = function(date) { + if ($.inArray(date.toString('yyyy-MM-dd'), response) != -1) { + return [false]; + } + return [true]; + }; + + $('#select-date').datepicker('option', 'beforeShowDay', beforeShowDayHandler); + }) + .fail(GeneralFunctions.ajaxFailureHandler); } };