* Optimized js code for the backend pages.

This commit is contained in:
alextselegidis@gmail.com 2013-09-25 15:43:17 +00:00
parent 3450bd93b1
commit 148258385c
17 changed files with 1596 additions and 1409 deletions

View file

@ -474,8 +474,11 @@ class Backend_api extends CI_Controller {
try { try {
$this->load->model('customers_model'); $this->load->model('customers_model');
$customer = json_decode($_POST['customer'], true); $customer = json_decode($_POST['customer'], true);
$this->customers_model->add($customer); $customer_id = $this->customers_model->add($customer);
echo json_encode(AJAX_SUCCESS); echo json_encode(array(
'status' => AJAX_SUCCESS,
'id' => $customer_id
));
} catch(Exception $exc) { } catch(Exception $exc) {
echo json_encode(array( echo json_encode(array(
'exceptions' => array(exceptionToJavaScript($exc)) 'exceptions' => array(exceptionToJavaScript($exc))
@ -509,8 +512,11 @@ class Backend_api extends CI_Controller {
try { try {
$this->load->model('services_model'); $this->load->model('services_model');
$service = json_decode($_POST['service'], true); $service = json_decode($_POST['service'], true);
$this->services_model->add($service); $service_id =$this->services_model->add($service);
echo json_encode(AJAX_SUCCESS); echo json_encode(array(
'status' => AJAX_SUCCESS,
'id' => $service_id
));
} catch(Exception $exc) { } catch(Exception $exc) {
echo json_encode(array( echo json_encode(array(
'exceptions' => array(exceptionToJavaScript($exc)) 'exceptions' => array(exceptionToJavaScript($exc))
@ -568,8 +574,11 @@ class Backend_api extends CI_Controller {
try { try {
$this->load->model('services_model'); $this->load->model('services_model');
$category = json_decode($_POST['category'], true); $category = json_decode($_POST['category'], true);
$this->services_model->add_category($category); $category_id = $this->services_model->add_category($category);
echo json_encode(AJAX_SUCCESS); echo json_encode(array(
'status' => AJAX_SUCCESS,
'id' => $category_id
));
} catch(Exception $exc) { } catch(Exception $exc) {
echo json_encode(array( echo json_encode(array(
'exceptions' => array(exceptionToJavaScript($exc)) 'exceptions' => array(exceptionToJavaScript($exc))
@ -644,15 +653,21 @@ class Backend_api extends CI_Controller {
* *
* @param array $_POST['admin'] A json encoded array that contains the admin data. If an 'id' * @param array $_POST['admin'] A json encoded array that contains the admin data. If an 'id'
* value is provided then the record is going to be updated. * value is provided then the record is going to be updated.
* @return string Returns the success contant 'AJAX_SUCCESS' so javascript knows that * @return array Returns an array with the operation status and the record id that was
* everything completed successfully. * saved into the database.
*/ */
public function ajax_save_admin() { public function ajax_save_admin() {
try { try {
$this->load->model('admins_model'); $this->load->model('admins_model');
$admin = json_decode($_POST['admin'], true); $admin = json_decode($_POST['admin'], true);
$this->admins_model->add($admin); $admin_id = $this->admins_model->add($admin);
echo json_encode(AJAX_SUCCESS);
$response = array(
'status' => AJAX_SUCCESS,
'id' => $admin_id
);
echo json_encode($response);
} catch(Exception $exc) { } catch(Exception $exc) {
echo json_encode(array( echo json_encode(array(
'exceptions' => array(exceptionToJavaScript($exc)) 'exceptions' => array(exceptionToJavaScript($exc))
@ -722,8 +737,13 @@ class Backend_api extends CI_Controller {
->get_setting('company_working_plan'); ->get_setting('company_working_plan');
} }
$this->providers_model->add($provider); $provider_id = $this->providers_model->add($provider);
echo json_encode(AJAX_SUCCESS);
echo json_encode(array(
'status' => AJAX_SUCCESS,
'id' => $provider_id
));
} catch(Exception $exc) { } catch(Exception $exc) {
echo json_encode(array( echo json_encode(array(
'exceptions' => array(exceptionToJavaScript($exc)) 'exceptions' => array(exceptionToJavaScript($exc))
@ -786,8 +806,12 @@ class Backend_api extends CI_Controller {
try { try {
$this->load->model('secretaries_model'); $this->load->model('secretaries_model');
$secretary = json_decode($_POST['secretary'], true); $secretary = json_decode($_POST['secretary'], true);
$this->secretaries_model->add($secretary); $secretary_id = $this->secretaries_model->add($secretary);
echo json_encode(AJAX_SUCCESS);
echo json_encode(array(
'status' => AJAX_SUCCESS,
'id' => $secretary_id
));
} catch(Exception $exc) { } catch(Exception $exc) {
echo json_encode(array( echo json_encode(array(
'exceptions' => array(exceptionToJavaScript($exc)) 'exceptions' => array(exceptionToJavaScript($exc))

View file

@ -204,16 +204,6 @@ class Secretaries_Model extends CI_Model {
throw new Exception('Invalid email address provided : ' . $secretary['email']); throw new Exception('Invalid email address provided : ' . $secretary['email']);
} }
// Validate admin username
if (isset($secretary['settings']['username'])) {
$num_rows = $this->db->get_where('ea_user_settings',
array('username' => $secretary['settings']['username']))->num_rows();
if ($num_rows > 0) {
throw new Exception('Username already exists, please select another '
. 'and try again (username: ' . $secretary['settings']['username'] . ')');
}
}
// Validate admin password // Validate admin password
if (isset($secretary['settings']['password'])) { if (isset($secretary['settings']['password'])) {
if (strlen($secretary['settings']['password']) < MIN_PASSWORD_LENGTH) { if (strlen($secretary['settings']['password']) < MIN_PASSWORD_LENGTH) {

View file

@ -18,14 +18,21 @@
</script> </script>
<div id="customers-page" class="row-fluid"> <div id="customers-page" class="row-fluid">
<div id="filter" class="span4"> <div id="filter-customers" class="filter-records column span4">
<div class="input-append"> <form class="input-append">
<input class="span12" type="text" id="filter-key" /> <input class="key span8" type="text" />
<button type="button" class="btn" id="filter-customers">Filter</button> <button class="filter btn" type="submit">
</div> <i class="icon-filter"></i>
Filter
</button>
<button class="clear btn" type="button">
<i class="icon-remove-circle"></i>
Clear
</button>
</form>
<h2>Customers</h2> <h2>Customers</h2>
<div id="filter-results"></div> <div class="results"></div>
</div> </div>
<div id="details" class="span7 row-fluid"> <div id="details" class="span7 row-fluid">

View file

@ -28,16 +28,24 @@
?> ?>
<div id="services" class="tab-content"> <div id="services" class="tab-content">
<?php // FILTER SERVICES ?> <?php // FILTER SERVICES ?>
<div class="filter span4"> <div id="filter-services" class="filter-records column span4">
<div class="input-append"> <form class="input-append">
<input class="filter-key span12" type="text" /> <input class="key span8" type="text" />
<button class="filter-services btn" type="button">Filter</button> <button class="filter btn" type="submit">
</div> <i class="icon-filter"></i>
Filter
</button>
<button class="clear btn" type="button">
<i class="icon-remove-circle"></i>
Clear
</button>
</form>
<h2>Services</h2> <h2>Services</h2>
<div class="filter-results"></div> <div class="results"></div>
</div> </div>
<div class="details span7"> <div class="details column span7">
<div class="btn-toolbar"> <div class="btn-toolbar">
<div class="add-edit-delete-group btn-group"> <div class="add-edit-delete-group btn-group">
<button id="add-service" class="btn"> <button id="add-service" class="btn">
@ -97,14 +105,21 @@
// -------------------------------------------------------------- // --------------------------------------------------------------
?> ?>
<div id="categories" class="tab-content" style="display:none;"> <div id="categories" class="tab-content" style="display:none;">
<div class="filter span4"> <div id="filter-categories" class="filter-records column span4">
<div class="input-append"> <form class="input-append">
<input class="filter-key span12" type="text" class="" /> <input class="key span8" type="text" class="" />
<button class="filter-categories btn" type="button">Filter</button> <button class="filter btn" type="submit">
</div> <i class="icon-filter"></i>
Filter
</button>
<button class="clear btn" type="button">
<i class="icon-remove-circle"></i>
Clear
</button>
</form>
<h2>Categories</h2> <h2>Categories</h2>
<div class="filter-results"></div> <div class="results"></div>
</div> </div>
<div class="details span7"> <div class="details span7">

View file

@ -1,5 +1,7 @@
<script type="text/javascript" <script type="text/javascript"
src="<?php echo $base_url; ?>assets/js/backend_settings.js"></script> src="<?php echo $base_url; ?>assets/js/backend_settings.js"></script>
<script type="text/javascript"
src="<?php echo $base_url; ?>assets/js/working_plan.js"></script>
<script type="text/javascript" <script type="text/javascript"
src="<?php echo $base_url; ?>assets/js/libs/jquery/jquery-ui-timepicker-addon.js"></script> src="<?php echo $base_url; ?>assets/js/libs/jquery/jquery-ui-timepicker-addon.js"></script>
<script type="text/javascript" <script type="text/javascript"
@ -65,7 +67,7 @@
<a href="<?php echo $this->config->base_url(); ?>" class="btn btn-primary btn-large"> <a href="<?php echo $this->config->base_url(); ?>" class="btn btn-primary btn-large">
<i class="icon-calendar icon-white"></i> <i class="icon-calendar icon-white"></i>
Visit Book Appointment Page Book Appointment Page
</a> </a>
</fieldset> </fieldset>
</form> </form>
@ -174,7 +176,7 @@
<br> <br>
<table id="breaks" class="table table-striped"> <table class="breaks table table-striped">
<thead> <thead>
<tr> <tr>
<th>Day</th> <th>Day</th>
@ -255,8 +257,8 @@
<br> <br>
<button type="button" id="user-notifications" class="btn" data-toggle="button"> <button type="button" id="user-notifications" class="btn" data-toggle="button">
<i class="icon-asterisk"></i> <i class="icon-envelope"></i>
Receive Email Notifications Receive Notifications
</button> </button>
</fieldset> </fieldset>
</form> </form>

View file

@ -8,6 +8,9 @@
<script type="text/javascript" <script type="text/javascript"
src="<?php echo $base_url; ?>assets/js/backend_users_secretaries.js"></script> src="<?php echo $base_url; ?>assets/js/backend_users_secretaries.js"></script>
<script type="text/javascript"
src="<?php echo $base_url; ?>assets/js/working_plan.js"></script>
<script type="text/javascript" <script type="text/javascript"
src="<?php echo $base_url; ?>assets/js/libs/jquery/jquery-ui-timepicker-addon.js"></script> src="<?php echo $base_url; ?>assets/js/libs/jquery/jquery-ui-timepicker-addon.js"></script>
<script type="text/javascript" <script type="text/javascript"
@ -30,25 +33,45 @@
<div id="users-page" class="row-fluid"> <div id="users-page" class="row-fluid">
<?php // Page Tabs ?> <?php
// ---------------------------------------------------------------------
//
// Page Navigation
//
// ---------------------------------------------------------------------
?>
<ul class="nav nav-tabs"> <ul class="nav nav-tabs">
<li class="admins-tab tab active"><a>Admins</a></li> <li class="admins-tab tab active"><a>Admins</a></li>
<li class="providers-tab tab"><a>Providers</a></li> <li class="providers-tab tab"><a>Providers</a></li>
<li class="secretaries-tab tab"><a>Secretaries</a></li> <li class="secretaries-tab tab"><a>Secretaries</a></li>
</ul> </ul>
<?php // Admin Tab ?> <?php
// ---------------------------------------------------------------------
//
// Admins Tab
//
// ---------------------------------------------------------------------
?>
<div id="admins" class="tab-content"> <div id="admins" class="tab-content">
<div class="filter span4"> <div id="filter-admins" class="filter-records column span4">
<div class="input-append"> <form class="input-append">
<input class="filter-key span12" type="text" /> <input class="key span8" type="text" />
<button class="filter-admins btn" type="button">Filter</button> <button class="filter btn" type="submit">
</div> <i class="icon-filter"></i>
Filter
</button>
<button class="clear btn" type="button">
<i class="icon-remove-circle"></i>
Clear
</button>
</form>
<h2>Admins</h2> <h2>Admins</h2>
<div class="filter-results"></div> <div class="results"></div>
</div> </div>
<div class="details span7"> <div class="details column span7">
<div class="btn-toolbar"> <div class="btn-toolbar">
<div class="add-edit-delete-group btn-group"> <div class="add-edit-delete-group btn-group">
<button id="add-admin" class="btn"> <button id="add-admin" class="btn">
@ -123,26 +146,40 @@
<br> <br>
<button type="button" id="admin-notifications" class="btn" data-toggle="button"> <button type="button" id="admin-notifications" class="btn" data-toggle="button">
<i class="icon-asterisk"></i> <i class="icon-envelope"></i>
<span>Receive Email Notifications</span> <span>Receive Notifications</span>
</button> </button>
</div> </div>
</div> </div>
</div> </div>
</div> </div>
<?php // Providers Tab ?> <?php
// ---------------------------------------------------------------------
//
// Providers Tab
//
// ---------------------------------------------------------------------
?>
<div id="providers" class="tab-content" style="display:none;"> <div id="providers" class="tab-content" style="display:none;">
<div class="filter span4"> <div id="filter-providers" class="filter-records column span4">
<div class="input-append"> <form class="input-append">
<input class="filter-key span12" type="text" /> <input class="key span8" type="text" />
<button class="filter-providers btn" type="button">Filter</button> <button class="filter btn" type="submit">
</div> <i class="icon-filter"></i>
Filter
</button>
<button class="clear btn" type="button">
<i class="icon-remove-circle"></i>
Clear
</button>
</form>
<h2>Providers</h2> <h2>Providers</h2>
<div class="filter-results"></div> <div class="results"></div>
</div> </div>
<div class="details span7"> <div class="details column span7">
<div class="btn-toolbar span5"> <div class="btn-toolbar span5">
<div class="add-edit-delete-group btn-group"> <div class="add-edit-delete-group btn-group">
<button id="add-provider" class="btn"> <button id="add-provider" class="btn">
@ -167,13 +204,16 @@
</div> </div>
<div class="switch-view pull-right"> <div class="switch-view pull-right">
<strong>Current View</strong>
<div class="display-details current">Details</div> <div class="display-details current">Details</div>
<div class="display-working-plan">Working Plan</div> <div class="display-working-plan">Working Plan</div>
</div> </div>
<?php // This form message is outside the details view, so that it can be
// visible when the user has working plan view active. ?>
<div class="form-message alert" style="display:none;"></div> <div class="form-message alert" style="display:none;"></div>
<div class="details-view"> <div class="details-view provider-view">
<h2>Details</h2> <h2>Details</h2>
<input type="hidden" id="provider-id" class="record-id" /> <input type="hidden" id="provider-id" class="record-id" />
@ -223,8 +263,8 @@
<br> <br>
<button type="button" id="provider-notifications" class="btn" data-toggle="button"> <button type="button" id="provider-notifications" class="btn" data-toggle="button">
<i class="icon-asterisk"></i> <i class="icon-envelope"></i>
<span>Receive Email Notifications</span> <span>Receive Notifications</span>
</button> </button>
<br><br> <br><br>
@ -235,7 +275,7 @@
</div> </div>
</div> </div>
<div class="working-plan-view" style="display: none;"> <div class="working-plan-view provider-view" style="display: none;">
<h2>Working Plan</h2> <h2>Working Plan</h2>
<table class="working-plan table table-striped"> <table class="working-plan table table-striped">
<thead> <thead>
@ -302,7 +342,7 @@
<br> <br>
<table id="breaks" class="table table-striped"> <table class="breaks table table-striped">
<thead> <thead>
<tr> <tr>
<th>Day</th> <th>Day</th>
@ -318,18 +358,32 @@
</div> </div>
</div> </div>
<?php // Secretaries Tab ?> <?php
// ---------------------------------------------------------------------
//
// Secretaries Tab
//
// ---------------------------------------------------------------------
?>
<div id="secretaries" class="tab-content" style="display:none;"> <div id="secretaries" class="tab-content" style="display:none;">
<div class="filter span4"> <div id="filter-secretaries" class="filter-records column span4">
<div class="input-append"> <form class="input-append">
<input class="filter-key span12" type="text" /> <input class="key span8" type="text" />
<button class="filter-secretaries btn" type="button">Filter</button> <button class="filter btn" type="submit">
</div> <i class="icon-filter"></i>
Filter
</button>
<button class="clear btn" type="button">
<i class="icon-remove-circle"></i>
Clear
</button>
</form>
<h2>Secretaries</h2> <h2>Secretaries</h2>
<div class="filter-results"></div> <div class="results"></div>
</div> </div>
<div class="details span7"> <div class="details column span7">
<div class="btn-toolbar"> <div class="btn-toolbar">
<div class="add-edit-delete-group btn-group"> <div class="add-edit-delete-group btn-group">
<button id="add-secretary" class="btn"> <button id="add-secretary" class="btn">
@ -404,7 +458,7 @@
<br> <br>
<button type="button" id="secretary-notifications" class="btn" data-toggle="button"> <button type="button" id="secretary-notifications" class="btn" data-toggle="button">
<i class="icon-asterisk"></i> <i class="icon-envelope"></i>
<span>Receive Notifications</span> <span>Receive Notifications</span>
</button> </button>

View file

@ -194,24 +194,25 @@ body .modal-header h3 {
/* BACKEND CUSTOMERS PAGE /* BACKEND CUSTOMERS PAGE
-------------------------------------------------------------------- */ -------------------------------------------------------------------- */
#customers-page #filter { #customers-page #filter-customers {
margin: 15px 0px 15px 15px; margin: 15px 0px 15px 15px;
} }
#customers-page #filter-results { #customers-page .filter-records .results {
overflow-y: auto; overflow-y: auto;
max-height: 650px;
} }
#customers-page #filter-results .customer-row { #customers-page #filter-customers .results .customer-row {
padding: 10px 7px; border-radius: 3px; padding: 10px 7px; border-radius: 3px;
} }
#customers-page #filter-results .customer-row:hover { #customers-page #filter-customers .results .customer-row:hover {
background-color: #C6E7D5; background-color: #C6E7D5;
cursor: pointer; cursor: pointer;
} }
#customers-page #filter-results hr { #customers-page #filter-customers .results hr {
margin: 5px 0; margin: 5px 0;
} }
@ -270,6 +271,11 @@ body .modal-header h3 {
cursor: pointer; cursor: pointer;
} }
#services-page .filter-records .results {
overflow-y: auto;
max-height: 650px;
}
#services-page .service-row { #services-page .service-row {
padding: 10px 7px; padding: 10px 7px;
border-radius: 3px; border-radius: 3px;
@ -330,6 +336,11 @@ body .modal-header h3 {
cursor: pointer; cursor: pointer;
} }
#users-page .filter-records .results {
overflow-y: auto;
max-height: 650px;
}
#users-page .secretary-row, #users-page .secretary-row,
#users-page .provider-row, #users-page .provider-row,
#users-page .admin-row { #users-page .admin-row {
@ -358,7 +369,8 @@ body .modal-header h3 {
#users-page #secretary-notifications.active, #users-page #secretary-notifications.active,
#users-page #provider-notifications.active, #users-page #provider-notifications.active,
#users-page #admin-notifications.active { #users-page #admin-notifications.active {
background: #FFFF91; background: #B6DCFF;
box-shadow: none;
} }
#users-page #secretary-providers, #users-page #secretary-providers,
@ -377,11 +389,11 @@ body .modal-header h3 {
#users-page #providers .switch-view div { #users-page #providers .switch-view div {
display: inline-block; display: inline-block;
padding: 10px 15px; padding: 6px 13px;
border-radius: 4px; border-radius: 4px;
color: #333; color: #333;
float: left; float: left;
margin-right: 5px; margin-right: 3px;
cursor: pointer; cursor: pointer;
} }
@ -389,6 +401,13 @@ body .modal-header h3 {
background: #F5F5F5; background: #F5F5F5;
} }
#users-page #providers .switch-view strong {
display: inline-block;
float: left;
margin: 8px 20px;
font-size: 17px;
}
#users-page #providers .switch-view .current { #users-page #providers .switch-view .current {
color: #FFF; color: #FFF;
background: #95E4A8; background: #95E4A8;
@ -408,7 +427,7 @@ background: #95E4A8;
clear: both; clear: both;
} }
#users-page #providers #breaks .btn { #users-page #providers .breaks .btn {
margin-right: 5px; margin-right: 5px;
padding: 4px 7px; padding: 4px 7px;
} }
@ -437,21 +456,21 @@ padding: 4px 7px;
margin-bottom: 0; margin-bottom: 0;
} }
#business-logic #breaks .btn { #business-logic .breaks .btn {
margin-right: 5px; margin-right: 5px;
padding: 4px 7px; padding: 4px 7px;
} }
#business-logic #breaks input { #business-logic .breaks input {
margin-bottom: 0; margin-bottom: 0;
} }
#business-logic #breaks .editable form { #business-logic .breaks .editable form {
margin: 0; margin: 0;
} }
#business-logic #breaks .editable select, #business-logic .breaks .editable select,
#business-logic #breaks .editable input { #business-logic .breaks .editable input {
margin: 0; margin: 0;
cursor: pointer; cursor: pointer;
} }
@ -463,3 +482,8 @@ padding: 4px 7px;
#business-logic .ui-spinner { #business-logic .ui-spinner {
border: none; border: none;
} }
#settings-page #user-notifications.active {
background: #B6DCFF;
box-shadow: none;
}

View file

@ -640,7 +640,7 @@ var BackendCalendar = {
$('#enable-sync span').text('Enable Sync'); $('#enable-sync span').text('Enable Sync');
$('#google-sync').prop('disabled', true); $('#google-sync').prop('disabled', true);
return; return false;
} }
}); });
} }
@ -1477,7 +1477,7 @@ var BackendCalendar = {
$.each(provider['services'], function(index, serviceId) { $.each(provider['services'], function(index, serviceId) {
if (serviceId == $dialog.find('#select-service').val()) { if (serviceId == $dialog.find('#select-service').val()) {
canProvideService = true; canProvideService = true;
return; return false;
} }
}); });
@ -1495,7 +1495,7 @@ var BackendCalendar = {
$.each(GlobalVariables.availableServices, function(index, service) { $.each(GlobalVariables.availableServices, function(index, service) {
if (service['id'] == $dialog.find('#select-service').val()) { if (service['id'] == $dialog.find('#select-service').val()) {
serviceDuration = service['duration']; serviceDuration = service['duration'];
return; return false;
} }
}); });

View file

@ -6,26 +6,29 @@
* @namespace BackendCustomers * @namespace BackendCustomers
*/ */
var BackendCustomers = { var BackendCustomers = {
filterResults: {}, /**
selectedCustomer: {}, * The page helper contains methods that implement each record type functionality
selectedAppointment: {}, * (for now there is only the CustomersHelper).
*
* @type {object{
*/
helper: {},
/** /**
* This method initializes the backend customers page. If you use this namespace * This method initializes the backend customers page. If you use this namespace
* in a different page do not use this method. * in a different page do not use this method.
* *
* @param {bool} bindDefaultEventHandlers Whether to bind the default event handlers * @param {bool} defaultEventHandlers (OPTIONAL = false) Whether to bind the default
* or not. * event handlers or not.
*/ */
initialize: function(bindDefaultEventHandlers) { initialize: function(defaultEventHandlers) {
if (bindDefaultEventHandlers === undefined) { if (defaultEventHandlers == undefined) defaultEventHandlers = false;
bindDefaultEventHandlers = false; // default value
}
BackendCustomers.filterCustomers(''); BackendCustomers.helper = new CustomersHelper();
$('#details').find('input, textarea').prop('readonly', true); BackendCustomers.helper.resetForm();
BackendCustomers.helper.filter('');
if (bindDefaultEventHandlers) { if (defaultEventHandlers) {
BackendCustomers.bindEventHandlers(); BackendCustomers.bindEventHandlers();
} }
}, },
@ -34,31 +37,64 @@ var BackendCustomers = {
* Default event handlers declaration for backend customers page. * Default event handlers declaration for backend customers page.
*/ */
bindEventHandlers: function() { bindEventHandlers: function() {
CustomersHelper.prototype.bindEventHandlers();
}
};
/**
* This class contains the methods that are used in the backend customers page.
*
* @class CustomersHelper
*/
var CustomersHelper = function() {
this.filterResults = {};
};
/**
* Binds the default event handlers of the backend customers page.
*/
CustomersHelper.prototype.bindEventHandlers = function() {
/**
* Event: Filter Customers Form "Submit"
*/
$('#filter-customers form').submit(function() {
event.preventDefault();
var key = $('#filter-customers .key').val();
$('#filter-customers .selected-row').removeClass('selected-row');
BackendCustomers.helper.resetForm();
BackendCustomers.helper.filter(key);
});
/**
* Event: Filter Customers Clear Button "Click"
*/
$('#filter-customers .clear').click(function() {
$('#filter-customers .key').val('');
BackendCustomers.helper.filter('');
});
/** /**
* Event: Customer Row "Click" * Event: Customer Row "Click"
* *
* Display the customer data of the selected row. * Display the customer data of the selected row.
*/ */
$(document).on('click', '.customer-row', function() { $(document).on('click', '.customer-row', function() {
if ($('#filter-customers').prop('disabled')) { if ($('#filter-customers .filter').prop('disabled')) {
return; // Do nothing when user edits a customer record. return; // Do nothing when user edits a customer record.
} }
$('#filter-results .selected-row').removeClass('selected-row');
$(this).addClass('selected-row');
var customerId = $(this).attr('data-id'); var customerId = $(this).attr('data-id');
var customer; var customer = {};
$.each(BackendCustomers.helper.filterResults, function(index, item) {
$.each(BackendCustomers.filterResults, function(index, item) { if (item.id == customerId) {
if (item.id === customerId) {
customer = item; customer = item;
return; return false;
} }
}); });
BackendCustomers.selectedCustomer = customer; BackendCustomers.helper.display(customer);
BackendCustomers.displayCustomer(customer); $('#filter-customers .selected-row').removeClass('selected-row');
$(this).addClass('selected-row');
$('#edit-customer, #delete-customer').prop('disabled', false); $('#edit-customer, #delete-customer').prop('disabled', false);
}); });
@ -71,40 +107,36 @@ var BackendCustomers = {
$('#customer-appointments .selected-row').removeClass('selected-row'); $('#customer-appointments .selected-row').removeClass('selected-row');
$(this).addClass('selected-row'); $(this).addClass('selected-row');
var customerId = $('#filter-customers .selected-row').attr('data-id');
var appointmentId = $(this).attr('data-id'); var appointmentId = $(this).attr('data-id');
var appointment; var appointment = {};
$.each(BackendCustomers.selectedCustomer.appointments, function(index, item) { $.each(BackendCustomers.helper.filterResults, function(index, c) {
if (item.id === appointmentId) { if (c.id === customerId) {
appointment = item; $.each(c.appointments, function(index, a) {
return; if (a.id == appointmentId) {
appointment = a;
return false;
}
});
return false;
} }
}); });
BackendCustomers.selectedAppointment = appointment; BackendCustomers.helper.displayAppointment(appointment);
BackendCustomers.displayAppointment(appointment);
});
/**
* Event: Filter Customers Button "Click"
*
* Filter customer rows with given string.
*/
$('#filter-customers').click(function() {
BackendCustomers.filterCustomers($('#filter-key').val());
}); });
/** /**
* Event: Add Customer Button "Click" * Event: Add Customer Button "Click"
*/ */
$('#add-customer').click(function() { $('#add-customer').click(function() {
BackendCustomers.resetForm(); BackendCustomers.helper.resetForm();
$('#add-edit-delete-group').hide(); $('#add-edit-delete-group').hide();
$('#save-cancel-group').show(); $('#save-cancel-group').show();
$('#details').find('input, textarea').prop('readonly', false); $('#details').find('input, textarea').prop('readonly', false);
$('#filter-customers').prop('disabled', true);
$('.selected-row').removeClass('selected-row'); $('#filter-customers button').prop('disabled', true);
$('#filter-results').css('color', '#AAA'); $('#filter-customers .results').css('color', '#AAA');
}); });
/** /**
@ -114,29 +146,26 @@ var BackendCustomers = {
$('#details').find('input, textarea').prop('readonly', false); $('#details').find('input, textarea').prop('readonly', false);
$('#add-edit-delete-group').hide(); $('#add-edit-delete-group').hide();
$('#save-cancel-group').show(); $('#save-cancel-group').show();
$('#filter-customers').prop('disabled', true);
$('#filter-results').css('color', '#AAA'); $('#filter-customers button').prop('disabled', true);
$('#filter-customers .results').css('color', '#AAA');
}); });
/** /**
* Event: Cancel Customer Add/Edit Operation Button "Click" * Event: Cancel Customer Add/Edit Operation Button "Click"
*/ */
$('#cancel-customer').click(function() { $('#cancel-customer').click(function() {
$('#details').find('input, textarea').prop('readonly', true); var id = $('#customer-id').val();
$('#save-cancel-group').hide(); BackendCustomers.helper.resetForm();
$('#add-edit-delete-group').show(); if (id != '') {
$('#filter-customers').prop('disabled', false); BackendCustomers.helper.select(id, true);
$('#filter-results').css('color', ''); }
// Reset the selected appointments data.
$('#filter-results .selected-row').trigger('click');
}); });
/** /**
* Event: Save Add/Edit Customer Operation "Click" * Event: Save Add/Edit Customer Operation "Click"
*/ */
$('#save-customer').click(function() { $('#save-customer').click(function() {
$('#filter-results').css('color', '');
var customer = { var customer = {
'first_name': $('#first-name').val(), 'first_name': $('#first-name').val(),
'last_name': $('#last-name').val(), 'last_name': $('#last-name').val(),
@ -152,17 +181,21 @@ var BackendCustomers = {
customer.id = $('#customer-id').val(); customer.id = $('#customer-id').val();
} }
BackendCustomers.saveCustomer(customer); if (!BackendCustomers.helper.validate(customer)) return;
BackendCustomers.helper.save(customer);
}); });
/** /**
* Event: Delete Customer Button "Click" * Event: Delete Customer Button "Click"
*/ */
$('#delete-customer').click(function() { $('#delete-customer').click(function() {
var customerId = $('#customer-id').val();
var messageBtns = { var messageBtns = {
'Delete': function() { 'Delete': function() {
var customerId = BackendCustomers.selectedCustomer.id; BackendCustomers.helper.delete(customerId);
BackendCustomers.deleteCustomer(customerId); $('#message_box').dialog('close');
}, },
'Cancel': function() { 'Cancel': function() {
@ -173,198 +206,76 @@ var BackendCustomers = {
GeneralFunctions.displayMessageBox('Delete Customer', 'Are you sure that you want ' GeneralFunctions.displayMessageBox('Delete Customer', 'Are you sure that you want '
+ 'to delete this customer? This action cannot be undone.', messageBtns); + 'to delete this customer? This action cannot be undone.', messageBtns);
}); });
}, };
/** /**
* This method displays the customer data on the right part of the page. * Save a customer record to the database (via ajax post).
* When a customer is selected the user can make changes and update the
* customer record.
* *
* @param {int} customerId Selected customer's record id. * @param {object} customer Contains the customer data.
*/ */
displayCustomer: function(customer) { CustomersHelper.prototype.save = function(customer) {
if (customer === undefined) {
throw 'DisplayCustomer: customer is undefined';
}
BackendCustomers.resetForm();
$('#customer-id').val(customer.id);
$('#first-name').val(customer.first_name);
$('#last-name').val(customer.last_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);
$('#notes').val(customer.notes);
$.each(customer.appointments, function(index, appointment) {
var start = Date.parse(appointment.start_datetime).toString('dd/MM/yyyy HH:mm');
var end = Date.parse(appointment.end_datetime).toString('dd/MM/yyyy HH:mm');
var html =
'<div class="appointment-row" data-id="' + appointment.id + '">' +
start + ' - ' + end + '<br>' +
appointment.service.name + ', ' +
appointment.provider.first_name + ' ' + appointment.provider.last_name +
'</div>';
$('#customer-appointments').append(html);
});
},
/**
* This method makes an ajax call to the server and save the changes of
* an existing customer record, or inserts a new customer row when on insert
* mode.
*
* NOTICE: User the "deleteCustomer" method to delete a customer record.
*
* @param {object} customer Contains the customer data. If "id" is not
* provided then the record is going to be inserted.
*/
saveCustomer: function(customer) {
if (!BackendCustomers.validateForm()) return;
var postUrl = GlobalVariables.baseUrl + 'backend_api/ajax_save_customer'; var postUrl = GlobalVariables.baseUrl + 'backend_api/ajax_save_customer';
var postData = { 'customer': JSON.stringify(customer) }; var postData = { 'customer': JSON.stringify(customer) };
$.post(postUrl, postData, function(response) { $.post(postUrl, postData, function(response) {
if (response.exceptions) { ///////////////////////////////////////////////////////////
response.exceptions = GeneralFunctions.parseExceptions(response.exceptions); console.log('Save Customer Response:', response);
GeneralFunctions.displayMessageBox(Backend.EXCEPTIONS_TITLE, Backend.EXCEPTIONS_MESSAGE); ///////////////////////////////////////////////////////////
$('#message_box').append(GeneralFunctions.exceptionsToHtml(response.exceptions));
return;
}
if (response.warnings) { if (!GeneralFunctions.handleAjaxExceptions(response)) return;
response.warnings = GeneralFunctions.parseExceptions(response.warnings);
GeneralFunctions.displayMessageBox(Backend.WARNINGS_TITLE, Backend.WARNINGS_MESSAGE);
$('#message_box').append(GeneralFunctions.exceptionsToHtml(response.warnings));
}
$('#add-edit-delete-group').show(); Backend.displayNotification('Customer saved successfully!');
$('#save-cancel-group').hide(); BackendCustomers.helper.resetForm();
$('#filter-customers').prop('disabled', false); $('#filter-customers .key').val('');
$('#details').find('input, textarea').prop('readonly', true); BackendCustomers.helper.filter('', response.id, true);
BackendCustomers.filterCustomers($('#filter-key').val());
// On edit mode keep the customer data on form.
if (customer.id) {
$.each(BackendCustomers.filterResults, function(index, item) {
if (item.id == customer.id) {
customer.appointments = item.appointments; // w/ appointments
return;
}
});
BackendCustomers.displayCustomer(customer);
$('#edit-customer, #delete-customer').prop('disabled', false);
}
}, 'json'); }, 'json');
}, };
/** /**
* This method makes an ajax call to the server and deletes the selected * Delete a customer record from database.
* customer record.
* *
* @param {int} customerId The customer record id to be deleted. * @param {numeric} id Record id to be deleted.
*/ */
deleteCustomer: function(customerId) { CustomersHelper.prototype.delete = function(id) {
var postUrl = GlobalVariables.baseUrl + 'backend_api/ajax_delete_customer'; var postUrl = GlobalVariables.baseUrl + 'backend_api/ajax_delete_customer';
var postData = { 'customer_id': BackendCustomers.selectedCustomer.id }; var postData = { 'customer_id': id };
$.post(postUrl, postData, function(response) { $.post(postUrl, postData, function(response) {
if (response.exceptions) { ////////////////////////////////////////////////////
response.exceptions = GeneralFunctions.parseExceptions(response.exceptions); //console.log('Delete customer response:', response);
GeneralFunctions.displayMessageBox('Unexpected Issues', 'Unfortunately the ' ////////////////////////////////////////////////////
+ 'filter operation could not complete successfully. The following '
+ 'issues occured.');
$('#message_box').append(GeneralFunctions.exceptionsToHtml(response.exceptions));
return;
}
if (response.warnings) { if (!GeneralFunctions.handleAjaxExceptions(response)) return;
response.warnings = GeneralFunctions.parseExceptions(response.warnings);
GeneralFunctions.displayMessageBox('Unexpected Warnings', 'The filter operation '
+ 'complete with the following warnings.');
$('#message_box').append(GeneralFunctions.exceptionsToHtml(response.warnings));
}
$('#message_box').dialog('close'); Backend.displayNotification('Customer deleted successfully!');
BackendCustomers.filterCustomers($('#filter-key').val()); BackendCustomers.helper.resetForm();
BackendCustomers.helper.filter($('#filter-customers .key').val());
}, 'json'); }, 'json');
}, };
/** /**
* This method filters the system registered customers. Pass an empty string * Validate customer data before save (insert or update).
* to display all customers.
* *
* @param {string} key The filter key string. * @param {object} customer Contains the customer data.
*/ */
filterCustomers: function(key) { CustomersHelper.prototype.validate = function(customer) {
$('#filter-results').html('');
BackendCustomers.resetForm();
var postUrl = GlobalVariables.baseUrl + 'backend_api/ajax_filter_customers';
var postData = { 'key': key };
$.post(postUrl, postData, function(response) {
if (response.exceptions) {
response.exceptions = GeneralFunctions.parseExceptions(response.exceptions);
GeneralFunctions.displayMessageBox('Unexpected Issues', 'Unfortunately the '
+ 'filter operation could not complete successfully. The following '
+ 'issues occured.');
$('#message_box').append(GeneralFunctions.exceptionsToHtml(response.exceptions));
return;
}
if (response.warnings) {
response.warnings = GeneralFunctions.parseExceptions(response.warnings);
GeneralFunctions.displayMessageBox('Unexpected Warnings', 'The filter operation '
+ 'complete with the following warnings.');
$('#message_box').append(GeneralFunctions.exceptionsToHtml(response.warnings));
}
BackendCustomers.filterResults = response;
$.each(response, function(index, customer) {
var html =
'<div class="customer-row" data-id="' + customer.id + '">' +
'<strong>' +
customer.first_name + ' ' + customer.last_name +
'</strong><br>' +
'<span>' + customer.email + '</span> | ' +
'<span>' + customer.phone_number + '</span>' +
'</div><hr>';
$('#filter-results').append(html);
});
}, 'json');
},
/**
* This method validates the main customer form of the page. There are certain
* rules that the record must fullfil before getting into the system database.
*
* @return {bool} Returns the validation result.
*/
validateForm: function() {
try {
$('#form-message').hide(); $('#form-message').hide();
$('.required').css('border', ''); $('.required').css('border', '');
// :: CHECK REQUIRED FIELDS try {
var missingRequiredField = false; // Validate required fields.
var missingRequired = false;
$('.required').each(function() { $('.required').each(function() {
if ($(this).val() == '') { if ($(this).val() == '') {
$(this).css('border', '2px solid red'); $(this).css('border', '2px solid red');
missingRequiredField = true; missingRequired = true;
} }
}); });
if (missingRequiredField) { if (missingRequired) {
throw 'Fields with * are required!'; throw 'Fields with * are required!';
} }
// :: CHECK EMAIL ADDRESS // Validate email address.
if (!GeneralFunctions.validateEmail($('#email').val())) { if (!GeneralFunctions.validateEmail($('#email').val())) {
$('#email').css('border', '2px solid red'); $('#email').css('border', '2px solid red');
throw 'Invalid email address!'; throw 'Invalid email address!';
@ -376,24 +287,154 @@ var BackendCustomers = {
$('#form-message').text(exc).show(); $('#form-message').text(exc).show();
return false; return false;
} }
}, };
/** /**
* Bring the customer data form back to its initial state. * Bring the customer form back to its initial state.
*/ */
resetForm: function() { CustomersHelper.prototype.resetForm = function() {
$('#details').find('input, textarea').val(''); $('#details').find('input, textarea').val('');
$('#customer-appointments').html(''); $('#customer-appointments').html('');
$('#appointment-details').html(''); $('#appointment-details').html('');
$('#edit-customer, #delete-customer').prop('disabled', true); $('#edit-customer, #delete-customer').prop('disabled', true);
}, $('#add-edit-delete-group').show();
$('#save-cancel-group').hide();
/** $('#filter-customers button').prop('disabled', false);
$('#filter-customers .selected-row').removeClass('selected-row');
$('#filter-customers .results').css('color', '');
};
/**
* Display a customer record into the form.
*
* @param {object} customer Contains the customer record data.
*/
CustomersHelper.prototype.display = function(customer) {
$('#customer-id').val(customer.id);
$('#first-name').val(customer.first_name);
$('#last-name').val(customer.last_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);
$('#notes').val(customer.notes);
$('#customer-appointments').empty();
$.each(customer.appointments, function(index, appointment) {
var start = Date.parse(appointment.start_datetime).toString('dd/MM/yyyy HH:mm');
var end = Date.parse(appointment.end_datetime).toString('dd/MM/yyyy HH:mm');
var html =
'<div class="appointment-row" data-id="' + appointment.id + '">' +
start + ' - ' + end + '<br>' +
appointment.service.name + ', ' +
appointment.provider.first_name + ' ' + appointment.provider.last_name +
'</div>';
$('#customer-appointments').append(html);
});
};
/**
* Filter customer records.
*
* @param {string} key This key string is used to filter the customer records.
* @param {numeric} selectId (OPTIONAL = undefined) If set then after the filter
* operation the record with the given id will be selected (but not displayed).
* @param {bool} display (OPTIONAL = false) If true then the selected record will
* be displayed on the form.
*/
CustomersHelper.prototype.filter = function(key, selectId, display) {
if (display == undefined) display = false;
var postUrl = GlobalVariables.baseUrl + 'backend_api/ajax_filter_customers';
var postData = { 'key': key };
$.post(postUrl, postData, function(response) {
///////////////////////////////////////////////////////
console.log('Filter Customers Response:', response);
///////////////////////////////////////////////////////
if (!GeneralFunctions.handleAjaxExceptions(response)) return;
BackendCustomers.helper.filterResults = response;
$('#filter-customers .results').html('');
$.each(response, function(index, customer) {
var html = BackendCustomers.helper.getFilterHtml(customer);
$('#filter-customers .results').append(html);
});
if (response.length == 0) {
$('#filter-customers .results').html('<em>No records found...</em>');
}
if (selectId != undefined) {
BackendCustomers.helper.select(selectId, display);
}
}, 'json');
};
/**
* Get the filter results row html code.
*
* @param {object} customer Contains the customer data.
* @return {string} Returns the record html code.
*/
CustomersHelper.prototype.getFilterHtml = function(customer) {
var html =
'<div class="customer-row" data-id="' + customer.id + '">' +
'<strong>' +
customer.first_name + ' ' + customer.last_name +
'</strong><br>' +
'<span>' + customer.email + '</span> | ' +
'<span>' + customer.phone_number + '</span>' +
'</div><hr>';
return html;
};
/**
* Select a specific record from the current filter results. If the customer id does not exist
* in the list then no record will be selected.
*
* @param {numeric} id The record id to be selected from the filter results.
* @param {bool} display (OPTIONAL = false) If true then the method will display the record
* on the form.
*
* @task The selected row must always be visible (even if a vertical scroll bar is used to
* navigate through the filter results).
*/
CustomersHelper.prototype.select = function(id, display) {
if (display == undefined) display = false;
$('#filter-customers .selected-row').removeClass('selected-row');
$('#filter-customers .customer-row').each(function() {
if ($(this).attr('data-id') == id) {
$(this).addClass('selected-row');
return false;
}
});
if (display) {
$.each(BackendCustomers.helper.filterResults, function(index, customer) {
if (customer.id == id) {
BackendCustomers.helper.display(customer);
$('#edit-customer, #delete-customer').prop('disabled', false);
return false;
}
});
}
};
/**
* Display appointment details on customers backend page. * Display appointment details on customers backend page.
* *
* @param {object} appointment Appointment data * @param {object} appointment Appointment data
*/ */
displayAppointment: function(appointment) { CustomersHelper.prototype.displayAppointment = function(appointment) {
var start = Date.parse(appointment.start_datetime).toString('dd/MM/yyyy HH:mm'); var start = Date.parse(appointment.start_datetime).toString('dd/MM/yyyy HH:mm');
var end = Date.parse(appointment.end_datetime).toString('dd/MM/yyyy HH:mm'); var end = Date.parse(appointment.end_datetime).toString('dd/MM/yyyy HH:mm');
@ -405,5 +446,4 @@ var BackendCustomers = {
'</div>'; '</div>';
$('#appointment-details').html(html); $('#appointment-details').html(html);
}
}; };

View file

@ -69,227 +69,14 @@ var BackendServices = {
$('.filter-key').val(''); $('.filter-key').val('');
}); });
/** ServicesHelper.prototype.bindEventHandlers();
* Event: Filter Services Button "Click" CategoriesHelper.prototype.bindEventHandlers();
*/
$('.filter-services').click(function() {
var key = $('#services .filter-key').val();
$('.selected-row').removeClass('selected-row');
BackendServices.helper.resetForm();
BackendServices.helper.filter(key);
});
/**
* Event: Filter Categories Button "Click"
*/
$('.filter-categories').click(function() {
var key = $('#categories .filter-key').val();
$('.selected-row').removeClass('selected-row');
BackendServices.helper.resetForm();
BackendServices.helper.filter(key);
});
/**
* Event: Filter Service Row "Click"
*
* Display the selected service data to the user.
*/
$(document).on('click', '.service-row', function() {
if ($('#services .filter-services').prop('disabled')) {
$('#services .filter-results').css('color', '#AAA');
return; // exit because we are on edit mode
}
var service = { 'id': $(this).attr('data-id') };
$.each(BackendServices.helper.filterResults, function(index, item) {
if (item.id === service.id) {
service = item;
return;
}
});
BackendServices.helper.display(service);
$('.selected-row').removeClass('selected-row');
$(this).addClass('selected-row');
$('#edit-service, #delete-service').prop('disabled', false);
});
/**
* Event: Filter Categories Row "Click"
*
* Displays the selected row data on the right side of the page.
*/
$(document).on('click', '.category-row', function() {
if ($('#categories .filter-categories').prop('disabled')) {
$('#categories .filter-results').css('color', '#AAA');
return; // exit because we are on edit mode
}
var category = { 'id': $(this).attr('data-id') };
$.each(BackendServices.helper.filterResults, function(index, item) {
if (item.id === category.id) {
category = item;
return;
}
});
BackendServices.helper.display(category);
$('.selected-row').removeClass('selected-row');
$(this).addClass('selected-row');
$('#edit-category, #delete-category').prop('disabled', false);
});
/**
* Event: Add New Service Button "Click"
*/
$('#add-service').click(function() {
BackendServices.helper.resetForm();
$('#services .add-edit-delete-group').hide();
$('#services .save-cancel-group').show();
$('#services .details').find('input, textarea').prop('readonly', false);
$('#services .details').find('select').prop('disabled', false);
$('#service-duration').spinner('enable');
$('#services .filter-services').prop('disabled', true);
$('#services .filter-results').css('color', '#AAA');
});
/**
* Event: Add Category Button "Click"
*/
$('#add-category').click(function() {
BackendServices.helper.resetForm();
$('#categories .add-edit-delete-group').hide();
$('#categories .save-cancel-group').show();
$('#categories .details').find('input, textarea').prop('readonly', false);
$('#categories .filter-categories').prop('disabled', true);
$('#categories .filter-results').css('color', '#AAA');
});
/**
* Event: Cancel Service Button "Click"
*
* Cancel add or edit of a service record.
*/
$('#cancel-service').click(function() {
BackendServices.helper.resetForm();
});
/**
* Event: Cancel Category Button "Click"
*/
$('#cancel-category').click(function() {
BackendServices.helper.resetForm();
});
/**
* Event: Save Service Button "Click"
*/
$('#save-service').click(function() {
var service = {
'name': $('#service-name').val(),
'duration': $('#service-duration').val(),
'price': $('#service-price').val(),
'currency': $('#service-currency').val(),
'description': $('#service-description').val()
};
if ($('#service-category').val() !== 'null') {
service.id_service_categories = $('#service-category').val();
} else {
service.id_service_categories = null;
}
if ($('#service-id').val() !== '') {
service.id = $('#service-id').val();
}
if (!BackendServices.helper.validate(service)) return;
BackendServices.helper.save(service);
});
/**
* Event: Categories Save Button "Click"
*/
$('#save-category').click(function() {
var category = {
'name': $('#category-name').val(),
'description': $('#category-description').val()
};
if ($('#category-id').val() !== '') {
category.id = $('#category-id').val();
}
if (!BackendServices.helper.validate(category)) return;
BackendServices.helper.save(category);
});
/**
* Event: Edit Service Button "Click"
*/
$('#edit-service').click(function() {
$('#services .add-edit-delete-group').hide();
$('#services .save-cancel-group').show();
$('.filter-services').prop('disabled', true);
$('#services .filter-results').css('color', '#AAA');
$('#services .details').find('input, textarea').prop('readonly', false);
$('#services .details select').prop('disabled', false);
$('#service-duration').spinner('enable');
});
/**
* Event: Edit Category Button "Click"
*/
$('#edit-category').click(function() {
$('#categories .add-edit-delete-group').hide();
$('#categories .save-cancel-group').show();
$('.filter-categories').prop('disabled', true);
$('#categories .filter-results').css('color', '#AAA');
$('#categories .details').find('input, textarea').prop('readonly', false);
});
/**
* Event: Delete Service Button "Click"
*/
$('#delete-service').click(function() {
var serviceId = $('#service-id').val();
var messageBtns = {
'Delete': function() {
BackendServices.helper.delete(serviceId);
$('#message_box').dialog('close');
},
'Cancel': function() {
$('#message_box').dialog('close');
}
};
GeneralFunctions.displayMessageBox('Delete Service', 'Are you sure that you want '
+ 'to delete this record? This action cannot be undone.', messageBtns);
});
$('#delete-category').click(function() {
var categoryId = $('#category-id').val();
var messageBtns = {
'Delete': function() {
BackendServices.helper.delete(categoryId);
$('#message_box').dialog('close');
},
'Cancel': function() {
$('#message_box').dialog('close');
}
};
GeneralFunctions.displayMessageBox('Delete Category', 'Are you sure that you want '
+ 'to delete this record? This action cannot be undone.', messageBtns);
});
}, },
/** /**
* Update the service category listbox. Use this method every time a change is made * Update the service category listbox. Use this method every time a change is made
* to the service categories db table. * to the service categories db table.
*
* @param {array} categories Contains the available category objects.
*/ */
updateAvailableCategories: function() { updateAvailableCategories: function() {
var postUrl = GlobalVariables.baseUrl + 'backend_api/ajax_filter_service_categories'; var postUrl = GlobalVariables.baseUrl + 'backend_api/ajax_filter_service_categories';
@ -322,6 +109,142 @@ var ServicesHelper = function() {
this.filterResults = {}; this.filterResults = {};
}; };
ServicesHelper.prototype.bindEventHandlers = function() {
/**
* Event: Filter Services Form "Submit"
*/
$('#filter-services form').submit(function() {
event.preventDefault();
var key = $('#filter-services .key').val();
$('#filter-services .selected-row').removeClass('selected-row');
BackendServices.helper.resetForm();
BackendServices.helper.filter(key);
});
/**
* Event: Filter Service Cancel Button "Click"
*/
$('#filter-services .clear').click(function() {
$('#filter-services .key').val('');
BackendServices.helper.filter('');
});
/**
* Event: Filter Service Row "Click"
*
* Display the selected service data to the user.
*/
$(document).on('click', '.service-row', function() {
if ($('#filter-services .filter').prop('disabled')) {
$('#filter-services .results').css('color', '#AAA');
return; // exit because we are on edit mode
}
var serviceId = $(this).attr('data-id');
var service = {};
$.each(BackendServices.helper.filterResults, function(index, item) {
if (item.id === serviceId) {
service = item;
return false;
}
});
BackendServices.helper.display(service);
$('#filter-services .selected-row').removeClass('selected-row');
$(this).addClass('selected-row');
$('#edit-service, #delete-service').prop('disabled', false);
});
/**
* Event: Add New Service Button "Click"
*/
$('#add-service').click(function() {
BackendServices.helper.resetForm();
$('#services .add-edit-delete-group').hide();
$('#services .save-cancel-group').show();
$('#services .details').find('input, textarea').prop('readonly', false);
$('#services .details').find('select').prop('disabled', false);
$('#service-duration').spinner('enable');
$('#filter-services button').prop('disabled', true);
$('#filter-services .results').css('color', '#AAA');
});
/**
* Event: Cancel Service Button "Click"
*
* Cancel add or edit of a service record.
*/
$('#cancel-service').click(function() {
var id = $('#service-id').val();
BackendServices.helper.resetForm();
if (id != '') {
BackendServices.helper.select(id, true);
}
});
/**
* Event: Save Service Button "Click"
*/
$('#save-service').click(function() {
var service = {
'name': $('#service-name').val(),
'duration': $('#service-duration').val(),
'price': $('#service-price').val(),
'currency': $('#service-currency').val(),
'description': $('#service-description').val()
};
if ($('#service-category').val() !== 'null') {
service.id_service_categories = $('#service-category').val();
} else {
service.id_service_categories = null;
}
if ($('#service-id').val() !== '') {
service.id = $('#service-id').val();
}
if (!BackendServices.helper.validate(service)) return;
BackendServices.helper.save(service);
});
/**
* Event: Edit Service Button "Click"
*/
$('#edit-service').click(function() {
$('#services .add-edit-delete-group').hide();
$('#services .save-cancel-group').show();
$('#services .details').find('input, textarea').prop('readonly', false);
$('#services .details select').prop('disabled', false);
$('#service-duration').spinner('enable');
$('#filter-services button').prop('disabled', true);
$('#filter-services .results').css('color', '#AAA');
});
/**
* Event: Delete Service Button "Click"
*/
$('#delete-service').click(function() {
var serviceId = $('#service-id').val();
var messageBtns = {
'Delete': function() {
BackendServices.helper.delete(serviceId);
$('#message_box').dialog('close');
},
'Cancel': function() {
$('#message_box').dialog('close');
}
};
GeneralFunctions.displayMessageBox('Delete Service', 'Are you sure that you want '
+ 'to delete this record? This action cannot be undone.', messageBtns);
});
};
/** /**
* Save service record to database. * Save service record to database.
* *
@ -329,23 +252,30 @@ var ServicesHelper = function() {
* then the update operation is going to be executed. * then the update operation is going to be executed.
*/ */
ServicesHelper.prototype.save = function(service) { ServicesHelper.prototype.save = function(service) {
////////////////////////////////////////////////
//console.log('Service data to save:', service);
////////////////////////////////////////////////
var postUrl = GlobalVariables.baseUrl + 'backend_api/ajax_save_service'; var postUrl = GlobalVariables.baseUrl + 'backend_api/ajax_save_service';
var postData = { 'service': JSON.stringify(service) }; var postData = { 'service': JSON.stringify(service) };
$.post(postUrl, postData, function(response) { $.post(postUrl, postData, function(response) {
console.log('Save Service Response:', response); //////////////////////////////////////////////////
//console.log('Save Service Response:', response);
//////////////////////////////////////////////////
if (!GeneralFunctions.handleAjaxExceptions(response)) return; if (!GeneralFunctions.handleAjaxExceptions(response)) return;
Backend.displayNotification('Service saved successfully!'); Backend.displayNotification('Service saved successfully!');
BackendServices.helper.resetForm(); BackendServices.helper.resetForm();
BackendServices.helper.filter($('#services .filter-key').val()); $('#filter-services .key').val('');
BackendServices.helper.filter('', response.id, true);
}, 'json'); }, 'json');
}; };
/** /**
* Delete a service records from database. * Delete a service record from database.
* *
* @param {int} id Record id to be deleted. * @param {numeric} id Record id to be deleted.
*/ */
ServicesHelper.prototype.delete = function(id) { ServicesHelper.prototype.delete = function(id) {
var postUrl = GlobalVariables.baseUrl + 'backend_api/ajax_delete_service'; var postUrl = GlobalVariables.baseUrl + 'backend_api/ajax_delete_service';
@ -353,7 +283,7 @@ ServicesHelper.prototype.delete = function(id) {
$.post(postUrl, postData, function(response) { $.post(postUrl, postData, function(response) {
//////////////////////////////////////////////////// ////////////////////////////////////////////////////
console.log('Delete service response:', response); //console.log('Delete service response:', response);
//////////////////////////////////////////////////// ////////////////////////////////////////////////////
if (!GeneralFunctions.handleAjaxExceptions(response)) return; if (!GeneralFunctions.handleAjaxExceptions(response)) return;
@ -361,7 +291,7 @@ ServicesHelper.prototype.delete = function(id) {
Backend.displayNotification('Service deleted successfully!'); Backend.displayNotification('Service deleted successfully!');
BackendServices.helper.resetForm(); BackendServices.helper.resetForm();
BackendServices.helper.filter($('#services .filter-key').val()); BackendServices.helper.filter($('#filter-services .key').val());
}); });
}; };
@ -404,8 +334,10 @@ ServicesHelper.prototype.resetForm = function() {
$('#edit-service, #delete-service').prop('disabled', true); $('#edit-service, #delete-service').prop('disabled', true);
$('#services .details').find('input, textarea').prop('readonly', true); $('#services .details').find('input, textarea').prop('readonly', true);
$('#service-category').prop('disabled', true); $('#service-category').prop('disabled', true);
$('.filter-services').prop('disabled', false);
$('#services .filter-results').css('color', ''); $('#filter-services .selected-row').removeClass('selected-row');
$('#filter-services button').prop('disabled', false);
$('#filter-services .results').css('color', '');
}; };
/** /**
@ -429,25 +361,39 @@ ServicesHelper.prototype.display = function(service) {
* Filters service records depending a string key. * Filters service records depending a string key.
* *
* @param {string} key This is used to filter the service records of the database. * @param {string} key This is used to filter the service records of the database.
* @param {numeric} selectId (OPTIONAL = undefined) If set then after the filter
* operation the record with this id will be selected (but not displayed).
* @param {bool} display (OPTIONAL = false) If true then the selected record will
* be displayed on the form.
*/ */
ServicesHelper.prototype.filter = function(key) { ServicesHelper.prototype.filter = function(key, selectId, display) {
if (display == undefined) display = false;
var postUrl = GlobalVariables.baseUrl + 'backend_api/ajax_filter_services'; var postUrl = GlobalVariables.baseUrl + 'backend_api/ajax_filter_services';
var postData = { 'key': key }; var postData = { 'key': key };
$.post(postUrl, postData, function(response) { $.post(postUrl, postData, function(response) {
///////////////////////////////////////////////////// /////////////////////////////////////////////////////
console.log('Filter services response:', response); //console.log('Filter services response:', response);
///////////////////////////////////////////////////// /////////////////////////////////////////////////////
if (!GeneralFunctions.handleAjaxExceptions(response)) return; if (!GeneralFunctions.handleAjaxExceptions(response)) return;
BackendServices.helper.filterResults = response; BackendServices.helper.filterResults = response;
$('#services .filter-results').html('');
$('#filter-services .results').html('');
$.each(response, function(index, service) { $.each(response, function(index, service) {
var html = ServicesHelper.prototype.getFilterHtml(service); var html = ServicesHelper.prototype.getFilterHtml(service);
$('#services .filter-results').append(html); $('#filter-services .results').append(html);
}); });
if (response.length == 0) {
$('#filter-services .result').html('<em>No results found ...</em>');
}
if (selectId != undefined) {
BackendServices.helper.select(selectId, display);
}
}, 'json'); }, 'json');
}; };
@ -468,6 +414,40 @@ ServicesHelper.prototype.getFilterHtml = function(service) {
return html; return html;
}; };
/**
* Select a specific record from the current filter results. If the service id does not exist
* in the list then no record will be selected.
*
* @param {numeric} id The record id to be selected from the filter results.
* @param {bool} display (OPTIONAL = false) If true then the method will display the record
* on the form.
*
* @task The selected row must always be visible (even if a vertical scroll bar is used to
* navigate through the filter results).
*/
ServicesHelper.prototype.select = function(id, display) {
if (display == undefined) display = false;
$('#filter-services .selected-row').removeClass('selected-row');
$('#filter-services .service-row').each(function() {
if ($(this).attr('data-id') == id) {
$(this).addClass('selected-row');
return false;
}
});
if (display) {
$.each(BackendServices.helper.filterResults, function(index, service) {
if (service.id == id) {
BackendServices.helper.display(service);
$('#edit-service, #delete-service').prop('disabled', false);
return false;
}
});
}
};
/** /**
* This class contains the core method implementations that belong to the categories tab * This class contains the core method implementations that belong to the categories tab
* of the backend services page. * of the backend services page.
@ -478,12 +458,139 @@ var CategoriesHelper = function() {
this.filterResults = {}; this.filterResults = {};
}; };
/**
* Binds the default event handlers of the categories tab.
*/
CategoriesHelper.prototype.bindEventHandlers = function() {
/**
* Event: Filter Categories Cancel Button "Click"
*/
$('#filter-categories .clear').click(function() {
$('#filter-categories .key').val('');
BackendServices.helper.filter('');
});
/**
* Event: Filter Categories Form "Submit"
*/
$('#filter-categories form').submit(function() {
event.preventDefault();
var key = $('#filter-categories .key').val();
$('.selected-row').removeClass('selected-row');
BackendServices.helper.resetForm();
BackendServices.helper.filter(key);
});
/**
* Event: Filter Categories Row "Click"
*
* Displays the selected row data on the right side of the page.
*/
$(document).on('click', '.category-row', function() {
if ($('#filter-categories .filter').prop('disabled')) {
$('#filter-categories .results').css('color', '#AAA');
return; // exit because we are on edit mode
}
var categoryId = $(this).attr('data-id');
var category = {};
$.each(BackendServices.helper.filterResults, function(index, item) {
if (item.id === categoryId) {
category = item;
return false;
}
});
BackendServices.helper.display(category);
$('#filter-categories .selected-row').removeClass('selected-row');
$(this).addClass('selected-row');
$('#edit-category, #delete-category').prop('disabled', false);
});
/**
* Event: Add Category Button "Click"
*/
$('#add-category').click(function() {
BackendServices.helper.resetForm();
$('#categories .add-edit-delete-group').hide();
$('#categories .save-cancel-group').show();
$('#categories .details').find('input, textarea').prop('readonly', false);
$('#filter-categories button').prop('disabled', true);
$('#filter-categories .results').css('color', '#AAA');
});
/**
* Event: Edit Category Button "Click"
*/
$('#edit-category').click(function() {
$('#categories .add-edit-delete-group').hide();
$('#categories .save-cancel-group').show();
$('#categories .details').find('input, textarea').prop('readonly', false);
$('#filter-categories button').prop('disabled', true);
$('#filter-categories .results').css('color', '#AAA');
});
/**
* Event: Delete Category Button "Click"
*/
$('#delete-category').click(function() {
var categoryId = $('#category-id').val();
var messageBtns = {
'Delete': function() {
BackendServices.helper.delete(categoryId);
$('#message_box').dialog('close');
},
'Cancel': function() {
$('#message_box').dialog('close');
}
};
GeneralFunctions.displayMessageBox('Delete Category', 'Are you sure that you want '
+ 'to delete this record? This action cannot be undone.', messageBtns);
});
/**
* Event: Categories Save Button "Click"
*/
$('#save-category').click(function() {
var category = {
'name': $('#category-name').val(),
'description': $('#category-description').val()
};
if ($('#category-id').val() !== '') {
category.id = $('#category-id').val();
}
if (!BackendServices.helper.validate(category)) return;
BackendServices.helper.save(category);
});
/**
* Event: Cancel Category Button "Click"
*/
$('#cancel-category').click(function() {
var id = $('#category-id').val();
BackendServices.helper.resetForm();
if (id != '') {
BackendServices.helper.select(id, true);
}
});
};
/** /**
* Filter service categories records. * Filter service categories records.
* *
* @param {string} key This key string is used to filter the category records. * @param {string} key This key string is used to filter the category records.
* @param {numeric} selectId (OPTIONAL = undefined) If set then after the filter
* operation the record with the given id will be selected (but not displayed).
* @param {bool} display (OPTIONAL = false) If true then the selected record will
* be displayed on the form.
*/ */
CategoriesHelper.prototype.filter = function(key) { CategoriesHelper.prototype.filter = function(key, selectId, display) {
var postUrl = GlobalVariables.baseUrl + 'backend_api/ajax_filter_service_categories'; var postUrl = GlobalVariables.baseUrl + 'backend_api/ajax_filter_service_categories';
var postData = { 'key': key }; var postData = { 'key': key };
@ -495,12 +602,21 @@ CategoriesHelper.prototype.filter = function(key) {
if (!GeneralFunctions.handleAjaxExceptions(response)) return; if (!GeneralFunctions.handleAjaxExceptions(response)) return;
BackendServices.helper.filterResults = response; BackendServices.helper.filterResults = response;
$('#categories .filter-results').html('');
$('#filter-categories .results').html('');
$.each(response, function(index, category) { $.each(response, function(index, category) {
var html = BackendServices.helper.getFilterHtml(category); var html = BackendServices.helper.getFilterHtml(category);
$('#categories .filter-results').append(html); $('#filter-categories .results').append(html);
}); });
if (response.length == 0) {
$('#filter-categories .results').html('<em>No records found...</em>');
}
if (selectId != undefined) {
BackendServices.helper.select(selectId, display);
}
}, 'json'); }, 'json');
}; };
@ -522,7 +638,8 @@ CategoriesHelper.prototype.save = function(category) {
Backend.displayNotification('Service saved successfully!'); Backend.displayNotification('Service saved successfully!');
BackendServices.helper.resetForm(); BackendServices.helper.resetForm();
BackendServices.helper.filter($('#categories .filter-key').val()); $('#filter-categories .key').val('');
BackendServices.helper.filter('', response.id, true);
BackendServices.updateAvailableCategories(); BackendServices.updateAvailableCategories();
}); });
}; };
@ -546,7 +663,7 @@ CategoriesHelper.prototype.delete = function(id) {
Backend.displayNotification('Category deleted successfully!'); Backend.displayNotification('Category deleted successfully!');
BackendServices.helper.resetForm(); BackendServices.helper.resetForm();
BackendServices.helper.filter($('#categories .filter-key').val()); BackendServices.helper.filter($('#filter-categories .key').val());
BackendServices.updateAvailableCategories(); BackendServices.updateAvailableCategories();
}); });
}; };
@ -597,8 +714,10 @@ CategoriesHelper.prototype.resetForm = function() {
$('#categories .details').find('input, textarea').val(''); $('#categories .details').find('input, textarea').val('');
$('#categories .details').find('input, textarea').prop('readonly', true); $('#categories .details').find('input, textarea').prop('readonly', true);
$('#edit-category, #delete-category').prop('disabled', true); $('#edit-category, #delete-category').prop('disabled', true);
$('#categories .filter-results').css('color', '');
$('#categories .filter-categories').prop('disabled', false); $('#filter-categories .selected-row').removeClass('selected-row');
$('#filter-categories .results').css('color', '');
$('#filter-categories button').prop('disabled', false);
}; };
/** /**
@ -616,3 +735,36 @@ CategoriesHelper.prototype.getFilterHtml = function(category) {
return html; return html;
}; };
/**
* Select a specific record from the current filter results. If the category id does not exist
* in the list then no record will be selected.
*
* @param {numeric} id The record id to be selected from the filter results.
* @param {bool} display (OPTIONAL = false) If true then the method will display the record
* on the form.
*
* @task The selected row must always be visible (even if a vertical scroll bar is used to
* navigate through the filter results).
*/
CategoriesHelper.prototype.select = function(id, display) {
if (display == undefined) display = false;
$('#filter-categories .selected-row').removeClass('selected-row');
$('#filter-categories .category-row').each(function() {
if ($(this).attr('data-id') == id) {
$(this).addClass('selected-row');
return false;
}
});
if (display) {
$.each(BackendServices.helper.filterResults, function(index, category) {
if (category.id == id) {
BackendServices.helper.display(category);
$('#edit-category, #delete-category').prop('disabled', false);
return false;
}
});
}
};

