mirror of
https://github.com/alextselegidis/easyappointments.git
synced 2024-11-22 16:02:54 +03:00
Added user friendly display of exceptions, raised on php (need to apply this methodology to the rest of the code).
This commit is contained in:
parent
6050bf75c3
commit
bd6cab36f0
6 changed files with 440 additions and 323 deletions
|
@ -19,59 +19,64 @@ class Appointments extends CI_Controller {
|
|||
$this->load->model('Settings_Model');
|
||||
|
||||
if (strtoupper($_SERVER['REQUEST_METHOD']) !== 'POST') {
|
||||
$available_services = $this->Services_Model->get_available_services();
|
||||
$available_providers = $this->Providers_Model->get_available_providers();
|
||||
$company_name = $this->Settings_Model->get_setting('company_name');
|
||||
try {
|
||||
$available_services = $this->Services_Model->get_available_services();
|
||||
$available_providers = $this->Providers_Model->get_available_providers();
|
||||
$company_name = $this->Settings_Model->get_setting('company_name');
|
||||
|
||||
// If an appointment hash is provided then it means that the customer
|
||||
// is trying to edit a registered record.
|
||||
if ($appointment_hash !== ''){
|
||||
// Load the appointments data and set the manage mode of the page.
|
||||
$manage_mode = TRUE;
|
||||
|
||||
$results = $this->Appointments_Model
|
||||
->get_batch(array('hash' => $appointment_hash));
|
||||
|
||||
if (count($results) === 0) {
|
||||
// The requested appointment doesn't exist in the database. Display
|
||||
// a message to the customer.
|
||||
$view_data = array(
|
||||
'message_title' => 'Appointment Not Found!',
|
||||
'message_text' => 'The appointment you requested does not exist in the '
|
||||
. 'database anymore.',
|
||||
'message_icon' => $this->config->item('base_url') . 'assets/images/error.png'
|
||||
);
|
||||
// If an appointment hash is provided then it means that the customer
|
||||
// is trying to edit a registered appointment record.
|
||||
if ($appointment_hash !== ''){
|
||||
// Load the appointments data and enable the manage mode of the page.
|
||||
$manage_mode = TRUE;
|
||||
|
||||
$appointments_results = $this->Appointments_Model
|
||||
->get_batch(array('hash' => $appointment_hash));
|
||||
|
||||
$this->load->view('appointments/message', $view_data);
|
||||
return;
|
||||
}
|
||||
|
||||
// Php 5.3 does not support treating a function result as an array.
|
||||
$appointment_data = $results[0];
|
||||
|
||||
$provider_data = $this->Providers_Model
|
||||
->get_row($appointment_data['id_users_provider']);
|
||||
$customer_data = $this->Customers_Model
|
||||
->get_row($appointment_data['id_users_customer']);
|
||||
} else {
|
||||
// The customer is going to book an appointment so there is no
|
||||
// need for the manage functionality to be initialized.
|
||||
$manage_mode = FALSE;
|
||||
$appointment_data = array();
|
||||
$provider_data = array();
|
||||
$customer_data = array();
|
||||
}
|
||||
if (count($appointments_results) === 0) {
|
||||
// The requested appointment doesn't exist in the database. Display
|
||||
// a message to the customer.
|
||||
$view_data = array(
|
||||
'message_title' => 'Appointment Not Found!',
|
||||
'message_text' => 'The appointment you requested does not exist in '
|
||||
. 'the system database anymore.',
|
||||
'message_icon' => $this->config->item('base_url')
|
||||
. 'assets/images/error.png'
|
||||
);
|
||||
$this->load->view('appointments/message', $view_data);
|
||||
return;
|
||||
}
|
||||
|
||||
// Load the book appointment view.
|
||||
$view_data = array (
|
||||
'available_services' => $available_services,
|
||||
'available_providers' => $available_providers,
|
||||
'company_name' => $company_name,
|
||||
'manage_mode' => $manage_mode,
|
||||
'appointment_data' => $appointment_data,
|
||||
'provider_data' => $provider_data,
|
||||
'customer_data' => $customer_data
|
||||
);
|
||||
$appointment_data = $appointments_results[0];
|
||||
|
||||
$provider_data = $this->Providers_Model
|
||||
->get_row($appointment_data['id_users_provider']);
|
||||
$customer_data = $this->Customers_Model
|
||||
->get_row($appointment_data['id_users_customer']);
|
||||
|
||||
} else {
|
||||
// The customer is going to book a new appointment so there is no
|
||||
// need for the manage functionality to be initialized.
|
||||
$manage_mode = FALSE;
|
||||
$appointment_data = array();
|
||||
$provider_data = array();
|
||||
$customer_data = array();
|
||||
}
|
||||
|
||||
// Load the book appointment view.
|
||||
$view_data = array (
|
||||
'available_services' => $available_services,
|
||||
'available_providers' => $available_providers,
|
||||
'company_name' => $company_name,
|
||||
'manage_mode' => $manage_mode,
|
||||
'appointment_data' => $appointment_data,
|
||||
'provider_data' => $provider_data,
|
||||
'customer_data' => $customer_data
|
||||
);
|
||||
|
||||
} catch(Exception $exc) {
|
||||
$view_data['exceptions'][] = $exc;
|
||||
}
|
||||
|
||||
$this->load->view('appointments/book', $view_data);
|
||||
|
||||
|
@ -79,6 +84,7 @@ class Appointments extends CI_Controller {
|
|||
// The page is a post-back. Register the appointment and send notification emails
|
||||
// to the provider and the customer that are related to the appointment. If google
|
||||
// sync is enabled then add the appointment to the provider's account.
|
||||
|
||||
try {
|
||||
$post_data = json_decode($_POST['post_data'], true);
|
||||
$appointment_data = $post_data['appointment'];
|
||||
|
@ -104,66 +110,74 @@ class Appointments extends CI_Controller {
|
|||
// :: SYNCHRONIZE APPOINTMENT WITH PROVIDER'S GOOGLE CALENDAR
|
||||
// The provider must have previously granted access to his google calendar account
|
||||
// in order to sync the appointment.
|
||||
$google_sync = $this->Providers_Model->get_setting('google_sync',
|
||||
$appointment_data['id_users_provider']);
|
||||
try {
|
||||
$google_sync = $this->Providers_Model->get_setting('google_sync',
|
||||
$appointment_data['id_users_provider']);
|
||||
|
||||
if ($google_sync == TRUE) {
|
||||
$google_token = json_decode($this->Providers_Model
|
||||
->get_setting('google_token', $appointment_data['id_users_provider']));
|
||||
|
||||
$this->load->library('google_sync');
|
||||
$this->google_sync->refresh_token($google_token->refresh_token);
|
||||
if ($google_sync == TRUE) {
|
||||
$google_token = json_decode($this->Providers_Model
|
||||
->get_setting('google_token', $appointment_data['id_users_provider']));
|
||||
|
||||
if ($post_data['manage_mode'] === FALSE) {
|
||||
// Add appointment to Google Calendar.
|
||||
$this->google_sync->add_appointment($appointment_data['id']);
|
||||
} else {
|
||||
// Update appointment to Google Calendar.
|
||||
$appointment_data['id_google_calendar'] =
|
||||
$this->Appointments_Model
|
||||
$this->load->library('google_sync');
|
||||
$this->google_sync->refresh_token($google_token->refresh_token);
|
||||
|
||||
if ($post_data['manage_mode'] === FALSE) {
|
||||
// Add appointment to Google Calendar.
|
||||
$this->google_sync->add_appointment($appointment_data, $provider_data,
|
||||
$service_data, $customer_data, $company_settings);
|
||||
} else {
|
||||
// Update appointment to Google Calendar.
|
||||
$appointment_data['id_google_calendar'] = $this->Appointments_Model
|
||||
->get_value('id_google_calendar', $appointment_data['id']);
|
||||
|
||||
$this->google_sync->update_appointment($appointment_data, $provider_data,
|
||||
$service_data, $customer_data, $company_settings);
|
||||
}
|
||||
}
|
||||
|
||||
$this->google_sync->update_appointment($appointment_data, $provider_data,
|
||||
$service_data, $customer_data, $company_settings);
|
||||
}
|
||||
}
|
||||
} catch(SyncException $syn_exc) {
|
||||
$view_data['exceptions'][] = $syn_exc;
|
||||
}
|
||||
|
||||
// :: SEND NOTIFICATION EMAILS TO BOTH CUSTOMER AND PROVIDER
|
||||
$this->load->library('Notifications');
|
||||
|
||||
if (!$post_data['manage_mode']) {
|
||||
$customer_title = 'Your appointment has been successfully booked!';
|
||||
$customer_message = 'Thank you for arranging an appointment with us. '
|
||||
. 'Below you can see the appointment details. Make changes '
|
||||
. 'by clicking the appointment link.';
|
||||
$customer_link = $this->config->item('base_url') . 'appointments/index/'
|
||||
. $appointment_data['hash'];
|
||||
|
||||
$provider_title = 'A new appointment has been added to your plan.';
|
||||
$provider_message = 'You can make changes by clicking the appointment '
|
||||
. 'link below';
|
||||
$provider_link = $this->config->item('base_url') . 'backend/'
|
||||
. $appointment_data['hash'];
|
||||
} else {
|
||||
$customer_title = 'Appointment changes have been successfully saved!';
|
||||
$customer_message = '';
|
||||
$customer_link = $this->config->item('base_url') . 'appointments/index/'
|
||||
. $appointment_data['hash'];
|
||||
|
||||
$provider_title = 'Appointment details have changed.';
|
||||
$provider_message = '';
|
||||
$provider_link = $this->config->item('base_url') . 'backend/'
|
||||
. $appointment_data['hash'];
|
||||
try {
|
||||
$this->load->library('Notifications');
|
||||
|
||||
if (!$post_data['manage_mode']) {
|
||||
$customer_title = 'Your appointment has been successfully booked!';
|
||||
$customer_message = 'Thank you for arranging an appointment with us. '
|
||||
. 'Below you can see the appointment details. Make changes '
|
||||
. 'by clicking the appointment link.';
|
||||
$customer_link = $this->config->item('base_url') . 'appointments/index/'
|
||||
. $appointment_data['hash'];
|
||||
|
||||
$provider_title = 'A new appointment has been added to your plan.';
|
||||
$provider_message = 'You can make changes by clicking the appointment '
|
||||
. 'link below';
|
||||
$provider_link = $this->config->item('base_url') . 'backend/'
|
||||
. $appointment_data['hash'];
|
||||
} else {
|
||||
$customer_title = 'Appointment changes have been successfully saved!';
|
||||
$customer_message = '';
|
||||
$customer_link = $this->config->item('base_url') . 'appointments/index/'
|
||||
. $appointment_data['hash'];
|
||||
|
||||
$provider_title = 'Appointment details have changed.';
|
||||
$provider_message = '';
|
||||
$provider_link = $this->config->item('base_url') . 'backend/'
|
||||
. $appointment_data['hash'];
|
||||
}
|
||||
|
||||
$this->notifications->send_appointment_details($appointment_data, $provider_data,
|
||||
$service_data, $customer_data,$company_settings, $customer_title,
|
||||
$customer_message, $customer_link, $customer_data['email']);
|
||||
|
||||
$this->notifications->send_appointment_details($appointment_data, $provider_data,
|
||||
$service_data, $customer_data, $company_settings, $provider_title,
|
||||
$provider_message, $provider_link, $provider_data['email']);
|
||||
} catch(NotificationException $not_exc) {
|
||||
$view_data['exceptions'][] = $not_exc;
|
||||
}
|
||||
|
||||
$this->notifications->send_appointment_details($appointment_data, $provider_data,
|
||||
$service_data, $customer_data,$company_settings, $customer_title,
|
||||
$customer_message, $customer_link, $customer_data['email']);
|
||||
|
||||
$this->notifications->send_appointment_details($appointment_data, $provider_data,
|
||||
$service_data, $customer_data, $company_settings, $provider_title,
|
||||
$provider_message, $provider_link, $provider_data['email']);
|
||||
|
||||
|
||||
// :: LOAD THE BOOK SUCCESS VIEW
|
||||
$view_data = array(
|
||||
'appointment_data' => $appointment_data,
|
||||
|
@ -173,10 +187,7 @@ class Appointments extends CI_Controller {
|
|||
);
|
||||
|
||||
} catch(Exception $exc) {
|
||||
$view_data['error'] = array(
|
||||
'message' => $exc->getMessage(),
|
||||
'technical' => $exc->getTraceAsString()
|
||||
);
|
||||
$view_data['exceptions'][] = $exc;
|
||||
}
|
||||
|
||||
$this->load->view('appointments/book_success', $view_data);
|
||||
|
@ -257,14 +268,15 @@ class Appointments extends CI_Controller {
|
|||
/**
|
||||
* [AJAX] Get the available appointment hours for the given date.
|
||||
*
|
||||
* This method answers to an AJAX request. It calculates the available hours for the
|
||||
* given service, provider and date.
|
||||
* This method answers to an AJAX request. It calculates the available hours
|
||||
* for thegiven service, provider and date.
|
||||
*
|
||||
* @param numeric $_POST['service_id'] The selected service's record id.
|
||||
* @param numeric $_POST['provider_id'] The selected provider's record id.
|
||||
* @param string $_POST['selected_date'] The selected date of which the available hours
|
||||
* we want to see.
|
||||
* @param numeric $_POST['service_duration'] The selected service duration in minutes.
|
||||
* @param string $_POST['selected_date'] The selected date of which the
|
||||
* available hours we want to see.
|
||||
* @param numeric $_POST['service_duration'] The selected service duration in
|
||||
* minutes.
|
||||
* @return Returns a json object with the available hours.
|
||||
*/
|
||||
public function ajax_get_available_hours() {
|
||||
|
@ -272,78 +284,86 @@ class Appointments extends CI_Controller {
|
|||
$this->load->model('Appointments_Model');
|
||||
$this->load->model('Settings_Model');
|
||||
|
||||
// If manage mode is TRUE then the following we should not consider the selected
|
||||
// appointment when calculating the available time periods of the provider.
|
||||
$exclude_appointments = ($_POST['manage_mode'] === 'true')
|
||||
? array($_POST['appointment_id'])
|
||||
: array();
|
||||
|
||||
$empty_periods = $this->get_provider_available_time_periods($_POST['provider_id'],
|
||||
$_POST['selected_date'], $exclude_appointments);
|
||||
|
||||
// Calculate the available appointment hours for the given date.
|
||||
// The empty spaces are broken down to 15 min and if the service
|
||||
// fit in each quarter then a new available hour is added to the
|
||||
// $available hours array.
|
||||
$available_hours = array();
|
||||
|
||||
foreach($empty_periods as $period) {
|
||||
$start_hour = new DateTime($_POST['selected_date'] . ' ' . $period['start']);
|
||||
$end_hour = new DateTime($_POST['selected_date'] . ' ' . $period['end']);
|
||||
|
||||
$minutes = $start_hour->format('i');
|
||||
|
||||
if ($minutes % 15 != 0) {
|
||||
// Change the start hour of the current space in order to be
|
||||
// on of the following: 00, 15, 30, 45.
|
||||
if ($minutes < 15) {
|
||||
$start_hour->setTime($start_hour->format('H'), 15);
|
||||
} else if ($minutes < 30) {
|
||||
$start_hour->setTime($start_hour->format('H'), 30);
|
||||
} else if ($minutes < 45) {
|
||||
$start_hour->setTime($start_hour->format('H'), 45);
|
||||
} else {
|
||||
$start_hour->setTime($start_hour->format('H') + 1, 00);
|
||||
try {
|
||||
// If manage mode is TRUE then the following we should not consider the selected
|
||||
// appointment when calculating the available time periods of the provider.
|
||||
$exclude_appointments = ($_POST['manage_mode'] === 'true')
|
||||
? array($_POST['appointment_id'])
|
||||
: array();
|
||||
|
||||
$empty_periods = $this->get_provider_available_time_periods($_POST['provider_id'],
|
||||
$_POST['selected_date'], $exclude_appointments);
|
||||
|
||||
// Calculate the available appointment hours for the given date.
|
||||
// The empty spaces are broken down to 15 min and if the service
|
||||
// fit in each quarter then a new available hour is added to the
|
||||
// $available hours array.
|
||||
|
||||
$available_hours = array();
|
||||
|
||||
foreach($empty_periods as $period) {
|
||||
$start_hour = new DateTime($_POST['selected_date'] . ' ' . $period['start']);
|
||||
$end_hour = new DateTime($_POST['selected_date'] . ' ' . $period['end']);
|
||||
|
||||
$minutes = $start_hour->format('i');
|
||||
|
||||
if ($minutes % 15 != 0) {
|
||||
// Change the start hour of the current space in order to be
|
||||
// on of the following: 00, 15, 30, 45.
|
||||
if ($minutes < 15) {
|
||||
$start_hour->setTime($start_hour->format('H'), 15);
|
||||
} else if ($minutes < 30) {
|
||||
$start_hour->setTime($start_hour->format('H'), 30);
|
||||
} else if ($minutes < 45) {
|
||||
$start_hour->setTime($start_hour->format('H'), 45);
|
||||
} else {
|
||||
$start_hour->setTime($start_hour->format('H') + 1, 00);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$curr_hour = $start_hour;
|
||||
$diff = $curr_hour->diff($end_hour);
|
||||
|
||||
while(($diff->h * 60 + $diff->i) > intval($_POST['service_duration'])) {
|
||||
$available_hours[] = $curr_hour->format('H:i');
|
||||
$curr_hour->add(new DateInterval("PT15M"));
|
||||
|
||||
$curr_hour = $start_hour;
|
||||
$diff = $curr_hour->diff($end_hour);
|
||||
}
|
||||
}
|
||||
|
||||
// If the selected date is today, remove past hours. It is important
|
||||
// include the timeout before booking that is set in the backoffice
|
||||
// the system. Normally we might want the customer to book an appointment
|
||||
// that is at least half or one hour from now. The setting is stored in
|
||||
// minutes.
|
||||
if (date('m/d/Y', strtotime($_POST['selected_date'])) == date('m/d/Y')) {
|
||||
if ($_POST['manage_mode'] === 'true') {
|
||||
$book_advance_timeout = 0;
|
||||
} else {
|
||||
$book_advance_timeout = $this->Settings_Model
|
||||
->get_setting('book_advance_timeout');
|
||||
}
|
||||
|
||||
foreach($available_hours as $index=>$value) {
|
||||
$available_hour = strtotime($value);
|
||||
$current_hour = strtotime('+' . $book_advance_timeout
|
||||
. ' minutes', strtotime('now'));
|
||||
|
||||
if ($available_hour <= $current_hour) {
|
||||
unset($available_hours[$index]);
|
||||
|
||||
while(($diff->h * 60 + $diff->i) > intval($_POST['service_duration'])) {
|
||||
$available_hours[] = $curr_hour->format('H:i');
|
||||
$curr_hour->add(new DateInterval("PT15M"));
|
||||
$diff = $curr_hour->diff($end_hour);
|
||||
}
|
||||
}
|
||||
|
||||
// If the selected date is today, remove past hours. It is important
|
||||
// include the timeout before booking that is set in the backoffice
|
||||
// the system. Normally we might want the customer to book an appointment
|
||||
// that is at least half or one hour from now. The setting is stored in
|
||||
// minutes.
|
||||
if (date('m/d/Y', strtotime($_POST['selected_date'])) == date('m/d/Y')) {
|
||||
if ($_POST['manage_mode'] === 'true') {
|
||||
$book_advance_timeout = 0;
|
||||
} else {
|
||||
$book_advance_timeout = $this->Settings_Model->get_setting(
|
||||
'book_advance_timeout');
|
||||
}
|
||||
|
||||
foreach($available_hours as $index=>$value) {
|
||||
$available_hour = strtotime($value);
|
||||
$current_hour = strtotime('+' . $book_advance_timeout . ' minutes',
|
||||
strtotime('now'));
|
||||
|
||||
if ($available_hour <= $current_hour) {
|
||||
unset($available_hours[$index]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$available_hours = array_values($available_hours);
|
||||
|
||||
echo json_encode($available_hours);
|
||||
|
||||
} catch(Exception $exc) {
|
||||
echo json_encode(array(
|
||||
'exceptions' => array( exceptionToJavascript($exc) )
|
||||
));
|
||||
}
|
||||
|
||||
$available_hours = array_values($available_hours);
|
||||
|
||||
echo json_encode($available_hours);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -392,7 +412,7 @@ class Appointments extends CI_Controller {
|
|||
|
||||
} catch(Exception $exc) {
|
||||
echo json_encode(array(
|
||||
'error' => $exc->getMessage()
|
||||
'exceptions' => array( exceptionToJavascript($exc) )
|
||||
));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
<?php
|
||||
<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed');
|
||||
|
||||
/**
|
||||
* Database Exception Class
|
||||
|
@ -20,5 +20,54 @@ class NotificationException extends Exception {}
|
|||
*/
|
||||
class SyncException extends Exception {}
|
||||
|
||||
/**
|
||||
* Print an exception to an HTML text.
|
||||
*
|
||||
* This method is used to display exceptions in a way that is userful and easy
|
||||
* for the user to see. It uses the Bootstrap CSS accordion markup to display
|
||||
* the message and when the user clicks on it the exception trace will be revealed.
|
||||
*
|
||||
* @param Exception $exception The exception to be displayed.
|
||||
* @return string Returns the html markup of the exception.
|
||||
*/
|
||||
function exceptionToHtml($exception) {
|
||||
return
|
||||
'<div class="accordion" id="error-accordion">
|
||||
<div class="accordion-group">
|
||||
<div class="accordion-heading">
|
||||
<a class="accordion-toggle" data-toggle="collapse"
|
||||
data-parent="#error-accordion" href="#error-technical">' .
|
||||
$exception->getMessage() . '
|
||||
</a>
|
||||
</div>
|
||||
<div id="error-technical" class="accordion-body collapse">
|
||||
<div class="accordion-inner">
|
||||
<pre>' . $exception->getTraceAsString() . '</pre>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>';
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a javascript object of a given exception.
|
||||
*
|
||||
* This method is pretty useful whenever we need to pass an exception object
|
||||
* to javascript during ajax calls.
|
||||
*
|
||||
* @param Exception $exception The given exception object.
|
||||
* @return string Returns the json encoded object of the exception.
|
||||
*/
|
||||
function exceptionToJavascript($exception) {
|
||||
return json_encode(array(
|
||||
'code' => $exception->getCode(),
|
||||
'file' => $exception->getFile(),
|
||||
'line' => $exception->getLine(),
|
||||
'message' => $exception->getMessage(),
|
||||
'previous' => $exception->getPrevious(),
|
||||
'trace' => $exception->getTraceAsString()
|
||||
));
|
||||
}
|
||||
|
||||
/* End of file exception_types_helper.php */
|
||||
/* Location: ./application/helpers/exception_types_helper.php */
|
|
@ -136,6 +136,19 @@
|
|||
}
|
||||
?>
|
||||
|
||||
<?php
|
||||
// ------------------------------------------------------
|
||||
// DISPLAY EXCEPTIONS (IF ANY)
|
||||
// ------------------------------------------------------
|
||||
if (isset($exceptions)) {
|
||||
echo '<div style="margin: 10px">';
|
||||
echo '<h4>Unexpected Errors</h4>';
|
||||
foreach($exceptions as $exception) {
|
||||
echo exceptionToHtml($exception);
|
||||
}
|
||||
echo '</div>';
|
||||
}
|
||||
?>
|
||||
<?php
|
||||
// ------------------------------------------------------
|
||||
// SELECT SERVICE AND PROVIDER
|
||||
|
|
|
@ -192,26 +192,14 @@
|
|||
</button>
|
||||
|
||||
<?php
|
||||
// Display error message (if any).
|
||||
if (isset($error)) {
|
||||
echo '
|
||||
<hr>
|
||||
<h4>An Unexpected Error Occured</h4>
|
||||
<div class="accordion" id="error-accordion">
|
||||
<div class="accordion-group">
|
||||
<div class="accordion-heading">
|
||||
<a class="accordion-toggle" data-toggle="collapse"
|
||||
data-parent="#error-accordion" href="#error-technical">' .
|
||||
$error['message'] . '
|
||||
</a>
|
||||
</div>
|
||||
<div id="error-technical" class="accordion-body collapse">
|
||||
<div class="accordion-inner">
|
||||
<pre>' . $error['technical'] . '</pre>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>';
|
||||
// Display exceptions (if any).
|
||||
if (isset($exceptions)) {
|
||||
echo '<div style="margin: 10px">';
|
||||
echo '<h4>Unexpected Errors</h4>';
|
||||
foreach($exceptions as $exception) {
|
||||
echo exceptionToHtml($exception);
|
||||
}
|
||||
echo '</div>';
|
||||
}
|
||||
?>
|
||||
</div>
|
||||
|
|
|
@ -21,7 +21,7 @@ var FrontendBook = {
|
|||
* @param {bool} manageMode (OPTIONAL) Determines whether the customer is going
|
||||
* to make changes to an existing appointment rather than booking a new one.
|
||||
*/
|
||||
initialize : function(bindEventHandlers, manageMode) {
|
||||
initialize: function(bindEventHandlers, manageMode) {
|
||||
if (bindEventHandlers === undefined) {
|
||||
bindEventHandlers = true; // Default Value
|
||||
}
|
||||
|
@ -44,10 +44,10 @@ var FrontendBook = {
|
|||
});
|
||||
|
||||
$('#select-date').datepicker({
|
||||
dateFormat : 'dd-mm-yy',
|
||||
minDate : 0,
|
||||
defaultDate : Date.today(),
|
||||
onSelect : function(dateText, instance) {
|
||||
dateFormat: 'dd-mm-yy',
|
||||
minDate: 0,
|
||||
defaultDate: Date.today(),
|
||||
onSelect: function(dateText, instance) {
|
||||
FrontendBook.getAvailableHours(dateText);
|
||||
FrontendBook.updateConfirmFrame();
|
||||
}
|
||||
|
@ -73,9 +73,9 @@ var FrontendBook = {
|
|||
* This method binds the necessary event handlers for the book
|
||||
* appointments page.
|
||||
*/
|
||||
bindEventHandlers : function() {
|
||||
bindEventHandlers: function() {
|
||||
/**
|
||||
* Event : Selected Provider "Changed"
|
||||
* Event: Selected Provider "Changed"
|
||||
*
|
||||
* Whenever the provider changes the available appointment
|
||||
* date - time periods must be updated.
|
||||
|
@ -86,7 +86,7 @@ var FrontendBook = {
|
|||
});
|
||||
|
||||
/**
|
||||
* Event : Selected Service "Changed"
|
||||
* Event: Selected Service "Changed"
|
||||
*
|
||||
* When the user clicks on a service, its available providers should
|
||||
* become visible.
|
||||
|
@ -113,7 +113,7 @@ var FrontendBook = {
|
|||
});
|
||||
|
||||
/**
|
||||
* Event : Next Step Button "Clicked"
|
||||
* Event: Next Step Button "Clicked"
|
||||
*
|
||||
* This handler is triggered every time the user pressed the
|
||||
* "next" button on the book wizard. Some special tasks might
|
||||
|
@ -155,7 +155,7 @@ var FrontendBook = {
|
|||
});
|
||||
|
||||
/**
|
||||
* Event : Back Step Button "Clicked"
|
||||
* Event: Back Step Button "Clicked"
|
||||
*
|
||||
* This handler is triggered every time the user pressed the
|
||||
* "back" button on the book wizard.
|
||||
|
@ -171,7 +171,7 @@ var FrontendBook = {
|
|||
});
|
||||
|
||||
/**
|
||||
* Event : Available Hour "Click"
|
||||
* Event: Available Hour "Click"
|
||||
*
|
||||
* Triggered whenever the user clicks on an available hour
|
||||
* for his appointment.
|
||||
|
@ -195,10 +195,10 @@ var FrontendBook = {
|
|||
event.preventDefault();
|
||||
|
||||
var dialogButtons = {
|
||||
'Yes' : function() {
|
||||
'Yes': function() {
|
||||
$('#cancel-appointment-form').submit();
|
||||
},
|
||||
'No' : function() {
|
||||
'No': function() {
|
||||
$('#message_box').dialog('close');
|
||||
}
|
||||
};
|
||||
|
@ -210,7 +210,7 @@ var FrontendBook = {
|
|||
}
|
||||
|
||||
/**
|
||||
* Event : Book Appointment Form "Submit"
|
||||
* Event: Book Appointment Form "Submit"
|
||||
*
|
||||
* Before the form is submitted to the server we need to make sure that
|
||||
* in the meantime the selected appointment date/time wasn't reserved by
|
||||
|
@ -219,37 +219,37 @@ var FrontendBook = {
|
|||
* @task Fix the problem with this event handler. Book does not work anymore.
|
||||
*/
|
||||
$('#book-appointment-form').submit(function() {
|
||||
event.preventDefault();
|
||||
|
||||
var formData = jQuery.parseJSON($('input[name="post_data"]').val());
|
||||
|
||||
var postData = {
|
||||
'id_users_provider' : formData['appointment']['id_users_provider'],
|
||||
'id_services' : formData['appointment']['id_services'],
|
||||
'start_datetime' : formData['appointment']['start_datetime']
|
||||
};
|
||||
|
||||
var postUrl = GlobalVariables.baseUrl + 'appointments/ajax_check_datetime_availability';
|
||||
|
||||
$.post(postUrl, postData, function(response) {
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
console.log('Check Date/Time Availability Post Response :', response);
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
|
||||
if (response.error) {
|
||||
GeneralFunctions.displayMessageBox('An Unexpected Error Occured',
|
||||
response.error);
|
||||
}
|
||||
|
||||
if (response === true) {
|
||||
$('#book-appointment-form').submit();
|
||||
} else {
|
||||
GeneralFunctions.displayMessageBox('Appointment Hour Taken', 'Unfortunately '
|
||||
+ 'the selected appointment hour is not available anymore. Please select '
|
||||
+ 'another hour.');
|
||||
FrontendBook.getAvailableHours($('#select-date').val());
|
||||
}
|
||||
}, 'json');
|
||||
// event.preventDefault();
|
||||
//
|
||||
// var formData = jQuery.parseJSON($('input[name="post_data"]').val());
|
||||
//
|
||||
// var postData = {
|
||||
// 'id_users_provider' : formData['appointment']['id_users_provider'],
|
||||
// 'id_services' : formData['appointment']['id_services'],
|
||||
// 'start_datetime' : formData['appointment']['start_datetime']
|
||||
// };
|
||||
//
|
||||
// var postUrl = GlobalVariables.baseUrl + 'appointments/ajax_check_datetime_availability';
|
||||
//
|
||||
// $.post(postUrl, postData, function(response) {
|
||||
// ////////////////////////////////////////////////////////////////////////
|
||||
// console.log('Check Date/Time Availability Post Response :', response);
|
||||
// ////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// if (response.error) {
|
||||
// GeneralFunctions.displayMessageBox('An Unexpected Error Occured',
|
||||
// response.error);
|
||||
// }
|
||||
//
|
||||
// if (response === true) {
|
||||
// $('#book-appointment-form').submit();
|
||||
// } else {
|
||||
// GeneralFunctions.displayMessageBox('Appointment Hour Taken', 'Unfortunately '
|
||||
// + 'the selected appointment hour is not available anymore. Please select '
|
||||
// + 'another hour.');
|
||||
// FrontendBook.getAvailableHours($('#select-date').val());
|
||||
// }
|
||||
// }, 'json');
|
||||
});
|
||||
},
|
||||
|
||||
|
@ -260,7 +260,7 @@ var FrontendBook = {
|
|||
* @param {string} selDate The selected date of which the available
|
||||
* hours we need to receive.
|
||||
*/
|
||||
getAvailableHours : function(selDate) {
|
||||
getAvailableHours: function(selDate) {
|
||||
// Find the selected service duration (it is going to
|
||||
// be send within the "postData" object.
|
||||
var selServiceDuration = 15; // Default value of duration (in minutes).
|
||||
|
@ -276,70 +276,69 @@ var FrontendBook = {
|
|||
? GlobalVariables.appointmentData['id'] : undefined;
|
||||
|
||||
var postData = {
|
||||
'service_id' : $('#select-service').val(),
|
||||
'provider_id' : $('#select-provider').val(),
|
||||
'selected_date' : selDate,
|
||||
'service_duration' : selServiceDuration,
|
||||
'manage_mode' : FrontendBook.manageMode,
|
||||
'appointment_id' : appointmentId
|
||||
};
|
||||
'service_id': $('#select-service').val(),
|
||||
'provider_id': $('#select-provider').val(),
|
||||
'selected_date': selDate,
|
||||
'service_duration': selServiceDuration,
|
||||
'manage_mode': FrontendBook.manageMode,
|
||||
'appointment_id': appointmentId
|
||||
}
|
||||
|
||||
// Make ajax post request and get the available hours.
|
||||
var ajaxurl = GlobalVariables.baseUrl + 'appointments/ajax_get_available_hours';
|
||||
jQuery.post(ajaxurl, postData, function(postResponse) {
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
//console.log('\n\n Get Available Hours Post Response :', postResponse, '\n\n');
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
jQuery.post(ajaxurl, postData, function(response) {
|
||||
///////////////////////////////////////////////////////////////
|
||||
//console.log('Get Available Hours JSON Response :', response);
|
||||
///////////////////////////////////////////////////////////////
|
||||
|
||||
try {
|
||||
var jsonResponse = jQuery.parseJSON(postResponse);
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
//console.log('\n\n Get Available Hours JSON Response :', jsonResponse, '\n\n');
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
if (jsonResponse.length > 0) {
|
||||
// Fill the available time div
|
||||
var currColumn = 1;
|
||||
$('#available-hours').html('<div style="width:50px; float:left;"></div>');
|
||||
|
||||
$.each(jsonResponse, function(index, availableHour) {
|
||||
if ((currColumn * 10) < (index + 1)) {
|
||||
currColumn++;
|
||||
$('#available-hours')
|
||||
.append('<div style="width:50px; float:left;"></div>');
|
||||
}
|
||||
|
||||
$('#available-hours div:eq(' + (currColumn - 1) + ')')
|
||||
.append('<span class="available-hour">' + availableHour
|
||||
+ '</span><br/>');
|
||||
});
|
||||
|
||||
if (FrontendBook.manageMode) {
|
||||
// Set the appointment start time as selected.
|
||||
$('.available-hour').removeClass('selected-hour');
|
||||
$('.available-hour').filter(function() {
|
||||
return $(this).text() === Date.parseExact(
|
||||
GlobalVariables.appointmentData['start_datetime'],
|
||||
'yyyy-MM-dd HH:mm:ss').toString('HH:mm');
|
||||
}).addClass('selected-hour');
|
||||
} else {
|
||||
// Set the first item as selected.
|
||||
$('.available-hour:eq(0)').addClass('selected-hour');
|
||||
}
|
||||
|
||||
FrontendBook.updateConfirmFrame();
|
||||
} else {
|
||||
$('#available-hours').text('There are no available appointment'
|
||||
+ 'hours for the selected date. Please choose another '
|
||||
+ 'date.');
|
||||
}
|
||||
|
||||
} catch(exception) {
|
||||
if (response.exceptions) {
|
||||
// Display a friendly message to the user with the exceptions information.
|
||||
response.exceptions = GeneralFunctions.parseExceptions(response.exceptions);
|
||||
GeneralFunctions.displayMessageBox('Unexpected Error', 'An unexpected '
|
||||
+ 'error occured during the available hours calculation. Please '
|
||||
+ 'refresh the page and try again.');
|
||||
$('#message_box').append(GeneralFunctions.exceptionsToHtml(response.exceptions));
|
||||
console.log('Get Available Hours Exceptions:', response.exceptions);
|
||||
return;
|
||||
}
|
||||
});
|
||||
|
||||
// The response contains the available hours for the selected provider and
|
||||
// service. Fill the available hours div with response data.
|
||||
if (response.length > 0) {
|
||||
|
||||
var currColumn = 1;
|
||||
$('#available-hours').html('<div style="width:50px; float:left;"></div>');
|
||||
|
||||
$.each(response, function(index, availableHour) {
|
||||
if ((currColumn * 10) < (index + 1)) {
|
||||
currColumn++;
|
||||
$('#available-hours').append('<div style="width:50px; float:left;"></div>');
|
||||
}
|
||||
|
||||
$('#available-hours div:eq(' + (currColumn - 1) + ')').append(
|
||||
'<span class="available-hour">' + availableHour + '</span><br/>');
|
||||
});
|
||||
|
||||
if (FrontendBook.manageMode) {
|
||||
// Set the appointment's start time as the default selection.
|
||||
$('.available-hour').removeClass('selected-hour');
|
||||
$('.available-hour').filter(function() {
|
||||
return $(this).text() === Date.parseExact(
|
||||
GlobalVariables.appointmentData['start_datetime'],
|
||||
'yyyy-MM-dd HH:mm:ss').toString('HH:mm');
|
||||
}).addClass('selected-hour');
|
||||
} else {
|
||||
// Set the first available hour as the default selection.
|
||||
$('.available-hour:eq(0)').addClass('selected-hour');
|
||||
}
|
||||
|
||||
FrontendBook.updateConfirmFrame();
|
||||
|
||||
} else {
|
||||
$('#available-hours').text('There are no available appointment'
|
||||
+ 'hours for the selected date. Please choose another date.');
|
||||
}
|
||||
}, 'json');
|
||||
},
|
||||
|
||||
/**
|
||||
|
@ -348,7 +347,7 @@ var FrontendBook = {
|
|||
*
|
||||
* @return {bool} Returns the validation result.
|
||||
*/
|
||||
validateCustomerForm : function() {
|
||||
validateCustomerForm: function() {
|
||||
$('#wizard-frame-3 input').css('border', '');
|
||||
|
||||
try {
|
||||
|
@ -382,7 +381,7 @@ var FrontendBook = {
|
|||
* page with the latest customer settigns and input for the appointment
|
||||
* booking.
|
||||
*/
|
||||
updateConfirmFrame : function() {
|
||||
updateConfirmFrame: function() {
|
||||
// :: UPDATE APPOINTMENT DETAILS DIV
|
||||
var selectedDate = $('#select-date').datepicker('getDate');
|
||||
if (selectedDate !== null) {
|
||||
|
@ -420,22 +419,22 @@ var FrontendBook = {
|
|||
var postData = new Object();
|
||||
|
||||
postData['customer'] = {
|
||||
'last_name' : $('#last-name').val(),
|
||||
'first_name' : $('#first-name').val(),
|
||||
'email' : $('#email').val(),
|
||||
'phone_number' : $('#phone-number').val(),
|
||||
'address' : $('#address').val(),
|
||||
'city' : $('#city').val(),
|
||||
'zip_code' : $('#zip-code').val()
|
||||
'last_name': $('#last-name').val(),
|
||||
'first_name': $('#first-name').val(),
|
||||
'email': $('#email').val(),
|
||||
'phone_number': $('#phone-number').val(),
|
||||
'address': $('#address').val(),
|
||||
'city': $('#city').val(),
|
||||
'zip_code': $('#zip-code').val()
|
||||
};
|
||||
|
||||
postData['appointment'] = {
|
||||
'start_datetime' : $('#select-date').datepicker('getDate').toString('yyyy-MM-dd')
|
||||
+ ' ' + $('.selected-hour').text() + ':00',
|
||||
'end_datetime' : FrontendBook.calcEndDatetime(),
|
||||
'notes' : $('#notes').val(),
|
||||
'id_users_provider' : $('#select-provider').val(),
|
||||
'id_services' : $('#select-service').val()
|
||||
'start_datetime': $('#select-date').datepicker('getDate').toString('yyyy-MM-dd')
|
||||
+ ' ' + $('.selected-hour').text() + ':00',
|
||||
'end_datetime': FrontendBook.calcEndDatetime(),
|
||||
'notes': $('#notes').val(),
|
||||
'id_users_provider': $('#select-provider').val(),
|
||||
'id_services': $('#select-service').val()
|
||||
};
|
||||
|
||||
postData['manage_mode'] = FrontendBook.manageMode;
|
||||
|
@ -454,7 +453,7 @@ var FrontendBook = {
|
|||
*
|
||||
* @return {string} Returns the end datetime in string format.
|
||||
*/
|
||||
calcEndDatetime : function() {
|
||||
calcEndDatetime: function() {
|
||||
// Find selected service duration.
|
||||
var selServiceDuration = undefined;
|
||||
|
||||
|
@ -489,7 +488,7 @@ var FrontendBook = {
|
|||
* @param {object} customerData Selected customer's data.
|
||||
* @returns {bool} Returns the operation result.
|
||||
*/
|
||||
applyAppointmentData : function(appointmentData, providerData, customerData) {
|
||||
applyAppointmentData: function(appointmentData, providerData, customerData) {
|
||||
try {
|
||||
// Select Service & Provider
|
||||
$('#select-service').val(appointmentData['id_services']).trigger('change');
|
||||
|
@ -505,7 +504,6 @@ var FrontendBook = {
|
|||
$('#first-name').val(customerData['first_name']);
|
||||
$('#email').val(customerData['email']);
|
||||
$('#phone-number').val(customerData['phone_number']);
|
||||
|
||||
$('#address').val(customerData['address']);
|
||||
$('#city').val(customerData['city']);
|
||||
$('#zip-code').val(customerData['zip_code']);
|
||||
|
@ -516,7 +514,7 @@ var FrontendBook = {
|
|||
|
||||
return true;
|
||||
} catch(exc) {
|
||||
console.log(exc);
|
||||
console.log(exc); // log exception
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -175,5 +175,54 @@ var GeneralFunctions = {
|
|||
validateEmail: function(email) {
|
||||
var reg = /^([A-Za-z0-9_\-\.])+\@([A-Za-z0-9_\-\.])+\.([A-Za-z]{2,4})$/;
|
||||
return reg.test(email);
|
||||
},
|
||||
|
||||
/**
|
||||
* This method returns the exception html display for javascript ajax calls.
|
||||
* It uses the Bootstrap collapse module to show exception messages when the
|
||||
* user opens the "Details" collapse component.
|
||||
*
|
||||
* @param {array} exceptions Contains the exceptions to be displayed.
|
||||
* @returns {String} Returns the html markup for the exceptions.
|
||||
*/
|
||||
exceptionsToHtml: function(exceptions) {
|
||||
var html =
|
||||
'<div class="accordion" id="error-accordion">' +
|
||||
'<div class="accordion-group">' +
|
||||
'<div class="accordion-heading">' +
|
||||
'<a class="accordion-toggle" data-toggle="collapse" ' +
|
||||
'data-parent="#error-accordion" href="#error-technical">' +
|
||||
'Details' +
|
||||
'</a>' +
|
||||
'</div>';
|
||||
|
||||
$.each(exceptions, function(index, exception) {
|
||||
html +=
|
||||
'<div id="error-technical" class="accordion-body collapse">' +
|
||||
'<div class="accordion-inner">' +
|
||||
'<pre>' + exception['message'] + '</pre>' +
|
||||
'</div>' +
|
||||
'</div>';
|
||||
});
|
||||
|
||||
html += '</div></div>';
|
||||
|
||||
return html;
|
||||
},
|
||||
|
||||
/**
|
||||
* This method parse the json encoded strings that are fetched by ajax calls.
|
||||
*
|
||||
* @param {array} exceptions Exception array returned by an ajax call.
|
||||
* @returns {Array} Returns the parsed js objects.
|
||||
*/
|
||||
parseExceptions: function(exceptions) {
|
||||
var parsedExceptions = new Array();
|
||||
|
||||
$.each(exceptions, function(index, exception) {
|
||||
parsedExceptions.push(jQuery.parseJSON(exception));
|
||||
});
|
||||
|
||||
return parsedExceptions;
|
||||
}
|
||||
};
|
Loading…
Reference in a new issue