Ολοκλήρωση της βασικής ροής της περίπτωσης χρήσης 'Κράτηση Ραντεβού'.
|
@ -3,7 +3,7 @@
|
||||||
-- http://www.phpmyadmin.net
|
-- http://www.phpmyadmin.net
|
||||||
--
|
--
|
||||||
-- Φιλοξενητής: localhost
|
-- Φιλοξενητής: localhost
|
||||||
-- Χρόνος δημιουργίας: 14 Απρ 2013 στις 19:41:00
|
-- Χρόνος δημιουργίας: 20 Απρ 2013 στις 20:18:59
|
||||||
-- Έκδοση διακομιστή: 5.5.24-log
|
-- Έκδοση διακομιστή: 5.5.24-log
|
||||||
-- Έκδοση PHP: 5.4.3
|
-- Έκδοση PHP: 5.4.3
|
||||||
|
|
||||||
|
@ -30,7 +30,7 @@ CREATE TABLE IF NOT EXISTS `ea_appointments` (
|
||||||
`id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
|
`id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
|
||||||
`start_datetime` datetime DEFAULT NULL,
|
`start_datetime` datetime DEFAULT NULL,
|
||||||
`end_datetime` datetime DEFAULT NULL,
|
`end_datetime` datetime DEFAULT NULL,
|
||||||
`comments` text,
|
`notes` text,
|
||||||
`id_users_provider` bigint(20) unsigned NOT NULL,
|
`id_users_provider` bigint(20) unsigned NOT NULL,
|
||||||
`id_users_customer` bigint(20) unsigned NOT NULL,
|
`id_users_customer` bigint(20) unsigned NOT NULL,
|
||||||
`id_services` bigint(20) unsigned NOT NULL,
|
`id_services` bigint(20) unsigned NOT NULL,
|
||||||
|
@ -38,7 +38,7 @@ CREATE TABLE IF NOT EXISTS `ea_appointments` (
|
||||||
KEY `id_users_customer` (`id_users_customer`),
|
KEY `id_users_customer` (`id_users_customer`),
|
||||||
KEY `id_services` (`id_services`),
|
KEY `id_services` (`id_services`),
|
||||||
KEY `id_users_provider` (`id_users_provider`)
|
KEY `id_users_provider` (`id_users_provider`)
|
||||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8 AUTO_INCREMENT=1 ;
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8 AUTO_INCREMENT=18 ;
|
||||||
|
|
||||||
-- --------------------------------------------------------
|
-- --------------------------------------------------------
|
||||||
|
|
||||||
|
@ -49,6 +49,7 @@ CREATE TABLE IF NOT EXISTS `ea_appointments` (
|
||||||
CREATE TABLE IF NOT EXISTS `ea_roles` (
|
CREATE TABLE IF NOT EXISTS `ea_roles` (
|
||||||
`id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
|
`id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
|
||||||
`name` varchar(256) DEFAULT NULL,
|
`name` varchar(256) DEFAULT NULL,
|
||||||
|
`slug` varchar(256) DEFAULT NULL,
|
||||||
`is_admin` tinyint(4) DEFAULT NULL COMMENT '0',
|
`is_admin` tinyint(4) DEFAULT NULL COMMENT '0',
|
||||||
`services` int(4) DEFAULT NULL COMMENT '0',
|
`services` int(4) DEFAULT NULL COMMENT '0',
|
||||||
`providers` int(4) DEFAULT NULL COMMENT '0',
|
`providers` int(4) DEFAULT NULL COMMENT '0',
|
||||||
|
@ -56,14 +57,16 @@ CREATE TABLE IF NOT EXISTS `ea_roles` (
|
||||||
`notifications` int(4) DEFAULT NULL COMMENT '0',
|
`notifications` int(4) DEFAULT NULL COMMENT '0',
|
||||||
`appointments` int(4) DEFAULT NULL COMMENT '0',
|
`appointments` int(4) DEFAULT NULL COMMENT '0',
|
||||||
PRIMARY KEY (`id`)
|
PRIMARY KEY (`id`)
|
||||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8 AUTO_INCREMENT=2 ;
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8 AUTO_INCREMENT=4 ;
|
||||||
|
|
||||||
--
|
--
|
||||||
-- Άδειασμα δεδομένων του πίνακα `ea_roles`
|
-- Άδειασμα δεδομένων του πίνακα `ea_roles`
|
||||||
--
|
--
|
||||||
|
|
||||||
INSERT INTO `ea_roles` (`id`, `name`, `is_admin`, `services`, `providers`, `customers`, `notifications`, `appointments`) VALUES
|
INSERT INTO `ea_roles` (`id`, `name`, `slug`, `is_admin`, `services`, `providers`, `customers`, `notifications`, `appointments`) VALUES
|
||||||
(1, 'Administrator', 1, 15, 15, 15, 15, 15);
|
(1, 'Administrator', 'administrator', 1, 15, 15, 15, 15, 15),
|
||||||
|
(2, 'Provider', 'provider', 0, 0, 0, 15, 0, 15),
|
||||||
|
(3, 'Customer', 'customer', 0, 0, 0, 0, 0, 0);
|
||||||
|
|
||||||
-- --------------------------------------------------------
|
-- --------------------------------------------------------
|
||||||
|
|
||||||
|
@ -81,14 +84,43 @@ CREATE TABLE IF NOT EXISTS `ea_services` (
|
||||||
`id_service_categories` bigint(20) unsigned DEFAULT NULL,
|
`id_service_categories` bigint(20) unsigned DEFAULT NULL,
|
||||||
PRIMARY KEY (`id`),
|
PRIMARY KEY (`id`),
|
||||||
KEY `id_service_categories` (`id_service_categories`)
|
KEY `id_service_categories` (`id_service_categories`)
|
||||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8 AUTO_INCREMENT=2 ;
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8 AUTO_INCREMENT=4 ;
|
||||||
|
|
||||||
--
|
--
|
||||||
-- Άδειασμα δεδομένων του πίνακα `ea_services`
|
-- Άδειασμα δεδομένων του πίνακα `ea_services`
|
||||||
--
|
--
|
||||||
|
|
||||||
INSERT INTO `ea_services` (`id`, `name`, `duration`, `price`, `currency`, `description`, `id_service_categories`) VALUES
|
INSERT INTO `ea_services` (`id`, `name`, `duration`, `price`, `currency`, `description`, `id_service_categories`) VALUES
|
||||||
(1, 'General Examination', 20, '50.00', 'euro', 'Sample Description ...', NULL);
|
(1, 'Γενική Εξέταση', 20, '50.00', 'euro', 'Γενική εξέταση του ασθενή.', NULL),
|
||||||
|
(2, 'Εξέταση Καρδιάς', 30, '40.00', 'euro', 'Εξέταση του ασθενή για νοσήματα καρδιάς.', NULL),
|
||||||
|
(3, 'Νευρολογική Εξέταση', 20, '35.00', 'euro', 'Νευρολογική εξέταση του ασθενή.', NULL);
|
||||||
|
|
||||||
|
-- --------------------------------------------------------
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Δομή πίνακα για τον πίνακα `ea_services_providers`
|
||||||
|
--
|
||||||
|
|
||||||
|
CREATE TABLE IF NOT EXISTS `ea_services_providers` (
|
||||||
|
`id_users` bigint(20) unsigned NOT NULL,
|
||||||
|
`id_services` bigint(20) unsigned NOT NULL,
|
||||||
|
PRIMARY KEY (`id_users`,`id_services`),
|
||||||
|
KEY `id_services` (`id_services`)
|
||||||
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Άδειασμα δεδομένων του πίνακα `ea_services_providers`
|
||||||
|
--
|
||||||
|
|
||||||
|
INSERT INTO `ea_services_providers` (`id_users`, `id_services`) VALUES
|
||||||
|
(1, 1),
|
||||||
|
(2, 1),
|
||||||
|
(3, 1),
|
||||||
|
(4, 1),
|
||||||
|
(3, 2),
|
||||||
|
(4, 2),
|
||||||
|
(2, 3),
|
||||||
|
(3, 3);
|
||||||
|
|
||||||
-- --------------------------------------------------------
|
-- --------------------------------------------------------
|
||||||
|
|
||||||
|
@ -114,14 +146,16 @@ CREATE TABLE IF NOT EXISTS `ea_settings` (
|
||||||
`name` varchar(512) DEFAULT NULL,
|
`name` varchar(512) DEFAULT NULL,
|
||||||
`value` longtext,
|
`value` longtext,
|
||||||
PRIMARY KEY (`id`)
|
PRIMARY KEY (`id`)
|
||||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8 AUTO_INCREMENT=2 ;
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8 AUTO_INCREMENT=4 ;
|
||||||
|
|
||||||
--
|
--
|
||||||
-- Άδειασμα δεδομένων του πίνακα `ea_settings`
|
-- Άδειασμα δεδομένων του πίνακα `ea_settings`
|
||||||
--
|
--
|
||||||
|
|
||||||
INSERT INTO `ea_settings` (`id`, `name`, `value`) VALUES
|
INSERT INTO `ea_settings` (`id`, `name`, `value`) VALUES
|
||||||
(1, 'business_name', 'Javation & Co');
|
(1, 'business_name', 'Javation & Co'),
|
||||||
|
(2, 'business_working_hours', '{}'),
|
||||||
|
(3, NULL, NULL);
|
||||||
|
|
||||||
-- --------------------------------------------------------
|
-- --------------------------------------------------------
|
||||||
|
|
||||||
|
@ -146,14 +180,17 @@ CREATE TABLE IF NOT EXISTS `ea_users` (
|
||||||
`id_roles` bigint(20) unsigned NOT NULL,
|
`id_roles` bigint(20) unsigned NOT NULL,
|
||||||
PRIMARY KEY (`id`),
|
PRIMARY KEY (`id`),
|
||||||
KEY `id_roles` (`id_roles`)
|
KEY `id_roles` (`id_roles`)
|
||||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8 AUTO_INCREMENT=2 ;
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8 AUTO_INCREMENT=35 ;
|
||||||
|
|
||||||
--
|
--
|
||||||
-- Άδειασμα δεδομένων του πίνακα `ea_users`
|
-- Άδειασμα δεδομένων του πίνακα `ea_users`
|
||||||
--
|
--
|
||||||
|
|
||||||
INSERT INTO `ea_users` (`id`, `username`, `password`, `first_name`, `last_name`, `email`, `mobile_number`, `phone_number`, `address`, `city`, `state`, `zip_code`, `notes`, `id_roles`) VALUES
|
INSERT INTO `ea_users` (`id`, `username`, `password`, `first_name`, `last_name`, `email`, `mobile_number`, `phone_number`, `address`, `city`, `state`, `zip_code`, `notes`, `id_roles`) VALUES
|
||||||
(1, 'admin', 'admin', 'Alex', 'Tselegidis', 'alextselegidis@gmail.com', '123456789', '987654321', 'Pantazopoulou 11', 'Thessaloniki', NULL, '56121', 'This is me making Easy!Appointments', 1);
|
(1, 'admin', 'admin', 'Alex', 'Tselegidis', 'alextselegidis@gmail.com', '123456789', '987654321', 'Pantazopoulou 11', 'Thessaloniki', NULL, '56121', 'This is me making Easy!Appointments', 1),
|
||||||
|
(2, 'provider_1', 'provider_1', 'Γιώργος', 'Παπαδόπουλος', 'prov1@testing.gr', '1212121212', '2121212121', 'John Doe 23', 'Washington DC', NULL, '12345', 'This is a test provider', 2),
|
||||||
|
(3, 'provider_2', 'provider_2', 'Νίκος', 'Αναστασίου', 'prov2@test.gr', '1313133113131', '32132165146', 'Some Street 3', NULL, NULL, NULL, NULL, 2),
|
||||||
|
(4, 'provider_3', 'provider_3', 'Ηρώ', 'Καριοφύλη', 'prov3@test.gr', '239203490', '029340923', 'John Doe 3 ', NULL, NULL, NULL, NULL, 2);
|
||||||
|
|
||||||
--
|
--
|
||||||
-- Περιορισμοί για άχρηστους πίνακες
|
-- Περιορισμοί για άχρηστους πίνακες
|
||||||
|
@ -173,6 +210,13 @@ ALTER TABLE `ea_appointments`
|
||||||
ALTER TABLE `ea_services`
|
ALTER TABLE `ea_services`
|
||||||
ADD CONSTRAINT `ea_services_ibfk_1` FOREIGN KEY (`id_service_categories`) REFERENCES `ea_service_categories` (`id`) ON DELETE CASCADE ON UPDATE CASCADE;
|
ADD CONSTRAINT `ea_services_ibfk_1` FOREIGN KEY (`id_service_categories`) REFERENCES `ea_service_categories` (`id`) ON DELETE CASCADE ON UPDATE CASCADE;
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Περιορισμοί για πίνακα `ea_services_providers`
|
||||||
|
--
|
||||||
|
ALTER TABLE `ea_services_providers`
|
||||||
|
ADD CONSTRAINT `ea_services_providers_ibfk_1` FOREIGN KEY (`id_users`) REFERENCES `ea_users` (`id`) ON DELETE CASCADE ON UPDATE CASCADE,
|
||||||
|
ADD CONSTRAINT `ea_services_providers_ibfk_2` FOREIGN KEY (`id_services`) REFERENCES `ea_services` (`id`) ON DELETE CASCADE ON UPDATE CASCADE;
|
||||||
|
|
||||||
--
|
--
|
||||||
-- Περιορισμοί για πίνακα `ea_users`
|
-- Περιορισμοί για πίνακα `ea_users`
|
||||||
--
|
--
|
||||||
|
|
|
@ -6,19 +6,62 @@ class Appointments extends CI_Controller {
|
||||||
* for the customers.
|
* for the customers.
|
||||||
*/
|
*/
|
||||||
public function index() {
|
public function index() {
|
||||||
// Get business name.
|
if (strtoupper($_SERVER['REQUEST_METHOD']) != 'POST') {
|
||||||
$this->load->model('Settings');
|
// Display the appointment booking page to the customer.
|
||||||
$viewData['businessName'] = $this->Settings->getSetting('business_name');
|
// Get business name.
|
||||||
|
$this->load->model('Settings_Model');
|
||||||
// Get the available services and providers.
|
$viewData['businessName'] = $this->Settings_Model->getSetting('business_name');
|
||||||
$this->load->model('Services');
|
|
||||||
$viewData['availableServices'] = $this->Services->getAvailableServices();
|
// Get the available services and providers.
|
||||||
|
$this->load->model('Services_Model');
|
||||||
$this->load->model('Providers');
|
$viewData['availableServices'] = $this->Services_Model->getAvailableServices();
|
||||||
$viewData['availableProviders'] = $this->Providers->getAvailableProviders(); // Provider rows contain an array of which services they can provide.
|
|
||||||
|
$this->load->model('Providers_Model');
|
||||||
// Load the book appointment view.
|
$viewData['availableProviders'] = $this->Providers_Model->getAvailableProviders(); // Provider rows contain an array of which services they can provide.
|
||||||
$this->load->view('appointments/book', $viewData);
|
|
||||||
|
// Load the book appointment view.
|
||||||
|
$this->load->view('appointments/book', $viewData);
|
||||||
|
} else {
|
||||||
|
// Add the appointment to the database and display the success
|
||||||
|
// page to the customer.
|
||||||
|
$customerData = array(
|
||||||
|
'first_name' => $_POST['firstName'],
|
||||||
|
'last_name' => $_POST['lastName'],
|
||||||
|
'email' => $_POST['email'],
|
||||||
|
'phone_number' => $_POST['phoneNumber'],
|
||||||
|
'address' => $_POST['address'],
|
||||||
|
'city' => $_POST['city'],
|
||||||
|
'zip_code' => $_POST['zipCode']
|
||||||
|
);
|
||||||
|
|
||||||
|
$this->load->model('Customers_Model');
|
||||||
|
$customerId = $this->Customers_Model->add($customerData);
|
||||||
|
|
||||||
|
$appointmentData = array(
|
||||||
|
'start_datetime' => $_POST['startDatetime'],
|
||||||
|
'end_datetime' => $_POST['endDatetime'],
|
||||||
|
'notes' => $_POST['notes'],
|
||||||
|
'id_users_provider' => $_POST['providerId'],
|
||||||
|
'id_users_customer' => $customerId,
|
||||||
|
'id_services' => $_POST['serviceId'],
|
||||||
|
);
|
||||||
|
|
||||||
|
$this->load->model('Appointments_Model');
|
||||||
|
$this->Appointments_Model->add($appointmentData);
|
||||||
|
|
||||||
|
// Send an email to the customer with the appointment info.
|
||||||
|
$to = $customerData['email'];
|
||||||
|
$subject = 'Appointment Book Success';
|
||||||
|
$message = 'Hi there! Your appointment has been successfully booked.';
|
||||||
|
$headers = 'From: alextselegidis@gmail.com' . "\r\n" .
|
||||||
|
'Reply-To: alextselegidis@gmail.com' . "\r\n" .
|
||||||
|
'X-Mailer: PHP/' . phpversion();
|
||||||
|
|
||||||
|
mail($to, $subject, $message, $headers);
|
||||||
|
|
||||||
|
// Load the book appointment view.
|
||||||
|
$this->load->view('appointments/book-success');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -38,12 +81,26 @@ class Appointments extends CI_Controller {
|
||||||
// For now we just need to return a sample array. Dynamic calculation
|
// For now we just need to return a sample array. Dynamic calculation
|
||||||
// will be adding in future development.
|
// will be adding in future development.
|
||||||
$startTime = strtotime($_POST['selectedDate'] . ' 08:00') / 60; // Convert to minutes
|
$startTime = strtotime($_POST['selectedDate'] . ' 08:00') / 60; // Convert to minutes
|
||||||
$endTime = strtotime($_POST['selectedDate'] . ' 16:00') / 60; // Convert to minutes
|
$endTime = strtotime($_POST['selectedDate'] . ' 19:00') / 60; // Convert to minutes
|
||||||
|
|
||||||
for ($i=0; ($startTime*60 + $i*60)<=($endTime*60); $i+=intval($_POST['serviceDuration'])) {
|
for ($i=0; ($startTime*60 + $i*60)<=($endTime*60); $i+=intval($_POST['serviceDuration'])) {
|
||||||
$availableHours[] = date('H:i', $startTime * 60 + $i * 60);
|
$availableHours[] = date('H:i', $startTime * 60 + $i * 60);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// If the selected date is today, remove past hours.
|
||||||
|
if (date('m/d/Y', strtotime($_POST['selectedDate'])) == date('m/d/Y')) {
|
||||||
|
foreach($availableHours as $index=>$value) {
|
||||||
|
$availableHour = date('m/d/Y H:i', strtotime($value));
|
||||||
|
$currentHour = date('m/d/Y H:i');
|
||||||
|
|
||||||
|
if ($availableHour < $currentHour) {
|
||||||
|
unset($availableHours[$index]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$availableHours = array_values($availableHours);
|
||||||
|
|
||||||
echo json_encode($availableHours);
|
echo json_encode($availableHours);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
/*
|
|
||||||
* To change this template, choose Tools | Templates
|
|
||||||
* and open the template in the editor.
|
|
||||||
*/
|
|
||||||
?>
|
|
36
src/application/models/appointments_model.php
Normal file
|
@ -0,0 +1,36 @@
|
||||||
|
<?php
|
||||||
|
class Appointments_Model extends CI_Model {
|
||||||
|
public function __construct() {
|
||||||
|
parent::__construct();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function add($appointmentData) {
|
||||||
|
try {
|
||||||
|
if (!$this->exists($appointmentData)) {
|
||||||
|
$this->insert($appointmentData);
|
||||||
|
} else {
|
||||||
|
$this->update($appointmentData);
|
||||||
|
}
|
||||||
|
} catch (Exception $exc) {
|
||||||
|
echo $exc->getTraceAsString();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function exists($appointmentData) {
|
||||||
|
return false; // @task This check is going to be more complicated than just checking an email (customers model)
|
||||||
|
}
|
||||||
|
|
||||||
|
private function insert($appointmentData) {
|
||||||
|
$this->db->insert('ea_appointments', $appointmentData);
|
||||||
|
}
|
||||||
|
|
||||||
|
private function update($appointmentData) {
|
||||||
|
$this->db->where('id', $appointmentData['id']);
|
||||||
|
$this->db->update('ea_appointments', $appointmentData);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function delete($appointmentId) {
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
?>
|
|
@ -1,7 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
/*
|
|
||||||
* To change this template, choose Tools | Templates
|
|
||||||
* and open the template in the editor.
|
|
||||||
*/
|
|
||||||
?>
|
|
84
src/application/models/customers_model.php
Normal file
|
@ -0,0 +1,84 @@
|
||||||
|
<?php
|
||||||
|
class Customers_Model extends CI_Model {
|
||||||
|
public function __construct() {
|
||||||
|
parent::__construct();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This method adds a customer to the database. If the customer
|
||||||
|
* already exists then its data are going to be updated.
|
||||||
|
*
|
||||||
|
* @param array $customerData The customer data we want to add.
|
||||||
|
*/
|
||||||
|
public function add($customerData) {
|
||||||
|
try {
|
||||||
|
if (!$this->exists($customerData['email'])) {
|
||||||
|
$this->insert($customerData);
|
||||||
|
} else {
|
||||||
|
$this->update($customerData);
|
||||||
|
}
|
||||||
|
} catch(Exception $exc) {
|
||||||
|
// Send some info for the exception back to the browser.
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->db->insert_id();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This method checks if a customer exists on the database.
|
||||||
|
* The unique identifier for a customer is his email.
|
||||||
|
*
|
||||||
|
* @param string $customerEmail The customers email.
|
||||||
|
* @return bool Returns the operation result.
|
||||||
|
*/
|
||||||
|
public function exists($customerEmail) {
|
||||||
|
return false; // @task This should be implemented soon.
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This method inserts a customer into the database.
|
||||||
|
*
|
||||||
|
* @param array $customerData Associative array with the customers
|
||||||
|
* data. The key of the array should be the same as the database
|
||||||
|
* field names.
|
||||||
|
*/
|
||||||
|
private function insert($customerData) {
|
||||||
|
$this->db
|
||||||
|
->select('id')
|
||||||
|
->from('ea_roles')
|
||||||
|
->where('slug', 'customer');
|
||||||
|
|
||||||
|
$customerRoleId = $this->db->get()->row()->id;
|
||||||
|
|
||||||
|
if ($customerRoleId !== NULL) {
|
||||||
|
$customerData['id_roles'] = $customerRoleId;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!$this->db->insert('ea_users', $customerData)) {
|
||||||
|
throw new Exception('Could not insert customer to the database.');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private function update($customerData) {
|
||||||
|
$this->db->where('email', $customerData['email']);
|
||||||
|
if (!$this->db->update('ea_users', $customerData)) {
|
||||||
|
throw new Exception('Could not update customer to the database.');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This method deletes a customers from the database.
|
||||||
|
* All his appointmets will be deleted too (automatically
|
||||||
|
* through the foreign key constraint).
|
||||||
|
*
|
||||||
|
* @param int $customerId The id of the customer to be
|
||||||
|
* deleted.
|
||||||
|
*/
|
||||||
|
public function delete($customerId) {
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
?>
|
|
@ -1,5 +1,5 @@
|
||||||
<?php
|
<?php
|
||||||
class Providers extends CI_Model {
|
class Providers_Model extends CI_Model {
|
||||||
public function __construct() {
|
public function __construct() {
|
||||||
parent::__construct();
|
parent::__construct();
|
||||||
}
|
}
|
||||||
|
@ -12,22 +12,21 @@ class Providers extends CI_Model {
|
||||||
* data.
|
* data.
|
||||||
*/
|
*/
|
||||||
public function getAvailableProviders() {
|
public function getAvailableProviders() {
|
||||||
$sql = '
|
$this->db
|
||||||
SELECT ea_users.*
|
->select('ea_users.*')
|
||||||
FROM ea_users
|
->from('ea_users')
|
||||||
INNER JOIN ea_roles
|
->join('ea_roles', 'ea_roles.id = ea_users.id_roles', 'inner')
|
||||||
ON ea_users.id_roles = ea_roles.id
|
->where('ea_roles.slug', 'provider');
|
||||||
WHERE ea_roles.slug = "provider"';
|
|
||||||
|
|
||||||
$providers = $this->db->query($sql)->result_array();
|
$providers = $this->db->get()->result_array();
|
||||||
|
|
||||||
foreach($providers as &$provider) {
|
foreach($providers as &$provider) {
|
||||||
$sql = '
|
$this->db
|
||||||
SELECT id_services
|
->select('id_services')
|
||||||
FROM ea_services_providers
|
->from('ea_services_providers')
|
||||||
WHERE id_users = ' . $this->db->escape($provider['id']);
|
->where('id_users', $provider['id']);
|
||||||
|
|
||||||
$providerServices = $this->db->query($sql)->result_array();
|
$providerServices = $this->db->get()->result_array();
|
||||||
|
|
||||||
if (!isset($provider['services'])) {
|
if (!isset($provider['services'])) {
|
||||||
$provider['services'] = array();
|
$provider['services'] = array();
|
|
@ -1,5 +1,5 @@
|
||||||
<?php
|
<?php
|
||||||
class Services extends CI_Model {
|
class Services_Model extends CI_Model {
|
||||||
function __construct() {
|
function __construct() {
|
||||||
parent::__construct();
|
parent::__construct();
|
||||||
}
|
}
|
|
@ -1,7 +1,6 @@
|
||||||
<?php
|
<?php
|
||||||
class Settings extends CI_Model {
|
class Settings_Model extends CI_Model {
|
||||||
function __construct()
|
function __construct() {
|
||||||
{
|
|
||||||
parent::__construct();
|
parent::__construct();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -13,8 +12,7 @@ class Settings extends CI_Model {
|
||||||
* @return string Returns the database value for
|
* @return string Returns the database value for
|
||||||
* the selected setting.
|
* the selected setting.
|
||||||
*/
|
*/
|
||||||
function getSetting($name)
|
function getSetting($name) {
|
||||||
{
|
|
||||||
$query = $this->db->get_where('ea_settings', array('name' => $name));
|
$query = $this->db->get_where('ea_settings', array('name' => $name));
|
||||||
$setting = ($query->num_rows() > 0) ? $query->row() : '';
|
$setting = ($query->num_rows() > 0) ? $query->row() : '';
|
||||||
return $setting->value;
|
return $setting->value;
|
||||||
|
@ -30,8 +28,7 @@ class Settings extends CI_Model {
|
||||||
* @return bool Returns the operation success - failure
|
* @return bool Returns the operation success - failure
|
||||||
* result.
|
* result.
|
||||||
*/
|
*/
|
||||||
function setSetting($name, $value)
|
function setSetting($name, $value) {
|
||||||
{
|
|
||||||
$query = $this->db->get_where('ea_settings', array('name' => $name));
|
$query = $this->db->get_where('ea_settings', array('name' => $name));
|
||||||
if ($query->num_rows() > 0) {
|
if ($query->num_rows() > 0) {
|
||||||
// Update setting
|
// Update setting
|
41
src/application/views/appointments/book-success.php
Normal file
|
@ -0,0 +1,41 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<meta http-equiv="content-type" content="text/html; charset=UTF-8">
|
||||||
|
|
||||||
|
<?php // INCLUDE CSS FILES ?>
|
||||||
|
<link rel="stylesheet" type="text/css" href="<?php echo $this->config->base_url(); ?>assets/css/libs/bootstrap/bootstrap.css">
|
||||||
|
<link rel="stylesheet" type="text/css" href="<?php echo $this->config->base_url(); ?>assets/css/libs/bootstrap/bootstrap-responsive.css">
|
||||||
|
|
||||||
|
<?php // SET FAVICON FOR PAGE ?>
|
||||||
|
<link rel="icon" type="image/x-icon" href="<?php echo $this->config->base_url(); ?>assets/images/favicon.ico">
|
||||||
|
|
||||||
|
<style>
|
||||||
|
body {
|
||||||
|
background-color: #CAEDF3;
|
||||||
|
}
|
||||||
|
|
||||||
|
#success-frame {
|
||||||
|
width: 660px;
|
||||||
|
margin: 150px auto 0 auto;
|
||||||
|
background: #FFF;
|
||||||
|
box-shadow: 0px 1px 1px #B6B6B6;
|
||||||
|
min-height: 197px;
|
||||||
|
padding: 108px 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#success-icon {
|
||||||
|
float: left;
|
||||||
|
margin: 0px 26px 0 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div id="success-frame" class="container">
|
||||||
|
<img id="success-icon" src="<?php echo $this->config->base_url(); ?>/assets/images/success.png" />
|
||||||
|
<h2>Your appointment has been successfully registered.</h2>
|
||||||
|
<p>An email with the appointment details has been sented to you.</p>
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
</html>
|
|
@ -16,150 +16,25 @@
|
||||||
<script type="text/javascript" src="<?php echo $this->config->base_url(); ?>assets/js/libs/jquery/jquery.qtip.min.js"></script>
|
<script type="text/javascript" src="<?php echo $this->config->base_url(); ?>assets/js/libs/jquery/jquery.qtip.min.js"></script>
|
||||||
<script type="text/javascript" src="<?php echo $this->config->base_url(); ?>assets/js/libs/bootstrap/bootstrap.min.js"></script>
|
<script type="text/javascript" src="<?php echo $this->config->base_url(); ?>assets/js/libs/bootstrap/bootstrap.min.js"></script>
|
||||||
<script type="text/javascript" src="<?php echo $this->config->base_url(); ?>assets/js/libs/date.js"></script>
|
<script type="text/javascript" src="<?php echo $this->config->base_url(); ?>assets/js/libs/date.js"></script>
|
||||||
|
<script type="text/javascript" src="<?php echo $this->config->base_url(); ?>assets/js/frontend/book-appointment.js"></script>
|
||||||
|
|
||||||
<?php // SET FAVICON FOR PAGE ?>
|
<?php // SET FAVICON FOR PAGE ?>
|
||||||
<link rel="icon" type="image/x-icon" href="<?php echo $this->config->base_url(); ?>assets/images/favicon.ico">
|
<link rel="icon" type="image/x-icon" href="<?php echo $this->config->base_url(); ?>assets/images/favicon.ico">
|
||||||
|
|
||||||
|
<?php // JS GLOBAL VARIABLE DECLARATION ?>
|
||||||
|
<script type="text/javascript">
|
||||||
|
// Define some global variables.
|
||||||
|
GlobalVariables = {
|
||||||
|
services : <?php echo json_encode($availableServices); ?>,
|
||||||
|
providers : <?php echo json_encode($availableProviders); ?>,
|
||||||
|
baseUrl : '<?php echo $this->config->base_url(); ?>'
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<?php // JQUERY PAGE STUFF ?>
|
||||||
<script type="text/javascript">
|
<script type="text/javascript">
|
||||||
$(document).ready(function() {
|
$(document).ready(function() {
|
||||||
var services = <?php echo json_encode($availableServices); ?>;
|
bookAppointment.initialize(); // Begin jquery magic :P
|
||||||
var providers = <?php echo json_encode($availableProviders); ?>;
|
|
||||||
|
|
||||||
// When the user clicks on a service, its available providers should
|
|
||||||
// become visible.
|
|
||||||
$('#select-service').change(function() {
|
|
||||||
var currServiceId = $('#select-service').val();
|
|
||||||
$('#select-provider').empty();
|
|
||||||
|
|
||||||
$.each(providers, function(index, provider) {
|
|
||||||
$.each(provider['services'], function(index, serviceId) {
|
|
||||||
if (serviceId == currServiceId) {
|
|
||||||
// This provider can provide the selected service.
|
|
||||||
// Add him to the list box.
|
|
||||||
var option = new Option(provider['last_name'] + ' ' + provider['first_name'], provider['id']);
|
|
||||||
$('#select-provider').append(option);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
refreshAvailableHours(Date.today().toString('MM/dd/yyyy'));
|
|
||||||
});
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Selected Provider Changed Event Handler
|
|
||||||
*/
|
|
||||||
$('#select-provider').change(function() {
|
|
||||||
refreshAvailableHours(Date.today().toString('MM/dd/yyyy'));
|
|
||||||
});
|
|
||||||
|
|
||||||
$('#select-service').trigger('change');
|
|
||||||
|
|
||||||
$('.book-step').qtip({
|
|
||||||
position: {
|
|
||||||
my: 'top center',
|
|
||||||
at: 'bottom center'
|
|
||||||
},
|
|
||||||
style: {
|
|
||||||
classes: 'qtip-green qtip-shadow custom-qtip'
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
$('#select-date').datepicker({
|
|
||||||
//dateFormat : 'dd/mm/yy',
|
|
||||||
onSelect : function(dateText, inst) {
|
|
||||||
refreshAvailableHours(dateText);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
refreshAvailableHours(Date.today().toString('MM/dd/yyyy'));
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Next Step Button Clicked
|
|
||||||
*/
|
|
||||||
$('.button-next').click(function() {
|
|
||||||
var nextTabIndex = parseInt($(this).attr('data-step_index')) + 1;
|
|
||||||
|
|
||||||
$(this).parents().eq(1).hide('fade', function() {
|
|
||||||
$('.active-step').removeClass('active-step');
|
|
||||||
$('#step-' + nextTabIndex).addClass('active-step');
|
|
||||||
$('#book-appointment-' + nextTabIndex).show('fade');
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Back Step Button Clicked
|
|
||||||
*/
|
|
||||||
$('.button-back').click(function() {
|
|
||||||
var prevTabIndex = parseInt($(this).attr('data-step_index')) - 1;
|
|
||||||
|
|
||||||
$(this).parents().eq(1).hide('fade', function() {
|
|
||||||
$('.active-step').removeClass('active-step');
|
|
||||||
$('#step-' + prevTabIndex).addClass('active-step');
|
|
||||||
$('#book-appointment-' + prevTabIndex).show('fade');
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Available Hour Click Event Handler
|
|
||||||
*/
|
|
||||||
$('#available-hours').on('click', '.available-hour', function() {
|
|
||||||
$('.selected-hour').removeClass('selected-hour');
|
|
||||||
$(this).addClass('selected-hour');
|
|
||||||
});
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This function makes an ajax call and returns the available
|
|
||||||
* hours for the selected service, provider and date.
|
|
||||||
*/
|
|
||||||
function refreshAvailableHours(selDate) {
|
|
||||||
// Fetch the available hours of the current date
|
|
||||||
// for the chosen service and provider.
|
|
||||||
var selServiceDuration = 15; // Default duration.
|
|
||||||
$.each(services, function(index, service) {
|
|
||||||
if (service['id'] == $('#select-service').val()) {
|
|
||||||
selServiceDuration = service['duration'];
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
var postData = {
|
|
||||||
'serviceId' : $('#select-service').val(),
|
|
||||||
'providerId' : $('#select-provider').val(),
|
|
||||||
'selectedDate' : selDate,
|
|
||||||
'serviceDuration' : selServiceDuration
|
|
||||||
};
|
|
||||||
|
|
||||||
console.log('\n\n Get Available Hours Post Data:', postData, '\n\n');
|
|
||||||
|
|
||||||
// Make ajax post request and get the available hours.
|
|
||||||
var ajaxurl = '<?php echo $this->config->base_url(); ?>index.php/appointments/getAvailableHours';
|
|
||||||
jQuery.post(ajaxurl, postData, function(postResponse) {
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
|
||||||
console.log('\n\n Get Available Hours Post Response :', postResponse, '\n\n');
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
try {
|
|
||||||
var jsonResponse = jQuery.parseJSON(postResponse);
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
|
||||||
console.log('\n\n Get Available Hours Json Response :', jsonResponse, '\n\n');
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
// Fill the available time div
|
|
||||||
var currColumn = 1;
|
|
||||||
$('#available-hours').html('<div style="width:50px; float:left;"></div>');
|
|
||||||
$.each(jsonResponse, function(index, availableHour) {
|
|
||||||
if ((currColumn * 10) < (index + 1)) {
|
|
||||||
currColumn++;
|
|
||||||
$('#available-hours').append('<div style="width:50px; float:left;"></div>');
|
|
||||||
}
|
|
||||||
$('#available-hours div:eq(' + (currColumn - 1) + ')')
|
|
||||||
.append('<span class="available-hour">' + availableHour + '</span><br/>');
|
|
||||||
});
|
|
||||||
|
|
||||||
} catch(exception) {
|
|
||||||
// @task Display message to the user.
|
|
||||||
};
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
</head>
|
</head>
|
||||||
|
@ -188,97 +63,120 @@
|
||||||
|
|
||||||
<?php // SELECT SERVICE AND PROVIDER ?>
|
<?php // SELECT SERVICE AND PROVIDER ?>
|
||||||
<div id="book-appointment-1" class="book-appoinment-step">
|
<div id="book-appointment-1" class="book-appoinment-step">
|
||||||
<h2>Select Service & Provider</h2>
|
<div class="book-step-content">
|
||||||
<label for="select-service">Select Service</label>
|
<h2>Select Service & Provider</h2>
|
||||||
<select id="select-service">
|
<div class="span5">
|
||||||
<?php
|
<label for="select-service">Select Service</label>
|
||||||
foreach($availableServices as $service) {
|
<select id="select-service">
|
||||||
echo '<option value="' . $service['id'] . '">' . $service['name'] . '</option>';
|
<?php
|
||||||
}
|
foreach($availableServices as $service) {
|
||||||
?>
|
echo '<option value="' . $service['id'] . '">' . $service['name'] . '</option>';
|
||||||
</select>
|
}
|
||||||
|
?>
|
||||||
|
</select>
|
||||||
|
|
||||||
<label for="select-provider">Select Provider</label>
|
<label for="select-provider">Select Provider</label>
|
||||||
<select id="select-provider"></select>
|
<select id="select-provider"></select>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div class="command-buttons">
|
<div class="command-buttons">
|
||||||
<button type="button" id="button-next-1" class="btn button-next" data-step_index="1">Next</button>
|
<button type="button" id="button-next-1" class="btn button-next btn-primary" data-step_index="1">Next <i class="icon-forward icon-white"></i></button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<?php // APPOINTMENT DATE ?>
|
<?php // APPOINTMENT DATE ?>
|
||||||
<div id="book-appointment-2" class="book-appoinment-step" style="display:none;">
|
<div id="book-appointment-2" class="book-appoinment-step" style="display:none;">
|
||||||
<h2>Select Appointment Date And Time</h2>
|
<div class="book-step-content">
|
||||||
<div class="span3">
|
<h2>Select Appointment Date And Time</h2>
|
||||||
<div id="select-date"></div>
|
<div class="span3">
|
||||||
</div>
|
<div id="select-date"></div>
|
||||||
|
</div>
|
||||||
<div class="span3">
|
|
||||||
<?php // Available hours are going to be fetched via ajax call. ?>
|
<div class="span3">
|
||||||
<div id="available-hours"></div>
|
<?php // Available hours are going to be fetched via ajax call. ?>
|
||||||
|
<div id="available-hours"></div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="command-buttons">
|
<div class="command-buttons">
|
||||||
<button type="button" id="button-back-2" class="btn button-back" data-step_index="2">Back</button>
|
<button type="button" id="button-back-2" class="btn button-back" data-step_index="2"><i class="icon-backward"></i> Back</button>
|
||||||
<button type="button" id="button-next-2" class="btn button-next" data-step_index="2">Next</button>
|
<button type="button" id="button-next-2" class="btn button-next btn-primary" data-step_index="2">Next <i class="icon-forward icon-white"></i></button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<?php // CUSTOMER'S INFO ?>
|
<?php // CUSTOMER'S INFO ?>
|
||||||
<div id="book-appointment-3" class="book-appoinment-step" style="display:none;">
|
<div id="book-appointment-3" class="book-appoinment-step" style="display:none;">
|
||||||
<h2>Fill In Your Information</h2>
|
<div class="book-step-content">
|
||||||
|
<h2>Fill In Your Information</h2>
|
||||||
<div class="span3">
|
|
||||||
<label for="last-name">Last Name *</label>
|
|
||||||
<input type="text" id="last-name" maxlength="250" />
|
|
||||||
|
|
||||||
<label for="first-name">First Name</label>
|
<div class="span3">
|
||||||
<input type="text" id="first-name" maxlength="100" />
|
<label for="last-name">Last Name *</label>
|
||||||
|
<input type="text" id="last-name" class="required" maxlength="250" />
|
||||||
|
|
||||||
<label for="email">Email *</label>
|
<label for="first-name">First Name</label>
|
||||||
<input type="text" id="email" maxlength="250" />
|
<input type="text" id="first-name" maxlength="100" />
|
||||||
|
|
||||||
<label for="phone-number">Phone Number *</label>
|
<label for="email">Email *</label>
|
||||||
<input type="text" id="phone-number" maxlength="60" />
|
<input type="text" id="email" class="required" maxlength="250" />
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="span3">
|
|
||||||
<label for="address">Address</label>
|
|
||||||
<input type="text" id="address" maxlength="250" />
|
|
||||||
|
|
||||||
<label for="city">City</label>
|
<label for="phone-number">Phone Number *</label>
|
||||||
<input type="text" id="city" maxlength="120" />
|
<input type="text" id="phone-number" class="required" maxlength="60" />
|
||||||
|
|
||||||
|
<br/><br/>
|
||||||
|
<em class="text-error">Fields with * are mandatory.</em>
|
||||||
|
</div>
|
||||||
|
|
||||||
<label for="zip-code">Zip Code</label>
|
<div class="span3">
|
||||||
<input type="text" id="zip-code" maxlength="120" />
|
<label for="address">Address</label>
|
||||||
|
<input type="text" id="address" maxlength="250" />
|
||||||
|
|
||||||
<label for="notes">Notes</label>
|
<label for="city">City</label>
|
||||||
<textarea id="notes" maxlength="500"></textarea>
|
<input type="text" id="city" maxlength="120" />
|
||||||
|
|
||||||
|
<label for="zip-code">Zip Code</label>
|
||||||
|
<input type="text" id="zip-code" maxlength="120" />
|
||||||
|
|
||||||
|
<label for="notes">Notes</label>
|
||||||
|
<textarea id="notes" maxlength="500" rows="4"></textarea>
|
||||||
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="command-buttons">
|
<div class="command-buttons">
|
||||||
<button type="button" id="button-back-3" class="btn button-back" data-step_index="3">Back</button>
|
<button type="button" id="button-back-3" class="btn button-back" data-step_index="3"><i class="icon-backward"></i> Back</button>
|
||||||
<button type="button" id="button-next-3" class="btn button-next" data-step_index="3">Next</button>
|
<button type="button" id="button-next-3" class="btn button-next btn-primary" data-step_index="3">Next <i class="icon-forward icon-white"></i></button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<?php // CONFIRMATION STEP ?>
|
<?php // CONFIRMATION STEP ?>
|
||||||
<div id="book-appointment-4" class="book-appoinment-step" style="display:none;">
|
<div id="book-appointment-4" class="book-appoinment-step" style="display:none;">
|
||||||
<h2>Confirm Appointment</h2>
|
<div class="book-step-content">
|
||||||
|
<h2>Confirm Appointment</h2>
|
||||||
<div id="appointment-info">
|
|
||||||
|
<div id="appointment-info" class="span3"></div>
|
||||||
|
<div id="customer-info" class="span3"></div>
|
||||||
</div>
|
|
||||||
|
|
||||||
<div id="customer-info">
|
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="command-buttons">
|
<div class="command-buttons">
|
||||||
<button type="button" id="button-back-4" class="btn button-back" data-step_index="4">Back</button>
|
<button type="button" id="button-back-4" class="btn button-back" data-step_index="4"><i class="icon-backward"></i> Back</button>
|
||||||
<form>
|
<form id="book-appointment-form" style="display:inline-block" method="post">
|
||||||
<button type="submit" class="btn-success">Confirm Appointment</button>
|
<button type="submit" class="btn btn-success"><i class="icon-ok icon-white"></i> Confirm!</button>
|
||||||
|
|
||||||
|
<input type="hidden" name="lastName" />
|
||||||
|
<input type="hidden" name="firstName" />
|
||||||
|
<input type="hidden" name="email" />
|
||||||
|
<input type="hidden" name="phoneNumber" />
|
||||||
|
<input type="hidden" name="address" />
|
||||||
|
<input type="hidden" name="city" />
|
||||||
|
<input type="hidden" name="zipCode" />
|
||||||
|
|
||||||
|
<input type="hidden" name="startDatetime" />
|
||||||
|
<input type="hidden" name="endDatetime" />
|
||||||
|
<input type="hidden" name="notes" />
|
||||||
|
<input type="hidden" name="providerId" />
|
||||||
|
<input type="hidden" name="serviceId" />
|
||||||
|
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -289,4 +187,4 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
4
src/assets/css/libs/bootstrap/bootstrap.css
vendored
|
@ -2282,7 +2282,7 @@ table th[class*="span"],
|
||||||
*margin-right: .3em;
|
*margin-right: .3em;
|
||||||
line-height: 14px;
|
line-height: 14px;
|
||||||
vertical-align: text-top;
|
vertical-align: text-top;
|
||||||
background-image: url("../../../img/glyphicons-halflings.png");
|
background-image: url("../../../images/glyphicons-halflings.png");
|
||||||
background-position: 14px 14px;
|
background-position: 14px 14px;
|
||||||
background-repeat: no-repeat;
|
background-repeat: no-repeat;
|
||||||
}
|
}
|
||||||
|
@ -2306,7 +2306,7 @@ table th[class*="span"],
|
||||||
.dropdown-submenu:focus > a > [class^="icon-"],
|
.dropdown-submenu:focus > a > [class^="icon-"],
|
||||||
.dropdown-submenu:hover > a > [class*=" icon-"],
|
.dropdown-submenu:hover > a > [class*=" icon-"],
|
||||||
.dropdown-submenu:focus > a > [class*=" icon-"] {
|
.dropdown-submenu:focus > a > [class*=" icon-"] {
|
||||||
background-image: url("../../../img/glyphicons-halflings-white.png");
|
background-image: url("../../../images/glyphicons-halflings-white.png");
|
||||||
}
|
}
|
||||||
|
|
||||||
.icon-glass {
|
.icon-glass {
|
||||||
|
|
Before Width: | Height: | Size: 1.7 KiB |
Before Width: | Height: | Size: 418 B |
BIN
src/assets/css/libs/jquery/images/ui-bg_flat_0_aaaaaa_40x100.png
Normal file
After Width: | Height: | Size: 212 B |
BIN
src/assets/css/libs/jquery/images/ui-bg_flat_0_eeeeee_40x100.png
Normal file
After Width: | Height: | Size: 220 B |
Before Width: | Height: | Size: 206 B |
Before Width: | Height: | Size: 205 B |
Before Width: | Height: | Size: 220 B |
After Width: | Height: | Size: 208 B |
After Width: | Height: | Size: 208 B |
Before Width: | Height: | Size: 333 B |
Before Width: | Height: | Size: 207 B After Width: | Height: | Size: 207 B |
Before Width: | Height: | Size: 5.6 KiB |
Before Width: | Height: | Size: 336 B |
Before Width: | Height: | Size: 321 B |
Before Width: | Height: | Size: 328 B |
Before Width: | Height: | Size: 252 B |
After Width: | Height: | Size: 277 B |
After Width: | Height: | Size: 351 B |
Before Width: | Height: | Size: 353 B |
After Width: | Height: | Size: 280 B |
Before Width: | Height: | Size: 355 B |
Before Width: | Height: | Size: 328 B |
Before Width: | Height: | Size: 351 B |
Before Width: | Height: | Size: 203 B |
Before Width: | Height: | Size: 203 B |
Before Width: | Height: | Size: 349 B |
Before Width: | Height: | Size: 4.4 KiB After Width: | Height: | Size: 4.4 KiB |
Before Width: | Height: | Size: 4.4 KiB After Width: | Height: | Size: 4.4 KiB |
Before Width: | Height: | Size: 6.8 KiB |
BIN
src/assets/css/libs/jquery/images/ui-icons_454545_256x240.png
Normal file
After Width: | Height: | Size: 6.8 KiB |
Before Width: | Height: | Size: 4.4 KiB After Width: | Height: | Size: 4.4 KiB |
BIN
src/assets/css/libs/jquery/images/ui-icons_666666_256x240.png
Normal file
After Width: | Height: | Size: 6.8 KiB |
Before Width: | Height: | Size: 6.8 KiB |
Before Width: | Height: | Size: 4.4 KiB |
Before Width: | Height: | Size: 4.4 KiB |
Before Width: | Height: | Size: 4.4 KiB |
Before Width: | Height: | Size: 6.8 KiB |
Before Width: | Height: | Size: 4.4 KiB After Width: | Height: | Size: 4.4 KiB |
BIN
src/assets/css/libs/jquery/images/ui-icons_fa6676_256x240.png
Normal file
After Width: | Height: | Size: 4.4 KiB |
Before Width: | Height: | Size: 4.4 KiB |
Before Width: | Height: | Size: 6.2 KiB |
6
src/assets/css/libs/jquery/jquery-ui.min.css
vendored
|
@ -38,7 +38,7 @@ body {
|
||||||
}
|
}
|
||||||
|
|
||||||
#book-appointment #book-steps {
|
#book-appointment #book-steps {
|
||||||
width: 252px;
|
width: 204px;
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
float: right;
|
float: right;
|
||||||
margin-top: 15px;
|
margin-top: 15px;
|
||||||
|
@ -46,7 +46,21 @@ body {
|
||||||
|
|
||||||
#book-appointment .book-appoinment-step {
|
#book-appointment .book-appoinment-step {
|
||||||
padding: 10px 20px;
|
padding: 10px 20px;
|
||||||
height: 363px;
|
height: 434px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#book-appointment .book-appoinment-step .book-step-content {
|
||||||
|
height: 370px;
|
||||||
|
margin-bottom: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#book-appointment .command-buttons {
|
||||||
|
float: right;
|
||||||
|
}
|
||||||
|
|
||||||
|
#book-appointment .command-buttons .btn {
|
||||||
|
min-width: 80px;
|
||||||
|
margin-right: 10px;
|
||||||
}
|
}
|
||||||
|
|
||||||
#book-appointment .book-step {
|
#book-appointment .book-step {
|
||||||
|
@ -55,20 +69,34 @@ body {
|
||||||
width: 20px;
|
width: 20px;
|
||||||
float: left;
|
float: left;
|
||||||
background: #FFF;
|
background: #FFF;
|
||||||
padding: 10px;
|
padding: 3px;
|
||||||
margin-right: 15px;
|
margin-right: 15px;
|
||||||
|
margin-top: 10px;
|
||||||
border: 3px solid #38A07A;
|
border: 3px solid #38A07A;
|
||||||
}
|
}
|
||||||
|
|
||||||
#book-appointment .book-step strong {
|
#book-appointment .book-step strong {
|
||||||
font-size: 25px;
|
font-size: 18px;
|
||||||
display: block;
|
display: block;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
color: #B6DFC6;
|
color: #B6DFC6;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#book-appointment .active-step {
|
||||||
|
display: inline-block;
|
||||||
|
height: 20px;
|
||||||
|
width: 20px;
|
||||||
|
float: left;
|
||||||
|
background: #FFF;
|
||||||
|
padding: 10px;
|
||||||
|
margin-right: 15px;
|
||||||
|
margin-top: 0px;
|
||||||
|
border: 3px solid #38A07A;
|
||||||
|
}
|
||||||
|
|
||||||
#book-appointment .active-step strong {
|
#book-appointment .active-step strong {
|
||||||
color: #396946;
|
color: #396946;
|
||||||
|
font-size: 25px;
|
||||||
}
|
}
|
||||||
|
|
||||||
#book-appointment #frame-footer {
|
#book-appointment #frame-footer {
|
||||||
|
@ -82,6 +110,12 @@ body {
|
||||||
border-width: 2px;
|
border-width: 2px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#available-hours .available-hour {
|
||||||
|
font-size: 15px;
|
||||||
|
padding: 1px;
|
||||||
|
display: inline-block;
|
||||||
|
}
|
||||||
|
|
||||||
#available-hours .available-hour:hover {
|
#available-hours .available-hour:hover {
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
background-color: #CAEDF3;
|
background-color: #CAEDF3;
|
||||||
|
@ -93,3 +127,7 @@ body {
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
text-decoration: underline;
|
text-decoration: underline;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#book-appointment .span3 {
|
||||||
|
min-width: 270px; /* This is especially needed for ie8 */
|
||||||
|
}
|
||||||
|
|
BIN
src/assets/images/success.png
Normal file
After Width: | Height: | Size: 5.8 KiB |
283
src/assets/js/frontend/book-appointment.js
Normal file
|
@ -0,0 +1,283 @@
|
||||||
|
/**
|
||||||
|
* This class implements the book appointment page functionality.
|
||||||
|
* Once the initialize() method is called the page is fully functional
|
||||||
|
* and can serve the appointment booking process.
|
||||||
|
*
|
||||||
|
* @class Implelements the js part of the appointment booking page.
|
||||||
|
*/
|
||||||
|
var bookAppointment = {
|
||||||
|
/**
|
||||||
|
* This method initializes the book appointment page.
|
||||||
|
*/
|
||||||
|
initialize : function() {
|
||||||
|
// Initialize page components.
|
||||||
|
$('.book-step').qtip({
|
||||||
|
position: {
|
||||||
|
my: 'top center',
|
||||||
|
at: 'bottom center'
|
||||||
|
},
|
||||||
|
style: {
|
||||||
|
classes: 'qtip-green qtip-shadow custom-qtip'
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
$('#select-date').datepicker({
|
||||||
|
//dateFormat : 'dd/mm/yy',
|
||||||
|
minDate : 0,
|
||||||
|
defaultDate : Date.today(),
|
||||||
|
onSelect : function(dateText, inst) {
|
||||||
|
bookAppointment.refreshAvailableHours(dateText);
|
||||||
|
bookAppointment.updateConfirmData();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Bind event handlers.
|
||||||
|
bookAppointment.bindEventHandlers();
|
||||||
|
|
||||||
|
// Execute other necessary operations.
|
||||||
|
$('#select-service').trigger('change');
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This method binds the necessary event handlers
|
||||||
|
* for the book appointments page.
|
||||||
|
*/
|
||||||
|
bindEventHandlers : function() {
|
||||||
|
/**
|
||||||
|
* Event : Selected Provider "Changed"
|
||||||
|
*/
|
||||||
|
$('#select-provider').change(function() {
|
||||||
|
bookAppointment.refreshAvailableHours(Date.today().toString('MM/dd/yyyy'));
|
||||||
|
bookAppointment.updateConfirmData();
|
||||||
|
});
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Event : Selected Service "Changed"
|
||||||
|
*
|
||||||
|
* When the user clicks on a service, its available providers should
|
||||||
|
* become visible.
|
||||||
|
*/
|
||||||
|
$('#select-service').change(function() {
|
||||||
|
var currServiceId = $('#select-service').val();
|
||||||
|
$('#select-provider').empty();
|
||||||
|
|
||||||
|
$.each(GlobalVariables.providers, function(indexProvider, provider) {
|
||||||
|
$.each(provider['services'], function(indexService, serviceId) {
|
||||||
|
if (serviceId == currServiceId) {
|
||||||
|
// This provider can provide the selected service.
|
||||||
|
// Add him to the list box.
|
||||||
|
var optionHtml = '<option value="' + provider['id'] + '">' + provider['last_name']
|
||||||
|
+ ' ' + provider['first_name'] + '</option>';
|
||||||
|
$('#select-provider').append(optionHtml);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
bookAppointment.refreshAvailableHours(Date.today().toString('MM/dd/yyyy'));
|
||||||
|
bookAppointment.updateConfirmData();
|
||||||
|
});
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Event : Next Step Button "Clicked"
|
||||||
|
*/
|
||||||
|
$('.button-next').click(function() {
|
||||||
|
// If we are on the 3rd tab then we will need to validate the user's
|
||||||
|
// input.
|
||||||
|
if ($(this).attr('data-step_index') == 3) {
|
||||||
|
if (!bookAppointment.validateCustomerDataForm()) {
|
||||||
|
return; // Do not continue.
|
||||||
|
} else {
|
||||||
|
bookAppointment.updateConfirmData();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
var nextTabIndex = parseInt($(this).attr('data-step_index')) + 1;
|
||||||
|
|
||||||
|
$(this).parents().eq(1).hide('fade', function() {
|
||||||
|
$('.active-step').removeClass('active-step');
|
||||||
|
$('#step-' + nextTabIndex).addClass('active-step');
|
||||||
|
$('#book-appointment-' + nextTabIndex).show('fade');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Event : Back Step Button "Clicked"
|
||||||
|
*/
|
||||||
|
$('.button-back').click(function() {
|
||||||
|
var prevTabIndex = parseInt($(this).attr('data-step_index')) - 1;
|
||||||
|
|
||||||
|
$(this).parents().eq(1).hide('fade', function() {
|
||||||
|
$('.active-step').removeClass('active-step');
|
||||||
|
$('#step-' + prevTabIndex).addClass('active-step');
|
||||||
|
$('#book-appointment-' + prevTabIndex).show('fade');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Event : Available Hour "Click"
|
||||||
|
*/
|
||||||
|
$('#available-hours').on('click', '.available-hour', function() {
|
||||||
|
$('.selected-hour').removeClass('selected-hour');
|
||||||
|
$(this).addClass('selected-hour');
|
||||||
|
bookAppointment.updateConfirmData();
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This function makes an ajax call and returns the available
|
||||||
|
* hours for the selected service, provider and date.
|
||||||
|
*
|
||||||
|
* @param {string} selDate The selected date of which the available
|
||||||
|
* hours we need to receive.
|
||||||
|
*/
|
||||||
|
refreshAvailableHours : function(selDate) {
|
||||||
|
// Fetch the available hours of the current date
|
||||||
|
// for the chosen service and provider.
|
||||||
|
var selServiceDuration = 15; // Default duration.
|
||||||
|
$.each(GlobalVariables.services, function(index, service) {
|
||||||
|
if (service['id'] == $('#select-service').val()) {
|
||||||
|
selServiceDuration = service['duration'];
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
var postData = {
|
||||||
|
'serviceId' : $('#select-service').val(),
|
||||||
|
'providerId' : $('#select-provider').val(),
|
||||||
|
'selectedDate' : selDate,
|
||||||
|
'serviceDuration' : selServiceDuration
|
||||||
|
};
|
||||||
|
|
||||||
|
// Make ajax post request and get the available hours.
|
||||||
|
var ajaxurl = GlobalVariables.baseUrl + 'index.php/appointments/getAvailableHours';
|
||||||
|
jQuery.post(ajaxurl, postData, function(postResponse) {
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
//console.log('\n\n Get Available Hours Post Response :', postResponse, '\n\n');
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
try {
|
||||||
|
var jsonResponse = jQuery.parseJSON(postResponse);
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
//console.log('\n\n Get Available Hours JSON Response :', jsonResponse, '\n\n');
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
// Fill the available time div
|
||||||
|
var currColumn = 1;
|
||||||
|
$('#available-hours').html('<div style="width:50px; float:left;"></div>');
|
||||||
|
$.each(jsonResponse, function(index, availableHour) {
|
||||||
|
if ((currColumn * 10) < (index + 1)) {
|
||||||
|
currColumn++;
|
||||||
|
$('#available-hours').append('<div style="width:50px; float:left;"></div>');
|
||||||
|
}
|
||||||
|
|
||||||
|
$('#available-hours div:eq(' + (currColumn - 1) + ')')
|
||||||
|
.append('<span class="available-hour">' + availableHour + '</span><br/>');
|
||||||
|
});
|
||||||
|
|
||||||
|
// Set the first item as selected.
|
||||||
|
$('.available-hour:eq(0)').addClass('selected-hour');
|
||||||
|
bookAppointment.updateConfirmData();
|
||||||
|
|
||||||
|
} catch(exception) {
|
||||||
|
// @task Display message to the user.
|
||||||
|
};
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This function validates the customer's data input.
|
||||||
|
* It only checks for empty fields by the time.
|
||||||
|
*
|
||||||
|
* @return {bool} Returns the validation result.
|
||||||
|
*/
|
||||||
|
validateCustomerDataForm : function() {
|
||||||
|
var validationResult = true;
|
||||||
|
$('.required').css('border', '');
|
||||||
|
|
||||||
|
$('.required').each(function() {
|
||||||
|
if ($(this).val() == '') {
|
||||||
|
validationResult = false;
|
||||||
|
$(this).css('border', '2px solid red');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return validationResult;
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Every time this function is executed, it updates the confirmation
|
||||||
|
* page with the latest customer settigns and input for the appointment
|
||||||
|
* booking.
|
||||||
|
*/
|
||||||
|
updateConfirmData : function() {
|
||||||
|
/*** SET APPOINTMENT INFO ***/
|
||||||
|
var selectedDate = $('#select-date').datepicker('getDate');
|
||||||
|
if (selectedDate != null) {
|
||||||
|
selectedDate = Date.parse(selectedDate).toString('dd/MM/yyyy');
|
||||||
|
}
|
||||||
|
|
||||||
|
$('#appointment-info').html(
|
||||||
|
'<h4>' + $('#select-service option:selected').text() + '</h4>' +
|
||||||
|
$('#select-provider option:selected').text() + '<br/>' +
|
||||||
|
'<strong class="text-info">' + selectedDate + ' ' + $('.selected-hour').text() + '</strong>'
|
||||||
|
);
|
||||||
|
|
||||||
|
/*** SET CUSTOMER'S INFO ***/
|
||||||
|
$('#customer-info').html(
|
||||||
|
'<h4>' + $('#last-name').val() + ' ' + $('#first-name').val() + '</h4>' +
|
||||||
|
'Phone: ' + $('#phone-number').val() + '<br/>' +
|
||||||
|
'Email: ' + $('#email').val() + '<br/>' +
|
||||||
|
'Address: ' + $('#address').val() + '<br/>' +
|
||||||
|
'City: ' + $('#city').val() + '<br/>' +
|
||||||
|
'Zip Code: ' + $('#zip-code').val()
|
||||||
|
);
|
||||||
|
|
||||||
|
/*** UPDATE HIDDEN FIELD VALUES ***/
|
||||||
|
$('input[name="lastName"]').val($('#last-name').val());
|
||||||
|
$('input[name="firstName"]').val($('#first-name').val());
|
||||||
|
$('input[name="email"]').val($('#email').val());
|
||||||
|
$('input[name="phoneNumber"]').val($('#phone-number').val());
|
||||||
|
$('input[name="address"]').val($('#address').val());
|
||||||
|
$('input[name="city"]').val($('#city').val());
|
||||||
|
$('input[name="zipCode"]').val($('#zip-code').val());
|
||||||
|
|
||||||
|
var startDatetime = $('#select-date').datepicker('getDate').toString('yyyy-MM-dd') + ' ' + $('.selected-hour').text();
|
||||||
|
var endDatetime = bookAppointment.getEndDatetime();
|
||||||
|
$('input[name="startDatetime"]').val(startDatetime);
|
||||||
|
$('input[name="endDatetime"]').val(endDatetime);
|
||||||
|
$('input[name="notes"]').val($('#notes').val());
|
||||||
|
$('input[name="providerId"]').val($('#select-provider').val());
|
||||||
|
$('input[name="serviceId"]').val($('#select-service').val());
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This method calculates the end datetime of the current appointment.
|
||||||
|
* End datetime is depending on the service and start datetime fieldss.
|
||||||
|
*
|
||||||
|
* @return {string} Returns the end datetime in string format.
|
||||||
|
*/
|
||||||
|
getEndDatetime : function() {
|
||||||
|
// Find selected service duration.
|
||||||
|
var selServiceDuration = undefined;
|
||||||
|
|
||||||
|
$.each(GlobalVariables.services, function(index, service) {
|
||||||
|
if (service.id == $('#select-service').val()) {
|
||||||
|
selServiceDuration = service.duration;
|
||||||
|
return; // Stop searching ...
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Add the duration to the start datetime.
|
||||||
|
var startDatetime = $('#select-date').datepicker('getDate').toString('MM/dd/yyyy') + ' ' + $('.selected-hour').text();
|
||||||
|
startDatetime = Date.parseExact(startDatetime, 'MM/dd/yyyy HH:mm');
|
||||||
|
var endDatetime = undefined;
|
||||||
|
|
||||||
|
if (selServiceDuration != undefined && startDatetime != null) {
|
||||||
|
endDatetime = startDatetime.add({ minutstartDatetimees : parseInt(selServiceDuration) });
|
||||||
|
} else {
|
||||||
|
endDatetime = new Date();
|
||||||
|
}
|
||||||
|
|
||||||
|
return endDatetime.toString('yyyy-MM-dd HH:mm');
|
||||||
|
}
|
||||||
|
}
|