View file

@ -10,20 +10,10 @@ var BackendSettings = {
SETTINGS_USER: 'SETTINGS_USER', SETTINGS_USER: 'SETTINGS_USER',
/** /**
* This flag is used when trying to cancel row editing. It is * Use this WorkingPlan class instance to perform actions on the page's working plan
* true only whenever the user presses the cancel button. * tables.
*
* @type {bool}
*/ */
enableCancel: false, wp: {},
/**
* This flag determines whether the jeditables are allowed to submit. It is
* true only whenever the user presses the save button.
*
* @type {bool}
*/
enableSubmit: false,
/** /**
* Tab settings object. * Tab settings object.
@ -55,60 +45,9 @@ var BackendSettings = {
} }
}); });
$.each(workingPlan, function(index, workingDay) { BackendSettings.wp = new WorkingPlan();
if (workingDay != null) { BackendSettings.wp.setup(workingPlan);
$('#' + index).prop('checked', true); BackendSettings.wp.timepickers(false);
$('#' + index + '-start').val(workingDay.start);
$('#' + index + '-end').val(workingDay.end);
// Add the day's breaks on the breaks table.
$.each(workingDay.breaks, function(i, brk) {
var tr =
'<tr>' +
'<td class="break-day editable">' + GeneralFunctions.ucaseFirstLetter(index) + '</td>' +
'<td class="break-start editable">' + brk.start + '</td>' +
'<td class="break-end editable">' + brk.end + '</td>' +
'<td>' +
'<button type="button" class="btn edit-break" title="Edit Break">' +
'<i class="icon-pencil"></i>' +
'</button>' +
'<button type="button" class="btn delete-break" title="Delete Break">' +
'<i class="icon-remove"></i>' +
'</button>' +
'<button type="button" class="btn save-break hidden" title="Save Break">' +
'<i class="icon-ok"></i>' +
'</button>' +
'<button type="button" class="btn cancel-break hidden" title="Cancel Break">' +
'<i class="icon-ban-circle"></i>' +
'</button>' +
'</td>' +
'</tr>';
$('#breaks').append(tr);
});
} else {
$('#' + index).prop('checked', false);
$('#' + index + '-start').prop('disabled', true);
$('#' + index + '-end').prop('disabled', true);
}
});
// Make break cells editable.
BackendSettings.editableBreakDay($('#breaks .break-day'));
BackendSettings.editableBreakTime($('#breaks').find('.break-start, .break-end'));
// Set timepickers where needed.
$('.working-plan input').timepicker({
'timeFormat': 'HH:mm',
'onSelect': function(datetime, inst) {
// Start time must be earlier than end time.
var start = Date.parse($(this).parent().parent().find('.work-start').val());
var end = Date.parse($(this).parent().parent().find('.work-end').val());
if (start > end) {
$(this).parent().parent().find('.work-end').val(start.addHours(1).toString('HH:mm'));
}
}
});
// Book Advance Timeout Spinner // Book Advance Timeout Spinner
$('#book-advance-timeout').spinner({ $('#book-advance-timeout').spinner({
@ -150,6 +89,8 @@ var BackendSettings = {
* backend/settings html, so do not use this method on a different page. * backend/settings html, so do not use this method on a different page.
*/ */
bindEventHandlers: function() { bindEventHandlers: function() {
BackendSettings.wp.bindEventHandlers();
/** /**
* Event: Tab "Click" * Event: Tab "Click"
* *
@ -196,177 +137,6 @@ var BackendSettings = {
console.log('Settings To Save: ', settings); console.log('Settings To Save: ', settings);
////////////////////////////////////////////// //////////////////////////////////////////////
}); });
/**
* Event: Day Checkbox "Click"
*
* Enable or disable the time selection for each day.
*/
$('.working-plan input[type="checkbox"]').click(function() {
var id = $(this).attr('id');
if ($(this).prop('checked') == true) {
$('#' + id + '-start').prop('disabled', false).val('09:00');
$('#' + id + '-end').prop('disabled', false).val('18:00');
} else {
$('#' + id + '-start').prop('disabled', true).val('');
$('#' + id + '-end').prop('disabled', true).val('');
}
});
/**
* Event: Add Break Button "Click"
*
* A new row is added on the table and the user can enter the new break
* data. After that he can either press the save or cancel button.
*/
$('.add-break').click(function() {
var tr =
'<tr>' +
'<td class="break-day editable">Monday</td>' +
'<td class="break-start editable">09:00</td>' +
'<td class="break-end editable">10:00</td>' +
'<td>' +
'<button type="button" class="btn edit-break" title="Edit Break">' +
'<i class="icon-pencil"></i>' +
'</button>' +
'<button type="button" class="btn delete-break" title="Delete Break">' +
'<i class="icon-remove"></i>' +
'</button>' +
'<button type="button" class="btn save-break hidden" title="Save Break">' +
'<i class="icon-ok"></i>' +
'</button>' +
'<button type="button" class="btn cancel-break hidden" title="Cancel Break">' +
'<i class="icon-ban-circle"></i>' +
'</button>' +
'</td>' +
'</tr>';
$('#breaks').prepend(tr);
// Bind editable and event handlers.
tr = $('#breaks tr').get()[1];
BackendSettings.editableBreakDay($(tr).find('.break-day'));
BackendSettings.editableBreakTime($(tr).find('.break-start, .break-end'));
$(tr).find('.edit-break').trigger('click');
});
/**
* Event: Edit Break Button "Click"
*
* Enables the row editing for the "Breaks" table rows.
*/
$(document).on('click', '.edit-break', function() {
// Reset previous editable tds
var $previousEdt = $(this).closest('table').find('.editable').get();
$.each($previousEdt, function(index, edt) {
edt.reset();
});
// Make all cells in current row editable.
$(this).parent().parent().children().trigger('edit');
$(this).parent().parent().find('.break-start input, .break-end input').timepicker();
$(this).parent().parent().find('.break-day select').focus();
// Show save - cancel buttons.
$(this).closest('table').find('.edit-break, .delete-break').addClass('hidden');
$(this).parent().find('.save-break, .cancel-break').removeClass('hidden');
});
/**
* Event: Delete Break Button "Click"
*
* Removes the current line from the "Breaks" table.
*/
$(document).on('click', '.delete-break', function() {
$(this).parent().parent().remove();
});
/**
* Event: Cancel Break Button "Click"
*
* Bring the "#breaks" table back to its initial state.
*/
$(document).on('click', '.cancel-break', function() {
BackendSettings.enableCancel = true;
$(this).parent().parent().find('.cancel-editable').trigger('click');
BackendSettings.enableCancel = false;
$(this).closest('table').find('.edit-break, .delete-break').removeClass('hidden');
$(this).parent().find('.save-break, .cancel-break').addClass('hidden');
});
/**
* Event: Save Break Button "Click"
*
* Save the editable values and restore the table to its initial state.
*/
$(document).on('click', '.save-break', function() {
// Break's start time must always be prior to break's end.
var start = Date.parse($(this).parent().parent().find('.break-start input').val());
var end = Date.parse($(this).parent().parent().find('.break-end input').val());
if (start > end) {
$(this).parent().parent().find('.break-end input').val(start.addHours(1).toString('HH:mm'));
}
BackendSettings.enableSubmit = true;
$(this).parent().parent().find('.editable .submit-editable').trigger('click');
BackendSettings.enableSubmit = false;
$(this).closest('table').find('.edit-break, .delete-break').removeClass('hidden');
$(this).parent().find('.save-break, .cancel-break').addClass('hidden');
});
},
/**
* Initialize the editable functionality to the break day table cells.
*
* @param {object} $selector The cells to be initialized.
*/
editableBreakDay: function($selector) {
$selector.editable(function(value, settings) {
return value;
}, {
'type': 'select',
'data': '{ "Monday": "Monday", "Tuesday": "Tuesday", "Wednesday": "Wednesday", '
+ '"Thursday": "Thursday", "Friday": "Friday", "Saturday": "Saturday", '
+ '"Sunday": "Sunday", "selected": "Monday"}',
'event': 'edit',
'height': '30px',
'submit': '<button type="button" class="hidden submit-editable">Submit</button>',
'cancel': '<button type="button" class="hidden cancel-editable">Cancel</button>',
'onblur': 'ignore',
'onreset': function(settings, td) {
if (!BackendSettings.enableCancel) return false; // disable ESC button
},
'onsubmit': function(settings, td) {
if (!BackendSettings.enableSubmit) return false; // disable Enter button
}
});
},
/**
* Initialize the editable functionality to the break time table cells.
*
* @param {object} $selector The cells to be initialized.
*/
editableBreakTime: function($selector) {
$selector.editable(function(value, settings) {
// Do not return the value because the user needs to press the "Save" button.
return value;
}, {
'event': 'edit',
'height': '25px',
'submit': '<button type="button" class="hidden submit-editable">Submit</button>',
'cancel': '<button type="button" class="hidden cancel-editable">Cancel</button>',
'onblur': 'ignore',
'onreset': function(settings, td) {
if (!BackendSettings.enableCancel) return false; // disable ESC button
},
'onsubmit': function(settings, td) {
if (!BackendSettings.enableSubmit) return false; // disable Enter button
}
});
} }
}; };
@ -418,37 +188,9 @@ SystemSettings.prototype.get = function() {
}); });
// Business Logic Tab // Business Logic Tab
var workingPlan = {};
$('.working-plan input[type="checkbox"').each(function() {
var id = $(this).attr('id');
if ($(this).prop('checked') == true) {
workingPlan[id] = {}
workingPlan[id].start = $('#' + id + '-start').val();
workingPlan[id].end = $('#' + id + '-end').val();
workingPlan[id].breaks = [];
$('#breaks tr').each(function(index, tr) {
var day = $(tr).find('.break-day').text().toLowerCase();
if (day == id) {
var start = $(tr).find('.break-start').text();
var end = $(tr).find('.break-end').text();
workingPlan[id].breaks.push({
'start': start,
'end': end
});
}
});
} else {
workingPlan[id] = null;
}
});
settings.push({ settings.push({
'name': 'company_working_plan', 'name': 'company_working_plan',
'value': JSON.stringify(workingPlan) 'value': JSON.stringify(BackendSettings.wp.get())
}); });
settings.push({ settings.push({

View file

@ -15,20 +15,11 @@ var BackendUsers = {
helper: {}, helper: {},
/** /**
* This flag is used when trying to cancel row editing. It is * Use this class instance for performing actions on the working plan.
* true only whenever the user presses the cancel button.
* *
* @type {bool} * @type {object}
*/ */
enableCancel: false, wp: {},
/**
* This flag determines whether the jeditables are allowed to submit. It is
* true only whenever the user presses the save button.
*
* @type {bool}
*/
enableSubmit: false,
/** /**
* Initialize the backend users page. * Initialize the backend users page.
@ -44,6 +35,9 @@ var BackendUsers = {
BackendUsers.helper.resetForm(); BackendUsers.helper.resetForm();
BackendUsers.helper.filter(''); BackendUsers.helper.filter('');
BackendUsers.wp = new WorkingPlan();
BackendUsers.wp.bindEventHandlers();
// Fill the services and providers list boxes. // Fill the services and providers list boxes.
$.each(GlobalVariables.services, function(index, service) { $.each(GlobalVariables.services, function(index, service) {
var html = '<label class="checkbox"><input type="checkbox" data-id="' + service.id + '" />' var html = '<label class="checkbox"><input type="checkbox" data-id="' + service.id + '" />'
@ -150,7 +144,7 @@ var BackendUsers = {
}, 'json'); }, 'json');
}); });
// ----------------------------------------------------------------- // ------------------------------------------------------------------------
AdminsHelper.prototype.bindEventHandlers(); AdminsHelper.prototype.bindEventHandlers();
@ -161,5 +155,7 @@ var BackendUsers = {
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------
SecretariesHelper.prototype.bindEventHandlers(); SecretariesHelper.prototype.bindEventHandlers();
// ------------------------------------------------------------------------
} }
}; };

View file

@ -14,37 +14,48 @@ var AdminsHelper = function() {
*/ */
AdminsHelper.prototype.bindEventHandlers = function() { AdminsHelper.prototype.bindEventHandlers = function() {
/** /**
* Event: Filter Admins Button "Click" * Event: Filter Admins Form "Sumbit"
* *
* Filter the admin records with the given key string. * Filter the admin records with the given key string.
*/ */
$('.filter-admins').click(function() { $('#filter-admins form').submit(function() {
var key = $('#admins .filter-key').val(); event.preventDefault();
$('.selected-row').removeClass('selected-row'); var key = $('#filter-admins .key').val();
$('#filter-admins .selected-row').removeClass('selected-row');
BackendUsers.helper.resetForm(); BackendUsers.helper.resetForm();
BackendUsers.helper.filter(key); BackendUsers.helper.filter(key);
}); });
/**
* Event: Clear Filter Results Button "Click"
*/
$('#filter-admins .clear').click(function() {
BackendUsers.helper.filter('');
$('#filter-admins .key').val('');
});
/** /**
* Event: Filter Admin Row "Click" * Event: Filter Admin Row "Click"
* *
* Display the selected admin data to the user. * Display the selected admin data to the user.
*/ */
$(document).on('click', '.admin-row', function() { $(document).on('click', '.admin-row', function() {
if ($('#admins .filter-admins').prop('disabled')) { if ($('#filter-admins .filter').prop('disabled')) {
$('#admins .filter-results').css('color', '#AAA'); $('#filter-admins .results').css('color', '#AAA');
return; // exit because we are currently on edit mode return; // exit because we are currently on edit mode
} }
var admin = { 'id': $(this).attr('data-id') }; var adminId = $(this).attr('data-id');
var admin = {};
$.each(BackendUsers.helper.filterResults, function(index, item) { $.each(BackendUsers.helper.filterResults, function(index, item) {
if (item.id === admin.id) { if (item.id === adminId) {
admin = item; admin = item;
return; return false;
} }
}); });
BackendUsers.helper.display(admin); BackendUsers.helper.display(admin);
$('.selected-row').removeClass('selected-row'); $('#filter-admins .selected-row').removeClass('selected-row');
$(this).addClass('selected-row'); $(this).addClass('selected-row');
$('#edit-admin, #delete-admin').prop('disabled', false); $('#edit-admin, #delete-admin').prop('disabled', false);
}); });
@ -57,10 +68,10 @@ AdminsHelper.prototype.bindEventHandlers = function() {
$('#admins .add-edit-delete-group').hide(); $('#admins .add-edit-delete-group').hide();
$('#admins .save-cancel-group').show(); $('#admins .save-cancel-group').show();
$('#admins .details').find('input, textarea').prop('readonly', false); $('#admins .details').find('input, textarea').prop('readonly', false);
$('#admins .filter-admins').prop('disabled', true);
$('#admins .filter-results').css('color', '#AAA');
$('#admin-password, #admin-password-confirm').addClass('required'); $('#admin-password, #admin-password-confirm').addClass('required');
$('#admin-notifications').prop('disabled', false); $('#admin-notifications').prop('disabled', false);
$('#filter-admins button').prop('disabled', true);
$('#filter-admins .results').css('color', '#AAA');
}); });
/** /**
@ -69,11 +80,12 @@ AdminsHelper.prototype.bindEventHandlers = function() {
$('#edit-admin').click(function() { $('#edit-admin').click(function() {
$('#admins .add-edit-delete-group').hide(); $('#admins .add-edit-delete-group').hide();
$('#admins .save-cancel-group').show(); $('#admins .save-cancel-group').show();
$('.filter-admins').prop('disabled', true);
$('#admins .filter-results').css('color', '#AAA');
$('#admins .details').find('input, textarea').prop('readonly', false); $('#admins .details').find('input, textarea').prop('readonly', false);
$('#admin-password, #admin-password-confirm').removeClass('required'); $('#admin-password, #admin-password-confirm').removeClass('required');
$('#admin-notifications').prop('disabled', false); $('#admin-notifications').prop('disabled', false);
$('#filter-admins .filter').prop('disabled', true);
$('#filter-admins .results').css('color', '#AAA');
}); });
/** /**
@ -138,10 +150,11 @@ AdminsHelper.prototype.bindEventHandlers = function() {
* Cancel add or edit of an admin record. * Cancel add or edit of an admin record.
*/ */
$('#cancel-admin').click(function() { $('#cancel-admin').click(function() {
var id = $('#admin-id').val();
BackendUsers.helper.resetForm(); BackendUsers.helper.resetForm();
if ($('admins .selected-row').length == 0) return; if (id != '') {
var id = $('#admins .selected-row').attr('data-id'); BackendUsers.helper.select(id, true);
BackendUsers.helper.selectRecord(id); }
}); });
}; };
@ -165,11 +178,9 @@ AdminsHelper.prototype.save = function(admin) {
//////////////////////////////////////////////// ////////////////////////////////////////////////
if (!GeneralFunctions.handleAjaxExceptions(response)) return; if (!GeneralFunctions.handleAjaxExceptions(response)) return;
Backend.displayNotification('Admin saved successfully!'); Backend.displayNotification('Admin saved successfully!');
BackendUsers.helper.resetForm(true); BackendUsers.helper.resetForm();
// When adding a new record the "admin.id" will be undefined. In this situation $('#filter-admins .key').val('');
// no record will be selected because we do not yet know the id of the new record, BackendUsers.helper.filter('', response.id, true);
// but no error will occur either.
BackendUsers.helper.filter($('#admins .filter-key').val(), admin.id);
}, 'json'); }, 'json');
}; };
@ -189,7 +200,7 @@ AdminsHelper.prototype.delete = function(id) {
if (!GeneralFunctions.handleAjaxExceptions(response)) return; if (!GeneralFunctions.handleAjaxExceptions(response)) return;
Backend.displayNotification('Admin deleted successfully!'); Backend.displayNotification('Admin deleted successfully!');
BackendUsers.helper.resetForm(); BackendUsers.helper.resetForm();
BackendUsers.helper.filter($('#admins .filter-key').val()); BackendUsers.helper.filter($('#filter-admins .key').val());
}); });
}; };
@ -244,29 +255,23 @@ AdminsHelper.prototype.validate = function(admin) {
}; };
/** /**
* Resets the admin tab form back to its initial state. * Resets the admin form back to its initial state.
*
* @param {bool} keepRecordData (OPTIONAL = false) If false then the current record data
* will remain on the form.
*/ */
AdminsHelper.prototype.resetForm = function(keepRecordData) { AdminsHelper.prototype.resetForm = function() {
if (keepRecordData == undefined) keepRecordData = false;
$('#admins .add-edit-delete-group').show(); $('#admins .add-edit-delete-group').show();
$('#admins .save-cancel-group').hide(); $('#admins .save-cancel-group').hide();
$('#admins .details').find('input, textarea').prop('readonly', true); $('#admins .details').find('input, textarea').prop('readonly', true);
$('.filter-admins').prop('disabled', false);
$('#admins .filter-results').css('color', '');
$('#admins .form-message').hide(); $('#admins .form-message').hide();
$('#admin-notifications').prop('disabled', true); $('#admin-notifications').prop('disabled', true);
$('#admins .required').css('border', ''); $('#admins .required').css('border', '');
$('#admin-password, #admin-password-confirm').css('border', ''); $('#admin-password, #admin-password-confirm').css('border', '');
if (!keepRecordData) {
$('#admins .details').find('input, textarea').val(''); $('#admins .details').find('input, textarea').val('');
$('#admin-notifications').removeClass('active'); $('#admin-notifications').removeClass('active');
$('#edit-admin, #delete-admin').prop('disabled', true); $('#edit-admin, #delete-admin').prop('disabled', true);
}
$('#filter-admins .selected-row').removeClass('selected-row');
$('#filter-admins button').prop('disabled', false);
$('#filter-admins .results').css('color', '');
}; };
/** /**
@ -296,11 +301,17 @@ AdminsHelper.prototype.display = function(admin) {
}; };
/** /**
* Filters admin records depending a string key. * Filters admin records depending a key string.
* *
* @param {string} key This is used to filter the admin records of the database. * @param {string} key This string is used to filter the admin records of the database.
* @param {numeric} selectId (OPTIONAL = undefined) This record id will be selected when
* the filter operation is finished.
* @param {bool} display (OPTIONAL = false) If true the selected record data are going
* to be displayed on the details column (requires a selected record though).
*/ */
AdminsHelper.prototype.filter = function(key, selectRecordId) { AdminsHelper.prototype.filter = function(key, selectId, display) {
if (display == undefined) display = false;
var postUrl = GlobalVariables.baseUrl + 'backend_api/ajax_filter_admins'; var postUrl = GlobalVariables.baseUrl + 'backend_api/ajax_filter_admins';
var postData = { 'key': key }; var postData = { 'key': key };
@ -313,19 +324,18 @@ AdminsHelper.prototype.filter = function(key, selectRecordId) {
BackendUsers.helper.filterResults = response; BackendUsers.helper.filterResults = response;
$('#admins .filter-results').html(''); $('#filter-admins .results').html('');
$.each(response, function(index, admin) { $.each(response, function(index, admin) {
var html = AdminsHelper.prototype.getFilterHtml(admin); var html = AdminsHelper.prototype.getFilterHtml(admin);
$('#admins .filter-results').append(html); $('#filter-admins .results').append(html);
}); });
if (selectRecordId != undefined) { if (response.length == 0) {
$('.admin-row').each(function() { $('#filter-admins .results').html('<em>No results found ...</em>')
if ($(this).attr('data-id') == selectRecordId) {
$(this).addClass('selected-row');
return false;
} }
});
if (selectId != undefined) {
BackendUsers.helper.select(selectId, display);
} }
}, 'json'); }, 'json');
}; };
@ -347,33 +357,34 @@ AdminsHelper.prototype.getFilterHtml = function(admin) {
}; };
/** /**
* Select a specific record from the current filter results. If the admin does not exist in * Select a specific record from the current filter results. If the admin id does not exist
* the list then no record will be selected. * in the list then no record will be selected.
* *
* @param {numeric} id The record id to be selected. * @param {numeric} id The record id to be selected from the filter results.
* @param {bool} display (OPTIONAL = false) If true then the method will display the record * @param {bool} display (OPTIONAL = false) If true then the method will display the record
* on the form. * on the form.
*
* @task The selected row must always be visible (even if a vertical scroll bar is used to
* navigate through the filter results).
*/ */
AdminsHelper.prototype.selectRecord = function(id, display) { AdminsHelper.prototype.select = function(id, display) {
if (display == undefined) display = false; if (display == undefined) display = false;
$('#admins .selected-row').removeClass('selected-row'); $('#filter-admins .selected-row').removeClass('selected-row');
$('.admin-row').each(function() { $('.admin-row').each(function() {
if ($(this).attr('data-id') == id) { if ($(this).attr('data-id') == id) {
$(this).addClass('selected-row'); $(this).addClass('selected-row');
return; return false;
} }
}); });
if (display) { if (display) {
var admin; $.each(BackendUsers.helper.filterResults, function(index, admin) {
$.each(BackendUsers.helper.filterResults, function(index, item) { if (admin.id == id) {
if (item.id === id) {
admin = item;
BackendUsers.helper.display(admin); BackendUsers.helper.display(admin);
$('#edit-admin, #delete-admin').prop('disabled', false); $('#edit-admin, #delete-admin').prop('disabled', false);
return; return false;
} }
}); });
} }

View file

@ -14,37 +14,48 @@ var ProvidersHelper = function() {
*/ */
ProvidersHelper.prototype.bindEventHandlers = function() { ProvidersHelper.prototype.bindEventHandlers = function() {
/** /**
* Event: Filter Providers Button "Click" * Event: Filter Providers Form "Submit"
* *
* Filter the provider records with the given key string. * Filter the provider records with the given key string.
*/ */
$('.filter-providers').click(function() { $('#filter-providers form').submit(function() {
var key = $('#providers .filter-key').val(); event.preventDefault();
var key = $('#filter-providers .key').val();
$('.selected-row').removeClass('selected-row'); $('.selected-row').removeClass('selected-row');
BackendUsers.helper.resetForm(); BackendUsers.helper.resetForm();
BackendUsers.helper.filter(key); BackendUsers.helper.filter(key);
}); });
/**
* Event: Clear Filter Button "Click"
*/
$('#filter-providers .clear').click(function() {
BackendUsers.helper.filter('');
$('#filter-providers .key').val('');
});
/** /**
* Event: Filter Provider Row "Click" * Event: Filter Provider Row "Click"
* *
* Display the selected provider data to the user. * Display the selected provider data to the user.
*/ */
$(document).on('click', '.provider-row', function() { $(document).on('click', '.provider-row', function() {
if ($('#providers .filter-providers').prop('disabled')) { if ($('#filter-providers .filter').prop('disabled')) {
$('#providers .filter-results').css('color', '#AAA'); $('#filter-providers .results').css('color', '#AAA');
return; // exit because we are currently on edit mode return; // Exit because we are currently on edit mode.
} }
var provider = { 'id': $(this).attr('data-id') }; var providerId = $(this).attr('data-id');
var provider = {};
$.each(BackendUsers.helper.filterResults, function(index, item) { $.each(BackendUsers.helper.filterResults, function(index, item) {
if (item.id === provider.id) { if (item.id === providerId) {
provider = item; provider = item;
return; return false;
} }
}); });
BackendUsers.helper.display(provider); BackendUsers.helper.display(provider);
$('.selected-row').removeClass('selected-row'); $('#filter-providers .selected-row').removeClass('selected-row');
$(this).addClass('selected-row'); $(this).addClass('selected-row');
$('#edit-provider, #delete-provider').prop('disabled', false); $('#edit-provider, #delete-provider').prop('disabled', false);
}); });
@ -54,194 +65,19 @@ ProvidersHelper.prototype.bindEventHandlers = function() {
*/ */
$('#add-provider').click(function() { $('#add-provider').click(function() {
BackendUsers.helper.resetForm(); BackendUsers.helper.resetForm();
$('#filter-providers button').prop('disabled', true);
$('#filter-providers .results').css('color', '#AAA');
$('#providers .add-edit-delete-group').hide(); $('#providers .add-edit-delete-group').hide();
$('#providers .save-cancel-group').show(); $('#providers .save-cancel-group').show();
$('#providers .details').find('input, textarea').prop('readonly', false); $('#providers .details').find('input, textarea').prop('readonly', false);
$('#providers .filter-providers').prop('disabled', true);
$('#providers .filter-results').css('color', '#AAA');
$('#provider-password, #provider-password-confirm').addClass('required'); $('#provider-password, #provider-password-confirm').addClass('required');
$('#provider-notifications').prop('disabled', false); $('#provider-notifications').prop('disabled', false);
$('#provider-services input[type="checkbox"]').prop('disabled', false); $('#provider-services input[type="checkbox"]').prop('disabled', false);
$('#providers .add-break').prop('disabled', false);
$('.edit-break, .delete-break').prop('disabled', false);
$('#providers input[type="checkbox"]').prop('disabled', false); $('#providers input[type="checkbox"]').prop('disabled', false);
// Apply default working plan // Apply default working plan
$.each(GlobalVariables.workingPlan, function(index, workingDay) { BackendUsers.wp.setup(GlobalVariables.workingPlan);
if (workingDay != null) { BackendUsers.wp.timepickers(false);
$('#' + index).prop('checked', true);
$('#' + index + '-start').val(workingDay.start);
$('#' + index + '-end').val(workingDay.end);
// Add the day's breaks on the breaks table.
$.each(workingDay.breaks, function(i, brk) {
var tr =
'<tr>' +
'<td class="break-day editable">' + GeneralFunctions.ucaseFirstLetter(index) + '</td>' +
'<td class="break-start editable">' + brk.start + '</td>' +
'<td class="break-end editable">' + brk.end + '</td>' +
'<td>' +
'<button type="button" class="btn edit-break" title="Edit Break">' +
'<i class="icon-pencil"></i>' +
'</button>' +
'<button type="button" class="btn delete-break" title="Delete Break">' +
'<i class="icon-remove"></i>' +
'</button>' +
'<button type="button" class="btn save-break hidden" title="Save Break">' +
'<i class="icon-ok"></i>' +
'</button>' +
'<button type="button" class="btn cancel-break hidden" title="Cancel Break">' +
'<i class="icon-ban-circle"></i>' +
'</button>' +
'</td>' +
'</tr>';
$('#breaks').append(tr);
});
} else {
$('#' + index).prop('checked', false);
$('#' + index + '-start').prop('disabled', true);
$('#' + index + '-end').prop('disabled', true);
}
});
// Make break cells editable.
BackendUsers.helper.editableBreakDay($('#breaks .break-day'));
BackendUsers.helper.editableBreakTime($('#breaks').find('.break-start, .break-end'));
// Set timepickers where needed.
$('.working-plan input').timepicker({
'timeFormat': 'HH:mm',
'onSelect': function(datetime, inst) {
// Start time must be earlier than end time.
var start = Date.parse($(this).parent().parent().find('.work-start').val());
var end = Date.parse($(this).parent().parent().find('.work-end').val());
if (start > end) {
$(this).parent().parent().find('.work-end').val(start.addHours(1).toString('HH:mm'));
}
}
});
});
/**
* Event: Day Checkbox "Click"
*
* Enable or disable the time selection for each day.
*/
$('.working-plan input[type="checkbox"]').click(function() {
var id = $(this).attr('id');
if ($(this).prop('checked') == true) {
$('#' + id + '-start').prop('disabled', false).val('09:00');
$('#' + id + '-end').prop('disabled', false).val('18:00');
} else {
$('#' + id + '-start').prop('disabled', true).val('');
$('#' + id + '-end').prop('disabled', true).val('');
}
});
/**
* Event: Add Break Button "Click"
*
* A new row is added on the table and the user can enter the new break
* data. After that he can either press the save or cancel button.
*/
$('.add-break').click(function() {
var tr =
'<tr>' +
'<td class="break-day editable">Monday</td>' +
'<td class="break-start editable">09:00</td>' +
'<td class="break-end editable">10:00</td>' +
'<td>' +
'<button type="button" class="btn edit-break" title="Edit Break">' +
'<i class="icon-pencil"></i>' +
'</button>' +
'<button type="button" class="btn delete-break" title="Delete Break">' +
'<i class="icon-remove"></i>' +
'</button>' +
'<button type="button" class="btn save-break hidden" title="Save Break">' +
'<i class="icon-ok"></i>' +
'</button>' +
'<button type="button" class="btn cancel-break hidden" title="Cancel Break">' +
'<i class="icon-ban-circle"></i>' +
'</button>' +
'</td>' +
'</tr>';
$('#breaks').prepend(tr);
// Bind editable and event handlers.
tr = $('#breaks tr').get()[1];
BackendUsers.helper.editableBreakDay($(tr).find('.break-day'));
BackendUsers.helper.editableBreakTime($(tr).find('.break-start, .break-end'));
$(tr).find('.edit-break').trigger('click');
});
/**
* Event: Edit Break Button "Click"
*
* Enables the row editing for the "Breaks" table rows.
*/
$(document).on('click', '.edit-break', function() {
// Reset previous editable tds
var $previousEdt = $(this).closest('table').find('.editable').get();
$.each($previousEdt, function(index, edt) {
edt.reset();
});
// Make all cells in current row editable.
$(this).parent().parent().children().trigger('edit');
$(this).parent().parent().find('.break-start input, .break-end input').timepicker();
$(this).parent().parent().find('.break-day select').focus();
// Show save - cancel buttons.
$(this).closest('table').find('.edit-break, .delete-break').addClass('hidden');
$(this).parent().find('.save-break, .cancel-break').removeClass('hidden');
});
/**
* Event: Delete Break Button "Click"
*
* Removes the current line from the "Breaks" table.
*/
$(document).on('click', '.delete-break', function() {
$(this).parent().parent().remove();
});
/**
* Event: Cancel Break Button "Click"
*
* Bring the "#breaks" table back to its initial state.
*/
$(document).on('click', '.cancel-break', function() {
BackendUsers.enableCancel = true;
$(this).parent().parent().find('.cancel-editable').trigger('click');
BackendUsers.enableCancel = false;
$(this).closest('table').find('.edit-break, .delete-break').removeClass('hidden');
$(this).parent().find('.save-break, .cancel-break').addClass('hidden');
});
/**
* Event: Save Break Button "Click"
*
* Save the editable values and restore the table to its initial state.
*/
$(document).on('click', '.save-break', function() {
// Break's start time must always be prior to break's end.
var start = Date.parse($(this).parent().parent().find('.break-start input').val());
var end = Date.parse($(this).parent().parent().find('.break-end input').val());
if (start > end) {
$(this).parent().parent().find('.break-end input').val(start.addHours(1).toString('HH:mm'));
}
BackendUsers.enableSubmit = true;
$(this).parent().parent().find('.editable .submit-editable').trigger('click');
BackendUsers.enableSubmit = false;
$(this).closest('table').find('.edit-break, .delete-break').removeClass('hidden');
$(this).parent().find('.save-break, .cancel-break').addClass('hidden');
}); });
/** /**
@ -250,16 +86,15 @@ ProvidersHelper.prototype.bindEventHandlers = function() {
$('#edit-provider').click(function() { $('#edit-provider').click(function() {
$('#providers .add-edit-delete-group').hide(); $('#providers .add-edit-delete-group').hide();
$('#providers .save-cancel-group').show(); $('#providers .save-cancel-group').show();
$('.filter-providers').prop('disabled', true); $('#filter-providers button').prop('disabled', true);
$('#providers .filter-results').css('color', '#AAA'); $('#filter-providers .results').css('color', '#AAA');
$('#providers .details').find('input, textarea').prop('readonly', false); $('#providers .details').find('input, textarea').prop('readonly', false);
$('#provider-password, #provider-password-confirm').removeClass('required'); $('#provider-password, #provider-password-confirm').removeClass('required');
$('#provider-notifications').prop('disabled', false); $('#provider-notifications').prop('disabled', false);
$('#provider-services input[type="checkbox"]').prop('disabled', false); $('#provider-services input[type="checkbox"]').prop('disabled', false);
$('#providers').find('.add-break, .edit-break, .delete-break').prop('disabled', false);
$('#providers .add-break').prop('disabled', false);
$('.edit-break, .delete-break').prop('disabled', false);
$('#providers input[type="checkbox"]').prop('disabled', false); $('#providers input[type="checkbox"]').prop('disabled', false);
BackendUsers.wp.timepickers(false);
}); });
/** /**
@ -299,7 +134,7 @@ ProvidersHelper.prototype.bindEventHandlers = function() {
'notes': $('#provider-notes').val(), 'notes': $('#provider-notes').val(),
'settings': { 'settings': {
'username': $('#provider-username').val(), 'username': $('#provider-username').val(),
'working_plan': BackendUsers.helper.getWorkingPlan(), 'working_plan': JSON.stringify(BackendUsers.wp.get()),
'notifications': $('#provider-notifications').hasClass('active') 'notifications': $('#provider-notifications').hasClass('active')
} }
}; };
@ -333,22 +168,13 @@ ProvidersHelper.prototype.bindEventHandlers = function() {
* Cancel add or edit of an provider record. * Cancel add or edit of an provider record.
*/ */
$('#cancel-provider').click(function() { $('#cancel-provider').click(function() {
var id = $('#filter-providers .selected-row').attr('data-id');
BackendUsers.helper.resetForm(); BackendUsers.helper.resetForm();
if (id != '') {
var provider = { 'id': $('#providers .selected-row').attr('data-id') }; BackendUsers.helper.select(id, true);
$.each(BackendUsers.helper.filterResults, function(index, item) {
if (item.id === provider.id) {
provider = item;
return;
} }
}); });
BackendUsers.helper.display(provider);
$('#edit-provider, #delete-provider').prop('disabled', false);
});
/** /**
* Event: Display Provider Details "Click" * Event: Display Provider Details "Click"
*/ */
@ -393,17 +219,16 @@ ProvidersHelper.prototype.save = function(provider) {
/////////////////////////////////////////////////// ///////////////////////////////////////////////////
if (!GeneralFunctions.handleAjaxExceptions(response)) return; if (!GeneralFunctions.handleAjaxExceptions(response)) return;
Backend.displayNotification('Provider saved successfully!'); Backend.displayNotification('Provider saved successfully!');
BackendUsers.helper.resetForm(true); BackendUsers.helper.resetForm();
// If "id" is not defined then no record will be selected (applies when adding $('#filter-providers .key').val('');
// a new provider record). BackendUsers.helper.filter('', response.id, true);
BackendUsers.helper.filter($('#providers .filter-key').val(), provider.id);
}, 'json'); }, 'json');
}; };
/** /**
* Delete a provider record from database. * Delete a provider record from database.
* *
* @param {int} id Record id to be deleted. * @param {numeric} id Record id to be deleted.
*/ */
ProvidersHelper.prototype.delete = function(id) { ProvidersHelper.prototype.delete = function(id) {
var postUrl = GlobalVariables.baseUrl + 'backend_api/ajax_delete_provider'; var postUrl = GlobalVariables.baseUrl + 'backend_api/ajax_delete_provider';
@ -416,7 +241,7 @@ ProvidersHelper.prototype.delete = function(id) {
if (!GeneralFunctions.handleAjaxExceptions(response)) return; if (!GeneralFunctions.handleAjaxExceptions(response)) return;
Backend.displayNotification('Provider deleted successfully!'); Backend.displayNotification('Provider deleted successfully!');
BackendUsers.helper.resetForm(); BackendUsers.helper.resetForm();
BackendUsers.helper.filter($('#providers .filter-key').val()); BackendUsers.helper.filter($('#filter-providers .key').val());
}); });
}; };
@ -472,18 +297,15 @@ ProvidersHelper.prototype.validate = function(provider) {
/** /**
* Resets the admin tab form back to its initial state. * Resets the admin tab form back to its initial state.
*
* @param {bool} keepRecordData (OPTIONAL = false) If true then the current record data will
* remain on the form.
*/ */
ProvidersHelper.prototype.resetForm = function(keepRecordData) { ProvidersHelper.prototype.resetForm = function() {
if (keepRecordData == undefined) keepRecordData = false; $('#filter-providers .selected-row').removeClass('selected-row');
$('#filter-providers button').prop('disabled', false);
$('#filter-providers .results').css('color', '');
$('#providers .add-edit-delete-group').show(); $('#providers .add-edit-delete-group').show();
$('#providers .save-cancel-group').hide(); $('#providers .save-cancel-group').hide();
$('#providers .details').find('input, textarea').prop('readonly', true); $('#providers .details').find('input, textarea').prop('readonly', true);
$('.filter-providers').prop('disabled', false);
$('#providers .filter-results').css('color', '');
$('#providers .form-message').hide(); $('#providers .form-message').hide();
$('#provider-notifications').removeClass('active'); $('#provider-notifications').removeClass('active');
$('#provider-notifications').prop('disabled', true); $('#provider-notifications').prop('disabled', true);
@ -491,17 +313,16 @@ ProvidersHelper.prototype.resetForm = function(keepRecordData) {
$('#providers .required').css('border', ''); $('#providers .required').css('border', '');
$('#provider-password, #provider-password-confirm').css('border', ''); $('#provider-password, #provider-password-confirm').css('border', '');
$('#providers .add-break').prop('disabled', true); $('#providers .add-break').prop('disabled', true);
$('#providers input[type="checkbox"]').prop('disabled', true); BackendUsers.wp.timepickers(true);
$('#providers .working-plan input[type="text"]').timepicker('destroy'); $('#providers .working-plan input[type="text"]').timepicker('destroy');
$('#breaks').find('.edit-break, .delete-break').prop('disabled', true); $('.breaks').find('.edit-break, .delete-break').prop('disabled', true);
if (!keepRecordData) {
$('#edit-provider, #delete-provider').prop('disabled', true); $('#edit-provider, #delete-provider').prop('disabled', true);
$('#providers .details').find('input, textarea').val(''); $('#providers .details').find('input, textarea').val('');
$('#providers input[type="checkbox"]').prop('checked', false); $('#providers input[type="checkbox"]').prop('checked', false);
$('#provider-services input[type="checkbox"]').prop('checked', false); $('#provider-services input[type="checkbox"]').prop('checked', false);
$('#providers #breaks tbody').empty(); $('#providers .breaks tbody').empty();
}
}; };
/** /**
@ -539,74 +360,24 @@ ProvidersHelper.prototype.display = function(provider) {
}); });
// Display working plan // Display working plan
$('#providers #breaks tbody').empty(); $('#providers .breaks tbody').empty();
var workingPlan = $.parseJSON(provider.settings.working_plan); var workingPlan = $.parseJSON(provider.settings.working_plan);
$.each(workingPlan, function(index, workingDay) { BackendUsers.wp.setup(workingPlan);
if (workingDay != null) { $('.breaks').find('.edit-break, .delete-break').prop('disabled', true);
$('#' + index).prop('checked', true);
$('#' + index + '-start').val(workingDay.start);
$('#' + index + '-end').val(workingDay.end);
// Add the day's breaks on the breaks table.
$.each(workingDay.breaks, function(i, brk) {
var tr =
'<tr>' +
'<td class="break-day editable">' + GeneralFunctions.ucaseFirstLetter(index) + '</td>' +
'<td class="break-start editable">' + brk.start + '</td>' +
'<td class="break-end editable">' + brk.end + '</td>' +
'<td>' +
'<button type="button" class="btn edit-break" title="Edit Break">' +
'<i class="icon-pencil"></i>' +
'</button>' +
'<button type="button" class="btn delete-break" title="Delete Break">' +
'<i class="icon-remove"></i>' +
'</button>' +
'<button type="button" class="btn save-break hidden" title="Save Break">' +
'<i class="icon-ok"></i>' +
'</button>' +
'<button type="button" class="btn cancel-break hidden" title="Cancel Break">' +
'<i class="icon-ban-circle"></i>' +
'</button>' +
'</td>' +
'</tr>';
$('#breaks').append(tr);
});
} else {
$('#' + index).prop('checked', false);
$('#' + index + '-start').prop('disabled', true);
$('#' + index + '-end').prop('disabled', true);
}
});
$('.edit-break, .delete-break').prop('disabled', true);
// Make break cells editable.
BackendUsers.helper.editableBreakDay($('#breaks .break-day'));
BackendUsers.helper.editableBreakTime($('#breaks').find('.break-start, .break-end'));
// Set timepickers where needed.
$('.working-plan input').timepicker({
'timeFormat': 'HH:mm',
'onSelect': function(datetime, inst) {
// Start time must be earlier than end time.
var start = Date.parse($(this).parent().parent().find('.work-start').val());
var end = Date.parse($(this).parent().parent().find('.work-end').val());
if (start > end) {
$(this).parent().parent().find('.work-end').val(start.addHours(1).toString('HH:mm'));
}
}
});
}; };
/** /**
* Filters provider records depending a string key. * Filters provider records depending a string key.
* *
* @param {string} key This is used to filter the provider records of the database. * @param {string} key This is used to filter the provider records of the database.
* @param {numeric} selectRecordId (OPTIONAL) If set, when the function is complete * @param {numeric} selectId (OPTIONAL = undefined) If set, when the function is complete
* a result row can be set as selected. * a result row can be set as selected.
* @param {bool} display (OPTIONAL = false) If true then the selected record will be also
* displayed.
*/ */
ProvidersHelper.prototype.filter = function(key, selectRecordId) { ProvidersHelper.prototype.filter = function(key, selectId, display) {
if (display == undefined) display = false;
var postUrl = GlobalVariables.baseUrl + 'backend_api/ajax_filter_providers'; var postUrl = GlobalVariables.baseUrl + 'backend_api/ajax_filter_providers';
var postData = { 'key': key }; var postData = { 'key': key };
@ -619,19 +390,18 @@ ProvidersHelper.prototype.filter = function(key, selectRecordId) {
BackendUsers.helper.filterResults = response; BackendUsers.helper.filterResults = response;
$('#providers .filter-results').html(''); $('#filter-providers .results').html('');
$.each(response, function(index, provider) { $.each(response, function(index, provider) {
var html = ProvidersHelper.prototype.getFilterHtml(provider); var html = ProvidersHelper.prototype.getFilterHtml(provider);
$('#providers .filter-results').append(html); $('#filter-providers .results').append(html);
}); });
if (selectRecordId != undefined) { if (response.length == 0) {
$('.provider-row').each(function() { $('#filter-providers .results').html('<em>No results found ...</em>')
if ($(this).attr('data-id') == selectRecordId) {
$(this).addClass('selected-row');
return false;
} }
});
if (selectId != undefined) {
BackendUsers.helper.select(selectId, display);
} }
}, 'json'); }, 'json');
}; };
@ -652,44 +422,6 @@ ProvidersHelper.prototype.getFilterHtml = function(provider) {
return html; return html;
}; };
/**
* Get the current working plan.
*
* @return {string} Returns the working plan (already stringified).
*/
ProvidersHelper.prototype.getWorkingPlan = function() {
var workingPlan = {};
$('.working-plan input[type="checkbox"').each(function() {
var id = $(this).attr('id');
if ($(this).prop('checked') == true) {
workingPlan[id] = {}
workingPlan[id].start = $('#' + id + '-start').val();
workingPlan[id].end = $('#' + id + '-end').val();
workingPlan[id].breaks = [];
$('#breaks tr').each(function(index, tr) {
var day = $(tr).find('.break-day').text().toLowerCase();
if (day == id) {
var start = $(tr).find('.break-start').text();
var end = $(tr).find('.break-end').text();
workingPlan[id].breaks.push({
'start': start,
'end': end
});
}
});
} else {
workingPlan[id] = null;
}
});
return JSON.stringify(workingPlan);
};
/** /**
* Initialize the editable functionality to the break day table cells. * Initialize the editable functionality to the break day table cells.
* *
@ -715,7 +447,7 @@ ProvidersHelper.prototype.editableBreakDay = function($selector) {
if (!BackendUsers.enableSubmit) return false; // disable Enter button if (!BackendUsers.enableSubmit) return false; // disable Enter button
} }
}); });
}, };
/** /**
* Initialize the editable functionality to the break time table cells. * Initialize the editable functionality to the break time table cells.
@ -739,4 +471,33 @@ ProvidersHelper.prototype.editableBreakTime = function($selector) {
if (!BackendUsers.enableSubmit) return false; // disable Enter button if (!BackendUsers.enableSubmit) return false; // disable Enter button
} }
}); });
} };
/**
* Select and display a providers filter result on the form.
*
* @param {numeric} id Record id to be selected.
* @param {bool} display (OPTIONAL = false) If true the record will be displayed on the form.
*/
ProvidersHelper.prototype.select = function(id, display) {
if (display == undefined) display = false;
// Select record in filter results.
$('#filter-providers .provider-row').each(function() {
if ($(this).attr('data-id') == id) {
$(this).addClass('selected-row');
return false;
}
});
// Display record in form (if display = true).
if (display) {
$.each(BackendUsers.helper.filterResults, function(index, provider) {
if (provider.id == id) {
BackendUsers.helper.display(provider);
$('#edit-provider, #delete-provider').prop('disabled', false);
return false;
}
});
}
};

