- Τροποποιήσεις στα αρχεία και την δομή του κώδικα

- Υλοποίηση της πρώτης σελίδας του backend της εφαρμογής.
This commit is contained in:
alextselegidis@gmail.com 2013-06-12 15:31:16 +00:00
parent fcf58a7cf2
commit 6369da0893
20 changed files with 1155 additions and 65 deletions

View file

@ -102,16 +102,18 @@ class Appointments extends CI_Controller {
// Synchronize the appointment with the providers plan, if the // Synchronize the appointment with the providers plan, if the
// google sync option is enabled. // google sync option is enabled.
$this->load->library('google_sync');
$google_sync = $this->Providers_Model->get_setting('google_sync', $google_sync = $this->Providers_Model->get_setting('google_sync',
$appointment_data['id_users_provider']); $appointment_data['id_users_provider']);
if ($google_sync == TRUE) { if ($google_sync == TRUE) {
$google_token = $this->Providers_Model->get_setting('google_token', $google_token = $this->Providers_Model->get_setting('google_token',
$appointment_data['id_users_provider']); $appointment_data['id_users_provider']);
// Validate the token. If it isn't valid, the sync operation cannot
// Authenticate the token. If it isn't valid, the sync operation cannot
// be completed. // be completed.
if ($this->google_sync->validate_token($google_token) === TRUE) { $this->load->library('google_sync');
if ($this->google_sync->authenticate($google_token) === TRUE) {
if ($manage_mode === FALSE) { if ($manage_mode === FALSE) {
// Add appointment to Google Calendar. // Add appointment to Google Calendar.
$this->google_sync->add_appointment($appointment_data['id']); $this->google_sync->add_appointment($appointment_data['id']);
@ -122,7 +124,7 @@ class Appointments extends CI_Controller {
} }
} }
// Load the book appointment view. // Load the book success view.
$service_data = $this->Services_Model->get_row($appointment_data['id_services']); $service_data = $this->Services_Model->get_row($appointment_data['id_services']);
$provider_data = $this->Providers_Model->get_row($appointment_data['id_users_provider']); $provider_data = $this->Providers_Model->get_row($appointment_data['id_users_provider']);
$company_name = $this->Settings_Model->get_setting('company_name'); $company_name = $this->Settings_Model->get_setting('company_name');
@ -180,10 +182,22 @@ class Appointments extends CI_Controller {
// Delete the appointment from Google Calendar, if it is synced. // Delete the appointment from Google Calendar, if it is synced.
if ($appointment_data['id_google_calendar'] != NULL) { if ($appointment_data['id_google_calendar'] != NULL) {
$this->load->library('google_sync'); $google_sync = $this->Providers_Model->get_setting('google_sync',
$this->google_sync->delete_appointment($appointment_data['id']); $appointment_data['id_users_provider']);
if ($google_sync == TRUE) {
$this->load->library('google_sync');
// Get the provider's refresh token and try to authenticate the
// Google Calendar API usage.
$google_token = $this->Providers_Model->get_setting('google_token',
$appointment_data['id_users_provider']);
if ($this->google_sync->authendicate($google_token) === TRUE) {
$this->google_sync->delete_appointment($appointment_data['id']);
}
}
} }
} catch(Exception $exc) { } catch(Exception $exc) {
// Display the error message to the customer. // Display the error message to the customer.
$view_data['error_message'] = $exc->getMessage(); $view_data['error_message'] = $exc->getMessage();

View file

@ -0,0 +1,48 @@
<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed');
class Backend extends CI_Controller {
/**
* Display the main backend page.
*
* This method displays the main backend page. All users login permission can
* view this page which displays a calendar with the events of the selected
* provider or service. If a user has more priviledges he will see more menus
* at the top of the page.
*/
public function index() {
// @task Require user to be logged in the application.
$this->load->model('Providers_Model');
$this->load->model('Services_Model');
$this->load->model('Settings_Model');
// Display the main backend page.
$view_data['base_url'] = $this->config->item('base_url');
$view_data['company_name'] = $this->Settings_Model->get_setting('company_name');
$view_data['available_providers'] = $this->Providers_Model->get_available_providers();
$view_data['available_services'] = $this->Services_Model->get_available_services();
$this->load->view('backend/header', $view_data);
$this->load->view('backend/calendar', $view_data);
$this->load->view('backend/footer', $view_data);
}
public function customers() {
}
public function services() {
}
public function providers() {
}
public function settings() {
}
}
/* End of file backend.php */
/* Location: ./application/controllers/backend.php */

View file

@ -37,22 +37,21 @@ class Google_Sync {
} }
/** /**
* Validate the Google API access token of a provider. * Authenticate the Google API usage.
* *
* In order to manage a Google user's data, one need a valid access token. * This method must be executed every time we need to make actions on a
* This token is provided when the user grants the permission to a system * provider's Google Calendar account. A new token is necessary and the
* to access his Google account data. So before making any action we need * only way to get it is to use the stored refresh token that was provided
* to make sure that the available token is still valid. * when the provider granted consent to Easy!Appointments for use his
* Google Calendar account.
* *
* <strong>IMPORTANT!</strong> Always use this method before anything else * @param string $refresh_token The provider's refresh token. This value is
* in order to make sure that the token is being set and still valid. * stored in the database and used every time we need to make actions to his
* * Google Caledar account.
* @param string $access_token This token is normally stored in the database. * @return bool Returns the authenticate operation result.
* @return bool Returns the validation result.
*/ */
public function validate_token($access_token) { public function authenticate($refresh_token) {
$this->client->setAccessToken($access_token);
return $this->client->isAccessTokenExpired();
} }
/** /**

View file

@ -26,7 +26,7 @@
<link <link
rel="stylesheet" rel="stylesheet"
type="text/css" type="text/css"
href="<?php echo $this->config->base_url(); ?>assets/css/style.css"> href="<?php echo $this->config->base_url(); ?>assets/css/frontend.css">
<?php <?php
// ------------------------------------------------------------ // ------------------------------------------------------------
@ -34,32 +34,25 @@
// ------------------------------------------------------------ ?> // ------------------------------------------------------------ ?>
<script <script
type="text/javascript" type="text/javascript"
src="<?php echo $this->config->base_url(); ?>assets/js/libs/jquery/jquery.min.js"> src="<?php echo $this->config->base_url(); ?>assets/js/libs/jquery/jquery.min.js"></script>
</script>
<script <script
type="text/javascript" type="text/javascript"
src="<?php echo $this->config->base_url(); ?>assets/js/libs/jquery/jquery-ui.min.js"> src="<?php echo $this->config->base_url(); ?>assets/js/libs/jquery/jquery-ui.min.js"></script>
</script>
<script <script
type="text/javascript" type="text/javascript"
src="<?php echo $this->config->base_url(); ?>assets/js/libs/jquery/jquery.qtip.min.js"> src="<?php echo $this->config->base_url(); ?>assets/js/libs/jquery/jquery.qtip.min.js"></script>
</script>
<script <script
type="text/javascript" type="text/javascript"
src="<?php echo $this->config->base_url(); ?>assets/js/libs/bootstrap/bootstrap.min.js"> src="<?php echo $this->config->base_url(); ?>assets/js/libs/bootstrap/bootstrap.min.js"></script>
</script>
<script <script
type="text/javascript" type="text/javascript"
src="<?php echo $this->config->base_url(); ?>assets/js/libs/date.js"> src="<?php echo $this->config->base_url(); ?>assets/js/libs/date.js"></script>
</script>
<script <script
type="text/javascript" type="text/javascript"
src="<?php echo $this->config->base_url(); ?>assets/js/frontend/book_appointment.js"> src="<?php echo $this->config->base_url(); ?>assets/js/frontend_book.js"></script>
</script>
<script <script
type="text/javascript" type="text/javascript"
src="<?php echo $this->config->base_url(); ?>assets/js/general_functions.js"> src="<?php echo $this->config->base_url(); ?>assets/js/general_functions.js"></script>
</script>
<?php <?php
// ------------------------------------------------------------ // ------------------------------------------------------------
@ -86,7 +79,7 @@
}; };
$(document).ready(function() { $(document).ready(function() {
bookAppointment.initialize(true, GlobalVariables.manageMode); FrontendBook.initialize(true, GlobalVariables.manageMode);
GeneralFunctions.centerElementOnPage($('#book-appointment-wizard')); GeneralFunctions.centerElementOnPage($('#book-appointment-wizard'));
}); });
</script> </script>

View file

@ -149,16 +149,16 @@
'Your appointment has successfully been added to ' + 'Your appointment has successfully been added to ' +
'your Google Calendar account. <br>' + 'your Google Calendar account. <br>' +
'<a href="' + response.htmlLink + '">' + '<a href="' + response.htmlLink + '">' +
'Appointment Link' + 'Click here to view your appoinmtent on Google ' +
'Calendar.' +
'</a>' + '</a>' +
'</p>' + '</p>' +
'</div>' '</div>'
); );
$('#add-to-google-calendar').hide();
} else { } else {
throw 'Could not add the event to Google Calendar.'; throw 'Could not add the event to Google Calendar.';
} }
}); });
}); });
} catch(exc) { } catch(exc) {

View file

@ -6,8 +6,7 @@
<?php // INCLUDE JS FILES ?> <?php // INCLUDE JS FILES ?>
<script <script
type="text/javascript" type="text/javascript"
src="<?php echo $this->config->base_url(); ?>assets/js/libs/jquery/jquery.min.js"> src="<?php echo $this->config->base_url(); ?>assets/js/libs/jquery/jquery.min.js"></script>
</script>
<?php // INCLUDE CSS FILES ?> <?php // INCLUDE CSS FILES ?>
<link <link

View file

@ -0,0 +1,46 @@
<link rel="stylesheet" type="text/css"
href="<?php echo $base_url; ?>assets/css/libs/jquery/fullcalendar.css" />
<script type="text/javascript"
src="<?php echo $base_url; ?>assets/js/libs/jquery/fullcalendar.min.js"></script>
<script type="text/javascript"
src="<?php echo $base_url; ?>assets/js/backend_calendar.js"></script>
<script type="text/javascript">
var GlobalVariables = {
'availableProviders' : <?php echo json_encode($available_providers); ?>,
'availableServices' : <?php echo json_encode($available_services); ?>,
'baseUrl' : <?php echo '"' . $base_url . '"'; ?>
};
$(document).ready(function() {
BackendCalendar.initialize(true);
});
</script>
<div id="calendar-page">
<div id="calendar-toolbar">
<div id="calendar-filter">
<label for="select-provider">Provider Calendar</label>
<select id="select-provider"></select>
<br>
<label for="select-service">Service Calendar</label>
<select id="select-service"></select>
</div>
<div id="calendar-actions">
<button id="google-sync" class="btn btn-danger btn-large">
<i class="icon-refresh icon-white"></i>
Synchronize
</button>
<button id="enable-sync" class="btn btn-primary btn-large">
<i class="icon-calendar icon-white"></i>
Enable Sync
</button>
</div>
</div>
<div id="calendar"></div>
</div>

View file

@ -0,0 +1,10 @@
<div id="footer">
<div id="footer-content">
Powered by <a href="">Easy!Appointments</a> |
Copyright &copy; <?php echo date('Y'); ?>
<a href="http://www.alextselegidis.com">Alex Tselegidis</a> |
Licensed Under GPLv3
</div>
</div>
</body>
</html>

View file

@ -0,0 +1,106 @@
<!DOCTYPE html>
<html lang="en">
<head>
<title>Easy!Appointments Admin</title>
<meta http-equiv="content-type" content="text/html; charset=UTF-8">
<link rel="icon" type="image/x-icon"
href="<?php echo $base_url; ?>assets/images/favicon.ico">
<?php
// ------------------------------------------------------------
// INCLUDE CSS FILES
// ------------------------------------------------------------ ?>
<link
rel="stylesheet"
type="text/css"
href="<?php echo $base_url; ?>assets/css/libs/bootstrap/bootstrap.css">
<link
rel="stylesheet"
type="text/css"
href="<?php echo $base_url; ?>assets/css/libs/bootstrap/bootstrap-responsive.css">
<link
rel="stylesheet"
type="text/css"
href="<?php echo $base_url; ?>assets/css/libs/jquery/jquery-ui.min.css">
<link
rel="stylesheet"
type="text/css"
href="<?php echo $base_url; ?>assets/css/libs/jquery/jquery.qtip.min.css">
<link
rel="stylesheet"
type="text/css"
href="<?php echo $base_url; ?>assets/css/backend.css">
<?php
// ------------------------------------------------------------
// INCLUDE JAVASCRIPT FILES
// ------------------------------------------------------------ ?>
<script
type="text/javascript"
src="<?php echo $base_url; ?>assets/js/libs/jquery/jquery.min.js"></script>
<script
type="text/javascript"
src="<?php echo $base_url; ?>assets/js/libs/jquery/jquery-ui.min.js"></script>
<script
type="text/javascript"
src="<?php echo $base_url; ?>assets/js/libs/jquery/jquery.qtip.min.js"></script>
<script
type="text/javascript"
src="<?php echo $base_url; ?>assets/js/libs/bootstrap/bootstrap.min.js"></script>
<script
type="text/javascript"
src="<?php echo $base_url; ?>assets/js/libs/date.js"></script>
<script
type="text/javascript"
src="<?php echo $base_url; ?>assets/js/general_functions.js"></script>
<script
type="text/javascript"
src="<?php echo $base_url; ?>assets/js/backend.js"></script>
</head>
<body>
<div id="header">
<div id="header-logo">
<img src="<?php echo $base_url; ?>assets/images/logo.png">
<span><?php echo $company_name; ?></span>
</div>
<div id="header-menu">
<?php // CALENDAR MENU ITEM
// ------------------------------------------------------ ?>
<a href="<?php echo $base_url; ?>backend/calendar" class="menu-item">
Calendar
</a>
<?php // CUSTOMERS MENU ITEM
// ------------------------------------------------------ ?>
<a href="<?php echo $base_url; ?>backend/customers" class="menu-item">
Customers
</a>
<?php // SERVICES MENU ITEM
// ------------------------------------------------------ ?>
<a href="<?php echo $base_url; ?>backend/services" class="menu-item">
Services
</a>
<?php // PROVIDERS MENU ITEM
// ------------------------------------------------------ ?>
<a href="<?php echo $base_url; ?>backend/providers" class="menu-item">
Providers
</a>
<?php // SETTINGS MENU ITEM
// ------------------------------------------------------ ?>
<a href="<?php echo $base_url; ?>backend/settings" class="menu-item">
Settings
</a>
<?php // LOGOUT MENU ITEM
// ------------------------------------------------------ ?>
<a href="<?php echo $base_url; ?>backend/logout" class="menu-item">
Logout
</a>
</div>
</div>

View file

@ -0,0 +1,57 @@
/**
* BACKEND CSS FILE FOR EASY!APPOINTMENTS
*/
root {
display: block;
}
/* BACKEND GENERAL ELEMENTS
-------------------------------------------------------------------- */
#header {
height: 70px;
background-color: #35B66F;
border-bottom: 6px solid #247A4B;
}
#header #header-logo { display: inline-block; height: 60px; margin: 10px 15px 0px 15px; }
#header #header-logo img { float: left; width: 50px; height: 50px; margin-right: 6px; }
#header #header-logo span { float: left; font-size: 20px; color: white; margin-top: 16px; }
#header #header-menu { display: inline-block; float: right; height: 100%; }
#header #header-menu .menu-item { float: left; margin-right: 8px; margin-top: 10px;
padding: 15px 12px; min-width: 68px; text-align: center;
font-weight: bold; color: #FFF; text-decoration: none;
font-size: 16px; }
#header #header-menu .menu-item:hover { background-color: #247A4B; }
#footer {
background-color: #F7F7F7;
border-top: 1px solid #DDD;
}
#footer #footer-content { padding: 15px; }
/* BACKEND CALENDAR PAGE
-------------------------------------------------------------------- */
#calendar-page #calendar-toolbar { margin: 15px 10px 20px 10px; padding-bottom: 10px;
overflow: auto; border-bottom: 1px solid #D6D6D6; }
#calendar-page #calendar-filter { display: inline-block; float: left; }
#calendar-page #calendar-filter label { display: inline-block; margin-right: 7px;
font-weight: bold; font-size: 18px; width: 180px; }
#calendar-page #calendar-filter select { margin-top: 5px; }
#calendar-page #calendar-actions { display: inline-block; float: right; margin-top: 16px; }
#calendar-page #calendar { margin: 12px; }
/* BACKEND CUSTOMERS PAGE
-------------------------------------------------------------------- */
/* BACKEND SERVICES PAGE
-------------------------------------------------------------------- */
/* BACKEND PROVIDERS PAGE
-------------------------------------------------------------------- */
/* BACKEND SETTINGS PAGE
-------------------------------------------------------------------- */

