From f5250e55812bc7da1b89d907d71f6e43f29661db Mon Sep 17 00:00:00 2001 From: "alextselegidis@gmail.com" Date: Tue, 9 Jul 2013 14:46:48 +0000 Subject: [PATCH] * Insert custom unavailable time period on a provider's calendar. * Fixed and refactored existing code. * Updated database structure (appointment foreign keys need to be null, when the record is a unavailable time period). --- db/easy_appointments.sql | 32 ++- src/application/controllers/appointments.php | 112 ++++---- src/application/controllers/backend_api.php | 138 ++++++--- src/application/libraries/google_sync.php | 68 +++-- src/application/models/appointments_model.php | 66 ++++- src/application/models/services_model.php | 4 +- src/application/views/backend/calendar.php | 51 +++- src/assets/js/backend.js | 8 + src/assets/js/backend_calendar.js | 261 ++++++++++++------ src/configuration.php | 4 +- 10 files changed, 521 insertions(+), 223 deletions(-) diff --git a/db/easy_appointments.sql b/db/easy_appointments.sql index 2383909d..d66c0435 100644 --- a/db/easy_appointments.sql +++ b/db/easy_appointments.sql @@ -3,7 +3,7 @@ -- http://www.phpmyadmin.net -- -- Φιλοξενητής: localhost --- Χρόνος δημιουργίας: 26 Ιουν 2013 στις 12:29:46 +-- Χρόνος δημιουργίας: 09 Ιουλ 2013 στις 15:16:49 -- Έκδοση διακομιστή: 5.5.24-log -- Έκδοση PHP: 5.4.3 @@ -33,9 +33,10 @@ CREATE TABLE IF NOT EXISTS `ea_appointments` ( `end_datetime` datetime DEFAULT NULL, `notes` text, `hash` text, - `id_users_provider` bigint(20) unsigned NOT NULL, - `id_users_customer` bigint(20) unsigned NOT NULL, - `id_services` bigint(20) unsigned NOT NULL, + `is_unavailable` tinyint(4) DEFAULT '0', + `id_users_provider` bigint(20) unsigned DEFAULT NULL, + `id_users_customer` bigint(20) unsigned DEFAULT NULL, + `id_services` bigint(20) unsigned DEFAULT NULL, `id_google_calendar` text, PRIMARY KEY (`id`), KEY `id_users_customer` (`id_users_customer`), @@ -43,6 +44,22 @@ CREATE TABLE IF NOT EXISTS `ea_appointments` ( KEY `id_users_provider` (`id_users_provider`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8 AUTO_INCREMENT=25 ; +-- +-- Άδειασμα δεδομένων του πίνακα `ea_appointments` +-- + +INSERT INTO `ea_appointments` (`id`, `book_datetime`, `start_datetime`, `end_datetime`, `notes`, `hash`, `is_unavailable`, `id_users_provider`, `id_users_customer`, `id_services`, `id_google_calendar`) VALUES +(2, '2013-06-28 13:41:37', '2013-06-28 10:00:00', '2013-06-28 15:50:00', '', 'df05e96357b1f7eb9717524d40400b92', 0, 2, 5, 1, NULL), +(3, '2013-06-28 17:03:04', '2013-06-29 09:00:00', '2013-06-29 12:50:00', '', '0493a6fef5215cd83b9eca4de63cb9e9', 0, 2, 5, 1, 'vhd5nlv9pt32caanvtu8c9c8r0'), +(7, '2013-06-29 00:48:15', '2013-06-29 12:15:00', '2013-06-29 12:35:00', '', '5774937851046f65b87617eb14c6ee97', 0, 2, 5, 1, NULL), +(15, '2013-07-03 13:34:54', '2013-07-03 15:15:00', '2013-07-03 15:35:00', '', '98c777b9ee21be6091e15c4af35f6752', 0, 2, 5, 1, 'ibcgjhj1fu484s1c4bquroqtm0'), +(16, '2013-07-03 13:45:12', '2013-07-03 15:45:00', '2013-07-03 16:05:00', '', 'b828b3bb5dbc4e50f05b05cb239bfcd4', 0, 2, 5, 1, 'c48fcvqak1pulu78is971cmutg'), +(17, '2013-07-03 13:45:46', '2013-07-03 16:15:00', '2013-07-03 16:35:00', '', '1edb1f698d8c3606d8ac3c3371604782', 0, 2, 5, 1, 'cgqaavskrvp8048hvba8i9qa28'), +(18, '2013-07-03 13:46:08', '2013-07-03 16:45:00', '2013-07-03 17:05:00', '', 'a4dacd561468e89a74267dc148690a74', 0, 2, 5, 1, 'rrtfqiok2c7i7vbuuh4hjtcp4c'), +(20, '2013-07-03 17:51:49', '2013-07-04 09:00:00', '2013-07-04 09:20:00', '', '9e9814cf15a156d8d795d1e363463c65', 0, 2, 5, 1, 'i3v1unm6miuu1ran9idbivl130'), +(23, '2013-07-03 18:35:25', '2013-07-04 13:00:00', '2013-07-04 13:20:00', '', '64d9143d6004a03d2887d4f9909fd59e', 0, 2, 5, 1, 'fquo0ibainofdpbs26j8ae3r0c'), +(24, '2013-07-05 14:00:38', '2013-07-05 10:00:00', '2013-07-05 10:20:00', '', '13db3ecb2fe7b3e8a9131a21183db62c', 0, 2, 5, 1, 'jno45dehlqh8qufilgvnvj1dl0'); + -- -------------------------------------------------------- -- @@ -194,7 +211,8 @@ INSERT INTO `ea_users` (`id`, `first_name`, `last_name`, `email`, `mobile_number (1, 'Alex', 'Tselegidis', 'alextselegidis@gmail.com', '123456789', '123456789', 'Some Str', 'Some City', 'Some State', '12345', 'This is me making Easy!Appointments :P', 1), (2, 'Γεώργιος', 'Παπαδόπουλος', 'alextselegidis@gmail.com', '1111111111111', '1111111111111', '', '', NULL, '', 'This is a test provider (with my email for google syncing).', 2), (3, 'Νίκος', 'Αναστασίου', 'prov2@test.gr', '2222222222222', '2222222222222', 'Some Street 3', NULL, NULL, NULL, NULL, 2), -(4, 'Ηρώ', 'Καριοφύλη', 'prov3@test.gr', '3333333333333', '3333333333333', 'John Doe 3 ', NULL, NULL, NULL, NULL, 2); +(4, 'Ηρώ', 'Καριοφύλη', 'prov3@test.gr', '3333333333333', '3333333333333', 'John Doe 3 ', NULL, NULL, NULL, NULL, 2), +(5, '', 'a', 'alextselegidis@yahoo.gr', NULL, 'a', '', '', NULL, '', NULL, 3); -- -------------------------------------------------------- @@ -218,9 +236,9 @@ CREATE TABLE IF NOT EXISTS `ea_user_settings` ( -- INSERT INTO `ea_user_settings` (`id_users`, `username`, `password`, `working_plan`, `notifications`, `google_sync`, `google_token`) VALUES -(2, 'provider_1', 'provider_1', '{"monday":{"start":"09:00","end":"18:00","breaks":[{"start":"11:20","end":"11:30"},{"start":"14:30","end":"15:00"}]},"tuesday":{"start":"09:00","end":"18:00","breaks":[{"start":"11:20","end":"11:30"},{"start":"14:30","end":"15:00"}]},"wednesday":{"start":"09:00","end":"18:00","breaks":[{"start":"11:20","end":"11:30"},{"start":"14:30","end":"15:00"}]},"thursday":{"start":"09:00","end":"18:00","breaks":[{"start":"11:20","end":"11:30"},{"start":"14:30","end":"15:00"}]},"friday":{"start":"09:00","end":"18:00","breaks":[{"start":"11:20","end":"11:30"},{"start":"14:30","end":"15:00"}]},"saturday":{"start":"09:00","end":"18:00","breaks":[{"start":"11:20","end":"11:30"},{"start":"14:30","end":"15:00"}]},"sunday":{"start":"09:00","end":"18:00","breaks":[{"start":"11:20","end":"11:30"},{"start":"14:30","end":"15:00"}]}}', NULL, 1, NULL), +(2, 'provider_1', 'provider_1', '{"monday":{"start":"09:00","end":"18:00","breaks":[{"start":"11:20","end":"11:30"},{"start":"14:30","end":"15:00"}]},"tuesday":{"start":"09:00","end":"18:00","breaks":[{"start":"11:20","end":"11:30"},{"start":"14:30","end":"15:00"}]},"wednesday":{"start":"09:00","end":"18:00","breaks":[{"start":"11:20","end":"11:30"},{"start":"14:30","end":"15:00"}]},"thursday":{"start":"09:00","end":"18:00","breaks":[{"start":"11:20","end":"11:30"},{"start":"14:30","end":"15:00"}]},"friday":{"start":"09:00","end":"18:00","breaks":[{"start":"11:20","end":"11:30"},{"start":"14:30","end":"15:00"}]},"saturday":{"start":"09:00","end":"18:00","breaks":[{"start":"11:20","end":"11:30"},{"start":"14:30","end":"15:00"}]},"sunday":{"start":"09:00","end":"18:00","breaks":[{"start":"11:20","end":"11:30"},{"start":"14:30","end":"15:00"}]}}', NULL, 1, '{"access_token":"ya29.AHES6ZRq0T7vB1k0nueWwvYM8gQw7QapJm8_EyHaRwljzXo","token_type":"Bearer","expires_in":3600,"refresh_token":"1\\/o4GiIEXKTxm3HkWHAPGplqW2CcmGLQm7CV3iv19DrTw","created":1372844816}'), (3, 'provider_2', 'provider_2', '{"monday":{"start":"09:00","end":"18:00","breaks":[{"start":"11:20","end":"11:30"},{"start":"14:30","end":"15:00"}]},"tuesday":{"start":"09:00","end":"18:00","breaks":[{"start":"11:20","end":"11:30"},{"start":"14:30","end":"15:00"}]},"wednesday":{"start":"09:00","end":"18:00","breaks":[{"start":"11:20","end":"11:30"},{"start":"14:30","end":"15:00"}]},"thursday":{"start":"09:00","end":"18:00","breaks":[{"start":"11:20","end":"11:30"},{"start":"14:30","end":"15:00"}]},"friday":{"start":"09:00","end":"18:00","breaks":[{"start":"11:20","end":"11:30"},{"start":"14:30","end":"15:00"}]},"saturday":{"start":"09:00","end":"18:00","breaks":[{"start":"11:20","end":"11:30"},{"start":"14:30","end":"15:00"}]},"sunday":{"start":"09:00","end":"18:00","breaks":[{"start":"11:20","end":"11:30"},{"start":"14:30","end":"15:00"}]}}', NULL, 0, NULL), -(4, 'provider_3', 'provider_3', '{"monday":{"start":"09:00","end":"18:00","breaks":[{"start":"11:20","end":"11:30"},{"start":"14:30","end":"15:00"}]},"tuesday":{"start":"09:00","end":"18:00","breaks":[{"start":"11:20","end":"11:30"},{"start":"14:30","end":"15:00"}]},"wednesday":{"start":"09:00","end":"18:00","breaks":[{"start":"11:20","end":"11:30"},{"start":"14:30","end":"15:00"}]},"thursday":{"start":"09:00","end":"18:00","breaks":[{"start":"11:20","end":"11:30"},{"start":"14:30","end":"15:00"}]},"friday":{"start":"09:00","end":"18:00","breaks":[{"start":"11:20","end":"11:30"},{"start":"14:30","end":"15:00"}]},"saturday":{"start":"09:00","end":"18:00","breaks":[{"start":"11:20","end":"11:30"},{"start":"14:30","end":"15:00"}]},"sunday":{"start":"09:00","end":"18:00","breaks":[{"start":"11:20","end":"11:30"},{"start":"14:30","end":"15:00"}]}}', NULL, 1, NULL); +(4, 'provider_3', 'provider_3', '{"monday":{"start":"09:00","end":"18:00","breaks":[{"start":"11:20","end":"11:30"},{"start":"14:30","end":"15:00"}]},"tuesday":{"start":"09:00","end":"18:00","breaks":[{"start":"11:20","end":"11:30"},{"start":"14:30","end":"15:00"}]},"wednesday":{"start":"09:00","end":"18:00","breaks":[{"start":"11:20","end":"11:30"},{"start":"14:30","end":"15:00"}]},"thursday":{"start":"09:00","end":"18:00","breaks":[{"start":"11:20","end":"11:30"},{"start":"14:30","end":"15:00"}]},"friday":{"start":"09:00","end":"18:00","breaks":[{"start":"11:20","end":"11:30"},{"start":"14:30","end":"15:00"}]},"saturday":{"start":"09:00","end":"18:00","breaks":[{"start":"11:20","end":"11:30"},{"start":"14:30","end":"15:00"}]},"sunday":{"start":"09:00","end":"18:00","breaks":[{"start":"11:20","end":"11:30"},{"start":"14:30","end":"15:00"}]}}', NULL, 0, NULL); -- -- Περιορισμοί για άχρηστους πίνακες diff --git a/src/application/controllers/appointments.php b/src/application/controllers/appointments.php index f8201ea8..40d26185 100644 --- a/src/application/controllers/appointments.php +++ b/src/application/controllers/appointments.php @@ -47,20 +47,20 @@ class Appointments extends CI_Controller { return; } - $appointment_data = $appointments_results[0]; + $appointment = $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']); + $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_data = array(); - $provider_data = array(); - $customer_data = array(); + $appointment = array(); + $provider = array(); + $customer = array(); } // Load the book appointment view. @@ -69,9 +69,9 @@ class Appointments extends CI_Controller { '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' => $appointment, + 'provider_data' => $provider, + 'customer_data' => $customer ); } catch(Exception $exc) { @@ -86,20 +86,18 @@ class Appointments extends CI_Controller { // 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']; - $customer_data = $post_data['customer']; + $post_data = json_decode($_POST['post_data'], true); + $appointment = $post_data['appointment']; + $customer = $post_data['customer']; - $customer_id = $this->customers_model->add($customer_data); - $appointment_data['id_users_customer'] = $customer_id; + $customer_id = $this->customers_model->add($customer); + $appointment['id_users_customer'] = $customer_id; - $appointment_data['id'] = $this->appointments_model->add($appointment_data); - $appointment_data['hash'] = $this->appointments_model - ->get_value('hash', $appointment_data['id']); + $appointment['id'] = $this->appointments_model->add($appointment); + $appointment['hash'] = $this->appointments_model->get_value('hash', $appointment['id']); - $provider_data = $this->providers_model - ->get_row($appointment_data['id_users_provider']); - $service_data = $this->services_model->get_row($appointment_data['id_services']); + $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'), @@ -112,26 +110,28 @@ class Appointments extends CI_Controller { // in order to sync the appointment. try { $google_sync = $this->providers_model->get_setting('google_sync', - $appointment_data['id_users_provider']); + $appointment['id_users_provider']); if ($google_sync == TRUE) { $google_token = json_decode($this->providers_model - ->get_setting('google_token', $appointment_data['id_users_provider'])); + ->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. - $this->google_sync->add_appointment($appointment_data, $provider_data, - $service_data, $customer_data, $company_settings); + $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_data['id_google_calendar'] = $this->appointments_model - ->get_value('id_google_calendar', $appointment_data['id']); + $appointment['id_google_calendar'] = $this->appointments_model + ->get_value('id_google_calendar', $appointment['id']); - $this->google_sync->update_appointment($appointment_data, $provider_data, - $service_data, $customer_data, $company_settings); + $this->google_sync->update_appointment($appointment, $provider, + $service, $customer, $company_settings); } } } catch(Exception $exc) { @@ -148,41 +148,41 @@ class Appointments extends CI_Controller { . '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']; + . $appointment['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']; + . $appointment['hash']; } else { $customer_title = 'Appointment changes have been successfully saved!'; $customer_message = ''; $customer_link = $this->config->item('base_url') . 'appointments/index/' - . $appointment_data['hash']; + . $appointment['hash']; $provider_title = 'Appointment details have changed.'; $provider_message = ''; $provider_link = $this->config->item('base_url') . 'backend/' - . $appointment_data['hash']; + . $appointment['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, $provider, + $service, $customer,$company_settings, $customer_title, + $customer_message, $customer_link, $customer['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']); + $this->notifications->send_appointment_details($appointment, $provider, + $service, $customer, $company_settings, $provider_title, + $provider_message, $provider_link, $provider['email']); } catch(Exception $exc) { $view_data['exceptions'][] = $exc; } // :: LOAD THE BOOK SUCCESS VIEW $view_data = array( - 'appointment_data' => $appointment_data, - 'provider_data' => $provider_data, - 'service_data' => $service_data, + 'appointment_data' => $appointment, + 'provider_data' => $provider, + 'service_data' => $service, 'company_name' => $company_settings['company_name'] ); @@ -221,10 +221,10 @@ class Appointments extends CI_Controller { throw new Exception('No record matches the provided hash.'); } - $appointment_data = $records[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']); - $service_data = $this->services_model->get_row($appointment_data['id_services']); + $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'), @@ -233,22 +233,22 @@ class Appointments extends CI_Controller { ); // :: DELETE APPOINTMENT RECORD FROM THE DATABASE. - if (!$this->appointments_model->delete($appointment_data['id'])) { + 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_data['id_google_calendar'] != NULL) { + if ($appointment['id_google_calendar'] != NULL) { try { $google_sync = $this->providers_model->get_setting('google_sync', - $appointment_data['id_users_provider']); + $appointment['id_users_provider']); if ($google_sync == TRUE) { $google_token = json_decode($this->providers_model - ->get_setting('google_token', $provider_data['id'])); + ->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($appointment_data['id_google_calendar']); + $this->google_sync->delete_appointment($appointment['id_google_calendar']); } } catch(Exception $exc) { $exceptions[] = $exc; @@ -258,11 +258,11 @@ class Appointments extends CI_Controller { // :: SEND NOTIFICATION EMAILS TO CUSTOMER AND PROVIDER try { $this->load->library('Notifications'); - $this->notifications->send_delete_appointment($appointment_data, $provider_data, - $service_data, $customer_data, $company_settings, $provider_data['email'], + $this->notifications->send_delete_appointment($appointment, $provider, + $service, $customer, $company_settings, $provider['email'], $_POST['cancel_reason']); - $this->notifications->send_delete_appointment($appointment_data, $provider_data, - $service_data, $customer_data, $company_settings, $customer_data['email'], + $this->notifications->send_delete_appointment($appointment, $provider, + $service, $customer, $company_settings, $customer['email'], $_POST['cancel_reason']); } catch(Exception $exc) { $exceptions[] = $exc; diff --git a/src/application/controllers/backend_api.php b/src/application/controllers/backend_api.php index 751724e0..656e44e6 100644 --- a/src/application/controllers/backend_api.php +++ b/src/application/controllers/backend_api.php @@ -38,9 +38,11 @@ class Backend_api extends CI_Controller { $appointments = $this->appointments_model->get_batch($where_clause); foreach($appointments as &$appointment) { - $appointment['provider'] = $this->providers_model->get_row($appointment['id_users_provider']); - $appointment['service'] = $this->services_model->get_row($appointment['id_services']); - $appointment['customer'] = $this->customers_model->get_row($appointment['id_users_customer']); + if ($appointment['is_unavailable'] == FALSE) { + $appointment['provider'] = $this->providers_model->get_row($appointment['id_users_provider']); + $appointment['service'] = $this->services_model->get_row($appointment['id_services']); + $appointment['customer'] = $this->customers_model->get_row($appointment['id_users_customer']); + } } echo json_encode($appointments); @@ -71,27 +73,27 @@ class Backend_api extends CI_Controller { // :: SAVE CUSTOMER CHANGES TO DATABASE if (isset($_POST['customer_data'])) { - $customer_data = json_decode(stripcslashes($_POST['customer_data']), true); - $customer_data['id'] = $this->customers_model->add($customer_data); + $customer = json_decode(stripcslashes($_POST['customer_data']), true); + $customer['id'] = $this->customers_model->add($customer); } // :: SAVE APPOINTMENT CHANGES TO DATABASE if (isset($_POST['appointment_data'])) { - $appointment_data = json_decode(stripcslashes($_POST['appointment_data']), true); - $manage_mode = isset($appointment_data['id']); + $appointment = json_decode(stripcslashes($_POST['appointment_data']), true); + $manage_mode = isset($appointment['id']); // If the appointment does not contain the customer record id, then it // means that is is going to be inserted. Get the customer's record id. - if (!isset($appointment_data['id_users_customer'])) { - $appointment_data['id_users_customer'] = $customer_data['id']; + if (!isset($appointment['id_users_customer'])) { + $appointment['id_users_customer'] = $customer['id']; } - $appointment_data['id'] = $this->appointments_model->add($appointment_data); + $appointment['id'] = $this->appointments_model->add($appointment); } - $appointment_data = $this->appointments_model->get_row($appointment_data['id']); - $provider_data = $this->providers_model->get_row($appointment_data['id_users_provider']); - $customer_data = $this->customers_model->get_row($appointment_data['id_users_customer']); - $service_data = $this->services_model->get_row($appointment_data['id_services']); + $appointment = $this->appointments_model->get_row($appointment['id']); + $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'), @@ -102,21 +104,23 @@ class Backend_api extends CI_Controller { // :: SYNC APPOINTMENT CHANGES WITH GOOGLE CALENDAR try { $google_sync = $this->providers_model->get_setting('google_sync', - $appointment_data['id_users_provider']); + $appointment['id_users_provider']); if ($google_sync == TRUE) { $google_token = json_decode($this->providers_model->get_setting('google_token', - $appointment_data['id_users_provider'])); + $appointment['id_users_provider'])); $this->load->library('Google_Sync'); $this->google_sync->refresh_token($google_token->refresh_token); - if ($appointment_data['id_google_calendar'] == NULL) { - $this->google_sync->add_appointment($appointment_data, $provider_data, - $service_data, $customer_data, $company_settings); + if ($appointment['id_google_calendar'] == NULL) { + $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); // Store google calendar id. } else { - $this->google_sync->update_appointment($appointment_data, $provider_data, - $service_data, $customer_data, $company_settings); + $this->google_sync->update_appointment($appointment, $provider, + $service, $customer, $company_settings); } } } catch(Exception $exc) { @@ -133,32 +137,32 @@ class Backend_api extends CI_Controller { . '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']; + . $appointment['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']; + . $appointment['hash']; } else { $customer_title = 'Appointment changes have been successfully saved!'; $customer_message = ''; $customer_link = $this->config->item('base_url') . 'appointments/index/' - . $appointment_data['hash']; + . $appointment['hash']; $provider_title = 'Appointment details have changed.'; $provider_message = ''; $provider_link = $this->config->item('base_url') . 'backend/' - . $appointment_data['hash']; + . $appointment['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, $provider, + $service, $customer, $company_settings, $customer_title, + $customer_message, $customer_link, $customer['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']); + $this->notifications->send_appointment_details($appointment, $provider, + $service, $customer, $company_settings, $provider_title, + $provider_message, $provider_link, $provider['email']); } catch(Exception $exc) { $warnings[] = exceptionToJavascript($exc); @@ -298,7 +302,7 @@ class Backend_api extends CI_Controller { try { $this->load->model('customers_model'); - $key = $_POST['key']; //$this->db->escape($_POST['key']); + $key = $_POST['key']; // @task $this->db->escape($_POST['key']); $where_clause = 'first_name LIKE "%' . $key . '%" OR ' . @@ -316,6 +320,76 @@ class Backend_api extends CI_Controller { )); } } + + /** + * [AJAX] Insert of update unavailable time period to database. + * + * @param array $_POST['unavailable'] JSON encoded array that contains the unavailable + * period data. + */ + public function ajax_save_unavailable() { + try { + $this->load->model('appointments_model'); + $this->load->model('providers_model'); + + // Add appointment + $unavailable = json_decode($_POST['unavailable'], true); + $this->appointments_model->add_unavailable($unavailable); + + // Google Sync + try { + $google_sync = $this->providers_model->get_setting('google_sync', + $unavailable['id_users_provider']); + + if ($google_sync) { + $google_token = json_decode($this->providers_model->get_setting('google_token', + $unavailable['id_users_provider'])); + + $this->load->library('google_sync'); + $this->google_sync->refresh_token($google_token->refresh_token); + + // @task Sync with gcal. + $google_event = $this->google_sync->add_unavailable($unavailable); + + $unavailable['id_google_calendar'] = $google_event->id; + $this->appointments_model->add_unavailable($unavailable); + } + } catch(Exception $exc) { + $warnings[] = $exc; + } + + if (isset($warnings)) { + echo json_encode(array( + 'warnings' => $warnings + )); + } else { + echo json_encode('SUCCESS'); + } + + } catch(Exception $exc) { + echo json_encode(array( + 'exceptions' => array($exc) + )); + } + } + + /** + * [AJAX] Delete an unavailable time period from database. + * + * @param numeric $_POST['unavailable_id'] Record id to be deleted. + */ + public function ajax_delete_unavailable() { + try { + // Delete unavailable + + // Google Sync + + } catch(Exception $exc) { + echo json_encode(array( + 'exceptions' => array($exc) + )); + } + } } /* End of file backend_api.php */ diff --git a/src/application/libraries/google_sync.php b/src/application/libraries/google_sync.php index c21e849d..337f7a51 100644 --- a/src/application/libraries/google_sync.php +++ b/src/application/libraries/google_sync.php @@ -94,41 +94,40 @@ class Google_Sync { * If yes, the selected appointment record is going to be added to the Google * Calendar account. * - * @param array $appointment_data Contains the appointment record data. - * @param array $provider_data Contains the provider record data. - * @param array $service_data Contains the service record data. - * @param array $customer_data Contains the customer recod data. + * @param array $appointment Contains the appointment record data. + * @param array $provider Contains the provider record data. + * @param array $service Contains the service record data. + * @param array $customer Contains the customer recod data. * @parma array $company_settings Contains some company settings that are used * by this method. By the time the following values must be in the array: * 'company_name'. * @return Google_Event Returns the Google_Event class object. */ - public function add_appointment($appointment_data, $provider_data, $service_data, - $customer_data, $company_settings) { + public function add_appointment($appointment, $provider, $service, $customer, $company_settings) { $this->CI->load->helper('general'); $event = new Google_Event(); - $event->setSummary($service_data['name']); + $event->setSummary($service['name']); $event->setLocation($company_settings['company_name']); $start = new Google_EventDateTime(); - $start->setDateTime(date3339(strtotime($appointment_data['start_datetime']))); + $start->setDateTime(date3339(strtotime($appointment['start_datetime']))); $event->setStart($start); $end = new Google_EventDateTime(); - $end->setDateTime(date3339(strtotime($appointment_data['end_datetime']))); + $end->setDateTime(date3339(strtotime($appointment['end_datetime']))); $event->setEnd($end); $eventProvider = new Google_EventAttendee(); - $eventProvider->setDisplayName($provider_data['first_name'] . ' ' - . $provider_data['last_name']); - $eventProvider->setEmail($provider_data['email']); + $eventProvider->setDisplayName($provider['first_name'] . ' ' + . $provider['last_name']); + $eventProvider->setEmail($provider['email']); $eventCustomer = new Google_EventAttendee(); - $eventCustomer->setDisplayName($customer_data['first_name'] . ' ' - . $customer_data['last_name']); - $eventCustomer->setEmail($customer_data['email']); + $eventCustomer->setDisplayName($customer['first_name'] . ' ' + . $customer['last_name']); + $eventCustomer->setEmail($customer['email']); $event->attendees = array( $eventProvider, @@ -138,10 +137,6 @@ class Google_Sync { // Add the new event to the "primary" calendar. $created_event = $this->service->events->insert('primary', $event); - // Set the Google Calendar event id to the E!A database record. - $appointment_data['id_google_calendar'] = $created_event->id; - $this->CI->appointments_model->add($appointment_data); - return $created_event; } @@ -151,43 +146,42 @@ class Google_Sync { * This method updates the google calendar event item that is connected with the * provided appointment record of Easy!Appointments. * - * @param array $appointment_data Contains the appointment record data. - * @param array $provider_data Contains the provider record data. - * @param array $service_data Contains the service record data. - * @param array $customer_data Contains the customer recod data. + * @param array $appointment Contains the appointment record data. + * @param array $provider Contains the provider record data. + * @param array $service Contains the service record data. + * @param array $customer Contains the customer recod data. * @parma array $company_settings Contains some company settings that are used * by this method. By the time the following values must be in the array: * 'company_name'. * @return Google_Event Returns the Google_Event class object. */ - public function update_appointment($appointment_data, $provider_data, - $service_data, $customer_data, $company_settings) { + public function update_appointment($appointment, $provider, $service, $customer, $company_settings) { $this->CI->load->helper('general'); - $event = $this->service->events->get('primary', $appointment_data['id_google_calendar']); + $event = $this->service->events->get('primary', $appointment['id_google_calendar']); // Convert event to object - $event->setSummary($service_data['name']); + $event->setSummary($service['name']); $event->setLocation($company_settings['company_name']); $start = new Google_EventDateTime(); - $start->setDateTime(date3339(strtotime($appointment_data['start_datetime']))); + $start->setDateTime(date3339(strtotime($appointment['start_datetime']))); $event->setStart($start); $end = new Google_EventDateTime(); - $end->setDateTime(date3339(strtotime($appointment_data['end_datetime']))); + $end->setDateTime(date3339(strtotime($appointment['end_datetime']))); $event->setEnd($end); $event_provider = new Google_EventAttendee(); - $event_provider->setDisplayName($provider_data['first_name'] . ' ' - . $provider_data['last_name']); - $event_provider->setEmail($provider_data['email']); + $event_provider->setDisplayName($provider['first_name'] . ' ' + . $provider['last_name']); + $event_provider->setEmail($provider['email']); $event_customer = new Google_EventAttendee(); - $event_customer->setDisplayName($customer_data['first_name'] . ' ' - . $customer_data['last_name']); - $event_customer->setEmail($customer_data['email']); + $event_customer->setDisplayName($customer['first_name'] . ' ' + . $customer['last_name']); + $event_customer->setEmail($customer['email']); $event->attendees = array( $event_provider, @@ -208,6 +202,10 @@ class Google_Sync { public function delete_appointment($google_calendar_id) { $this->service->events->delete('primary', $google_calendar_id); } + + public function add_unavailble($unavailable) { + // @task Implement + } } /* End of file google_sync.php */ diff --git a/src/application/models/appointments_model.php b/src/application/models/appointments_model.php index 5cbbedfc..b992c4d3 100644 --- a/src/application/models/appointments_model.php +++ b/src/application/models/appointments_model.php @@ -217,12 +217,10 @@ class Appointments_Model extends CI_Model { */ public function delete($appointment_id) { if (!is_numeric($appointment_id)) { - throw new Exception('Invalid argument type $appointment_id : ' - . $appointment_id); + throw new Exception('Invalid argument type $appointment_id (value:"' . $appointment_id . '")'); } - $num_rows = $this->db->get_where('ea_appointments', - array('id' => $appointment_id))->num_rows(); + $num_rows = $this->db->get_where('ea_appointments', array('id' => $appointment_id))->num_rows(); if ($num_rows == 0) { return FALSE; // Record does not exist. @@ -315,6 +313,66 @@ class Appointments_Model extends CI_Model { $current_date = new DateTime(); return md5($current_date->getTimestamp()); } + + /** + * Inserts or updates an unavailable period record in the database. + * + * @param array $unavailable Contains the unavaible data. + * @return int Returns the record id. + */ + public function add_unavailable($unavailable) { + // Validate period + $start = strtotime($unavailable['start_datetime']); + $end = strtotime($unavailable['end_datetime']); + if ($start > $end) { + throw new Exception('Unavailable period start must be prior to end.'); + } + + // Validate provider record + $where_clause = array( + 'id' => $unavailable['id_users_provider'], + 'id_roles' => $this->db->get_where('ea_roles', array('slug' => DB_SLUG_PROVIDER))->row()->id + ); + + if ($this->db->get_where('ea_users', $where_clause)->num_rows() == 0) { + throw new Exception('Provider id was not found in database.'); + } + + // Add record to database (insert or update). + if (!isset($unavailable['id'])) { + $unavailable['book_datetime'] = date('Y-m-d H:i:s'); + $unavailable['is_unavailable'] = true; + + $this->db->insert('ea_appointments', $unavailable); + $unavailable['id'] = $this->db->insert_id(); + } else { + $this->db->where(array('id' => $unavailable['id'])); + $this->db->update('ea_appointments', $unavailable); + } + + return $unavailable['id']; + } + + /** + * Delete an unavailable period. + * + * @param numeric $unavailable_id Record id to be deleted. + */ + public function delete_unavailable($unavailable_id) { + if (!is_numeric($unavailable_id)) { + throw new Exception('Invalid argument type $appointment_id (value:"' . + $unavailable_id . '")'); + } + + $num_rows = $this->db->get_where('ea_appointments', array('id' => $unavailable_id)) + ->num_rows(); + if ($num_rows == 0) { + return FALSE; // Record does not exist. + } + + $this->db->where('id', $unavailable_id); + return $this->db->delete('ea_appointments'); + } } /* End of file appointments_model.php */ diff --git a/src/application/models/services_model.php b/src/application/models/services_model.php index 5395c08d..5ff035b2 100644 --- a/src/application/models/services_model.php +++ b/src/application/models/services_model.php @@ -10,14 +10,14 @@ class Services_Model extends CI_Model { /** * Get a specific row from the services db table. * - * @param int $service_id The record's id to be returned. + * @param numeric $service_id The record's id to be returned. * @return array Returns an associative array with the selected * record's data. Each key has the same name as the database * field names. */ public function get_row($service_id) { if (!is_numeric($service_id)) { - throw new Exception('$service_id argument is not an integer : ' . $service_id); + throw new Exception('$service_id argument is not an numeric (value: "' . $service_id . '")'); } return $this->db->get_where('ea_services', array('id' => $service_id))->row_array(); } diff --git a/src/application/views/backend/calendar.php b/src/application/views/backend/calendar.php index be214393..355f3d27 100644 --- a/src/application/views/backend/calendar.php +++ b/src/application/views/backend/calendar.php @@ -58,7 +58,7 @@ @@ -66,7 +66,7 @@ -
+
+ + + \ No newline at end of file diff --git a/src/assets/js/backend.js b/src/assets/js/backend.js index 6ef1b195..231eed72 100644 --- a/src/assets/js/backend.js +++ b/src/assets/js/backend.js @@ -22,6 +22,14 @@ $(document).ready(function() { * @namespace Backend */ var Backend = { + /** + * Backend Constants + */ + EXCEPTIONS_TITLE: 'Unexpected Issues', + EXCEPTIONS_MESSAGE: 'The operation could not complete due to unexpected issues. ', + WARNINGS_TITLE: 'Unexpected Warnings', + WARNINGS_MESSAGE: 'The operation completed but some warnings appeared. ', + /** * Place the backend footer always on the bottom of the page. */ diff --git a/src/assets/js/backend_calendar.js b/src/assets/js/backend_calendar.js index 6afa889a..94997aab 100644 --- a/src/assets/js/backend_calendar.js +++ b/src/assets/js/backend_calendar.js @@ -113,13 +113,10 @@ var BackendCalendar = { === BackendCalendar.FILTER_TYPE_SERVICE) { $('#google-sync, #enable-sync, #insert-appointment, #insert-unavailable') .prop('disabled', true); - // @task Hide the unavailable periods. } else { $('#google-sync, #enable-sync, #insert-appointment, #insert-unavailable') .prop('disabled', false); - // @task Show the unavailable periods. - // If the user has already the sync enabled then apply the proper // style changes. if ($('#select-filter-item option:selected').attr('google-sync') === 'true') { @@ -226,17 +223,14 @@ var BackendCalendar = { if (response.exceptions) { response.exceptions = GeneralFunctions.parseExceptions(response.exceptions); - GeneralFunctions.displayMessageBox('Unexpected Issues', 'Unfortunately ' - + 'the operation could not complete successfully. The following ' - + 'issues occured:'); + GeneralFunctions.displayMessageBox(Backend.EXCEPTIONS_TITLE, Backend.EXCEPTIONS_MESSAGE); $('#message_box').append(GeneralFunctions.exceptionsToHtml(response.exceptions)); return; } if (response.warnings) { response.warnings = GeneralFunctions.parseExceptions(response.warnings); - GeneralFunctions.displayMessageBox('Unexpected Warnings', 'The operation ' - + 'was completed but the following warnings appeared:'); + GeneralFunctions.displayMessageBox(Backend.WARNINGS_TITLE, Backend.WARNINGS_MESSAGE); $('#message_box').append(GeneralFunctions.exceptionsToHtml(response.warnings)); } @@ -260,7 +254,7 @@ var BackendCalendar = { * * Closes the dialog without saving any changes to the database. */ - $('#manage-appointment #cancel-button').click(function() { + $('#manage-appointment #cancel-appointment').click(function() { $('#manage-appointment').modal('hide'); }); @@ -270,7 +264,7 @@ var BackendCalendar = { * Stores the appointment changes or inserts a new appointment depending the dialog * mode. */ - $('#manage-appointment #save-button').click(function() { + $('#manage-appointment #save-appointment').click(function() { // Before doing anything the appointment data need to be validated. if (!BackendCalendar.validateAppointmentForm()) { return; // validation failed @@ -320,9 +314,7 @@ var BackendCalendar = { var successCallback = function(response) { if (response.exceptions) { response.exceptions = GeneralFunctions.parseExceptions(response.exceptions); - GeneralFunctions.displayMessageBox('Unexpected Issues', 'Unfortunately ' - + 'the operation could not complete successfully. The following ' - + 'issues occured:'); + GeneralFunctions.displayMessageBox(Backend.EXCEPTIONS_TITLE, Backend.EXCEPTIONS_MESSAGE); $('#messsage_box').append(GeneralFunctions.exceptionsToHtml(response.exceptions)); $dialog.find('.modal-header').append( @@ -357,10 +349,70 @@ var BackendCalendar = { }; // :: CALL THE UPDATE APPOINTMENT METHOD - BackendCalendar.saveAppointmentData(appointment, customer, + BackendCalendar.saveAppointment(appointment, customer, successCallback, errorCallback); }); + $('#manage-unavailable #save-unavailable').click(function() { + var $dialog = $('#manage-unavailable'); + + var start = Date.parseExact($dialog.find('#unavailable-start').val(), 'dd/MM/yyyy HH:mm'); + var end = Date.parseExact($dialog.find('#unavailable-end').val(), 'dd/MM/yyyy HH:mm'); + + if (start > end) { + // Start time is after end time - display message to user. + $dialog.find('.modal-message').html( + '
' + + 'Start date value is bigger than end date!' + + '
'); + return; + } + + // Unavailable period records go to the appointments table. + var unavailable = { + 'start_datetime': start.toString('yyyy-MM-dd HH:mm'), + 'end_datetime': end.toString('yyyy-MM-dd HH:mm'), + 'notes': $dialog.find('#unavailable-notes').val(), + 'id_users_provider': $('#select-filter-item').val() // curr provider + }; + + var successCallback = function(response) { + /////////////////////////////////////////////////////////////////// + console.log('Save Unavailable Time Period Response:', response); + /////////////////////////////////////////////////////////////////// + + if (response.exceptions) { + response.exceptions = GeneralFunctions.parseExceptions(response.exceptions); + GeneralFunctions.displayMessageBox(Backend.EXCEPTIONS_TITLE, Backend.EXCEPTIONS_MESSAGE); + $('#message_box').append(GeneralFunctions.exceptionsToHtml(response.exceptions)); + return; + } + + if (response.warnings) { + response.warnings = GeneralFunctions.parseExceptions(response.warnings); + GeneralFunctions.displayMessageBox(Backend.WARNINGS_TITLE, Backend.WARNINGS_MESSAGE); + $('#message_box').append(GeneralFunctions.exceptionsToHtml(response.warnings)); + } + + $('#manage-unavailable').modal('hide'); + }; + + var errorCallback = function(jqXHR, textStatus, errorThrown) { + //////////////////////////////////////////////////////////////////////// + console.log('Save Unavailable Error:', jqXHR, textStatus, errorThrown); + //////////////////////////////////////////////////////////////////////// + + GeneralFunctions.displayMessageBox('Communication Error', 'Unfortunately ' + + 'the operation could not complete due to server communication errors.'); + }; + + BackendCalendar.saveUnavalable(unavailable, successCallback, errorCallback); + }); + + $('#manage-unavailable #cancel-unavailable').click(function() { + $('#manage-unavailable').modal('hide'); + }); + /** * Event: Enable - Disable Synchronization Button "Click" * @@ -438,7 +490,10 @@ var BackendCalendar = { * a time period where he cannot accept any appointments. */ $('#insert-unavailable').click(function() { - // @task Implement this event handler. + BackendCalendar.resetUnavailableDialog(); + var $dialog = $('#manage-unavailable'); + $dialog.find('.modal-header h3').text('New Unavailable Period'); + $dialog.modal('show'); }); }, @@ -483,17 +538,14 @@ var BackendCalendar = { if (response.exceptions) { response.exceptions = GeneralFunctions.parseExceptions(response.exceptions); - GeneralFunctions.displayMessageBox('Unexpected Issues', 'Unfortunately ' - + 'the operation could not complete successfully. The following ' - + 'issues occured:'); + GeneralFunctions.displayMessageBox(Backend.EXCEPTIONS_TITLE, Backend.EXCEPTIONS_MESSAGE); $('#message_box').append(GeneralFunctions.exceptionsToHtml(response.exceptions)); return; } if (response.warnings) { response.warnings = GeneralFunctions.parseExceptions(response.exceptions); - GeneralFunctions.displayMessageBox('Unexpected Warnings', 'The operation was ' - + 'completed but the following warnings appeared.'); + GeneralFunctions.displayMessageBox(Backend.WARNINGS_TITLE, Backend.WARNINGS_MESSAGE); $('#message_box').append(GeneralFunctions.exceptionsToHtml(response.warnings)); } @@ -655,10 +707,8 @@ var BackendCalendar = { $('#calendar').fullCalendar('renderEvent', unavailablePeriod, true); }); - // @task Add custom unavailable periods. - currDateStart.addDays(1); currDateEnd.addDays(1); }); @@ -683,8 +733,7 @@ var BackendCalendar = { * @param {function} errorCallback (OPTIONAL) If defined, this function is * going to be executed on post failure. */ - saveAppointmentData : function(appointment, customer, - successCallback, errorCallback) { + saveAppointment: function(appointment, customer, successCallback, errorCallback) { var postUrl = GlobalVariables.baseUrl + 'backend_api/ajax_save_appointment'; var postData = {}; @@ -722,6 +771,29 @@ var BackendCalendar = { }); }, + /** + * Save unavailable period to database. + * + * @param {object} unavailable Containts the unavailable period data. + * @param {function} successCallback The ajax success callback function. + * @param {function} errorCallback The ajax failure callback function. + */ + saveUnavalable: function(unavailable, successCallback, errorCallback) { + var postUrl = GlobalVariables.baseUrl + 'backend_api/ajax_save_unavailable'; + + var postData = { + 'unavailable': JSON.stringify(unavailable) + }; + + $.ajax({ + 'type': 'POST', + 'url': postUrl, + 'data': postData, + 'success': successCallback, + 'error': errorCallback + }); + }, + /** * Calendar Event "Resize" Callback * @@ -755,9 +827,7 @@ var BackendCalendar = { var successCallback = function(response) { if (response.exceptions) { response.exceptions = GeneralFunctions.parseExceptions(response.exceptions); - GeneralFunctions.displayMessageBox('Unexpected Issues', 'Unfortunately ' - + 'the operation could not complete successfully. The following ' - + 'issues occured:'); + GeneralFunctions.displayMessageBox(Backend.EXCEPTIONS_TITLE, Backend.EXCEPTIONS_MESSAGE); $('#message_box').append(GeneralFunctions.exceptionsToHtml(response.exceptions)); return; } @@ -765,8 +835,7 @@ var BackendCalendar = { if (response.warnings) { // Display warning information to the user. response.warnings = GeneralFunctions.parseExceptions(response.warnings); - GeneralFunctions.displayMessageBox('Warnings', 'The operation completed but ' - + 'there were some warnings:'); + GeneralFunctions.displayMessageBox(Backend.WARNINGS_TITLE, Backend.WARNINGS_MESSAGE); $('#message_box').append(GeneralFunctions.exceptionsToHtml(response.warnings)); } @@ -796,7 +865,7 @@ var BackendCalendar = { }; // :: UPDATE APPOINTMENT DATA VIA AJAX CALL - BackendCalendar.saveAppointmentData(appointment, undefined, + BackendCalendar.saveAppointment(appointment, undefined, successCallback, undefined); }, @@ -836,39 +905,56 @@ var BackendCalendar = { calendarEventClick: function(event, jsEvent, view) { $('.popover').remove(); // Close all open popovers. - if ($(jsEvent.target).hasClass('fc-unavailable')) { - return; // do not show popover on unavailable events - } + var html; - // Display a popover with the event details. - var html = - '' + - 'Start ' - + event.start.toString('dd/MM/yyyy HH:mm') - + '
' + - 'End ' - + event.end.toString('dd/MM/yyyy HH:mm') - + '
' + - 'Service ' - + event.data['service']['name'] - + '
' + - 'Provider ' - + event.data['provider']['first_name'] + ' ' - + event.data['provider']['last_name'] - + '
' + - 'Customer ' - + event.data['customer']['first_name'] + ' ' - + event.data['customer']['last_name'] - + '
' + - '
' + - '' + - '' + - '' + - '
'; - + if ($(jsEvent.target.offsetParent).hasClass('fc-unavailable') + || $(jsEvent.target).parents().eq(1).hasClass('fc-unavailable')) { + html = + '' + + 'Start ' + + event.start.toString('dd/MM/yyyy HH:mm') + + '
' + + 'End ' + + event.end.toString('dd/MM/yyyy HH:mm') + + '
' + + '
' + + '' + + '' + + '' + + '
'; + } else { + html = + '' + + 'Start ' + + event.start.toString('dd/MM/yyyy HH:mm') + + '
' + + 'End ' + + event.end.toString('dd/MM/yyyy HH:mm') + + '
' + + 'Service ' + + event.data['service']['name'] + + '
' + + 'Provider ' + + event.data['provider']['first_name'] + ' ' + + event.data['provider']['last_name'] + + '
' + + 'Customer ' + + event.data['customer']['first_name'] + ' ' + + event.data['customer']['last_name'] + + '
' + + '
' + + '' + + '' + + '' + + '
'; + } + $(jsEvent.target).popover({ 'placement': 'top', 'title': event.title, @@ -921,9 +1007,7 @@ var BackendCalendar = { var successCallback = function(response) { if (response.exceptions) { response.exceptions = GeneralFunctions.parseExceptions(response.exceptions); - GeneralFunctions.displayMessageBox('Unexpected Issues', 'Unfortunately ' - + 'the operation could not complete successfully. The following ' - + 'issues occured:'); + GeneralFunctions.displayMessageBox(Backend.EXCEPTIONS_TITLE, Backend.EXCEPTIONS_MESSAGE); $('#message_box').append(GeneralFunctions.exceptionsToHtml(response.exceptions)); return; } @@ -931,8 +1015,7 @@ var BackendCalendar = { if (response.warnings) { // Display warning information to the user. response.warnings = GeneralFunctions.parseExceptions(response.warnings); - GeneralFunctions.displayMessageBox('Warnings', 'The operation completed but ' - + 'there were some warnings:'); + GeneralFunctions.displayMessageBox(Backend.WARNINGS_TITLE, Backend.WARNINGS_MESSAGE); $('#message_box').append(GeneralFunctions.exceptionsToHtml(response.warnings)); } @@ -972,7 +1055,7 @@ var BackendCalendar = { }; // :: UPDATE APPOINTMENT DATA VIA AJAX CALL - BackendCalendar.saveAppointmentData(appointment, undefined, + BackendCalendar.saveAppointment(appointment, undefined, successCallback, undefined); }, @@ -983,8 +1066,10 @@ var BackendCalendar = { * need to be made, in order to display proper information to the user. */ calendarViewDisplay : function(view) { - // Place the footer into correct position because the calendar - // height might change. + if ($('#select-filter-item').val() === null) { + return; + } + BackendCalendar.refreshCalendarAppointments( $('#calendar'), $('#select-filter-item').val(), @@ -1016,9 +1101,7 @@ var BackendCalendar = { if (response.exceptions) { response.exceptions = GeneralFunctions.parseExceptions(response.exceptions); - GeneralFunctions.displayMessageBox('Unexpected Issues', 'Unfortunately ' - + 'the operation could not complete successfully. The following ' - + 'issues occured:'); + GeneralFunctions.displayMessageBox(Backend.EXCEPTIONS_TITLE, Backend.EXCEPTIONS_MESSAGE); $('#message_box').append(GeneralFunctions.exceptionsToHtml(response.exceptions)); return; } @@ -1132,15 +1215,31 @@ var BackendCalendar = { return false; } }, - + /** - * This method adds an unavailable time period to calendar. - * - * @param {date} start The period start date and time. - * @param {date} end The period end date and time. - * @return {bool} Returns the operation result. + * Reset the "#manage-unavailable" dialog. Use this method to bring the dialog + * to the initial state before it becomes visible to the user. */ - addUnavailableTimePeriod: function(start, end) { - // @task Use this method whenever you need to add an unavailable period on calendar. + resetUnavailableDialog: function() { + var $dialog = $('#manage-unavailable'); + + // Set default time values + var start = new Date().toString('dd/MM/yyyy HH:mm'); + var end = new Date().addHours(1).toString('dd/MM/yyyy HH:mm'); + + $dialog.find('#unavailable-start').datetimepicker({ + 'dateFormat': 'dd/mm/yy', + 'minDate': 0 + }); + $dialog.find('#unavailable-start').val(start); + + $dialog.find('#unavailable-end').datetimepicker({ + 'dateFormat': 'dd/mm/yy', + 'minDate': 0 + }); + $dialog.find('#unavailable-end').val(end); + + // Clear the unavailable notes field. + $dialog.find('#unavailable-notes').val(''); } }; \ No newline at end of file diff --git a/src/configuration.php b/src/configuration.php index 146b204a..7ebebd4e 100644 --- a/src/configuration.php +++ b/src/configuration.php @@ -1,13 +1,13 @@