View file

@ -14,37 +14,48 @@ var SecretariesHelper = function() {
*/ */
SecretariesHelper.prototype.bindEventHandlers = function() { SecretariesHelper.prototype.bindEventHandlers = function() {
/** /**
* Event: Filter Secretaries Button "Click" * Event: Filter Secretaries Form "Submit"
* *
* Filter the secretary records with the given key string. * Filter the secretary records with the given key string.
*/ */
$('.filter-secretaries').click(function() { $('#filter-secretaries form').submit(function() {
var key = $('#secretaries .filter-key').val(); event.preventDefault();
$('.selected-row').removeClass('selected-row'); var key = $('#filter-secretaries .key').val();
$('#filter-secretaries .selected-row').removeClass('selected-row');
BackendUsers.helper.resetForm(); BackendUsers.helper.resetForm();
BackendUsers.helper.filter(key); BackendUsers.helper.filter(key);
}); });
/**
* Event: Clear Filter Results Button "Click"
*/
$('#filter-secretaries .clear').click(function() {
BackendUsers.helper.filter('');
$('#filter-secretaries .key').val('');
});
/** /**
* Event: Filter Secretary Row "Click" * Event: Filter Secretary Row "Click"
* *
* Display the selected secretary data to the user. * Display the selected secretary data to the user.
*/ */
$(document).on('click', '.secretary-row', function() { $(document).on('click', '.secretary-row', function() {
if ($('#secretaries .filter-secretaries').prop('disabled')) { if ($('#filter-secretaries .filter').prop('disabled')) {
$('#secretaries .filter-results').css('color', '#AAA'); $('#filter-secretaries .results').css('color', '#AAA');
return; // exit because we are currently on edit mode return; // exit because we are currently on edit mode
} }
var secretary = { 'id': $(this).attr('data-id') }; var secretaryId = $(this).attr('data-id');
var secretary = {};
$.each(BackendUsers.helper.filterResults, function(index, item) { $.each(BackendUsers.helper.filterResults, function(index, item) {
if (item.id === secretary.id) { if (item.id === secretaryId) {
secretary = item; secretary = item;
return; return false;
} }
}); });
BackendUsers.helper.display(secretary); BackendUsers.helper.display(secretary);
$('.selected-row').removeClass('selected-row'); $('#filter-secretaries .selected-row').removeClass('selected-row');
$(this).addClass('selected-row'); $(this).addClass('selected-row');
$('#edit-secretary, #delete-secretary').prop('disabled', false); $('#edit-secretary, #delete-secretary').prop('disabled', false);
}); });
@ -54,11 +65,12 @@ SecretariesHelper.prototype.bindEventHandlers = function() {
*/ */
$('#add-secretary').click(function() { $('#add-secretary').click(function() {
BackendUsers.helper.resetForm(); BackendUsers.helper.resetForm();
$('#filter-secretaries button').prop('disabled', true);
$('#filter-secretaries .results').css('color', '#AAA');
$('#secretaries .add-edit-delete-group').hide(); $('#secretaries .add-edit-delete-group').hide();
$('#secretaries .save-cancel-group').show(); $('#secretaries .save-cancel-group').show();
$('#secretaries .details').find('input, textarea').prop('readonly', false); $('#secretaries .details').find('input, textarea').prop('readonly', false);
$('#secretaries .filter-secretaries').prop('disabled', true);
$('#secretaries .filter-results').css('color', '#AAA');
$('#secretary-password, #secretary-password-confirm').addClass('required'); $('#secretary-password, #secretary-password-confirm').addClass('required');
$('#secretary-notifications').prop('disabled', false); $('#secretary-notifications').prop('disabled', false);
$('#secretary-providers input[type="checkbox"]').prop('disabled', false); $('#secretary-providers input[type="checkbox"]').prop('disabled', false);
@ -68,10 +80,11 @@ SecretariesHelper.prototype.bindEventHandlers = function() {
* Event: Edit Secretary Button "Click" * Event: Edit Secretary Button "Click"
*/ */
$('#edit-secretary').click(function() { $('#edit-secretary').click(function() {
$('#filter-secretaries button').prop('disabled', true);
$('#filter-secretaries .results').css('color', '#AAA');
$('#secretaries .add-edit-delete-group').hide(); $('#secretaries .add-edit-delete-group').hide();
$('#secretaries .save-cancel-group').show(); $('#secretaries .save-cancel-group').show();
$('.filter-secretaries').prop('disabled', true);
$('#secretaries .filter-results').css('color', '#AAA');
$('#secretaries .details').find('input, textarea').prop('readonly', false); $('#secretaries .details').find('input, textarea').prop('readonly', false);
$('#secretary-password, #secretary-password-confirm').removeClass('required'); $('#secretary-password, #secretary-password-confirm').removeClass('required');
$('#secretary-notifications').prop('disabled', false); $('#secretary-notifications').prop('disabled', false);
@ -82,11 +95,11 @@ SecretariesHelper.prototype.bindEventHandlers = function() {
* Event: Delete Secretary Button "Click" * Event: Delete Secretary Button "Click"
*/ */
$('#delete-secretary').click(function() { $('#delete-secretary').click(function() {
var providerId = $('#secretary-id').val(); var secretaryId = $('#secretary-id').val();
var messageBtns = { var messageBtns = {
'Delete': function() { 'Delete': function() {
BackendUsers.helper.delete(providerId); BackendUsers.helper.delete(secretaryId);
$('#message_box').dialog('close'); $('#message_box').dialog('close');
}, },
'Cancel': function() { 'Cancel': function() {
@ -148,7 +161,11 @@ SecretariesHelper.prototype.bindEventHandlers = function() {
* Cancel add or edit of an secretary record. * Cancel add or edit of an secretary record.
*/ */
$('#cancel-secretary').click(function() { $('#cancel-secretary').click(function() {
var id = $('#secretary-id').val();
BackendUsers.helper.resetForm(); BackendUsers.helper.resetForm();
if (id != '') {
BackendUsers.helper.select(id, true);
}
}); });
}; };
@ -173,7 +190,8 @@ SecretariesHelper.prototype.save = function(secretary) {
if (!GeneralFunctions.handleAjaxExceptions(response)) return; if (!GeneralFunctions.handleAjaxExceptions(response)) return;
Backend.displayNotification('Secretary saved successfully!'); Backend.displayNotification('Secretary saved successfully!');
BackendUsers.helper.resetForm(); BackendUsers.helper.resetForm();
BackendUsers.helper.filter($('#secretaries .filter-key').val()); $('#filter-secretaries .key').val('');
BackendUsers.helper.filter('', response.id, true);
}, 'json'); }, 'json');
}; };
@ -193,7 +211,7 @@ SecretariesHelper.prototype.delete = function(id) {
if (!GeneralFunctions.handleAjaxExceptions(response)) return; if (!GeneralFunctions.handleAjaxExceptions(response)) return;
Backend.displayNotification('Secretary deleted successfully!'); Backend.displayNotification('Secretary deleted successfully!');
BackendUsers.helper.resetForm(); BackendUsers.helper.resetForm();
BackendUsers.helper.filter($('#secretaries .filter-key').val()); BackendUsers.helper.filter($('#filter-secretaries .key').val());
}); });
}; };
@ -256,8 +274,6 @@ SecretariesHelper.prototype.resetForm = function() {
$('#secretaries .save-cancel-group').hide(); $('#secretaries .save-cancel-group').hide();
$('#edit-secretary, #delete-secretary').prop('disabled', true); $('#edit-secretary, #delete-secretary').prop('disabled', true);
$('#secretaries .details').find('input, textarea').prop('readonly', true); $('#secretaries .details').find('input, textarea').prop('readonly', true);
$('.filter-secretaries').prop('disabled', false);
$('#secretaries .filter-results').css('color', '');
$('#secretaries .form-message').hide(); $('#secretaries .form-message').hide();
$('#secretary-notifications').removeClass('active'); $('#secretary-notifications').removeClass('active');
$('#secretary-notifications').prop('disabled', true); $('#secretary-notifications').prop('disabled', true);
@ -265,6 +281,10 @@ SecretariesHelper.prototype.resetForm = function() {
$('#secretary-providers input[type="checkbox"]').prop('disabled', true); $('#secretary-providers input[type="checkbox"]').prop('disabled', true);
$('#secretaries .required').css('border', ''); $('#secretaries .required').css('border', '');
$('#secretary-password, #secretary-password-confirm').css('border', ''); $('#secretary-password, #secretary-password-confirm').css('border', '');
$('#filter-secretaries .selected-row').removeClass('selected-row');
$('#filter-secretaries button').prop('disabled', false);
$('#filter-secretaries .results').css('color', '');
}; };
/** /**
@ -306,10 +326,13 @@ SecretariesHelper.prototype.display = function(secretary) {
* Filters secretary records depending a string key. * Filters secretary records depending a string key.
* *
* @param {string} key This is used to filter the secretary records of the database. * @param {string} key This is used to filter the secretary records of the database.
* @param {numeric} selectRecordId (OPTIONAL) If provided then the given id will be * @param {numeric} selectId (OPTIONAL = undefined) If provided then the given id will be
* selected in the filter results (only selected, not displayed). * selected in the filter results (only selected, not displayed).
* @param {bool} display (OPTIONAL = false)
*/ */
SecretariesHelper.prototype.filter = function(key, selectRecordId) { SecretariesHelper.prototype.filter = function(key, selectId, display) {
if (display == undefined) display = false;
var postUrl = GlobalVariables.baseUrl + 'backend_api/ajax_filter_secretaries'; var postUrl = GlobalVariables.baseUrl + 'backend_api/ajax_filter_secretaries';
var postData = { 'key': key }; var postData = { 'key': key };
@ -322,19 +345,18 @@ SecretariesHelper.prototype.filter = function(key, selectRecordId) {
BackendUsers.helper.filterResults = response; BackendUsers.helper.filterResults = response;
$('#secretaries .filter-results').html(''); $('#filter-secretaries .results').html('');
$.each(response, function(index, secretary) { $.each(response, function(index, secretary) {
var html = SecretariesHelper.prototype.getFilterHtml(secretary); var html = SecretariesHelper.prototype.getFilterHtml(secretary);
$('#secretaries .filter-results').append(html); $('#filter-secretaries .results').append(html);
}); });
if (selectRecordId != undefined) { if (response.length == 0) {
$('.secretary-row').each(function() { $('#filter-secretaries .results').html('<em>No results found ...</em>')
if ($(this).attr('data-id') == selectRecordId) {
$(this).addClass('selected-row');
return false;
} }
});
if (selectId != undefined) {
BackendUsers.helper.select(selectId, display);
} }
}, 'json'); }, 'json');
}; };
@ -354,3 +376,37 @@ SecretariesHelper.prototype.getFilterHtml = function(secretary) {
return html; return html;
}; };
/**
* Select a specific record from the current filter results. If the secretary id does not exist
* in the list then no record will be selected.
*
* @param {numeric} id The record id to be selected from the filter results.
* @param {bool} display (OPTIONAL = false) If true then the method will display the record
* on the form.
*
* @task The selected row must always be visible (even if a vertical scroll bar is used to
* navigate through the filter results).
*/
SecretariesHelper.prototype.select = function(id, display) {
if (display == undefined) display = false;
$('#filter-secretaries .selected-row').removeClass('selected-row');
$('#filter-secretaries .secretary-row').each(function() {
if ($(this).attr('data-id') == id) {
$(this).addClass('selected-row');
return false;
}
});
if (display) {
$.each(BackendUsers.helper.filterResults, function(index, admin) {
if (admin.id == id) {
BackendUsers.helper.display(admin);
$('#edit-secretary, #delete-secretary').prop('disabled', false);
return false;
}
});
}
};

View file

@ -483,7 +483,7 @@ var FrontendBook = {
$.each(GlobalVariables.availableServices, function(index, service) { $.each(GlobalVariables.availableServices, function(index, service) {
if (service.id == $('#select-service').val()) { if (service.id == $('#select-service').val()) {
selServiceDuration = service.duration; selServiceDuration = service.duration;
return; // Stop searching ... return false; // Stop searching ...
} }
}); });

View file

@ -0,0 +1,313 @@
/**
* Contains the working plan functionality. The working plan DOM elements must be same
* in every page this class is used.
*
* @class WorkingPlan
*/
var WorkingPlan = function() {
/**
* This flag is used when trying to cancel row editing. It is
* true only whenever the user presses the cancel button.
*
* @type {bool}
*/
this.enableCancel = false;
/**
* This flag determines whether the jeditables are allowed to submit. It is
* true only whenever the user presses the save button.
*
* @type {bool}
*/
this.enableSubmit = false;
};
/**
* Setup the dom elements of a given working plan.
*
* @param {object} workingPlan Contains the working hours and breaks for each day of the week.
*/
WorkingPlan.prototype.setup = function(workingPlan) {
$.each(workingPlan, function(index, workingDay) {
if (workingDay != null) {
$('#' + index).prop('checked', true);
$('#' + index + '-start').val(workingDay.start);
$('#' + index + '-end').val(workingDay.end);
// Add the day's breaks on the breaks table.
$.each(workingDay.breaks, function(i, brk) {
var tr =
'<tr>' +
'<td class="break-day editable">' + GeneralFunctions.ucaseFirstLetter(index) + '</td>' +
'<td class="break-start editable">' + brk.start + '</td>' +
'<td class="break-end editable">' + brk.end + '</td>' +
'<td>' +
'<button type="button" class="btn edit-break" title="Edit Break">' +
'<i class="icon-pencil"></i>' +
'</button>' +
'<button type="button" class="btn delete-break" title="Delete Break">' +
'<i class="icon-remove"></i>' +
'</button>' +
'<button type="button" class="btn save-break hidden" title="Save Break">' +
'<i class="icon-ok"></i>' +
'</button>' +
'<button type="button" class="btn cancel-break hidden" title="Cancel Break">' +
'<i class="icon-ban-circle"></i>' +
'</button>' +
'</td>' +
'</tr>';
$('.breaks').append(tr);
});
} else {
$('#' + index).prop('checked', false);
$('#' + index + '-start').prop('disabled', true);
$('#' + index + '-end').prop('disabled', true);
}
});
// Make break cells editable.
WorkingPlan.prototype.editableBreakDay($('.breaks .break-day'));
WorkingPlan.prototype.editableBreakTime($('.breaks').find('.break-start, .break-end'));
};
/**
* This method makes editable the break day cells.
*
* @param {object} $selector The jquery selector ready for use.
*/
WorkingPlan.prototype.editableBreakDay = function($selector) {
$selector.editable(function(value, settings) {
return value;
}, {
'type': 'select',
'data': '{ "Monday": "Monday", "Tuesday": "Tuesday", "Wednesday": "Wednesday", '
+ '"Thursday": "Thursday", "Friday": "Friday", "Saturday": "Saturday", '
+ '"Sunday": "Sunday", "selected": "Monday"}',
'event': 'edit',
'height': '30px',
'submit': '<button type="button" class="hidden submit-editable">Submit</button>',
'cancel': '<button type="button" class="hidden cancel-editable">Cancel</button>',
'onblur': 'ignore',
'onreset': function(settings, td) {
if (!WorkingPlan.prototype.enableCancel) return false; // disable ESC button
},
'onsubmit': function(settings, td) {
if (!WorkingPlan.prototype.enableSubmit) return false; // disable Enter button
}
});
};
/**
* This method makes editable the break time cells.
*
* @param {object} $selector The jquery selector ready for use.
*/
WorkingPlan.prototype.editableBreakTime = function($selector) {
$selector.editable(function(value, settings) {
// Do not return the value because the user needs to press the "Save" button.
return value;
}, {
'event': 'edit',
'height': '25px',
'submit': '<button type="button" class="hidden submit-editable">Submit</button>',
'cancel': '<button type="button" class="hidden cancel-editable">Cancel</button>',
'onblur': 'ignore',
'onreset': function(settings, td) {
if (!WorkingPlan.prototype.enableCancel) return false; // disable ESC button
},
'onsubmit': function(settings, td) {
if (!WorkingPlan.prototype.enableSubmit) return false; // disable Enter button
}
});
};
/**
* Binds the event handlers for the working plan dom elements.
*/
WorkingPlan.prototype.bindEventHandlers = function() {
/**
* Event: Day Checkbox "Click"
*
* Enable or disable the time selection for each day.
*/
$('.working-plan input[type="checkbox"]').click(function() {
var id = $(this).attr('id');
if ($(this).prop('checked') == true) {
$('#' + id + '-start').prop('disabled', false).val('09:00');
$('#' + id + '-end').prop('disabled', false).val('18:00');
} else {
$('#' + id + '-start').prop('disabled', true).val('');
$('#' + id + '-end').prop('disabled', true).val('');
}
});
/**
* Event: Add Break Button "Click"
*
* A new row is added on the table and the user can enter the new break
* data. After that he can either press the save or cancel button.
*/
$('.add-break').click(function() {
var tr =
'<tr>' +
'<td class="break-day editable">Monday</td>' +
'<td class="break-start editable">09:00</td>' +
'<td class="break-end editable">10:00</td>' +
'<td>' +
'<button type="button" class="btn edit-break" title="Edit Break">' +
'<i class="icon-pencil"></i>' +
'</button>' +
'<button type="button" class="btn delete-break" title="Delete Break">' +
'<i class="icon-remove"></i>' +
'</button>' +
'<button type="button" class="btn save-break hidden" title="Save Break">' +
'<i class="icon-ok"></i>' +
'</button>' +
'<button type="button" class="btn cancel-break hidden" title="Cancel Break">' +
'<i class="icon-ban-circle"></i>' +
'</button>' +
'</td>' +
'</tr>';
$('.breaks').prepend(tr);
// Bind editable and event handlers.
tr = $('.breaks tr').get()[1];
BackendSettings.editableBreakDay($(tr).find('.break-day'));
BackendSettings.editableBreakTime($(tr).find('.break-start, .break-end'));
$(tr).find('.edit-break').trigger('click');
});
/**
* Event: Edit Break Button "Click"
*
* Enables the row editing for the "Breaks" table rows.
*/
$(document).on('click', '.edit-break', function() {
// Reset previous editable tds
var $previousEdt = $(this).closest('table').find('.editable').get();
$.each($previousEdt, function(index, edt) {
edt.reset();
});
// Make all cells in current row editable.
$(this).parent().parent().children().trigger('edit');
$(this).parent().parent().find('.break-start input, .break-end input').timepicker();
$(this).parent().parent().find('.break-day select').focus();
// Show save - cancel buttons.
$(this).closest('table').find('.edit-break, .delete-break').addClass('hidden');
$(this).parent().find('.save-break, .cancel-break').removeClass('hidden');
});
/**
* Event: Delete Break Button "Click"
*
* Removes the current line from the "Breaks" table.
*/
$(document).on('click', '.delete-break', function() {
$(this).parent().parent().remove();
});
/**
* Event: Cancel Break Button "Click"
*
* Bring the ".breaks" table back to its initial state.
*/
$(document).on('click', '.cancel-break', function() {
WorkingPlan.prototype.enableCancel = true;
$(this).parent().parent().find('.cancel-editable').trigger('click');
WorkingPlan.prototype.enableCancel = false;
$(this).closest('table').find('.edit-break, .delete-break').removeClass('hidden');
$(this).parent().find('.save-break, .cancel-break').addClass('hidden');
});
/**
* Event: Save Break Button "Click"
*
* Save the editable values and restore the table to its initial state.
*/
$(document).on('click', '.save-break', function() {
// Break's start time must always be prior to break's end.
var start = Date.parse($(this).parent().parent().find('.break-start input').val());
var end = Date.parse($(this).parent().parent().find('.break-end input').val());
if (start > end) {
$(this).parent().parent().find('.break-end input').val(start.addHours(1).toString('HH:mm'));
}
WorkingPlan.prototype.enableSubmit = true;
$(this).parent().parent().find('.editable .submit-editable').trigger('click');
WorkingPlan.prototype.enableSubmit = false;
$(this).closest('table').find('.edit-break, .delete-break').removeClass('hidden');
$(this).parent().find('.save-break, .cancel-break').addClass('hidden');
});
};
/**
* Get the working plan settings.
*
* @returns {object} Returns the working plan settings object.
*/
WorkingPlan.prototype.get = function() {
var workingPlan = {};
$('.working-plan input[type="checkbox"').each(function() {
var id = $(this).attr('id');
if ($(this).prop('checked') == true) {
workingPlan[id] = {}
workingPlan[id].start = $('#' + id + '-start').val();
workingPlan[id].end = $('#' + id + '-end').val();
workingPlan[id].breaks = [];
$('.breaks tr').each(function(index, tr) {
var day = $(tr).find('.break-day').text().toLowerCase();
if (day == id) {
var start = $(tr).find('.break-start').text();
var end = $(tr).find('.break-end').text();
workingPlan[id].breaks.push({
'start': start,
'end': end
});
}
});
} else {
workingPlan[id] = null;
}
});
return workingPlan;
};
/**
* Enables or disabled the timepicker functionality from the working plan input
* text fields.
*
* @param {bool} disabled (OPTIONAL = false) If true then the timepickers will be
* disabled.
*/
WorkingPlan.prototype.timepickers = function(disabled) {
if (disabled == undefined) disabled == false;
if (disabled == false) {
// Set timepickers where needed.
$('.working-plan input').timepicker({
'timeFormat': 'HH:mm',
'onSelect': function(datetime, inst) {
// Start time must be earlier than end time.
var start = Date.parse($(this).parent().parent().find('.work-start').val());
var end = Date.parse($(this).parent().parent().find('.work-end').val());
if (start > end) {
$(this).parent().parent().find('.work-end').val(start.addHours(1).toString('HH:mm'));
}
}
});
} else {
$('.working-plan input').timepicker('destroy');
}
};