View file

@ -0,0 +1,579 @@
/*!
* FullCalendar v1.6.1 Stylesheet
* Docs & License: http://arshaw.com/fullcalendar/
* (c) 2013 Adam Shaw
*/
.fc {
direction: ltr;
text-align: left;
}
.fc table {
border-collapse: collapse;
border-spacing: 0;
}
html .fc,
.fc table {
font-size: 1em;
}
.fc td,
.fc th {
padding: 0;
vertical-align: top;
}
/* Header
------------------------------------------------------------------------*/
.fc-header td {
white-space: nowrap;
}
.fc-header-left {
width: 25%;
text-align: left;
}
.fc-header-center {
text-align: center;
}
.fc-header-right {
width: 25%;
text-align: right;
}
.fc-header-title {
display: inline-block;
vertical-align: top;
}
.fc-header-title h2 {
margin-top: 0;
white-space: nowrap;
}
.fc .fc-header-space {
padding-left: 10px;
}
.fc-header .fc-button {
margin-bottom: 1em;
vertical-align: top;
}
/* buttons edges butting together */
.fc-header .fc-button {
margin-right: -1px;
}
.fc-header .fc-corner-right, /* non-theme */
.fc-header .ui-corner-right { /* theme */
margin-right: 0; /* back to normal */
}
/* button layering (for border precedence) */
.fc-header .fc-state-hover,
.fc-header .ui-state-hover {
z-index: 2;
}
.fc-header .fc-state-down {
z-index: 3;
}
.fc-header .fc-state-active,
.fc-header .ui-state-active {
z-index: 4;
}
/* Content
------------------------------------------------------------------------*/
.fc-content {
clear: both;
}
.fc-view {
width: 100%; /* needed for view switching (when view is absolute) */
overflow: hidden;
}
/* Cell Styles
------------------------------------------------------------------------*/
.fc-widget-header, /* <th>, usually */
.fc-widget-content { /* <td>, usually */
border: 1px solid #ddd;
}
.fc-state-highlight { /* <td> today cell */ /* TODO: add .fc-today to <th> */
background: #fcf8e3;
}
.fc-cell-overlay { /* semi-transparent rectangle while dragging */
background: #bce8f1;
opacity: .3;
filter: alpha(opacity=30); /* for IE */
}
/* Buttons
------------------------------------------------------------------------*/
.fc-button {
position: relative;
display: inline-block;
padding: 0 .6em;
overflow: hidden;
height: 1.9em;
line-height: 1.9em;
white-space: nowrap;
cursor: pointer;
}
.fc-state-default { /* non-theme */
border: 1px solid;
}
.fc-state-default.fc-corner-left { /* non-theme */
border-top-left-radius: 4px;
border-bottom-left-radius: 4px;
}
.fc-state-default.fc-corner-right { /* non-theme */
border-top-right-radius: 4px;
border-bottom-right-radius: 4px;
}
/*
Our default prev/next buttons use HTML entities like &lsaquo; &rsaquo; &laquo; &raquo;
and we'll try to make them look good cross-browser.
*/
.fc-text-arrow {
margin: 0 .1em;
font-size: 2em;
font-family: "Courier New", Courier, monospace;
vertical-align: baseline; /* for IE7 */
}
.fc-button-prev .fc-text-arrow,
.fc-button-next .fc-text-arrow { /* for &lsaquo; &rsaquo; */
font-weight: bold;
}
/* icon (for jquery ui) */
.fc-button .fc-icon-wrap {
position: relative;
float: left;
top: 50%;
}
.fc-button .ui-icon {
position: relative;
float: left;
margin-top: -50%;
*margin-top: 0;
*top: -50%;
}
/*
button states
borrowed from twitter bootstrap (http://twitter.github.com/bootstrap/)
*/
.fc-state-default {
background-color: #f5f5f5;
background-image: -moz-linear-gradient(top, #ffffff, #e6e6e6);
background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#ffffff), to(#e6e6e6));
background-image: -webkit-linear-gradient(top, #ffffff, #e6e6e6);
background-image: -o-linear-gradient(top, #ffffff, #e6e6e6);
background-image: linear-gradient(to bottom, #ffffff, #e6e6e6);
background-repeat: repeat-x;
border-color: #e6e6e6 #e6e6e6 #bfbfbf;
border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);
color: #333;
text-shadow: 0 1px 1px rgba(255, 255, 255, 0.75);
box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05);
}
.fc-state-hover,
.fc-state-down,
.fc-state-active,
.fc-state-disabled {
color: #333333;
background-color: #e6e6e6;
}
.fc-state-hover {
color: #333333;
text-decoration: none;
background-position: 0 -15px;
-webkit-transition: background-position 0.1s linear;
-moz-transition: background-position 0.1s linear;
-o-transition: background-position 0.1s linear;
transition: background-position 0.1s linear;
}
.fc-state-down,
.fc-state-active {
background-color: #cccccc;
background-image: none;
outline: 0;
box-shadow: inset 0 2px 4px rgba(0, 0, 0, 0.15), 0 1px 2px rgba(0, 0, 0, 0.05);
}
.fc-state-disabled {
cursor: default;
background-image: none;
opacity: 0.65;
filter: alpha(opacity=65);
box-shadow: none;
}
/* Global Event Styles
------------------------------------------------------------------------*/
.fc-event {
border: 1px solid #3a87ad; /* default BORDER color */
background-color: #3a87ad; /* default BACKGROUND color */
color: #fff; /* default TEXT color */
font-size: .85em;
cursor: default;
}
a.fc-event {
text-decoration: none;
}
a.fc-event,
.fc-event-draggable {
cursor: pointer;
}
.fc-rtl .fc-event {
text-align: right;
}
.fc-event-inner {
width: 100%;
height: 100%;
overflow: hidden;
}
.fc-event-time,
.fc-event-title {
padding: 0 1px;
}
.fc .ui-resizable-handle {
display: block;
position: absolute;
z-index: 99999;
overflow: hidden; /* hacky spaces (IE6/7) */
font-size: 300%; /* */
line-height: 50%; /* */
}
/* Horizontal Events
------------------------------------------------------------------------*/
.fc-event-hori {
border-width: 1px 0;
margin-bottom: 1px;
}
.fc-ltr .fc-event-hori.fc-event-start,
.fc-rtl .fc-event-hori.fc-event-end {
border-left-width: 1px;
border-top-left-radius: 3px;
border-bottom-left-radius: 3px;
}
.fc-ltr .fc-event-hori.fc-event-end,
.fc-rtl .fc-event-hori.fc-event-start {
border-right-width: 1px;
border-top-right-radius: 3px;
border-bottom-right-radius: 3px;
}
/* resizable */
.fc-event-hori .ui-resizable-e {
top: 0 !important; /* importants override pre jquery ui 1.7 styles */
right: -3px !important;
width: 7px !important;
height: 100% !important;
cursor: e-resize;
}
.fc-event-hori .ui-resizable-w {
top: 0 !important;
left: -3px !important;
width: 7px !important;
height: 100% !important;
cursor: w-resize;
}
.fc-event-hori .ui-resizable-handle {
_padding-bottom: 14px; /* IE6 had 0 height */
}
/* Reusable Separate-border Table
------------------------------------------------------------*/
table.fc-border-separate {
border-collapse: separate;
}
.fc-border-separate th,
.fc-border-separate td {
border-width: 1px 0 0 1px;
}
.fc-border-separate th.fc-last,
.fc-border-separate td.fc-last {
border-right-width: 1px;
}
.fc-border-separate tr.fc-last th,
.fc-border-separate tr.fc-last td {
border-bottom-width: 1px;
}
.fc-border-separate tbody tr.fc-first td,
.fc-border-separate tbody tr.fc-first th {
border-top-width: 0;
}
/* Month View, Basic Week View, Basic Day View
------------------------------------------------------------------------*/
.fc-grid th {
text-align: center;
}
.fc .fc-week-number {
width: 22px;
text-align: center;
}
.fc .fc-week-number div {
padding: 0 2px;
}
.fc-grid .fc-day-number {
float: right;
padding: 0 2px;
}
.fc-grid .fc-other-month .fc-day-number {
opacity: 0.3;
filter: alpha(opacity=30); /* for IE */
/* opacity with small font can sometimes look too faded
might want to set the 'color' property instead
making day-numbers bold also fixes the problem */
}
.fc-grid .fc-day-content {
clear: both;
padding: 2px 2px 1px; /* distance between events and day edges */
}
/* event styles */
.fc-grid .fc-event-time {
font-weight: bold;
}
/* right-to-left */
.fc-rtl .fc-grid .fc-day-number {
float: left;
}
.fc-rtl .fc-grid .fc-event-time {
float: right;
}
/* Agenda Week View, Agenda Day View
------------------------------------------------------------------------*/
.fc-agenda table {
border-collapse: separate;
}
.fc-agenda-days th {
text-align: center;
}
.fc-agenda .fc-agenda-axis {
width: 50px;
padding: 0 4px;
vertical-align: middle;
text-align: right;
white-space: nowrap;
font-weight: normal;
}
.fc-agenda .fc-week-number {
font-weight: bold;
}
.fc-agenda .fc-day-content {
padding: 2px 2px 1px;
}
/* make axis border take precedence */
.fc-agenda-days .fc-agenda-axis {
border-right-width: 1px;
}
.fc-agenda-days .fc-col0 {
border-left-width: 0;
}
/* all-day area */
.fc-agenda-allday th {
border-width: 0 1px;
}
.fc-agenda-allday .fc-day-content {
min-height: 34px; /* TODO: doesnt work well in quirksmode */
_height: 34px;
}
/* divider (between all-day and slots) */
.fc-agenda-divider-inner {
height: 2px;
overflow: hidden;
}
.fc-widget-header .fc-agenda-divider-inner {
background: #eee;
}
/* slot rows */
.fc-agenda-slots th {
border-width: 1px 1px 0;
}
.fc-agenda-slots td {
border-width: 1px 0 0;
background: none;
}
.fc-agenda-slots td div {
height: 20px;
}
.fc-agenda-slots tr.fc-slot0 th,
.fc-agenda-slots tr.fc-slot0 td {
border-top-width: 0;
}
.fc-agenda-slots tr.fc-minor th,
.fc-agenda-slots tr.fc-minor td {
border-top-style: dotted;
}
.fc-agenda-slots tr.fc-minor th.ui-widget-header {
*border-top-style: solid; /* doesn't work with background in IE6/7 */
}
/* Vertical Events
------------------------------------------------------------------------*/
.fc-event-vert {
border-width: 0 1px;
}
.fc-event-vert.fc-event-start {
border-top-width: 1px;
border-top-left-radius: 3px;
border-top-right-radius: 3px;
}
.fc-event-vert.fc-event-end {
border-bottom-width: 1px;
border-bottom-left-radius: 3px;
border-bottom-right-radius: 3px;
}
.fc-event-vert .fc-event-time {
white-space: nowrap;
font-size: 10px;
}
.fc-event-vert .fc-event-inner {
position: relative;
z-index: 2;
}
.fc-event-vert .fc-event-bg { /* makes the event lighter w/ a semi-transparent overlay */
position: absolute;
z-index: 1;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: #fff;
opacity: .25;
filter: alpha(opacity=25);
}
.fc .ui-draggable-dragging .fc-event-bg, /* TODO: something nicer like .fc-opacity */
.fc-select-helper .fc-event-bg {
display: none\9; /* for IE6/7/8. nested opacity filters while dragging don't work */
}
/* resizable */
.fc-event-vert .ui-resizable-s {
bottom: 0 !important; /* importants override pre jquery ui 1.7 styles */
width: 100% !important;
height: 8px !important;
overflow: hidden !important;
line-height: 8px !important;
font-size: 11px !important;
font-family: monospace;
text-align: center;
cursor: s-resize;
}
.fc-agenda .ui-resizable-resizing { /* TODO: better selector */
_overflow: hidden;
}

View file

@ -0,0 +1,32 @@
/*!
* FullCalendar v1.6.1 Print Stylesheet
* Docs & License: http://arshaw.com/fullcalendar/
* (c) 2013 Adam Shaw
*/
/*
* Include this stylesheet on your page to get a more printer-friendly calendar.
* When including this stylesheet, use the media='print' attribute of the <link> tag.
* Make sure to include this stylesheet IN ADDITION to the regular fullcalendar.css.
*/
/* Events
-----------------------------------------------------*/
.fc-event {
background: #fff !important;
color: #000 !important;
}
/* for vertical events */
.fc-event-bg {
display: none !important;
}
.fc-event .ui-resizable-handle {
display: none !important;
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 KiB

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 22 KiB

After

Width:  |  Height:  |  Size: 7 KiB

27
src/assets/js/backend.js Normal file
View file

@ -0,0 +1,27 @@
/**
* Main javascript code for the backend section of Easy!Appointments.
*/
$(document).ready(function() {
$(window).resize(function() {
placeFooterToBottom();
}).trigger('resize');
});
/**
* Place the backend footer always on the bottom of the page.
*/
function placeFooterToBottom() {
var footerHandle = $('#footer');
if (window.innerHeight > $('body').height()) {
footerHandle.css({
'position' : 'absolute',
'width' : '100%',
'bottom' : '0px'
});
} else {
footerHandle.css({
'position' : 'static'
});
}
}

View file

@ -0,0 +1,66 @@
/**
* This namespace contains functions that are used by the backend calendar page.
*
* @namespace Handles the backend calendar page functionality.
*/
var BackendCalendar = {
/**
* This function makes the necessary initialization for the default backend
* calendar page. If this namespace is used in another page then this function
* might not be needed.
*
* @param {bool} defaultEventHandlers (OPTIONAL = TRUE) Determines whether the
* default event handlers will be set for the current page.
*/
initialize: function(defaultEventHandlers) {
if (defaultEventHandlers === undefined) defaultEventHandlers = true;
// :: INITIALIZE THE DOM ELEMENTS OF THE PAGE
$('#calendar').fullCalendar({
defaultView : 'basicWeek',
height : BackendCalendar.getCalendarHeight(),
windowResize : function(view) {
$('#calendar').fullCalendar('option', 'height',
BackendCalendar.getCalendarHeight());
}
});
// :: FILL THE SELECT ELEMENTS OF THE PAGE
$.each(GlobalVariables.availableProviders, function(index, provider) {
var option = new Option(provider['first_name'] + ' '
+ provider['last_name'], provider['id']);
$('#select-provider').append(option);
});
$.each(GlobalVariables.availableServices, function(index, service) {
var option = new Option(service['name'], service['id']);
$('#select-service').append(option);
});
// :: BIND THE DEFAULT EVENT HANDLERS
if (defaultEventHandlers === true) {
BackendCalendar.bindEventHandlers();
}
},
/**
* This method binds the default event handlers for the backend calendar
* page. If you do not need the default handlers then initialize the page
* by setting the "defaultEventHandlers" argument to "false".
*/
bindEventHandlers: function() {
},
/**
* This method calculates the proper calendar height, in order to be displayed
* correctly, even when the browser window is resizing.
*
* @return {int} Returns the calendar element height in pixels.
*/
getCalendarHeight: function () {
var result = window.innerHeight - $('#footer').height() - $('#header').height()
- $('#calendar-toolbar').height() - 80; // 80 for fine tuning
return (result > 500) ? result : 500; // Minimum height is 500px
}
};

View file

@ -5,7 +5,7 @@
* *
* @class Implements the js part of the appointment booking page. * @class Implements the js part of the appointment booking page.
*/ */
var bookAppointment = { var FrontendBook = {
/** /**
* Determines the functionality of the page. * Determines the functionality of the page.
* *
@ -31,7 +31,7 @@ var bookAppointment = {
manageMode = false; // Default Value manageMode = false; // Default Value
} }
bookAppointment.manageMode = manageMode; FrontendBook.manageMode = manageMode;
// Initialize page's components (tooltips, datepickers etc). // Initialize page's components (tooltips, datepickers etc).
$('.book-step').qtip({ $('.book-step').qtip({
@ -49,21 +49,21 @@ var bookAppointment = {
minDate : 0, minDate : 0,
defaultDate : Date.today(), defaultDate : Date.today(),
onSelect : function(dateText, instance) { onSelect : function(dateText, instance) {
bookAppointment.getAvailableHours(dateText); FrontendBook.getAvailableHours(dateText);
bookAppointment.updateConfirmFrame(); FrontendBook.updateConfirmFrame();
} }
}); });
// Bind the event handlers (might not be necessary every time // Bind the event handlers (might not be necessary every time
// we use this class). // we use this class).
if (bindEventHandlers) { if (bindEventHandlers) {
bookAppointment.bindEventHandlers(); FrontendBook.bindEventHandlers();
} }
// If the manage mode is true, the appointments data should be // If the manage mode is true, the appointments data should be
// loaded by default. // loaded by default.
if (bookAppointment.manageMode) { if (FrontendBook.manageMode) {
bookAppointment.applyAppointmentData(GlobalVariables.appointmentData, FrontendBook.applyAppointmentData(GlobalVariables.appointmentData,
GlobalVariables.providerData, GlobalVariables.customerData); GlobalVariables.providerData, GlobalVariables.customerData);
} else { } else {
$('#select-service').trigger('change'); // Load the available hours. $('#select-service').trigger('change'); // Load the available hours.
@ -82,8 +82,8 @@ var bookAppointment = {
* date - time periods must be updated. * date - time periods must be updated.
*/ */
$('#select-provider').change(function() { $('#select-provider').change(function() {
bookAppointment.getAvailableHours(Date.today().toString('dd-MM-yyyy')); FrontendBook.getAvailableHours(Date.today().toString('dd-MM-yyyy'));
bookAppointment.updateConfirmFrame(); FrontendBook.updateConfirmFrame();
}); });
/** /**
@ -109,8 +109,8 @@ var bookAppointment = {
}); });
}); });
bookAppointment.getAvailableHours(Date.today().toString('dd-MM-yyyy')); FrontendBook.getAvailableHours(Date.today().toString('dd-MM-yyyy'));
bookAppointment.updateConfirmFrame(); FrontendBook.updateConfirmFrame();
}); });
/** /**
@ -138,10 +138,10 @@ var bookAppointment = {
// If we are on the 3rd tab then we will need to validate the user's // If we are on the 3rd tab then we will need to validate the user's
// input before proceeding to the next step. // input before proceeding to the next step.
if ($(this).attr('data-step_index') === '3') { if ($(this).attr('data-step_index') === '3') {
if (!bookAppointment.validateCustomerForm()) { if (!FrontendBook.validateCustomerForm()) {
return; // Validation failed, do not continue. return; // Validation failed, do not continue.
} else { } else {
bookAppointment.updateConfirmFrame(); FrontendBook.updateConfirmFrame();
} }
} }
@ -180,10 +180,10 @@ var bookAppointment = {
$('#available-hours').on('click', '.available-hour', function() { $('#available-hours').on('click', '.available-hour', function() {
$('.selected-hour').removeClass('selected-hour'); $('.selected-hour').removeClass('selected-hour');
$(this).addClass('selected-hour'); $(this).addClass('selected-hour');
bookAppointment.updateConfirmFrame(); FrontendBook.updateConfirmFrame();
}); });
if (bookAppointment.manageMode) { if (FrontendBook.manageMode) {
/** /**
* Event: Cancel Appointment Button "Click" * Event: Cancel Appointment Button "Click"
* *
@ -230,7 +230,7 @@ var bookAppointment = {
// If the manage mode is true then the appointment's start // If the manage mode is true then the appointment's start
// date should return as available too. // date should return as available too.
var appointmentId = (bookAppointment.manageMode) var appointmentId = (FrontendBook.manageMode)
? GlobalVariables.appointmentData['id'] : undefined; ? GlobalVariables.appointmentData['id'] : undefined;
var postData = { var postData = {
@ -238,7 +238,7 @@ var bookAppointment = {
'provider_id' : $('#select-provider').val(), 'provider_id' : $('#select-provider').val(),
'selected_date' : selDate, 'selected_date' : selDate,
'service_duration' : selServiceDuration, 'service_duration' : selServiceDuration,
'manage_mode' : bookAppointment.manageMode, 'manage_mode' : FrontendBook.manageMode,
'appointment_id' : appointmentId 'appointment_id' : appointmentId
}; };
@ -272,7 +272,7 @@ var bookAppointment = {
+ '</span><br/>'); + '</span><br/>');
}); });
if (bookAppointment.manageMode) { if (FrontendBook.manageMode) {
// Set the appointment start time as selected. // Set the appointment start time as selected.
$('.available-hour').removeClass('selected-hour'); $('.available-hour').removeClass('selected-hour');
$('.available-hour').filter(function() { $('.available-hour').filter(function() {
@ -285,7 +285,7 @@ var bookAppointment = {
$('.available-hour:eq(0)').addClass('selected-hour'); $('.available-hour:eq(0)').addClass('selected-hour');
} }
bookAppointment.updateConfirmFrame(); FrontendBook.updateConfirmFrame();
} else { } else {
$('#available-hours').text('There are no available appointment' $('#available-hours').text('There are no available appointment'
+ 'hours for the selected date. Please choose another ' + 'hours for the selected date. Please choose another '
@ -365,15 +365,15 @@ var bookAppointment = {
postData['appointment'] = { postData['appointment'] = {
'start_datetime' : $('#select-date').datepicker('getDate').toString('yyyy-MM-dd') 'start_datetime' : $('#select-date').datepicker('getDate').toString('yyyy-MM-dd')
+ ' ' + $('.selected-hour').text() + ':00', + ' ' + $('.selected-hour').text() + ':00',
'end_datetime' : bookAppointment.calcEndDatetime(), 'end_datetime' : FrontendBook.calcEndDatetime(),
'notes' : $('#notes').val(), 'notes' : $('#notes').val(),
'id_users_provider' : $('#select-provider').val(), 'id_users_provider' : $('#select-provider').val(),
'id_services' : $('#select-service').val() 'id_services' : $('#select-service').val()
}; };
postData['manage_mode'] = bookAppointment.manageMode; postData['manage_mode'] = FrontendBook.manageMode;
if (bookAppointment.manageMode) { if (FrontendBook.manageMode) {
postData['appointment']['id'] = GlobalVariables.appointmentData['id']; postData['appointment']['id'] = GlobalVariables.appointmentData['id'];
postData['customer']['id'] = GlobalVariables.customerData['id']; postData['customer']['id'] = GlobalVariables.customerData['id'];
} }
@ -431,7 +431,7 @@ var bookAppointment = {
// Set Appointment Date // Set Appointment Date
$('#select-date').datepicker('setDate', Date.parseExact( $('#select-date').datepicker('setDate', Date.parseExact(
appointmentData['start_datetime'], 'yyyy-MM-dd HH:mm:ss')); appointmentData['start_datetime'], 'yyyy-MM-dd HH:mm:ss'));
bookAppointment.getAvailableHours($('#select-date').val()); FrontendBook.getAvailableHours($('#select-date').val());
// Apply Customer's Data // Apply Customer's Data
$('#last-name').val(customerData['last_name']); $('#last-name').val(customerData['last_name']);
@ -445,7 +445,7 @@ var bookAppointment = {
var appointmentNotes = (appointmentData['notes'] !== null) ? appointmentData['notes'] : ''; var appointmentNotes = (appointmentData['notes'] !== null) ? appointmentData['notes'] : '';
$('#notes').val(appointmentNotes); $('#notes').val(appointmentNotes);
bookAppointment.updateConfirmFrame(); FrontendBook.updateConfirmFrame();
return true; return true;
} catch(exc) { } catch(exc) {

File diff suppressed because one or more lines are too long

107
src/assets/js/libs/jquery/gcal.js vendored Normal file
View file

@ -0,0 +1,107 @@
/*!
* FullCalendar v1.6.1 Google Calendar Plugin
* Docs & License: http://arshaw.com/fullcalendar/
* (c) 2013 Adam Shaw
*/
(function($) {
var fc = $.fullCalendar;
var formatDate = fc.formatDate;
var parseISO8601 = fc.parseISO8601;
var addDays = fc.addDays;
var applyAll = fc.applyAll;
fc.sourceNormalizers.push(function(sourceOptions) {
if (sourceOptions.dataType == 'gcal' ||
sourceOptions.dataType === undefined &&
(sourceOptions.url || '').match(/^(http|https):\/\/www.google.com\/calendar\/feeds\//)) {
sourceOptions.dataType = 'gcal';
if (sourceOptions.editable === undefined) {
sourceOptions.editable = false;
}
}
});
fc.sourceFetchers.push(function(sourceOptions, start, end) {
if (sourceOptions.dataType == 'gcal') {
return transformOptions(sourceOptions, start, end);
}
});
function transformOptions(sourceOptions, start, end) {
var success = sourceOptions.success;
var data = $.extend({}, sourceOptions.data || {}, {
'start-min': formatDate(start, 'u'),
'start-max': formatDate(end, 'u'),
'singleevents': true,
'max-results': 9999
});
var ctz = sourceOptions.currentTimezone;
if (ctz) {
data.ctz = ctz = ctz.replace(' ', '_');
}
return $.extend({}, sourceOptions, {
url: sourceOptions.url.replace(/\/basic$/, '/full') + '?alt=json-in-script&callback=?',
dataType: 'jsonp',
data: data,
startParam: false,
endParam: false,
success: function(data) {
var events = [];
if (data.feed.entry) {
$.each(data.feed.entry, function(i, entry) {
var startStr = entry['gd$when'][0]['startTime'];
var start = parseISO8601(startStr, true);
var end = parseISO8601(entry['gd$when'][0]['endTime'], true);
var allDay = startStr.indexOf('T') == -1;
var url;
$.each(entry.link, function(i, link) {
if (link.type == 'text/html') {
url = link.href;
if (ctz) {
url += (url.indexOf('?') == -1 ? '?' : '&') + 'ctz=' + ctz;
}
}
});
if (allDay) {
addDays(end, -1); // make inclusive
}
events.push({
id: entry['gCal$uid']['value'],
title: entry['title']['$t'],
url: url,
start: start,
end: end,
allDay: allDay,
location: entry['gd$where'][0]['valueString'],
description: entry['content']['$t']
});
});
}
var args = [events].concat(Array.prototype.slice.call(arguments, 1));
var res = applyAll(success, this, args);
if ($.isArray(res)) {
return res;
}
return events;
}
});
}
// legacy
fc.gcalFeed = function(url, sourceOptions) {
return $.extend({}, sourceOptions, { url: url, dataType: 'gcal' });
};
})(jQuery);