Created
April 13, 2015 14:16
-
-
Save anonymous/9e49e4a67871f213a084 to your computer and use it in GitHub Desktop.
Change display of calendar to make only dates clickable in which there are free appointment slots
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed'); | |
class Appointments extends CI_Controller { | |
public function __construct() { | |
parent::__construct(); | |
$this->load->library('session'); | |
// Set user's selected language. | |
if ($this->session->userdata('language')) { | |
$this->config->set_item('language', $this->session->userdata('language')); | |
$this->lang->load('translations', $this->session->userdata('language')); | |
} else { | |
$this->lang->load('translations', $this->config->item('language')); // default | |
} | |
} | |
/** | |
* Default callback method of the application. | |
* | |
* This method creates the appointment book wizard. If an appointment hash | |
* is provided then it means that the customer followed the appointment | |
* manage link that was send with the book success email. | |
* | |
* @param string $appointment_hash The db appointment hash of an existing | |
* record. | |
*/ | |
public function index($appointment_hash = '') { | |
if (!$this->check_installation()) return; | |
$this->load->model('appointments_model'); | |
$this->load->model('providers_model'); | |
$this->load->model('services_model'); | |
$this->load->model('customers_model'); | |
$this->load->model('settings_model'); | |
if (strtoupper($_SERVER['REQUEST_METHOD']) !== 'POST') { | |
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 appointment record. | |
if ($appointment_hash !== ''){ | |
// Load the appointments data and enable 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 = array( | |
'message_title' => $this->lang->line('appointment_not_found'), | |
'message_text' => $this->lang->line('appointment_does_not_exist_in_db'), | |
'message_icon' => $this->config->item('base_url') | |
. 'assets/images/error.png', | |
'company_name' => $company_name | |
); | |
$this->load->view('appointments/message', $view); | |
return; | |
} | |
$appointment = $results[0]; | |
$provider = $this->providers_model->get_row($appointment['id_users_provider']); | |
$customer = $this->customers_model->get_row($appointment['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 = array(); | |
$provider = array(); | |
$customer = array(); | |
} | |
// Load the book appointment view. | |
$view = array ( | |
'available_services' => $available_services, | |
'available_providers' => $available_providers, | |
'company_name' => $company_name, | |
'manage_mode' => $manage_mode, | |
'appointment_data' => $appointment, | |
'provider_data' => $provider, | |
'customer_data' => $customer | |
); | |
} catch(Exception $exc) { | |
$view['exceptions'][] = $exc; | |
} | |
$this->load->view('appointments/book', $view); | |
} else { | |
// 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 = $post_data['appointment']; | |
$customer = $post_data['customer']; | |
if ($this->customers_model->exists($customer)) | |
$customer['id'] = $this->customers_model->find_record_id($customer); | |
$customer_id = $this->customers_model->add($customer); | |
$appointment['id_users_customer'] = $customer_id; | |
$appointment['id'] = $this->appointments_model->add($appointment); | |
$appointment['hash'] = $this->appointments_model->get_value('hash', $appointment['id']); | |
$provider = $this->providers_model->get_row($appointment['id_users_provider']); | |
$service = $this->services_model->get_row($appointment['id_services']); | |
$company_settings = array( | |
'company_name' => $this->settings_model->get_setting('company_name'), | |
'company_link' => $this->settings_model->get_setting('company_link'), | |
'company_email' => $this->settings_model->get_setting('company_email') | |
); | |
// :: 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. | |
try { | |
$google_sync = $this->providers_model->get_setting('google_sync', | |
$appointment['id_users_provider']); | |
if ($google_sync == TRUE) { | |
$google_token = json_decode($this->providers_model | |
->get_setting('google_token', $appointment['id_users_provider'])); | |
$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. | |
$google_event = $this->google_sync->add_appointment($appointment, $provider, | |
$service, $customer, $company_settings); | |
$appointment['id_google_calendar'] = $google_event->id; | |
$this->appointments_model->add($appointment); | |
} else { | |
// Update appointment to Google Calendar. | |
$appointment['id_google_calendar'] = $this->appointments_model | |
->get_value('id_google_calendar', $appointment['id']); | |
$this->google_sync->update_appointment($appointment, $provider, | |
$service, $customer, $company_settings); | |
} | |
} | |
} catch(Exception $exc) { | |
$view['exceptions'][] = $exc; | |
} | |
// :: SEND NOTIFICATION EMAILS TO BOTH CUSTOMER AND PROVIDER | |
try { | |
$this->load->library('Notifications'); | |
$send_provider = $this->providers_model | |
->get_setting('notifications', $provider['id']); | |
if (!$post_data['manage_mode']) { | |
$customer_title = $this->lang->line('appointment_booked'); | |
$customer_message = $this->lang->line('thank_your_for_appointment'); | |
$customer_link = $this->config->item('base_url') . 'appointments/index/' | |
. $appointment['hash']; | |
$provider_title = $this->lang->line('appointment_added_to_your_plan'); | |
$provider_message = $this->lang->line('appointment_link_description'); | |
$provider_link = $this->config->item('base_url') . 'backend/index/' | |
. $appointment['hash']; | |
} else { | |
$customer_title = $this->lang->line('appointment_changes_saved'); | |
$customer_message = ''; | |
$customer_link = $this->config->item('base_url') . 'appointments/index/' | |
. $appointment['hash']; | |
$provider_title = $this->lang->line('appointment_details_changed'); | |
$provider_message = ''; | |
$provider_link = $this->config->item('base_url') . 'backend/index/' | |
. $appointment['hash']; | |
} | |
$this->notifications->send_appointment_details($appointment, $provider, | |
$service, $customer,$company_settings, $customer_title, | |
$customer_message, $customer_link, $customer['email']); | |
if ($send_provider == TRUE) { | |
$this->notifications->send_appointment_details($appointment, $provider, | |
$service, $customer, $company_settings, $provider_title, | |
$provider_message, $provider_link, $provider['email']); | |
} | |
} catch(Exception $exc) { | |
$view['exceptions'][] = $exc; | |
} | |
// :: LOAD THE BOOK SUCCESS VIEW | |
$view = array( | |
'appointment_data' => $appointment, | |
'provider_data' => $provider, | |
'service_data' => $service, | |
'company_name' => $company_settings['company_name'] | |
); | |
} catch(Exception $exc) { | |
$view['exceptions'][] = $exc; | |
} | |
$this->load->view('appointments/book_success', $view); | |
} | |
} | |
/** | |
* Cancel an existing appointment. | |
* | |
* This method removes an appointment from the company's schedule. | |
* In order for the appointment to be deleted, the hash string must | |
* be provided. The customer can only cancel the appointment if the | |
* edit time period is not over yet. | |
* | |
* @param string $appointment_hash This is used to distinguish the | |
* appointment record. | |
* @param string $_POST['cancel_reason'] The text that describes why | |
* the customer cancelled the appointment. | |
*/ | |
public function cancel($appointment_hash) { | |
try { | |
$this->load->model('appointments_model'); | |
$this->load->model('providers_model'); | |
$this->load->model('customers_model'); | |
$this->load->model('services_model'); | |
$this->load->model('settings_model'); | |
// Check whether the appointment hash exists in the database. | |
$records = $this->appointments_model->get_batch(array('hash' => $appointment_hash)); | |
if (count($records) == 0) { | |
throw new Exception('No record matches the provided hash.'); | |
} | |
$appointment = $records[0]; | |
$provider = $this->providers_model->get_row($appointment['id_users_provider']); | |
$customer = $this->customers_model->get_row($appointment['id_users_customer']); | |
$service = $this->services_model->get_row($appointment['id_services']); | |
$company_settings = array( | |
'company_name' => $this->settings_model->get_setting('company_name'), | |
'company_email' => $this->settings_model->get_setting('company_email'), | |
'company_link' => $this->settings_model->get_setting('company_link') | |
); | |
// :: DELETE APPOINTMENT RECORD FROM THE DATABASE. | |
if (!$this->appointments_model->delete($appointment['id'])) { | |
throw new Exception('Appointment could not be deleted from the database.'); | |
} | |
// :: SYNC APPOINTMENT REMOVAL WITH GOOGLE CALENDAR | |
if ($appointment['id_google_calendar'] != NULL) { | |
try { | |
$google_sync = $this->providers_model->get_setting('google_sync', | |
$appointment['id_users_provider']); | |
if ($google_sync == TRUE) { | |
$google_token = json_decode($this->providers_model | |
->get_setting('google_token', $provider['id'])); | |
$this->load->library('Google_Sync'); | |
$this->google_sync->refresh_token($google_token->refresh_token); | |
$this->google_sync->delete_appointment($provider, $appointment['id_google_calendar']); | |
} | |
} catch(Exception $exc) { | |
$exceptions[] = $exc; | |
} | |
} | |
// :: SEND NOTIFICATION EMAILS TO CUSTOMER AND PROVIDER | |
try { | |
$this->load->library('Notifications'); | |
$send_provider = $this->providers_model | |
->get_setting('notifications', $provider['id']); | |
if ($send_provider == TRUE) { | |
$this->notifications->send_delete_appointment($appointment, $provider, | |
$service, $customer, $company_settings, $provider['email'], | |
$_POST['cancel_reason']); | |
} | |
$this->notifications->send_delete_appointment($appointment, $provider, | |
$service, $customer, $company_settings, $customer['email'], | |
$_POST['cancel_reason']); | |
} catch(Exception $exc) { | |
$exceptions[] = $exc; | |
} | |
} catch(Exception $exc) { | |
// Display the error message to the customer. | |
$exceptions[] = $exc; | |
} | |
$view = array(); | |
if (isset($exceptions)) { | |
$view['exceptions'] = $exceptions; | |
} | |
$this->load->view('appointments/cancel', $view); | |
} | |
/** | |
* [AJAX] Get the available appointment days for the given provider, service and timeframe. | |
* | |
* This method answers to an AJAX request. It calculates the available days | |
* for the given service, provider and timerange | |
* | |
* @param numeric $_POST['service_id'] The selected service's record id. | |
* @param numeric $_POST['provider_id'] The selected provider's record id. | |
* @param numeric $_POST['timeframe'] The number of days to look ahead. Default 30 days. | |
* @param numeric $_POST['service_duration'] The selected service duration in | |
* minutes. | |
* @param string $_POST['manage_mode'] Contains either 'true' or 'false' and determines | |
* the if current user is managing an already booked appointment or not. | |
* @param numeric $_POST['appointment_id'] If manage_mode is true, | |
* this should contain the current appointments id | |
* @return Returns a json object with the available hours. | |
*/ | |
public function ajax_get_available_days() { | |
/* This uses ajax_get_available_hours even though it is really bad form, | |
so that code changes are kept to a minimum. This is really bad form however. Sorry. */ | |
try { | |
$interval_oneday = new DateInterval( "P1D" ); | |
$today = new DateTime("today"); | |
$maxdays = (isset($_POST["timeframe"]) && is_int($_POST["timeframe"])) | |
? $_POST["timeframe"] | |
: 30; | |
$available_days = array(); | |
for ($i = 0; $i < $maxdays; $i++) { | |
$_POST["selected_date"] = $today->format('d-m-Y'); | |
// ARGH! | |
ob_start(); | |
$this->ajax_get_available_hours(); | |
$available_hours_string = ob_get_contents(); | |
ob_end_clean(); | |
$available_hours = json_decode($available_hours_string); | |
if (array_key_exists("exceptions", $available_hours)) { | |
continue; | |
} else { | |
if (count($available_hours)>0) { | |
$available_days[] = $today->format('d-m-Y'); | |
} | |
} | |
$today->add($interval_oneday); | |
} | |
echo json_encode($available_days); | |
} catch(Exception $exc) { | |
echo json_encode(array( | |
'exceptions' => array(exceptionToJavaScript($exc)) | |
)); | |
} | |
} | |
/** | |
* [AJAX] Get the available appointment hours for the given 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['manage_mode'] Contains either 'true' or 'false' and determines | |
* the if current user is managing an already booked appointment or not. | |
* @return Returns a json object with the available hours. | |
*/ | |
public function ajax_get_available_hours() { | |
$this->load->model('providers_model'); | |
$this->load->model('appointments_model'); | |
$this->load->model('settings_model'); | |
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); | |
} | |
} | |
$current_hour = $start_hour; | |
$diff = $current_hour->diff($end_hour); | |
while (($diff->h * 60 + $diff->i) >= intval($_POST['service_duration'])) { | |
$available_hours[] = $current_hour->format('H:i'); | |
$current_hour->add(new DateInterval("PT15M")); | |
$diff = $current_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); | |
sort($available_hours, SORT_STRING ); | |
$available_hours = array_values($available_hours); | |
echo json_encode($available_hours); | |
} catch(Exception $exc) { | |
echo json_encode(array( | |
'exceptions' => array(exceptionToJavaScript($exc)) | |
)); | |
} | |
} | |
/** | |
* Check whether the provider is still available in the selected appointment date. | |
* | |
* It might be times where two or more customers select the same appointment date and time. | |
* This shouldn't be allowed to happen, so one of the two customers will eventually get the | |
* prefered date and the other one will have to choose for another date. Use this method | |
* just before the customer confirms the appointment details. If the selected date was taken | |
* in the mean time, the customer must be prompted to select another time for his appointment. | |
* | |
* @param int $_POST['id_users_provider'] The selected provider's record id. | |
* @param int $_POST['id_services'] The selected service's record id. | |
* @param string $_POST['start_datetime'] This is a mysql formed string. | |
* @return bool Returns whether the selected datetime is still available. | |
*/ | |
public function ajax_check_datetime_availability() { | |
try { | |
$this->load->model('services_model'); | |
$service_duration = $this->services_model->get_value('duration', $_POST['id_services']); | |
$exclude_appointments = (isset($_POST['exclude_appointment_id'])) | |
? array($_POST['exclude_appointment_id']) : array(); | |
$available_periods = $this->get_provider_available_time_periods( | |
$_POST['id_users_provider'], $_POST['start_datetime'], $exclude_appointments); | |
$is_still_available = FALSE; | |
foreach($available_periods as $period) { | |
$appt_start = new DateTime($_POST['start_datetime']); | |
$appt_start = $appt_start->format('H:i'); | |
$appt_end = new DateTime($_POST['start_datetime']); | |
$appt_end->add(new DateInterval('PT' . $service_duration . 'M')); | |
$appt_end = $appt_end->format('H:i'); | |
$period_start = date('H:i', strtotime($period['start'])); | |
$period_end = date('H:i', strtotime($period['end'])); | |
if ($period_start <= $appt_start && $period_end >= $appt_end) { | |
$is_still_available = TRUE; | |
break; | |
} | |
} | |
echo json_encode($is_still_available); | |
} catch(Exception $exc) { | |
echo json_encode(array( | |
'exceptions' => array(exceptionToJavaScript($exc)) | |
)); | |
} | |
} | |
/** | |
* Get an array containing the free time periods (start - end) of a selected date. | |
* | |
* This method is very important because there are many cases where the system needs to | |
* know when a provider is avaible for an appointment. This method will return an array | |
* that belongs to the selected date and contains values that have the start and the end | |
* time of an available time period. | |
* | |
* @param numeric $provider_id The provider's record id. | |
* @param string $selected_date The date to be checked (MySQL formatted string). | |
* @param array $exclude_appointments This array contains the ids of the appointments that | |
* will not be taken into consideration when the available time periods are calculated. | |
* @return array Returns an array with the available time periods of the provider. | |
*/ | |
private function get_provider_available_time_periods($provider_id, $selected_date, | |
$exclude_appointments = array()) { | |
$this->load->model('appointments_model'); | |
$this->load->model('providers_model'); | |
// Get the provider's working plan and reserved appointments. | |
$working_plan = json_decode($this->providers_model->get_setting('working_plan', $provider_id), true); | |
$where_clause = array( | |
//'DATE(start_datetime)' => date('Y-m-d', strtotime($selected_date)), | |
'id_users_provider' => $provider_id | |
); | |
$reserved_appointments = $this->appointments_model->get_batch($where_clause); | |
// Sometimes it might be necessary to not take into account some appointment records | |
// in order to display what the providers' available time periods would be without them. | |
foreach ($exclude_appointments as $excluded_id) { | |
foreach ($reserved_appointments as $index => $reserved) { | |
if ($reserved['id'] == $excluded_id) { | |
unset($reserved_appointments[$index]); | |
} | |
} | |
} | |
// Find the empty spaces on the plan. The first split between the plan is due to | |
// a break (if exist). After that every reserved appointment is considered to be | |
// a taken space in the plan. | |
$selected_date_working_plan = $working_plan[strtolower(date('l', strtotime($selected_date)))]; | |
$available_periods_with_breaks = array(); | |
if (isset($selected_date_working_plan['breaks'])) { | |
if (count($selected_date_working_plan['breaks'])) { | |
foreach($selected_date_working_plan['breaks'] as $index=>$break) { | |
// Split the working plan to available time periods that do not | |
// contain the breaks in them. | |
$last_break_index = $index - 1; | |
if (count($available_periods_with_breaks) === 0) { | |
$start_hour = $selected_date_working_plan['start']; | |
$end_hour = $break['start']; | |
} else { | |
$start_hour = $selected_date_working_plan['breaks'][$last_break_index]['end']; | |
$end_hour = $break['start']; | |
} | |
$available_periods_with_breaks[] = array( | |
'start' => $start_hour, | |
'end' => $end_hour | |
); | |
} | |
// Add the period from the last break to the end of the day. | |
$available_periods_with_breaks[] = array( | |
'start' => $selected_date_working_plan['breaks'][$index]['end'], | |
'end' => $selected_date_working_plan['end'] | |
); | |
} else { | |
$available_periods_with_breaks[] = array( | |
'start' => $selected_date_working_plan['start'], | |
'end' => $selected_date_working_plan['end'] | |
); | |
} | |
} | |
// Break the empty periods with the reserved appointments. | |
$available_periods_with_appointments = $available_periods_with_breaks; | |
foreach($reserved_appointments as $appointment) { | |
foreach($available_periods_with_appointments as $index => &$period) { | |
$a_start = strtotime($appointment['start_datetime']); | |
$a_end = strtotime($appointment['end_datetime']); | |
$p_start = strtotime($selected_date . ' ' . $period['start']); | |
$p_end = strtotime($selected_date . ' ' .$period['end']); | |
if ($a_start <= $p_start && $a_end <= $p_end && $a_end <= $p_start) { | |
// The appointment does not belong in this time period, so we | |
// will not change anything. | |
} else if ($a_start <= $p_start && $a_end <= $p_end && $a_end >= $p_start) { | |
// The appointment starts before the period and finishes somewhere inside. | |
// We will need to break this period and leave the available part. | |
$period['start'] = date('H:i', $a_end); | |
} else if ($a_start >= $p_start && $a_end <= $p_end) { | |
// The appointment is inside the time period, so we will split the period | |
// into two new others. | |
unset($available_periods_with_appointments[$index]); | |
$available_periods_with_appointments[] = array( | |
'start' => date('H:i', $p_start), | |
'end' => date('H:i', $a_start) | |
); | |
$available_periods_with_appointments[] = array( | |
'start' => date('H:i', $a_end), | |
'end' => date('H:i', $p_end) | |
); | |
} else if ($a_start >= $p_start && $a_end >= $p_start && $a_start <= $p_end) { | |
// The appointment starts in the period and finishes out of it. We will | |
// need to remove the time that is taken from the appointment. | |
$period['end'] = date('H:i', $a_start); | |
} else if ($a_start >= $p_start && $a_end >= $p_end && $a_start >= $p_end) { | |
// The appointment does not belong in the period so do not change anything. | |
} else if ($a_start <= $p_start && $a_end >= $p_end && $a_start <= $p_end) { | |
// The appointment is bigger than the period, so this period needs to be | |
// removed. | |
unset($available_periods_with_appointments[$index]); | |
} | |
} | |
} | |
return array_values($available_periods_with_appointments); | |
} | |
/** | |
* This method checks whether the application is installed. | |
* | |
* This method resides in this controller because the "index()" function will | |
* be the first to be launched after the files are on the server. NOTE that the | |
* "configuration.php" file must be already set because we won't be able to | |
* connect to the database otherwise. | |
*/ | |
public function check_installation() { | |
try { | |
if (!$this->db->table_exists('ea_users')) { | |
// This is the first time the website is launched an the user needs to set | |
// the basic settings. Display the installation view page. | |
$view['base_url'] = $this->config->item('base_url'); | |
$this->load->view('general/installation', $view); | |
return FALSE; // Do not display the book appointment view file. | |
} else { | |
return TRUE; // Application installed, continue ... | |
} | |
} catch(Exception $exc) { | |
echo $exc->getTrace(); | |
} | |
} | |
/** | |
* Installs Easy!Appointments on server. | |
* | |
* @param array $_POST['admin'] Contains the initial admin user data. System needs at least | |
* one admin user to work. | |
* @param array $_POST['company'] Contains the basic company data. | |
*/ | |
public function ajax_install() { | |
try { | |
// Create E!A database structure. | |
$file_contents = file_get_contents($this->config->item('base_url') . 'assets/sql/structure.sql'); | |
$sql_queries = explode(';', $file_contents); | |
array_pop($sql_queries); | |
foreach($sql_queries as $query) { | |
$this->db->query($query); | |
} | |
// Insert admin | |
$this->load->model('admins_model'); | |
$admin = json_decode($_POST['admin'], true); | |
$admin['settings']['username'] = $admin['username']; | |
$admin['settings']['password'] = $admin['password']; | |
unset($admin['username'], $admin['password']); | |
$admin['id'] = $this->admins_model->add($admin); | |
$this->load->library('session'); | |
$this->session->set_userdata('user_id', $admin['id']); | |
$this->session->set_userdata('user_email', $admin['email']); | |
$this->session->set_userdata('role_slug', DB_SLUG_ADMIN); | |
$this->session->set_userdata('username', $admin['settings']['username']); | |
// Save company settings | |
$this->load->model('settings_model'); | |
$company = json_decode($_POST['company'], true); | |
$this->settings_model->set_setting('company_name', $company['company_name']); | |
$this->settings_model->set_setting('company_email', $company['company_email']); | |
$this->settings_model->set_setting('company_link', $company['company_link']); | |
// Try to send a notification email for the new installation. | |
// IMPORTANT: THIS WILL ONLY BE USED TO TRACK THE INSTALLATION NUMBER AND | |
// NO PERSONAL DATA WILL BE USED FOR OTHER CAUSE. | |
try { | |
$this->load->library('notifications'); | |
$this->notifications->send_new_installation($company['company_name'], | |
$company['company_email'], $company['company_link']); | |
} catch(Exception $exc) { | |
// Well, I guess we'll never know ... | |
} | |
echo json_encode(AJAX_SUCCESS); | |
} catch (Exception $exc) { | |
echo json_encode(array( | |
'exceptions' => array(exceptionToJavaScript($exc)) | |
)); | |
} | |
} | |
} | |
/* End of file appointments.php */ | |
/* Location: ./application/controllers/appointments.php */ |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* This namespace contains functions that implement the book appointment page | |
* functionality. Once the initialize() method is called the page is fully | |
* functional and can serve the appointment booking process. | |
* | |
* @namespace FrontendBook | |
*/ | |
var FrontendBook = { | |
/** | |
* Determines the functionality of the page. | |
* | |
* @type {bool} | |
*/ | |
manageMode: false, | |
/* | |
* Number of days to look ahead. | |
*/ | |
timeframe: 30, | |
/** | |
* This method initializes the book appointment page. | |
* | |
* @param {bool} bindEventHandlers (OPTIONAL) Determines whether the default | |
* event handlers will be binded to the dom elements. | |
* @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) { | |
if (bindEventHandlers === undefined) { | |
bindEventHandlers = true; // Default Value | |
} | |
if (manageMode === undefined) { | |
manageMode = false; // Default Value | |
} | |
FrontendBook.manageMode = manageMode; | |
// Initialize page's components (tooltips, datepickers etc). | |
$('.book-step').qtip({ | |
position: { | |
my: 'top center', | |
at: 'bottom center' | |
}, | |
style: { | |
classes: 'qtip-green qtip-shadow custom-qtip' | |
} | |
}); | |
$('#select-date').datepicker({ | |
dateFormat: 'dd-mm-yy', | |
firstDay: 1, // Monday | |
minDate: 0, | |
maxDate: "+" + FrontendBook.timeframe + "d", | |
defaultDate: Date.today(), | |
availableDays: [], // by default empty. | |
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'], | |
disabled: true, | |
beforeShowDay: function(date) { | |
var date_string = date.toString("dd-MM-yyyy"); | |
//console.log("date_sring:" + date_string); | |
console.log(date_string + ":" + $('#select-date').datepicker("option","availableDays").indexOf(date_string)); | |
if ($('#select-date').datepicker("option","availableDays").indexOf(date_string) >= 0) | |
return [true]; | |
return [false,"",EALang['no_available_hours']]; | |
}, | |
onSelect: function(dateText, instance) { | |
FrontendBook.getAvailableHours(dateText); | |
FrontendBook.updateConfirmFrame(); | |
} | |
}); | |
// Bind the event handlers (might not be necessary every time | |
// we use this class). | |
if (bindEventHandlers) { | |
FrontendBook.bindEventHandlers(); | |
} | |
// If the manage mode is true, the appointments data should be | |
// loaded by default. | |
if (FrontendBook.manageMode) { | |
FrontendBook.applyAppointmentData(GlobalVariables.appointmentData, | |
GlobalVariables.providerData, GlobalVariables.customerData); | |
} else { | |
$('#select-service').trigger('change'); // Load the available hours. | |
} | |
}, | |
/** | |
* This method binds the necessary event handlers for the book | |
* appointments page. | |
*/ | |
bindEventHandlers: function() { | |
/** | |
* Event: Selected Provider "Changed" | |
* | |
* Whenever the provider changes the available appointment | |
* date - time periods must be updated. | |
*/ | |
$('#select-provider').change(function() { | |
FrontendBook.updateCalendar(); | |
FrontendBook.getAvailableHours(Date.today().toString('dd-MM-yyyy')); | |
FrontendBook.updateConfirmFrame(); | |
}); | |
/** | |
* Event: Selected Service "Changed" | |
* | |
* When the user clicks on a service, its available providers should | |
* become visible. | |
*/ | |
$('#select-service').change(function() { | |
var currServiceId = $('#select-service').val(); | |
$('#select-provider').empty(); | |
$.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 == currServiceId) { | |
var optionHtml = '<option value="' + provider['id'] + '">' | |
+ provider['first_name'] + ' ' + provider['last_name'] | |
+ '</option>'; | |
$('#select-provider').append(optionHtml); | |
} | |
}); | |
}); | |
FrontendBook.updateCalendar(); | |
FrontendBook.getAvailableHours($('#select-date').val()); | |
FrontendBook.updateConfirmFrame(); | |
FrontendBook.updateServiceDescription($('#select-service').val(), $('#service-description')); | |
}); | |
/** | |
* 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 | |
* be perfomed, depending the current wizard step. | |
*/ | |
$('.button-next').click(function() { | |
// If we are on the 2nd tab then the user should have an appointment hour | |
// selected. | |
if ($(this).attr('data-step_index') === '2') { | |
if ($('.selected-hour').length == 0) { | |
if ($('#select-hour-prompt').length == 0) { | |
$('#available-hours').append('<br><br>' | |
+ '<strong id="select-hour-prompt" class="text-error">' | |
+ EALang['appointment_hour_missing'] | |
+ '</strong>'); | |
} | |
return; | |
} | |
} | |
// If we are on the 3rd tab then we will need to validate the user's | |
// input before proceeding to the next step. | |
if ($(this).attr('data-step_index') === '3') { | |
if (!FrontendBook.validateCustomerForm()) { | |
return; // Validation failed, do not continue. | |
} else { | |
FrontendBook.updateConfirmFrame(); | |
} | |
} | |
// Display the next step tab (uses jquery animation effect). | |
var nextTabIndex = parseInt($(this).attr('data-step_index')) + 1; | |
$(this).parents().eq(1).hide('fade', function() { | |
$('.active-step').removeClass('active-step'); | |
$('#step-' + nextTabIndex).addClass('active-step'); | |
$('#wizard-frame-' + nextTabIndex).show('fade'); | |
}); | |
}); | |
/** | |
* Event: Back Step Button "Clicked" | |
* | |
* This handler is triggered every time the user pressed the | |
* "back" button on the book wizard. | |
*/ | |
$('.button-back').click(function() { | |
var prevTabIndex = parseInt($(this).attr('data-step_index')) - 1; | |
$(this).parents().eq(1).hide('fade', function() { | |
$('.active-step').removeClass('active-step'); | |
$('#step-' + prevTabIndex).addClass('active-step'); | |
$('#wizard-frame-' + prevTabIndex).show('fade'); | |
}); | |
}); | |
/** | |
* Event: Available Hour "Click" | |
* | |
* Triggered whenever the user clicks on an available hour | |
* for his appointment. | |
*/ | |
$('#available-hours').on('click', '.available-hour', function() { | |
$('.selected-hour').removeClass('selected-hour'); | |
$(this).addClass('selected-hour'); | |
FrontendBook.updateConfirmFrame(); | |
}); | |
if (FrontendBook.manageMode) { | |
/** | |
* Event: Cancel Appointment Button "Click" | |
* | |
* When the user clicks the "Cancel" button this form is going to | |
* be submitted. We need the user to confirm this action because | |
* once the appointment is cancelled, it will be delete from the | |
* database. | |
*/ | |
$('#cancel-appointment').click(function(event) { | |
var dialogButtons = {}; | |
dialogButtons['OK'] = function() { | |
if ($('#cancel-reason').val() === '') { | |
$('#cancel-reason').css('border', '2px solid red'); | |
return; | |
} | |
$('#cancel-appointment-form textarea').val($('#cancel-reason').val()); | |
$('#cancel-appointment-form').submit(); | |
}; | |
dialogButtons[EALang['cancel']] = function() { | |
$('#message_box').dialog('close'); | |
}; | |
GeneralFunctions.displayMessageBox(EALang['cancel_appointment_title'], | |
EALang['write_appointment_removal_reason'], dialogButtons); | |
$('#message_box').append('<textarea id="cancel-reason" rows="3"></textarea>'); | |
$('#cancel-reason').css('width', '353px'); | |
return false; | |
}); | |
} | |
/** | |
* 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 | |
* another customer or event. | |
*/ | |
$('#book-appointment-submit').click(function(event) { | |
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'], | |
}; | |
if (GlobalVariables.manageMode) { | |
postData.exclude_appointment_id = GlobalVariables.appointmentData.id; | |
} | |
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.exceptions) { | |
response.exceptions = GeneralFunctions.parseExceptions(response.exceptions); | |
GeneralFunctions.displayMessageBox('Unexpected Issues', 'Unfortunately ' | |
+ 'the check appointment time availability could not be completed. ' | |
+ 'The following issues occurred:'); | |
$('#message_box').append(GeneralFunctions.exceptionsToHtml(response.exceptions)); | |
return false; | |
} | |
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'); | |
}); | |
}, | |
updateCalendar: function() { | |
// Find the selected service duration (it is going to | |
// be send within the "postData" object). | |
var selServiceDuration = 15; // Default value of duration (in minutes). | |
$.each(GlobalVariables.availableServices, function(index, service) { | |
if (service['id'] == $('#select-service').val()) { | |
selServiceDuration = service['duration']; | |
} | |
}); | |
// If the manage mode is true then the appointment's start | |
// date should return as available too. | |
var appointmentId = (FrontendBook.manageMode) | |
? GlobalVariables.appointmentData['id'] : undefined; | |
var postData = { | |
'service_id': $('#select-service').val(), | |
'provider_id': $('#select-provider').val(), | |
'service_duration': selServiceDuration, | |
'manage_mode': FrontendBook.manageMode, | |
'appointment_id': appointmentId, | |
'timeframe': FrontendBook.timeframe | |
}; | |
$('#select-date').datepicker("option","disabled",true); | |
$('#select-date').datepicker("refresh"); | |
// Make ajax post request and get the available hours. | |
var ajaxurl = GlobalVariables.baseUrl + 'appointments/ajax_get_available_days'; | |
jQuery.post(ajaxurl, postData, function(response) { | |
/////////////////////////////////////////////////////////////// | |
console.log('Get Available Days JSON Response:', response); | |
/////////////////////////////////////////////////////////////// | |
if (!GeneralFunctions.handleAjaxExceptions(response)) return; | |
// The response contains the available days for the selected provider, | |
// service and timeframe. save that info in the timepicker and refresh it. | |
$('#select-date').datepicker("option","availableDays", response); | |
$('#select-date').datepicker("option","disabled", false); | |
$('#select-date').datepicker("refresh"); | |
}, 'json'); | |
}, | |
/** | |
* This function makes an ajax call and returns the available | |
* hours for the selected service, provider and date. | |
* | |
* @param {string} selDate The selected date of which the available | |
* hours we need to receive. | |
*/ | |
getAvailableHours: function(selDate) { | |
$('#available-hours').empty(); | |
// Find the selected service duration (it is going to | |
// be send within the "postData" object). | |
var selServiceDuration = 15; // Default value of duration (in minutes). | |
$.each(GlobalVariables.availableServices, function(index, service) { | |
if (service['id'] == $('#select-service').val()) { | |
selServiceDuration = service['duration']; | |
} | |
}); | |
// If the manage mode is true then the appointment's start | |
// date should return as available too. | |
var appointmentId = (FrontendBook.manageMode) | |
? 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 | |
}; | |
// Make ajax post request and get the available hours. | |
var ajaxurl = GlobalVariables.baseUrl + 'appointments/ajax_get_available_hours'; | |
jQuery.post(ajaxurl, postData, function(response) { | |
/////////////////////////////////////////////////////////////// | |
console.log('Get Available Hours JSON Response:', response); | |
/////////////////////////////////////////////////////////////// | |
if (!GeneralFunctions.handleAjaxExceptions(response)) 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(EALang['no_available_hours']); | |
} | |
}, 'json'); | |
}, | |
/** | |
* This function validates the customer's data input. The user cannot contiue | |
* without passing all the validation checks. | |
* | |
* @return {bool} Returns the validation result. | |
*/ | |
validateCustomerForm: function() { | |
$('#wizard-frame-3 input').css('border', ''); | |
try { | |
// Validate required fields. | |
var missingRequiredField = false; | |
$('.required').each(function() { | |
if ($(this).val() == '') { | |
$(this).css('border', '2px solid red'); | |
missingRequiredField = true; | |
} | |
}); | |
if (missingRequiredField) { | |
throw EALang['fields_are_required']; | |
} | |
// Validate email address. | |
if (!GeneralFunctions.validateEmail($('#email').val())) { | |
$('#email').css('border', '2px solid red'); | |
throw EALang['invalid_email']; | |
} | |
return true; | |
} catch(exc) { | |
$('#form-message').text(exc); | |
return false; | |
} | |
}, | |
/** | |
* Every time this function is executed, it updates the confirmation | |
* page with the latest customer settigns and input for the appointment | |
* booking. | |
*/ | |
updateConfirmFrame: function() { | |
// Appointment Details | |
var selectedDate = $('#select-date').datepicker('getDate'); | |
if (selectedDate !== null) { | |
selectedDate = Date.parse(selectedDate).toString('dd/MM/yyyy'); | |
} | |
var selServiceId = $('#select-service').val(); | |
var servicePrice, serviceCurrency; | |
$.each(GlobalVariables.availableServices, function(index, service) { | |
if (service.id == selServiceId) { | |
servicePrice = '<br>' + service.price; | |
serviceCurrency = service.currency; | |
return false; // break loop | |
} | |
}); | |
$('#appointment-details').html( | |
'<h4>' + $('#select-service option:selected').text() + '</h4>' + | |
'<p>' | |
+ '<strong class="text-info">' | |
+ $('#select-provider option:selected').text() + '<br>' | |
+ selectedDate + ' ' + $('.selected-hour').text() | |
+ servicePrice + ' ' + serviceCurrency | |
+ '</strong>' + | |
'</p>' | |
); | |
// Customer Details | |
$('#customer-details').html( | |
'<h4>' + $('#first-name').val() + ' ' + $('#last-name').val() + '</h4>' + | |
'<p>' + | |
EALang['phone'] + ': ' + $('#phone-number').val() + | |
'<br/>' + | |
EALang['email'] + ': ' + $('#email').val() + | |
'<br/>' + | |
EALang['address'] + ': ' + $('#address').val() + | |
'<br/>' + | |
EALang['city'] + ': ' + $('#city').val() + | |
'<br/>' + | |
EALang['zip_code'] + ': ' + $('#zip-code').val() + | |
'</p>' | |
); | |
// Update appointment form data for submission to server when the user confirms | |
// the appointment. | |
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() | |
}; | |
postData['appointment'] = { | |
'start_datetime': $('#select-date').datepicker('getDate').toString('yyyy-MM-dd') | |
+ ' ' + $('.selected-hour').text() + ':00', | |
'end_datetime': FrontendBook.calcEndDatetime(), | |
'notes': $('#notes').val(), | |
'is_unavailable': false, | |
'id_users_provider': $('#select-provider').val(), | |
'id_services': $('#select-service').val() | |
}; | |
postData['manage_mode'] = FrontendBook.manageMode; | |
if (FrontendBook.manageMode) { | |
postData['appointment']['id'] = GlobalVariables.appointmentData['id']; | |
postData['customer']['id'] = GlobalVariables.customerData['id']; | |
} | |
$('input[name="post_data"]').val(JSON.stringify(postData)); | |
}, | |
/** | |
* This method calculates the end datetime of the current appointment. | |
* End datetime is depending on the service and start datetime fieldss. | |
* | |
* @return {string} Returns the end datetime in string format. | |
*/ | |
calcEndDatetime: function() { | |
// Find selected service duration. | |
var selServiceDuration = undefined; | |
$.each(GlobalVariables.availableServices, function(index, service) { | |
if (service.id == $('#select-service').val()) { | |
selServiceDuration = service.duration; | |
return false; // Stop searching ... | |
} | |
}); | |
// Add the duration to the start datetime. | |
var startDatetime = $('#select-date').datepicker('getDate').toString('dd-MM-yyyy') | |
+ ' ' + $('.selected-hour').text(); | |
startDatetime = Date.parseExact(startDatetime, 'dd-MM-yyyy HH:mm'); | |
var endDatetime = undefined; | |
if (selServiceDuration !== undefined && startDatetime !== null) { | |
endDatetime = startDatetime.add({ 'minutes' : parseInt(selServiceDuration) }); | |
} else { | |
endDatetime = new Date(); | |
} | |
return endDatetime.toString('yyyy-MM-dd HH:mm:ss'); | |
}, | |
/** | |
* This method applies the appointment's data to the wizard so | |
* that the user can start making changes on an existing record. | |
* | |
* @param {object} appointment Selected appointment's data. | |
* @param {object} provider Selected provider's data. | |
* @param {object} customer Selected customer's data. | |
* @returns {bool} Returns the operation result. | |
*/ | |
applyAppointmentData: function(appointment, provider, customer) { | |
try { | |
// Select Service & Provider | |
$('#select-service').val(appointment['id_services']).trigger('change'); | |
$('#select-provider').val(appointment['id_users_provider']); | |
// Set Appointment Date | |
$('#select-date').datepicker('setDate', | |
Date.parseExact(appointment['start_datetime'], 'yyyy-MM-dd HH:mm:ss')); | |
FrontendBook.getAvailableHours($('#select-date').val()); | |
// Apply Customer's Data | |
$('#last-name').val(customer['last_name']); | |
$('#first-name').val(customer['first_name']); | |
$('#email').val(customer['email']); | |
$('#phone-number').val(customer['phone_number']); | |
$('#address').val(customer['address']); | |
$('#city').val(customer['city']); | |
$('#zip-code').val(customer['zip_code']); | |
var appointmentNotes = (appointment['notes'] !== null) | |
? appointment['notes'] : ''; | |
$('#notes').val(appointmentNotes); | |
FrontendBook.updateConfirmFrame(); | |
return true; | |
} catch(exc) { | |
console.log(exc); // log exception | |
return false; | |
} | |
}, | |
/** | |
* This method updates a div's html content with a brief description of the | |
* user selected service (only if available in db). This is usefull for the | |
* customers upon selecting the correct service. | |
* | |
* @param {int} serviceId The selected service record id. | |
* @param {object} $div The destination div jquery object (e.g. provide $('#div-id') | |
* object as value). | |
*/ | |
updateServiceDescription: function(serviceId, $div) { | |
var html = ''; | |
$.each(GlobalVariables.availableServices, function(index, service) { | |
if (service.id == serviceId) { // Just found the service. | |
html = '<strong>' + service.name + ' </strong>'; | |
if (service.description != '' && service.description != null) { | |
html += '<br>' + service.description + '<br>'; | |
} | |
if (service.duration != '' && service.duration != null) { | |
html += '[' + EALang['duration'] + ' ' + service.duration | |
+ ' ' + EALang['minutes'] + '] '; | |
} | |
if (service.price != '' && service.price != null) { | |
html += '[' + EALang['price'] + ' ' + service.price + ' ' + service.currency + ']'; | |
} | |
html += '<br>'; | |
return false; | |
} | |
}); | |
$div.html(html); | |
if (html != '') { | |
$div.show(); | |
} else { | |
$div.hide(); | |
} | |
} | |
}; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment