Finish insert appointment from backend.

This commit is contained in:
alextselegidis@gmail.com 2013-06-28 21:54:12 +00:00
parent 71fb87d685
commit 6050bf75c3
9 changed files with 281 additions and 114 deletions

View file

@ -17,10 +17,11 @@ class Backend extends CI_Controller {
$this->load->model('Settings_Model');
// Display the main backend page.
$view_data['base_url'] = $this->config->item('base_url');
$view_data['base_url'] = $this->config->item('base_url');
$view_data['book_advance_timeout'] = $this->Settings_Model->get_setting('book_advance_timeout');
$view_data['company_name'] = $this->Settings_Model->get_setting('company_name');
$view_data['available_providers'] = $this->Providers_Model->get_available_providers();
$view_data['available_services'] = $this->Services_Model->get_available_services();
$view_data['available_services'] = $this->Services_Model->get_available_services();
$this->load->view('backend/header', $view_data);
$this->load->view('backend/calendar', $view_data);
@ -96,7 +97,7 @@ class Backend extends CI_Controller {
* @param array $_POST['customer_data'] (OPTIONAL) Array with the customer
* data.
*/
public function ajax_save_appointment_changes() {
public function ajax_save_appointment() {
try {
$this->load->model('Appointments_Model');
$this->load->model('Providers_Model');
@ -104,16 +105,23 @@ class Backend extends CI_Controller {
$this->load->model('Customers_Model');
$this->load->model('Settings_Model');
// :: SAVE APPOINTMENT CHANGES TO DATABASE
if (isset($_POST['appointment_data'])) {
$appointment_data = json_decode(stripcslashes($_POST['appointment_data']), true);
$this->Appointments_Model->add($appointment_data);
}
// :: SAVE CUSTOMER CHANGES TO DATABASE
if (isset($_POST['customer_data'])) {
$customer_data = json_decode(stripcslashes($_POST['customer_data']), true);
$this->Customers_Model->add($customer_data);
$customer_data['id'] = $this->Customers_Model->add($customer_data);
}
// :: SAVE APPOINTMENT CHANGES TO DATABASE
if (isset($_POST['appointment_data'])) {
$appointment_data = json_decode(stripcslashes($_POST['appointment_data']), true);
// 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'];
}
$appointment_data['id'] = $this->Appointments_Model->add($appointment_data);
}
$appointment_data = $this->Appointments_Model->get_row($appointment_data['id']);
@ -128,20 +136,24 @@ class Backend extends CI_Controller {
);
// :: SYNC APPOINTMENT CHANGES WITH GOOGLE CALENDAR
if ($appointment_data['id_google_calendar'] != NULL) {
$google_sync = $this->Providers_Model
->get_setting('google_sync', $appointment_data['id_users_provider']);
$google_sync = $this->Providers_Model
->get_setting('google_sync', $appointment_data['id_users_provider']);
if ($google_sync == TRUE) {
$google_token = json_decode($this->Providers_Model
->get_setting('google_token', $appointment_data['id_users_provider']));
$this->load->library('Google_Sync');
$this->google_sync->refresh_token($google_token->refresh_token);
if ($google_sync == TRUE) {
$google_token = json_decode($this->Providers_Model
->get_setting('google_token', $appointment_data['id_users_provider']));
$this->load->library('Google_Sync');
$this->google_sync->refresh_token($google_token->refresh_token);
$this->google_sync->update_appointment($appointment_data, $provider_data,
$service_data, $customer_data, $company_settings);
}
if ($appointment_data['id_google_calendar'] == NULL) {
$this->google_sync->add_appointment($appointment_data, $provider_data,
$service_data, $customer_data, $company_settings);
} else {
$this->google_sync->update_appointment($appointment_data, $provider_data,
$service_data, $customer_data, $company_settings);
}
}
// :: SEND EMAIL NOTIFICATIONS TO PROVIDER AND CUSTOMER

View file

@ -225,7 +225,7 @@
<input type="text" id="phone-number" class="required" maxlength="60" />
<br/><br/>
<em id="form-message" class="text-error">Fields with * are mandatory.</em>
<em id="form-message" class="text-error">Fields with * are required!</em>
</div>
<div class="span3">

View file

@ -14,7 +14,8 @@
var GlobalVariables = {
'availableProviders' : <?php echo json_encode($available_providers); ?>,
'availableServices' : <?php echo json_encode($available_services); ?>,
'baseUrl' : <?php echo '"' . $base_url . '"'; ?>
'baseUrl' : <?php echo '"' . $base_url . '"'; ?>,
'bookAdvanceTimeout' : <?php echo $book_advance_timeout; ?>
};
$(document).ready(function() {
@ -73,6 +74,7 @@
<button type="button" class="close" data-dismiss="modal"
aria-hidden="true">&times;</button>
<h3>Edit Appointment</h3>
<div id="modal-message" class="alert" style="display: none;"></div>
</div>
<div class="modal-body">
@ -124,23 +126,23 @@
</div>
<div class="control-group">
<label for="last-name" class="control-label">Last Name</label>
<label for="last-name" class="control-label">Last Name *</label>
<div class="controls">
<input type="text" id="last-name" />
<input type="text" id="last-name" class="required" />
</div>
</div>
<div class="control-group">
<label for="email" class="control-label">Email</label>
<label for="email" class="control-label">Email *</label>
<div class="controls">
<input type="text" id="email" />
<input type="text" id="email" class="required" />
</div>
</div>
<div class="control-group">
<label for="phone-number" class="control-label">Phone Number</label>
<label for="phone-number" class="control-label">Phone Number *</label>
<div class="controls">
<input type="text" id="phone-number" />
<input type="text" id="phone-number" class="required" />
</div>
</div>

View file

@ -1,8 +1,9 @@
<!DOCTYPE html>
<html lang="en">
<head>
<title>Easy!Appointments Admin</title>
<title>Easy!Appointments Backend</title>
<meta http-equiv="content-type" content="text/html; charset=UTF-8">
<link rel="icon" type="image/x-icon"
href="<?php echo $base_url; ?>assets/images/favicon.ico">

View file

@ -35,6 +35,8 @@ root {
background: rgba(255, 255, 255, 0.75);}
#loading img { margin: auto; display: block; }
#modal-message { margin: 10px 0px; }
/* BACKEND CALENDAR PAGE
-------------------------------------------------------------------- */
#calendar-page #calendar-toolbar { margin: 15px 10px 20px 10px; padding-bottom: 10px;

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.2 KiB

View file

@ -161,72 +161,38 @@ var BackendCalendar = {
$(this).parents().eq(2).remove(); // Hide the popover
var appointmentData = BackendCalendar.lastFocusedEventData.data;
var modalHandle = $('#manage-appointment');
var dialogHandle = $('#manage-appointment');
BackendCalendar.resetAppointmentDialog();
// :: APPLY APPOINTMENT DATA AND SHOW TO MODAL DIALOG
modalHandle.find('input, textarea').val('');
modalHandle.find('#appointment-id').val(appointmentData['id']);
// Fill the services listbox and select the appointment service.
$.each(GlobalVariables.availableServices, function(index, service) {
var option = new Option(service['name'], service['id']);
modalHandle.find('#select-service').append(option);
});
$('#manage-appointment #select-service').val(
appointmentData['id_services']);
// Fill the providers listbox with providers that can serve the appointment's
// service and then select the user's provider.
$.each(GlobalVariables.availableProviders, function(index, provider) {
var canProvideService = false;
$.each(provider['services'], function(index, service) {
if (service === appointmentData['id_services']) {
canProvideService = true;
return;
}
});
if (canProvideService) {
var option = new Option(provider['first_name'] + ' '
+ provider['last_name'], provider['id']);
modalHandle.find('#select-provider').append(option);
}
});
modalHandle.find('#select-provider').val(appointmentData['id_users_provider']);
dialogHandle.find('.modal-header h3').text('Edit Appointment');
dialogHandle.find('#appointment-id').val(appointmentData['id']);
dialogHandle.find('#select-service').val(appointmentData['id_services']);
dialogHandle.find('#select-provider').val(appointmentData['id_users_provider']);
// Set the start and end datetime of the appointment.\
var startDatetime = Date.parseExact(appointmentData['start_datetime'],
'yyyy-MM-dd HH:mm:ss').toString('dd/MM/yyyy HH:mm');
modalHandle.find('#start-datetime').datetimepicker({
dateFormat : 'dd/mm/yy',
defaultValue: startDatetime
});
modalHandle.find('#start-datetime').val(startDatetime);
'yyyy-MM-dd HH:mm:ss').toString('dd/MM/yyyy HH:mm');
dialogHandle.find('#start-datetime').val(startDatetime);
var endDatetime = Date.parseExact(appointmentData['end_datetime'],
'yyyy-MM-dd HH:mm:ss').toString('dd/MM/yyyy HH:mm');
modalHandle.find('#end-datetime').datetimepicker({
dateFormat : 'dd/mm/yy',
defaultValue: endDatetime
});
modalHandle.find('#end-datetime').val(endDatetime);
dialogHandle.find('#end-datetime').val(endDatetime);
var customerData = appointmentData['customer'];
modalHandle.find('#customer-id').val(appointmentData['id_users_customer']);
modalHandle.find('#first-name').val(customerData['first_name']);
modalHandle.find('#last-name').val(customerData['last_name']);
modalHandle.find('#email').val(customerData['email']);
modalHandle.find('#phone-number').val(customerData['phone_number']);
modalHandle.find('#address').val(customerData['address']);
modalHandle.find('#city').val(customerData['city']);
modalHandle.find('#zip-code').val(customerData['zip_code']);
modalHandle.find('#notes').val(appointmentData['notes']);
dialogHandle.find('#customer-id').val(appointmentData['id_users_customer']);
dialogHandle.find('#first-name').val(customerData['first_name']);
dialogHandle.find('#last-name').val(customerData['last_name']);
dialogHandle.find('#email').val(customerData['email']);
dialogHandle.find('#phone-number').val(customerData['phone_number']);
dialogHandle.find('#address').val(customerData['address']);
dialogHandle.find('#city').val(customerData['city']);
dialogHandle.find('#zip-code').val(customerData['zip_code']);
dialogHandle.find('#notes').val(appointmentData['notes']);
// :: DISPLAY THE MANAGE APPOINTMENTS MODAL DIALOG
$('#manage-appointment').modal('show');
dialogHandle.modal('show');
});
/**
@ -249,7 +215,7 @@ var BackendCalendar = {
$.post(postUrl, postData, function(response) {
/////////////////////////////////////////////////////////
//console.log('Delete Appointment Response :', response);
console.log('Delete Appointment Response :', response);
/////////////////////////////////////////////////////////
$('#message_box').dialog('close');
@ -279,7 +245,7 @@ var BackendCalendar = {
/**
* Event: Manage Appointments Dialog Cancel Button "Click"
*
* Closes the dialog without making any actions.
* Closes the dialog without saving any changes to the database.
*/
$('#manage-appointment #cancel-button').click(function() {
$('#manage-appointment').modal('hide');
@ -288,9 +254,15 @@ var BackendCalendar = {
/**
* Event: Manage Appointments Dialog Save Button "Click"
*
* Stores the appointment changes.
* Stores the appointment changes or inserts a new appointment depending the dialog
* mode.
*/
$('#manage-appointment #save-button').click(function() {
// Before doing anything the appointment data need to be validated.
if (!BackendCalendar.validateAppointmentForm()) {
return; // validation failed
}
// :: PREPARE APPOINTMENT DATA FOR AJAX CALL
var modalHandle = $('#manage-appointment');
@ -303,17 +275,21 @@ var BackendCalendar = {
'dd/MM/yyyy HH:mm').toString('yyyy-MM-dd HH:mm:ss');
var appointmentData = {
'id' : modalHandle.find('#appointment-id').val(),
'id_services' : modalHandle.find('#select-service').val(),
'id_users_provider' : modalHandle.find('#select-provider').val(),
'id_users_customer' : modalHandle.find('#customer-id').val(),
'start_datetime' : startDatetime,
'end_datetime' : endDatetime,
'notes' : modalHandle.find('#notes').val()
};
if (modalHandle.find('#appointment-id').val() !== '') {
// Set the id value, only if we are editing an appointment.
appointmentData['id'] = modalHandle.find('#appointment-id').val();
}
var customerData = {
'id' : modalHandle.find('#customer-id').val(),
'first_name' : modalHandle.find('#first-name').val(),
'last_name' : modalHandle.find('#last-name').val(),
'email' : modalHandle.find('#email').val(),
@ -323,6 +299,12 @@ var BackendCalendar = {
'zip_code' : modalHandle.find('#zip-code').val()
};
if (modalHandle.find('#customer-id').val() !== '') {
// Set the id value, only if we are editing an appointment.
customerData['id'] = modalHandle.find('#customer-id').val();
appointmentData['id_users_customer'] = customerData['id'];
}
// :: DEFINE SUCCESS EVENT CALLBACK
var successCallback = function(response) {
if (response.error) {
@ -359,7 +341,7 @@ var BackendCalendar = {
};
// :: CALL THE UPDATE APPOINTMENT METHOD
BackendCalendar.updateAppointmentData(appointmentData, customerData,
BackendCalendar.saveAppointmentData(appointmentData, customerData,
successCallback, errorCallback);
});
@ -419,6 +401,33 @@ var BackendCalendar = {
});
}
});
/**
* Event : Insert Appointment Button "Click"
*
* When the user presses this button, the manage appointment dialog opens and lets
* the user to create a new appointment.
*/
$('#insert-appointment').click(function() {
var dialogHandle = $('#manage-appointment');
BackendCalendar.resetAppointmentDialog();
// :: PREPARE THE MANAGE APPOINTMENT DIALOG FOR INSERTION
dialogHandle.find('.modal-header h3').text('New Appointment');
// :: DISPLAY THE MANAGE APPOINTMENT MODAL DIALOG
dialogHandle.modal('show');
});
/**
* Event : Insert Unavailable Time Period Button "Click"
*
* When the user clicks this button a popup dialog appears and the use can set
* a time period where he cannot accept any appointments.
*/
$('#insert-unavailable').click(function() {
// @task Implement this event handler.
});
},
/**
@ -495,10 +504,10 @@ var BackendCalendar = {
* @param {function} errorCallback (OPTIONAL) If defined, this function is
* going to be executed on post failure.
*/
updateAppointmentData : function(appointmentData, customerData,
saveAppointmentData : function(appointmentData, customerData,
successCallback, errorCallback) {
// :: MAKE AN AJAX CALL TO SERVER - STORE APPOINTMENT DATA
var postUrl = GlobalVariables.baseUrl + 'backend/ajax_save_appointment_changes';
var postUrl = GlobalVariables.baseUrl + 'backend/ajax_save_appointment';
var postData = {};
postData['appointment_data'] = JSON.stringify(appointmentData);
@ -514,7 +523,7 @@ var BackendCalendar = {
dataType : 'json',
success : function(response) {
/////////////////////////////////////////////////////////////
console.log('Update Appointment Data Response:', response);
console.log('Save Appointment Data Response:', response);
/////////////////////////////////////////////////////////////
if (successCallback !== undefined) {
@ -523,7 +532,7 @@ var BackendCalendar = {
},
error : function(jqXHR, textStatus, errorThrown) {
//////////////////////////////////////////////////////////////////
console.log('Update Appointment Data Error:', jqXHR, textStatus,
console.log('Save Appointment Data Error:', jqXHR, textStatus,
errorThrown);
//////////////////////////////////////////////////////////////////
@ -579,7 +588,7 @@ var BackendCalendar = {
.toString('yyyy-MM-dd HH:mm:ss');
var postUrl = GlobalVariables.baseUrl
+ 'backend/ajax_save_appointment_changes';
+ 'backend/ajax_save_appointment';
var postData = {
'appointment_data' : JSON.stringify(appointmentData)
@ -601,7 +610,7 @@ var BackendCalendar = {
};
// :: UPDATE APPOINTMENT DATA VIA AJAX CALL
BackendCalendar.updateAppointmentData(appointmentData, undefined,
BackendCalendar.saveAppointmentData(appointmentData, undefined,
successCallback, undefined);
},
@ -742,7 +751,7 @@ var BackendCalendar = {
event.data['end_datetime'] = appointmentData['end_datetime'];
var postUrl = GlobalVariables.baseUrl
+ 'backend/ajax_save_appointment_changes';
+ 'backend/ajax_save_appointment';
var postData = {
'appointment_data' : JSON.stringify(appointmentData)
};
@ -764,7 +773,7 @@ var BackendCalendar = {
};
// :: UPDATE APPOINTMENT DATA VIA AJAX CALL
BackendCalendar.updateAppointmentData(appointmentData, undefined,
BackendCalendar.saveAppointmentData(appointmentData, undefined,
successCallback, undefined);
},
@ -816,5 +825,117 @@ var BackendCalendar = {
}
}, 'json');
},
/**
* This method resets the manage appointment dialog modal to its initial
* state. After that you can make any modification might be necessary in
* order to bring the dialog to the desired state.
*/
resetAppointmentDialog: function() {
var dialogHandle = $('#manage-appointment');
// :: EMPTY FORM FIELDS
dialogHandle.find('input, textarea').val('');
dialogHandle.find('#modal-message').hide();
dialogHandle.find('#select-service, #select-provider').empty();
// :: PREPARE SERVICE AND PROVIDER LISTBOXES
$.each(GlobalVariables.availableServices, function(index, service) {
var option = new Option(service['name'], service['id']);
dialogHandle.find('#select-service').append(option);
});
dialogHandle.find('#select-service').val(
dialogHandle.find('#select-service').eq(0).attr('value'));
// Fill the providers listbox with providers that can serve the appointment's
// service and then select the user's provider.
$.each(GlobalVariables.availableProviders, function(index, provider) {
var canProvideService = false;
$.each(provider['services'], function(index, service) {
if (service == dialogHandle.find('#select-service').val()) {
canProvideService = true;
return;
}
});
if (canProvideService) { // Add the provider to the listbox.
var option = new Option(provider['first_name']
+ ' ' + provider['last_name'], provider['id']);
dialogHandle.find('#select-provider').append(option);
}
});
// :: SETUP START AND END DATETIME PICKERS
// Get the selected service duration. It will be needed in order to calculate
// the appointment end datetime.
var serviceDuration = 0;
$.each(GlobalVariables.availableServices, function(index, service) {
if (service['id'] == dialogHandle.find('#select-service').val()) {
serviceDuration = service['duration'];
return;
}
});
var startDatetime = new Date().addMinutes(GlobalVariables.bookAdvanceTimeout)
.toString('dd/MM/yyyy HH:mm');
var endDatetime = new Date().addMinutes(GlobalVariables.bookAdvanceTimeout)
.addMinutes(serviceDuration).toString('dd/MM/yyyy HH:mm');
dialogHandle.find('#start-datetime').datetimepicker({
dateFormat : 'dd/mm/yy',
minDate : 0
});
dialogHandle.find('#start-datetime').val(startDatetime);
dialogHandle.find('#end-datetime').datetimepicker({
dateFormat : 'dd/mm/yy',
minDate : 0
});
dialogHandle.find('#end-datetime').val(endDatetime);
},
/**
* Validate the manage appointment dialog data. Validation checks need to
* run every time the data are going to be saved.
*
* @returns {bool} Returns the validation result.
*/
validateAppointmentForm: function() {
var dialogHandle = $('#manage-appointment');
// Reset previous validation css formating.
dialogHandle.find('.control-group').removeClass('error');
dialogHandle.find('#modal-message').hide();
try {
// :: CHECK REQUIRED FIELDS
var missingRequiredField = false;
dialogHandle.find('.required').each(function() {
if ($(this).val() === '') {
$(this).parents().eq(1).addClass('error');
missingRequiredField = true;
}
});
if (missingRequiredField) {
throw 'Fields with * are required!';
}
// :: CHECK EMAIL ADDRESS
if (!GeneralFunctions.validateEmail(dialogHandle.find('#email').val())) {
dialogHandle.find('#email').parents().eq(1).addClass('error');
throw 'Invalid email address!';
}
return true;
} catch(exc) {
dialogHandle.find('#modal-message')
.addClass('alert-error')
.text(exc)
.show('fade');
return false;
}
}
};

View file

@ -215,6 +215,8 @@ var FrontendBook = {
* 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.
*
* @task Fix the problem with this event handler. Book does not work anymore.
*/
$('#book-appointment-form').submit(function() {
event.preventDefault();
@ -245,7 +247,7 @@ var FrontendBook = {
GeneralFunctions.displayMessageBox('Appointment Hour Taken', 'Unfortunately '
+ 'the selected appointment hour is not available anymore. Please select '
+ 'another hour.');
FrontendBook.getAvailableHours($('#select-date').datepicker('getDate'));
FrontendBook.getAvailableHours($('#select-date').val());
}
}, 'json');
});
@ -341,23 +343,38 @@ var FrontendBook = {
},
/**
* This function validates the customer's data input.
* It only checks for empty fields by the time.
* 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() {
var validationResult = true;
$('.required').css('border', '');
$('.required').each(function() {
if ($(this).val() == '') {
validationResult = false;
$(this).css('border', '2px solid red');
$('#wizard-frame-3 input').css('border', '');
try {
// :: CHECK REQUIRED FIELDS
var missingRequiredField = false;
$('.required').each(function() {
if ($(this).val() == '') {
$(this).css('border', '2px solid red');
missingRequiredField = true;
}
});
if (missingRequiredField) {
throw 'Fields with * are required!';
}
});
return validationResult;
// :: CHECK EMAIL ADDRESS
if (!GeneralFunctions.validateEmail($('#email').val())) {
$('#email').css('border', '2px solid red');
throw 'Invalid email address!';
}
return true;
} catch(exc) {
$('#form-message').text(exc);
return false;
}
},
/**

View file

@ -163,5 +163,17 @@ var GeneralFunctions = {
}
throw new Error("Unable to copy obj! Its type isn't supported.");
},
/**
* This method validates an email address. If the address is not on the proper
* form then the result is FALSE.
*
* @param {string} email The email address to be checked.
* @returns {bool} Returns the validation result.
*/
validateEmail: function(email) {
var reg = /^([A-Za-z0-9_\-\.])+\@([A-Za-z0-9_\-\.])+\.([A-Za-z]{2,4})$/;
return reg.test(email);
}
};