guest booking self-management feature + layout fixes
- add manage_token column to bookings (DB migration done) - generate unique token per booking, include manage link in confirmation emails (no/en/hu) - new routes: manage-booking, manage-booking-process, manage-booking-cancel - new views: manage-booking.php, manage-booking-cancelled.php - 24h cutoff enforcement for cancel/modify; emails sent to guest + studio CC - fix manage-booking step 3 float layout (overflow:auto BFC clearfix) - fix booking page time slot overflow: bookingResultsWrapper 378px -> 360px Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -94,30 +94,6 @@ $route['bookings'] = 'admin/bookings';
|
||||
$route['bookings/add-booking'] = 'admin/add_booking';
|
||||
$route['bookings/update-booking/(:any)'] = 'admin/update_booking/$1';
|
||||
$route['bookings/booking-process'] = 'admin/booking_process';
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
$route['(:any)/manage-booking/(:any)'] = 'pages/manage_booking/$1/$2';
|
||||
$route['manage-booking-process'] = 'pages/manage_booking_process';
|
||||
$route['manage-booking-cancel'] = 'pages/manage_booking_cancel';
|
||||
|
||||
@@ -324,6 +324,7 @@ class Pages extends CI_Controller {
|
||||
$servicelength = gmdate('H:i:s', $totalLengthSeconds);
|
||||
|
||||
// 3. Build booking array
|
||||
$manageToken = bin2hex(random_bytes(16));
|
||||
$bookingArray = array(
|
||||
'guest_name' => $_POST['guest_name'],
|
||||
'guest_email' => $_POST['guest_email'],
|
||||
@@ -335,6 +336,7 @@ class Pages extends CI_Controller {
|
||||
'service_ids' => serialize($selectedServiceArray),
|
||||
'guest_confirmed' => '0',
|
||||
'guest_confirm_code' => '1234',
|
||||
'manage_token' => $manageToken,
|
||||
);
|
||||
|
||||
$bookingDate = $bookingArray['booking_date'];
|
||||
@@ -459,6 +461,7 @@ class Pages extends CI_Controller {
|
||||
$content .= '</table></td>';
|
||||
$content .= '<tr><td>Totalpris: </td><td><strong>'.$totalServicePrice.' kr</strong></td></tr>';
|
||||
$content .= '</table>';
|
||||
$content .= '<br /><br /><a href="'.SITEURL.$_POST['lang'].'/manage-booking/'.$manageToken.'">Administrer bestilling</a><br />';
|
||||
$content .= '<br /> Dersom noe skulle dukke opp og du ikke kan komme til avtalen din, vennligst gi oss beskjed minst 24 timer i forveien, slik at vi kan gi timen videre til en annen kunde og våre kollegers tid ikke blir stående ubrukt; avbestillinger innen 24 timer, eller manglende oppmøte, vil bli belastet med full pris for behandlingen; avbestilling kan gjøres via e-post til <a href="mailto:info@studiobeve.no">info@studiobeve.no</a> eller ved å sende oss en melding på Instagram eller Facebook. Takk for forståelsen og samarbeidet!';
|
||||
$content .= '<br />';
|
||||
$content .= '<br /> STUDIOBEVE';
|
||||
@@ -483,6 +486,7 @@ class Pages extends CI_Controller {
|
||||
$content .= '</table></td>';
|
||||
$content .= '<tr><td>Total price: </td><td><strong>'.$totalServicePrice.' kr</strong></td></tr>';
|
||||
$content .= '</table>';
|
||||
$content .= '<br /><br /><a href="'.SITEURL.$_POST['lang'].'/manage-booking/'.$manageToken.'">Manage booking</a><br />';
|
||||
$content .= '<br /> If something comes up and you can’t make it to your booked appointment, please let us know at least 24 hours in advance so we can offer the time slot to another guest and our colleagues’ time won’t remain unused; cancellations within 24 hours or no-shows will be charged the full service fee; you can cancel by emailing <a href="mailto:info@studiobeve.no">info@studiobeve.no</a>, or by sending us a message on Instagram or Facebook. Thank you for your understanding and cooperation!';
|
||||
$content .= '<br />';
|
||||
$content .= '<br /> STUDIOBEVE';
|
||||
@@ -507,6 +511,7 @@ class Pages extends CI_Controller {
|
||||
$content .= '</table></td>';
|
||||
$content .= '<tr><td>Összesen fizetendő: </td><td><strong>'.$totalServicePrice.' kr</strong></td></tr>';
|
||||
$content .= '</table>';
|
||||
$content .= '<br /><br /><a href="'.SITEURL.$_POST['lang'].'/manage-booking/'.$manageToken.'">Foglalás kezelése</a><br />';
|
||||
$content .= '<br /> Kérünk, ha valami közbejön, és mégsem tudsz eljönni a lefoglalt időpontodra, jelezd nekünk legalább 24 órával előre, így más vendégnek is tudunk szabad időpontot biztosítani, és kollégáink ideje sem marad kihasználatlanul; 24 órán belüli lemondás, illetve meg nem jelenés esetén a szolgáltatás teljes díja felszámításra kerül; a lemondást az <a href="mailto:info@studiobeve.no">info@studiobeve.no</a>
|
||||
e-mail címen, vagy Instagram- és Facebook-üzenetben tudod megtenni. Köszönjük a megértést és az együttműködést!';
|
||||
$content .= '<br />';
|
||||
@@ -666,38 +671,284 @@ class Pages extends CI_Controller {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
public function manage_booking($lang, $token){
|
||||
$this->load->helper('url');
|
||||
$this->load->model('Service_model');
|
||||
|
||||
$booking = $this->Service_model->getBookingByToken($token);
|
||||
if(!$booking){
|
||||
show_404();
|
||||
return;
|
||||
}
|
||||
|
||||
// Determine booking type from services
|
||||
$serviceIds = unserialize($booking->service_ids);
|
||||
$subpage = 'barber';
|
||||
if(is_array($serviceIds) && !empty($serviceIds)){
|
||||
$firstService = $this->Service_model->getServiceById($serviceIds[0]);
|
||||
if($firstService){
|
||||
$subpage = $firstService->service_type;
|
||||
}
|
||||
}
|
||||
|
||||
$now = new DateTime('now', new DateTimeZone('Europe/Oslo'));
|
||||
$appointmentDT = new DateTime($booking->booking_date.' '.$booking->booking_start_time, new DateTimeZone('Europe/Oslo'));
|
||||
|
||||
$data['token'] = $token;
|
||||
$data['booking'] = $booking;
|
||||
$data['selectedLang'] = $lang;
|
||||
$data['subpage'] = $subpage;
|
||||
$data['pageTitle'] = '';
|
||||
$data['status'] = 'ok';
|
||||
|
||||
if($appointmentDT < $now){
|
||||
$data['status'] = 'expired';
|
||||
} elseif(($appointmentDT->getTimestamp() - $now->getTimestamp()) < 86400){
|
||||
$data['status'] = 'cutoff';
|
||||
}
|
||||
|
||||
$data['services'] = $this->Service_model->getAllServiceByServiceType($subpage, $lang);
|
||||
$data['workers'] = $this->Service_model->getActiveWorkers($subpage);
|
||||
$data['selectedServiceIds'] = is_array($serviceIds) ? $serviceIds : array();
|
||||
$data['worker'] = $this->Service_model->getWorkerById($booking->worker_id);
|
||||
|
||||
$this->load->view('pages/manage-booking', $data);
|
||||
}
|
||||
|
||||
public function manage_booking_process(){
|
||||
$this->load->helper('url');
|
||||
$this->load->model('Service_model');
|
||||
|
||||
if(!isset($_POST['token']) || !isset($_POST['sendBooking'])){
|
||||
header('Location:'.SITEURL);
|
||||
return;
|
||||
}
|
||||
|
||||
$token = $_POST['token'];
|
||||
$booking = $this->Service_model->getBookingByToken($token);
|
||||
if(!$booking){
|
||||
show_404();
|
||||
return;
|
||||
}
|
||||
|
||||
$now = new DateTime('now', new DateTimeZone('Europe/Oslo'));
|
||||
$appointmentDT = new DateTime($booking->booking_date.' '.$booking->booking_start_time, new DateTimeZone('Europe/Oslo'));
|
||||
if(($appointmentDT->getTimestamp() - $now->getTimestamp()) < 86400){
|
||||
$this->output->set_status_header(403)->set_content_type('application/json')
|
||||
->set_output(json_encode(['error' => 'Modification cutoff has passed.']));
|
||||
return;
|
||||
}
|
||||
|
||||
// Build selected service array and total length
|
||||
$selectedServiceArray = array();
|
||||
$totalLengthSeconds = 0;
|
||||
foreach($_POST as $key => $value){
|
||||
if(strpos($key, 'service_') === 0 && $value == '1'){
|
||||
$serviceId = str_replace('service_', '', $key);
|
||||
$selectedServiceArray[] = $serviceId;
|
||||
$service = $this->Service_model->getServiceById($serviceId);
|
||||
if($service){
|
||||
$parts = explode(':', $service->service_time);
|
||||
$totalLengthSeconds += ($parts[0] * 3600) + ($parts[1] * 60);
|
||||
}
|
||||
}
|
||||
}
|
||||
$servicelength = gmdate('H:i:s', $totalLengthSeconds);
|
||||
|
||||
$newBookingDate = $_POST['booking_date'];
|
||||
$newStartTime = $_POST['booking_start_time'];
|
||||
$newWorkerId = $_POST['worker_id'];
|
||||
$lang = $_POST['lang'];
|
||||
$subpage = $_POST['subpage'];
|
||||
|
||||
// Schedule check
|
||||
$weekday = date('w', strtotime($newBookingDate));
|
||||
$schedule = $this->Service_model->getWorkerScheduleByDay($newWorkerId, $weekday);
|
||||
if(!$schedule){
|
||||
$this->output->set_status_header(403)->set_content_type('application/json')
|
||||
->set_output(json_encode(['error' => 'Worker is not available on this day.']));
|
||||
return;
|
||||
}
|
||||
if($newStartTime < $schedule->start_time || $newStartTime >= $schedule->end_time){
|
||||
$this->output->set_status_header(403)->set_content_type('application/json')
|
||||
->set_output(json_encode(['error' => 'Booking time is outside worker schedule.']));
|
||||
return;
|
||||
}
|
||||
if(!$this->Service_model->isWorkerAvailableThisWeek($newWorkerId, $newBookingDate)){
|
||||
$this->output->set_status_header(403)->set_content_type('application/json')
|
||||
->set_output(json_encode(['error' => 'Worker only works every second week.']));
|
||||
return;
|
||||
}
|
||||
|
||||
// Slot availability (temporarily exclude current booking)
|
||||
$this->Service_model->updateBooking($booking->booking_id, ['booking_date' => '1970-01-01']);
|
||||
$available = $this->Service_model->getAvailableTimes($newWorkerId, $newBookingDate, $servicelength);
|
||||
$this->Service_model->updateBooking($booking->booking_id, ['booking_date' => $booking->booking_date]);
|
||||
|
||||
if(!is_array($available) || !in_array($newStartTime, $available)){
|
||||
$this->output->set_status_header(409)->set_content_type('application/json')
|
||||
->set_output(json_encode(['error' => 'Conflict. Timeslot is taken or does not fit the service.']));
|
||||
return;
|
||||
}
|
||||
|
||||
// 3-month limit
|
||||
$today = new DateTime();
|
||||
$maxDate = (clone $today)->modify('+3 months');
|
||||
$selectedDate = new DateTime($newBookingDate);
|
||||
if($selectedDate > $maxDate){
|
||||
$this->output->set_status_header(403)->set_content_type('application/json')
|
||||
->set_output(json_encode(['error' => 'Bookings can only be made up to 3 months in advance.']));
|
||||
return;
|
||||
}
|
||||
|
||||
// Calculate finish time
|
||||
$bookingStart = new DateTime($newStartTime);
|
||||
$bookingLength = new DateTime($servicelength);
|
||||
$bookingEnd = clone $bookingStart;
|
||||
$bookingEnd->add(new DateInterval('PT'.intval($bookingLength->format('H')).'H'));
|
||||
$bookingEnd->add(new DateInterval('PT'.intval($bookingLength->format('i')).'M'));
|
||||
$closingTime = new DateTime('18:00');
|
||||
if($bookingEnd > $closingTime){
|
||||
$this->output->set_status_header(403)->set_content_type('application/json')
|
||||
->set_output(json_encode(['error' => 'Selected time exceeds business hours.']));
|
||||
return;
|
||||
}
|
||||
$finishTime = $bookingEnd->format('H:i:s');
|
||||
|
||||
// Update booking
|
||||
$this->Service_model->updateBooking($booking->booking_id, array(
|
||||
'worker_id' => $newWorkerId,
|
||||
'booking_date' => $newBookingDate,
|
||||
'booking_start_time' => $newStartTime,
|
||||
'booking_finish_time' => $finishTime,
|
||||
'service_ids' => serialize($selectedServiceArray),
|
||||
));
|
||||
|
||||
$worker = $this->Service_model->getWorkerById($newWorkerId);
|
||||
$serviceArray = array();
|
||||
foreach($selectedServiceArray as $serviceItem){
|
||||
$sel = $this->Service_model->getServiceById($serviceItem);
|
||||
if(is_object($sel)) $serviceArray[] = $sel;
|
||||
}
|
||||
|
||||
$manageLink = SITEURL.$lang.'/manage-booking/'.$token;
|
||||
$totalServicePrice = 0;
|
||||
foreach($serviceArray as $s){ $totalServicePrice += $s->service_price; }
|
||||
|
||||
switch($lang){
|
||||
case 'no':
|
||||
$subject = '[studiobeve] Din bestilling er oppdatert';
|
||||
$content = 'Kjære gjest,<br />Din bestilling er oppdatert.<br /><br />';
|
||||
$content .= '<table>';
|
||||
$content .= '<tr><td>Arbeider: </td><td>'.$worker->worker_name.'</td></tr>';
|
||||
$content .= '<tr><td>Dato: </td><td>'.$newBookingDate.'</td></tr>';
|
||||
$content .= '<tr><td>Tid: </td><td>'.$newStartTime.' - '.$finishTime.'</td></tr>';
|
||||
$content .= '<tr><td>Tjenester: </td><td><table>';
|
||||
foreach($serviceArray as $s){ $content .= '<tr><td>'.$s->service_name_no.'</td><td>'.$s->service_price.' kr</td></tr>'; }
|
||||
$content .= '</table></td><tr><td>Totalpris: </td><td><strong>'.$totalServicePrice.' kr</strong></td></tr></table>';
|
||||
$content .= '<br /><br /><a href="'.$manageLink.'">Administrer bestilling</a>';
|
||||
$content .= '<br /><br /> STUDIOBEVE';
|
||||
break;
|
||||
case 'hu':
|
||||
$subject = '[studiobeve] A foglalásod módosítva lett';
|
||||
$content = 'Kedves Vendégünk,<br />A foglalásod módosítva lett.<br /><br />';
|
||||
$content .= '<table>';
|
||||
$content .= '<tr><td>Dolgozó: </td><td>'.$worker->worker_name.'</td></tr>';
|
||||
$content .= '<tr><td>Dátum: </td><td>'.$newBookingDate.'</td></tr>';
|
||||
$content .= '<tr><td>Időpont: </td><td>'.$newStartTime.' - '.$finishTime.'</td></tr>';
|
||||
$content .= '<tr><td>Szolgáltatás(ok): </td><td><table>';
|
||||
foreach($serviceArray as $s){ $content .= '<tr><td>'.$s->service_name_hu.'</td><td>'.$s->service_price.' kr</td></tr>'; }
|
||||
$content .= '</table></td><tr><td>Összesen: </td><td><strong>'.$totalServicePrice.' kr</strong></td></tr></table>';
|
||||
$content .= '<br /><br /><a href="'.$manageLink.'">Foglalás kezelése</a>';
|
||||
$content .= '<br /><br /> STUDIOBEVE';
|
||||
break;
|
||||
default:
|
||||
$subject = '[studiobeve] Your booking has been updated';
|
||||
$content = 'Dear Guest,<br />Your booking has been updated.<br /><br />';
|
||||
$content .= '<table>';
|
||||
$content .= '<tr><td>Worker: </td><td>'.$worker->worker_name.'</td></tr>';
|
||||
$content .= '<tr><td>Date: </td><td>'.$newBookingDate.'</td></tr>';
|
||||
$content .= '<tr><td>Time: </td><td>'.$newStartTime.' - '.$finishTime.'</td></tr>';
|
||||
$content .= '<tr><td>Services: </td><td><table>';
|
||||
foreach($serviceArray as $s){ $content .= '<tr><td>'.$s->service_name_en.'</td><td>'.$s->service_price.' kr</td></tr>'; }
|
||||
$content .= '</table></td><tr><td>Total price: </td><td><strong>'.$totalServicePrice.' kr</strong></td></tr></table>';
|
||||
$content .= '<br /><br /><a href="'.$manageLink.'">Manage booking</a>';
|
||||
$content .= '<br /><br /> STUDIOBEVE';
|
||||
}
|
||||
|
||||
$emailArray = array(array(
|
||||
'addressee_email' => $booking->guest_email,
|
||||
'addressee_name' => $booking->guest_name,
|
||||
'subject' => $subject,
|
||||
'content' => $content,
|
||||
'attachments' => array()
|
||||
));
|
||||
$this->load->model('User_model');
|
||||
$this->User_model->sendEmail($emailArray, $lang, '');
|
||||
|
||||
header('Location:'.SITEURL.$lang.'/booking-finished/'.$subpage);
|
||||
}
|
||||
|
||||
public function manage_booking_cancel(){
|
||||
$this->load->helper('url');
|
||||
$this->load->model('Service_model');
|
||||
$this->load->model('User_model');
|
||||
|
||||
if(!isset($_POST['token'])){
|
||||
header('Location:'.SITEURL);
|
||||
return;
|
||||
}
|
||||
|
||||
$token = $_POST['token'];
|
||||
$lang = isset($_POST['lang']) ? $_POST['lang'] : 'en';
|
||||
$booking = $this->Service_model->getBookingByToken($token);
|
||||
if(!$booking){
|
||||
show_404();
|
||||
return;
|
||||
}
|
||||
|
||||
$now = new DateTime('now', new DateTimeZone('Europe/Oslo'));
|
||||
$appointmentDT = new DateTime($booking->booking_date.' '.$booking->booking_start_time, new DateTimeZone('Europe/Oslo'));
|
||||
if(($appointmentDT->getTimestamp() - $now->getTimestamp()) < 86400){
|
||||
$this->output->set_status_header(403)->set_content_type('application/json')
|
||||
->set_output(json_encode(['error' => 'Cancellation cutoff has passed.']));
|
||||
return;
|
||||
}
|
||||
|
||||
$worker = $this->Service_model->getWorkerById($booking->worker_id);
|
||||
|
||||
switch($lang){
|
||||
case 'no':
|
||||
$subject = '[studiobeve] Din bestilling er avbestilt';
|
||||
$content = 'Kjære gjest,<br />Din reservasjon den '.$booking->booking_date.' kl. '.date('H:i', strtotime($booking->booking_start_time)).' med '.$worker->worker_name.' er avbestilt.<br /><br /> STUDIOBEVE';
|
||||
break;
|
||||
case 'hu':
|
||||
$subject = '[studiobeve] A foglalásod törölve lett';
|
||||
$content = 'Kedves Vendégünk,<br />A '.$booking->booking_date.' '.$booking->booking_start_time.'-os foglalásod '.$worker->worker_name.'-nál törölve lett.<br /><br /> STUDIOBEVE';
|
||||
break;
|
||||
default:
|
||||
$subject = '[studiobeve] Your booking has been cancelled';
|
||||
$content = 'Dear Guest,<br />Your booking on '.$booking->booking_date.' at '.date('H:i', strtotime($booking->booking_start_time)).' with '.$worker->worker_name.' has been cancelled.<br /><br /> STUDIOBEVE';
|
||||
}
|
||||
|
||||
$emailArray = array(array(
|
||||
'addressee_email' => $booking->guest_email,
|
||||
'addressee_name' => $booking->guest_name,
|
||||
'subject' => $subject,
|
||||
'content' => $content,
|
||||
'attachments' => array()
|
||||
));
|
||||
$this->User_model->sendEmail($emailArray, $lang, '');
|
||||
|
||||
$this->Service_model->deleteBooking($booking->booking_id);
|
||||
|
||||
$data['selectedLang'] = $lang;
|
||||
$data['booking'] = $booking;
|
||||
$data['worker'] = $worker;
|
||||
$data['pageTitle'] = '';
|
||||
$this->load->view('pages/manage-booking-cancelled', $data);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -531,15 +531,16 @@ class Service_model extends CI_Model {
|
||||
$this->load->database();
|
||||
$query = $this->db->query("INSERT INTO bookings (
|
||||
guest_name,
|
||||
guest_email,
|
||||
guest_phone,
|
||||
guest_email,
|
||||
guest_phone,
|
||||
worker_id,
|
||||
booking_date,
|
||||
booking_start_time,
|
||||
booking_finish_time,
|
||||
service_ids,
|
||||
guest_confirmed,
|
||||
guest_confirm_code
|
||||
guest_confirm_code,
|
||||
manage_token
|
||||
) VALUES(
|
||||
'".$bookingArray['guest_name']."',
|
||||
'".$bookingArray['guest_email']."',
|
||||
@@ -550,9 +551,16 @@ class Service_model extends CI_Model {
|
||||
'".$bookingArray['booking_finish_time']."',
|
||||
'".$bookingArray['service_ids']."',
|
||||
'".$bookingArray['guest_confirmed']."',
|
||||
'".$bookingArray['guest_confirm_code']."'
|
||||
'".$bookingArray['guest_confirm_code']."',
|
||||
'".$bookingArray['manage_token']."'
|
||||
);");
|
||||
}
|
||||
|
||||
public function getBookingByToken($token){
|
||||
$this->load->database();
|
||||
$query = $this->db->query('SELECT * FROM bookings WHERE manage_token = "'.$this->db->escape_str($token).'" LIMIT 1;');
|
||||
return $query->num_rows() > 0 ? $query->result()[0] : false;
|
||||
}
|
||||
|
||||
public function getWorkerSchedule($worker_id) {
|
||||
return $this->db
|
||||
|
||||
@@ -0,0 +1,44 @@
|
||||
<?php
|
||||
// Determine subpage from the booking's service type to pick correct skeleton
|
||||
$serviceIds = unserialize($booking->service_ids);
|
||||
$subpage = 'barber';
|
||||
if(is_array($serviceIds) && !empty($serviceIds)){
|
||||
$firstService = $this->Service_model->getServiceById($serviceIds[0]);
|
||||
if($firstService) $subpage = $firstService->service_type;
|
||||
}
|
||||
|
||||
if($subpage == 'beauty'){
|
||||
include(getcwd().'/application/views/includes/beauty-skeleton-top.php');
|
||||
} else {
|
||||
include(getcwd().'/application/views/includes/barber-skeleton-top.php');
|
||||
}
|
||||
|
||||
$messages = array(
|
||||
'no' => 'Din bestilling den <strong>'.$booking->booking_date.'</strong> kl. <strong>'.date('H:i', strtotime($booking->booking_start_time)).'</strong> med <strong>'.$worker->worker_name.'</strong> er avbestilt.',
|
||||
'en' => 'Your booking on <strong>'.$booking->booking_date.'</strong> at <strong>'.date('H:i', strtotime($booking->booking_start_time)).'</strong> with <strong>'.$worker->worker_name.'</strong> has been cancelled.',
|
||||
'hu' => 'A <strong>'.$booking->booking_date.'</strong> <strong>'.date('H:i', strtotime($booking->booking_start_time)).'</strong>-os foglalásod <strong>'.$worker->worker_name.'</strong>-nál törölve lett.',
|
||||
);
|
||||
|
||||
$titles = array(
|
||||
'no' => 'Bestilling avbestilt',
|
||||
'en' => 'Booking cancelled',
|
||||
'hu' => 'Foglalás törölve',
|
||||
);
|
||||
|
||||
$lang = $selectedLang;
|
||||
$msg = isset($messages[$lang]) ? $messages[$lang] : $messages['en'];
|
||||
$title = isset($titles[$lang]) ? $titles[$lang] : $titles['en'];
|
||||
?>
|
||||
|
||||
<div class="bookingContainer" style="min-height:400px; padding:20px;">
|
||||
<div class="bookingThankYouTitle"><?php echo $title; ?></div>
|
||||
<div class="bookingThankYouMessageTitle" style="margin-top:15px;"><?php echo $msg; ?></div>
|
||||
</div>
|
||||
|
||||
<?php
|
||||
if($subpage == 'beauty'){
|
||||
include(getcwd().'/application/views/includes/beauty-skeleton-bottom.php');
|
||||
} else {
|
||||
include(getcwd().'/application/views/includes/barber-skeleton-bottom.php');
|
||||
}
|
||||
?>
|
||||
@@ -0,0 +1,637 @@
|
||||
<?php
|
||||
if($subpage == 'beauty'){
|
||||
include(getcwd().'/application/views/includes/beauty-skeleton-top.php');
|
||||
} else {
|
||||
include(getcwd().'/application/views/includes/barber-skeleton-top.php');
|
||||
}
|
||||
|
||||
$lang = $selectedLang;
|
||||
|
||||
$labels = array(
|
||||
'no' => array(
|
||||
'title' => 'Administrer bestilling',
|
||||
'current' => 'Din nåværende bestilling',
|
||||
'date' => 'Dato',
|
||||
'time' => 'Tid',
|
||||
'worker' => 'Arbeider',
|
||||
'services' => 'Tjenester',
|
||||
'total' => 'Totalpris',
|
||||
'cancel_btn' => 'Avbestill bestillingen',
|
||||
'cancel_confirm' => 'Er du sikker på at du vil avbestille bestillingen?',
|
||||
'modify_title' => 'Endre bestilling',
|
||||
'step1' => 'TRINN 1',
|
||||
'step2' => 'TRINN 2',
|
||||
'step3' => 'TRINN 3',
|
||||
'services_label' => 'Tjenester',
|
||||
'choose_worker' => 'Velg en arbeider',
|
||||
'next' => 'Neste',
|
||||
'back' => 'Tilbake',
|
||||
'send' => 'Bekreft endring',
|
||||
'no_times' => 'Ingen ledige tider denne dagen!',
|
||||
'expired_msg' => 'Denne bestillingen er allerede passert og kan ikke endres.',
|
||||
'cutoff_msg' => 'Bestillingen er innen 24 timer og kan ikke endres eller avbestilles.',
|
||||
),
|
||||
'hu' => array(
|
||||
'title' => 'Foglalás kezelése',
|
||||
'current' => 'Jelenlegi foglalásod',
|
||||
'date' => 'Dátum',
|
||||
'time' => 'Időpont',
|
||||
'worker' => 'Dolgozó',
|
||||
'services' => 'Szolgáltatás(ok)',
|
||||
'total' => 'Összesen',
|
||||
'cancel_btn' => 'Foglalás törlése',
|
||||
'cancel_confirm' => 'Biztosan törölni szeretnéd a foglalást?',
|
||||
'modify_title' => 'Foglalás módosítása',
|
||||
'step1' => '1. LÉPÉS',
|
||||
'step2' => '2. LÉPÉS',
|
||||
'step3' => '3. LÉPÉS',
|
||||
'services_label' => 'Szolgáltatások',
|
||||
'choose_worker' => 'Válassz dolgozót',
|
||||
'next' => 'Tovább',
|
||||
'back' => 'Vissza',
|
||||
'send' => 'Módosítás megerősítése',
|
||||
'no_times' => 'Ezen a napon nincs szabad időpont!',
|
||||
'expired_msg' => 'Ez a foglalás már elmúlt, nem módosítható.',
|
||||
'cutoff_msg' => 'A foglalás 24 órán belül van, nem módosítható vagy törölhető.',
|
||||
),
|
||||
'en' => array(
|
||||
'title' => 'Manage Booking',
|
||||
'current' => 'Your current booking',
|
||||
'date' => 'Date',
|
||||
'time' => 'Time',
|
||||
'worker' => 'Worker',
|
||||
'services' => 'Services',
|
||||
'total' => 'Total price',
|
||||
'cancel_btn' => 'Cancel booking',
|
||||
'cancel_confirm' => 'Are you sure you want to cancel your booking?',
|
||||
'modify_title' => 'Modify booking',
|
||||
'step1' => 'STEP 1',
|
||||
'step2' => 'STEP 2',
|
||||
'step3' => 'STEP 3',
|
||||
'services_label' => 'Services',
|
||||
'choose_worker' => 'Choose a worker',
|
||||
'next' => 'Next',
|
||||
'back' => 'Back',
|
||||
'send' => 'Confirm changes',
|
||||
'no_times' => 'There is no available time on this day!',
|
||||
'expired_msg' => 'This booking has already passed and cannot be modified.',
|
||||
'cutoff_msg' => 'Your booking is within 24 hours and can no longer be changed or cancelled.',
|
||||
),
|
||||
);
|
||||
|
||||
$l = isset($labels[$lang]) ? $labels[$lang] : $labels['en'];
|
||||
?>
|
||||
|
||||
<style>
|
||||
/* ── Manage-booking overrides ───────────────────────────────────────────── */
|
||||
|
||||
/* Navigation buttons: use normal flow instead of position:absolute */
|
||||
#manageForm .bookingButtonContainer {
|
||||
position: static;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
padding: 15px 10px 10px;
|
||||
height: auto;
|
||||
}
|
||||
#manageForm .bookingButton,
|
||||
#manageForm .leftButton,
|
||||
#manageForm .rightButton {
|
||||
position: static;
|
||||
}
|
||||
|
||||
/* Worker table: allow natural height for pre-rendered workers */
|
||||
#manageForm .workerTable {
|
||||
height: auto;
|
||||
margin-bottom: 20px;
|
||||
width: 100%;
|
||||
max-width: 500px;
|
||||
}
|
||||
|
||||
/* Step 3: overflow:auto creates a BFC that contains floated children */
|
||||
#manageForm #bookingStep3 {
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
/* Summary table */
|
||||
.manage-summary-table {
|
||||
width: 100%;
|
||||
max-width: 540px;
|
||||
margin: 0 auto;
|
||||
border-collapse: collapse;
|
||||
}
|
||||
.manage-summary-table td {
|
||||
padding: 8px 12px;
|
||||
border: 1px solid #e0c5bb;
|
||||
vertical-align: top;
|
||||
}
|
||||
.manage-summary-table td:first-child {
|
||||
font-weight: bold;
|
||||
white-space: nowrap;
|
||||
width: 130px;
|
||||
background: #fdf5f2;
|
||||
}
|
||||
.manage-summary-box {
|
||||
background: #fdf5f2;
|
||||
border-radius: 6px;
|
||||
padding: 20px;
|
||||
margin: 15px auto;
|
||||
max-width: 580px;
|
||||
text-align: left;
|
||||
}
|
||||
.manage-summary-title {
|
||||
text-align: center;
|
||||
font-size: 1.1em;
|
||||
color: #a5705b;
|
||||
margin-bottom: 14px;
|
||||
letter-spacing: 0.05em;
|
||||
text-transform: uppercase;
|
||||
}
|
||||
.manage-cancel-bar {
|
||||
text-align: center;
|
||||
margin: 20px auto;
|
||||
max-width: 580px;
|
||||
}
|
||||
.manage-cancel-btn {
|
||||
background: #7a3a2a;
|
||||
color: #fff;
|
||||
border: none;
|
||||
padding: 11px 28px;
|
||||
border-radius: 4px;
|
||||
cursor: pointer;
|
||||
font-size: 0.85em;
|
||||
letter-spacing: 0.08em;
|
||||
text-transform: uppercase;
|
||||
}
|
||||
.manage-cancel-btn:hover {
|
||||
background: #5e2a1a;
|
||||
}
|
||||
.manage-divider {
|
||||
border: none;
|
||||
border-top: 1px solid #d9b8ac;
|
||||
margin: 30px auto;
|
||||
max-width: 580px;
|
||||
}
|
||||
.manage-modify-title {
|
||||
font-size: 1em;
|
||||
text-align: center;
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.08em;
|
||||
color: #a5705b;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
/* ─────────────────────────────────────────────────────────────────────── */
|
||||
</style>
|
||||
|
||||
<div class="bookingContainer">
|
||||
<div class="bookingTitle"><?php echo $l['title']; ?></div>
|
||||
|
||||
<?php if($status == 'expired'): ?>
|
||||
<p style="color:#c0392b; text-align:center; margin-top:30px; padding:20px;"><?php echo $l['expired_msg']; ?></p>
|
||||
|
||||
<?php elseif($status == 'cutoff'): ?>
|
||||
<p style="color:#c0392b; text-align:center; margin-top:30px; padding:20px;"><?php echo $l['cutoff_msg']; ?></p>
|
||||
|
||||
<?php else: ?>
|
||||
|
||||
<!-- Current booking summary -->
|
||||
<div class="manage-summary-box">
|
||||
<div class="manage-summary-title"><?php echo $l['current']; ?></div>
|
||||
<table class="manage-summary-table">
|
||||
<tr>
|
||||
<td><?php echo $l['date']; ?></td>
|
||||
<td><?php echo $booking->booking_date; ?></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><?php echo $l['time']; ?></td>
|
||||
<td><?php echo date('H:i', strtotime($booking->booking_start_time)); ?> – <?php echo date('H:i', strtotime($booking->booking_finish_time)); ?></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><?php echo $l['worker']; ?></td>
|
||||
<td><?php echo htmlspecialchars($worker->worker_name); ?></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><?php echo $l['services']; ?></td>
|
||||
<td>
|
||||
<?php
|
||||
$totalPrice = 0;
|
||||
$serviceIds = unserialize($booking->service_ids);
|
||||
if(is_array($serviceIds)){
|
||||
echo '<ul style="margin:0; padding-left:16px;">';
|
||||
foreach($serviceIds as $sid){
|
||||
$svc = $this->Service_model->getServiceById($sid);
|
||||
if($svc){
|
||||
$name = ($lang == 'hu') ? $svc->service_name_hu : (($lang == 'no') ? $svc->service_name_no : $svc->service_name_en);
|
||||
$totalPrice += $svc->service_price;
|
||||
echo '<li>'.htmlspecialchars($name).' — '.$svc->service_price.' kr</li>';
|
||||
}
|
||||
}
|
||||
echo '</ul>';
|
||||
}
|
||||
?>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><?php echo $l['total']; ?></td>
|
||||
<td><strong><?php echo $totalPrice; ?> kr</strong></td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<!-- Cancel -->
|
||||
<div class="manage-cancel-bar">
|
||||
<form method="post" action="<?php echo SITEURL; ?>manage-booking-cancel"
|
||||
onsubmit="return confirm('<?php echo addslashes($l['cancel_confirm']); ?>');">
|
||||
<input type="hidden" name="token" value="<?php echo htmlspecialchars($token); ?>">
|
||||
<input type="hidden" name="lang" value="<?php echo htmlspecialchars($lang); ?>">
|
||||
<button type="submit" class="manage-cancel-btn"><?php echo $l['cancel_btn']; ?></button>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<hr class="manage-divider">
|
||||
|
||||
<!-- Modify section -->
|
||||
<div class="manage-modify-title"><?php echo $l['modify_title']; ?></div>
|
||||
|
||||
<ul class="steps-indicator steps-3">
|
||||
<li>
|
||||
<div class="stepTitleContainer">
|
||||
<div class="stepLine"></div>
|
||||
<div class="stepCircle activeStep" id="stepCircle1"></div>
|
||||
<div class="stepTitle"><?php echo $l['step1']; ?></div>
|
||||
</div>
|
||||
</li>
|
||||
<li>
|
||||
<div class="stepTitleContainer">
|
||||
<div class="stepLine"></div>
|
||||
<div class="stepCircle" id="stepCircle2"></div>
|
||||
<div class="stepTitle"><?php echo $l['step2']; ?></div>
|
||||
</div>
|
||||
</li>
|
||||
<li>
|
||||
<div class="stepTitleContainer">
|
||||
<div class="stepCircle" id="stepCircle3"></div>
|
||||
<div class="stepTitle"><?php echo $l['step3']; ?></div>
|
||||
</div>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<div class="totalPanelContainer">
|
||||
<div id="totalPanel" style="display:none;">
|
||||
<div class="serviceBookingDateContainer">
|
||||
<div id="serviceBookingDate"></div>
|
||||
<div id="serviceBookingTime"></div>
|
||||
</div>
|
||||
<div class="serviceBookingWorkerContainer"></div>
|
||||
<div class="serviceContent"></div>
|
||||
<div class="totalSelectedTime"></div>
|
||||
<div class="totalPrice"></div>
|
||||
</div>
|
||||
<div id="totalPanelBtnContainer">
|
||||
<div id="totalPanelBtn" style="display:none;"><i class="fas fa-caret-right"></i></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<form method="post" action="<?php echo SITEURL; ?>manage-booking-process" id="manageForm">
|
||||
<input type="hidden" name="token" value="<?php echo htmlspecialchars($token); ?>">
|
||||
<input type="hidden" name="lang" value="<?php echo htmlspecialchars($lang); ?>">
|
||||
<input type="hidden" name="subpage" value="<?php echo htmlspecialchars($subpage); ?>">
|
||||
<input type="hidden" name="sendBooking" value="1">
|
||||
|
||||
<!-- Step 1: Services -->
|
||||
<div class="BookingStepContainer" id="bookingStep1">
|
||||
<div class="totalTime"><input type="time" id="servicelength" name="servicelength" value="00:00"></div>
|
||||
|
||||
<div class="bookingTable">
|
||||
<div class="panel panel-primary">
|
||||
<div class="panel-heading"><?php echo $l['services_label']; ?></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="serviceTable">
|
||||
<div class="serviceHeader">
|
||||
<div class="serviceCol serviceNameCol">Service name</div>
|
||||
<div class="serviceCol"></div>
|
||||
<div class="serviceCol servicePriceCol">Price</div>
|
||||
<div class="serviceCol serviceInfoCol"></div>
|
||||
<div class="serviceCol serviceCheckCol"></div>
|
||||
</div>
|
||||
<?php
|
||||
function manage_canon_cat($s) {
|
||||
$s = html_entity_decode((string)$s, ENT_QUOTES | ENT_HTML5, 'UTF-8');
|
||||
$s = strip_tags($s);
|
||||
return trim($s);
|
||||
}
|
||||
if(is_array($services) && count($services) > 0){
|
||||
$groups = array();
|
||||
$order = array();
|
||||
foreach($services as $serviceItem){
|
||||
$label = manage_canon_cat($serviceItem->service_category ?? '');
|
||||
if($label === '') $label = 'Other';
|
||||
if(!isset($groups[$label])){ $groups[$label] = array(); $order[] = $label; }
|
||||
$groups[$label][] = $serviceItem;
|
||||
}
|
||||
foreach($order as $label){
|
||||
?>
|
||||
<div class="serviceRow">
|
||||
<div class="serviceCol" style="width:100%"><h4><?php echo htmlspecialchars($label); ?></h4></div>
|
||||
</div>
|
||||
<?php
|
||||
foreach($groups[$label] as $serviceItem){
|
||||
$isChecked = in_array($serviceItem->service_id, $selectedServiceIds);
|
||||
?>
|
||||
<div class="serviceRow">
|
||||
<div class="serviceCol serviceNameCol" id="serviceName_<?php echo $serviceItem->service_id; ?>">
|
||||
<?php echo htmlspecialchars($serviceItem->service_name); ?>
|
||||
</div>
|
||||
<div class="serviceCol">
|
||||
<input type="time" class="serviceTime" id="time_<?php echo $serviceItem->service_id; ?>" value="<?php echo $serviceItem->service_time; ?>"/>
|
||||
</div>
|
||||
<div class="serviceCol servicePriceCol" id="servicePrice_<?php echo $serviceItem->service_id; ?>">
|
||||
<?php echo $serviceItem->service_price; ?>
|
||||
</div>
|
||||
<div class="serviceCol serviceInfoCol">
|
||||
<div class="serviceInfoIcon">
|
||||
<i class="fas fa-info-circle"></i>
|
||||
<div class="serviceInfoLabel"><?php echo htmlspecialchars($serviceItem->service_description); ?></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="serviceCol serviceCheckCol">
|
||||
<input type="hidden" name="service_<?php echo $serviceItem->service_id; ?>" value="0"/>
|
||||
<input type="checkbox"
|
||||
class="service <?php echo $serviceItem->serv_cat_slug; ?>"
|
||||
id="<?php echo $serviceItem->service_id; ?>"
|
||||
name="service_<?php echo $serviceItem->service_id; ?>"
|
||||
value="1"
|
||||
<?php echo $isChecked ? 'checked' : ''; ?>/>
|
||||
</div>
|
||||
</div>
|
||||
<?php
|
||||
}
|
||||
}
|
||||
}
|
||||
?>
|
||||
</div>
|
||||
<div class="bookingButtonContainer">
|
||||
<span></span>
|
||||
<input type="button" class="rightButton bookingButton" onclick="goToStep(2);" value="<?php echo $l['next']; ?>"/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Step 2: Worker -->
|
||||
<div class="BookingStepContainer" id="bookingStep2" style="display:none;">
|
||||
<input type="hidden" name="worker_id" id="worker_id" value="<?php echo $booking->worker_id; ?>">
|
||||
<div class="bookingHeader"><?php echo $l['choose_worker']; ?></div>
|
||||
<div class="workerTable" id="workerTable">
|
||||
<?php
|
||||
if(is_array($workers)){
|
||||
foreach($workers as $workerItem){
|
||||
$isSelected = ($workerItem->worker_id == $booking->worker_id);
|
||||
?>
|
||||
<label for="worker_<?php echo $workerItem->worker_id; ?>">
|
||||
<div class="profileRow">
|
||||
<div class="profileCell profileRadioBtn">
|
||||
<input type="radio" name="worker_radio" class="workers"
|
||||
id="worker_<?php echo $workerItem->worker_id; ?>"
|
||||
onclick="setWorker(<?php echo $workerItem->worker_id; ?>)"
|
||||
<?php echo $isSelected ? 'checked' : ''; ?>>
|
||||
</div>
|
||||
<div class="profileCell profileImage">
|
||||
<img src="<?php echo SITEURL; ?>assets/img/<?php echo $workerItem->worker_profile_img; ?>" style="width:65px;height:65px;border-radius:50%;object-fit:cover;">
|
||||
</div>
|
||||
<div class="profileCell">
|
||||
<div class="profileName"><?php echo htmlspecialchars($workerItem->worker_name); ?></div>
|
||||
<div class="profileDescription"><?php echo htmlspecialchars($workerItem->worker_info); ?></div>
|
||||
</div>
|
||||
</div>
|
||||
</label>
|
||||
<?php
|
||||
}
|
||||
}
|
||||
?>
|
||||
</div>
|
||||
<div class="bookingButtonContainer">
|
||||
<input type="button" class="leftButton bookingButton" onclick="goToStep(1);" value="<?php echo $l['back']; ?>"/>
|
||||
<input type="button" class="rightButton bookingButton" onclick="goToStep(3);" value="<?php echo $l['next']; ?>"/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Step 3: Date & time -->
|
||||
<div class="BookingStepContainer" id="bookingStep3" style="display:none;">
|
||||
<div class="bookingCalendar">
|
||||
<div id="datepicker"></div>
|
||||
</div>
|
||||
<div class="bookingResultsWrapper">
|
||||
<div class="availableTimesContainerTitle"></div>
|
||||
<div class="availableTimesContainer" style="padding:5px;">
|
||||
<input type="hidden" name="booking_date" id="booking_date" value="<?php echo date('Y-m-d'); ?>">
|
||||
<input type="hidden" name="booking_start_time" id="booking_time" value="">
|
||||
<div class="availableTimes"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div style="clear:both;"></div>
|
||||
<div class="bookingButtonContainer">
|
||||
<input type="button" class="leftButton bookingButton" onclick="goToStep(2);" value="<?php echo $l['back']; ?>"/>
|
||||
<input type="submit" class="rightButton bookingButton" id="sendManageBtn" name="sendBooking" value="<?php echo $l['send']; ?>" disabled/>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
var noTimesMsg = '<?php echo addslashes($l['no_times']); ?>';
|
||||
|
||||
$(document).ready(function(){
|
||||
recalcServices();
|
||||
|
||||
$('#totalPanelBtn').click(function(){
|
||||
if($('#totalPanel').is(':visible')){
|
||||
$('#totalPanelBtn').html('<i class="fas fa-caret-left"></i>');
|
||||
$('#totalPanel').hide();
|
||||
$('#totalPanelBtn').css('border-top-left-radius','5px');
|
||||
$('#totalPanelBtn').css('border-bottom-left-radius','5px');
|
||||
} else {
|
||||
$('#totalPanelBtn').html('<i class="fas fa-caret-right"></i>');
|
||||
$('#totalPanel').show();
|
||||
$('#totalPanelBtn').css('border-top-left-radius','0px');
|
||||
$('#totalPanelBtn').css('border-bottom-left-radius','0px');
|
||||
}
|
||||
});
|
||||
|
||||
$('.service').click(function(){
|
||||
recalcServices();
|
||||
if($('.service').is(':checked')){
|
||||
var selectedClasses = $(this).attr('class');
|
||||
var selectedclassesArray = selectedClasses.split(' ');
|
||||
$('.service').each(function(){
|
||||
var actualElementArray = $(this).attr('class').split(' ');
|
||||
if(selectedclassesArray[1] !== actualElementArray[1]){
|
||||
$(this).attr('disabled', true);
|
||||
}
|
||||
});
|
||||
getAvailableWorkersByServiceCategorySlug(selectedclassesArray[1]);
|
||||
} else {
|
||||
$('.service').attr('disabled', false);
|
||||
}
|
||||
});
|
||||
|
||||
$('#booking_time').change(function(){
|
||||
if($(this).val() !== ''){
|
||||
$('#sendManageBtn').prop('disabled', false);
|
||||
} else {
|
||||
$('#sendManageBtn').prop('disabled', true);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
function recalcServices(){
|
||||
var totalPrice = 0;
|
||||
var classIsChecked = 0;
|
||||
$('#servicelength').val('00:00');
|
||||
var selectedServices = '<div class="selectedServiceTable">';
|
||||
selectedServices += '<div class="totalServiceRow serviceHeader"><div class="selectedServiceCol totalSelectedServiceName">Service name</div><div class="selectedServiceCol totalSelectedServicePrice">Price</div></div>';
|
||||
|
||||
$('.service').each(function(){
|
||||
if($(this).is(':checked')){
|
||||
classIsChecked = 1;
|
||||
var selected_id = $(this).attr('id');
|
||||
var priceEl = document.getElementById('servicePrice_'+selected_id).innerHTML.trim();
|
||||
totalPrice += parseInt(priceEl);
|
||||
var nameEl = document.getElementById('serviceName_'+selected_id).innerHTML.trim();
|
||||
selectedServices += '<div class="totalServiceRow"><div class="selectedServiceCol totalSelectedServiceName">'+nameEl+'</div><div class="selectedServiceCol totalSelectedServicePrice">'+priceEl+' kr</div></div>';
|
||||
|
||||
var currentTotal = $('#servicelength').val();
|
||||
var svcDT = new Date('<?php echo date('Y-m-d'); ?> ' + $('#time_'+selected_id).val());
|
||||
var subH = moment.utc(currentTotal,'HH:mm').add(svcDT.getHours(),'hour').format('HH:mm');
|
||||
var subM = moment.utc(subH,'HH:mm').add(svcDT.getMinutes(),'minutes').format('HH:mm');
|
||||
$('#servicelength').val(subM);
|
||||
}
|
||||
});
|
||||
|
||||
selectedServices += '</div>';
|
||||
$('.serviceContent').html(selectedServices);
|
||||
$('.totalPrice').html('<span class="totalTitle">Total:</span> <span>'+totalPrice+'</span><span class="totalTitle"> kr</span>');
|
||||
$('.totalSelectedTime').html('<span class="totalTitle">Total time:</span> <span>'+$('#servicelength').val()+'</span>');
|
||||
|
||||
if(classIsChecked){
|
||||
$('#totalPanelBtn').show();
|
||||
$('#totalPanel').show();
|
||||
} else {
|
||||
$('#totalPanelBtn').hide();
|
||||
$('#totalPanel').hide();
|
||||
}
|
||||
}
|
||||
|
||||
function getAvailableWorkersByServiceCategorySlug(categorySlug){
|
||||
$.ajax({
|
||||
url: '<?php echo base_url(); ?>ajax',
|
||||
type: 'POST',
|
||||
data: { action: 'getAvailableWorkersByServiceCategory', serv_cat_slug: categorySlug },
|
||||
dataType: 'json',
|
||||
}).done(function(result){
|
||||
$('#workerTable').html(result.workerListShow);
|
||||
if(result.workers && result.workers.length > 0){
|
||||
setWorker(result.workers[0].worker_id);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
$(function(){
|
||||
$('#datepicker').datepicker({
|
||||
firstDay: 1,
|
||||
defaultDate: new Date(),
|
||||
dateFormat: 'yy-mm-dd',
|
||||
onSelect: function(dateText){
|
||||
$('#booking_date').val(this.value);
|
||||
$('#sendManageBtn').prop('disabled', true);
|
||||
$('#booking_time').val('');
|
||||
getAvailableTimesOfTheDay(this.value);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
function getAvailableTimesOfTheDay(selectedDate){
|
||||
$('.bookingResultsWrapper').show();
|
||||
$('#serviceBookingDate').html(selectedDate).show();
|
||||
|
||||
$.ajax({
|
||||
url: '<?php echo base_url(); ?>ajax',
|
||||
type: 'POST',
|
||||
data: {
|
||||
action: 'getAvailableTimes',
|
||||
worker_id: $('#worker_id').val(),
|
||||
servicelength: $('#servicelength').val(),
|
||||
selectedDate: selectedDate
|
||||
},
|
||||
}).done(function(result){
|
||||
if(result != 0){
|
||||
$('.availableTimes').html(result);
|
||||
} else {
|
||||
$('.availableTimes').html(noTimesMsg);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function setSelectedTime(time, id){
|
||||
$('#booking_time').val(time).trigger('change');
|
||||
$('#serviceBookingTime').html(time).show();
|
||||
$('.availableBookingTime').removeClass('selectedTime');
|
||||
$('#bookingTime_'+id).addClass('selectedTime');
|
||||
}
|
||||
|
||||
function goToStep(stepNumber){
|
||||
if(canGotoNextStep(stepNumber)){
|
||||
$('.stepCircle').removeClass('activeStep');
|
||||
$('.BookingStepContainer').hide();
|
||||
$('#bookingStep'+stepNumber).show();
|
||||
|
||||
if(stepNumber >= 3){
|
||||
$('#stepCircle1, #stepCircle2, #stepCircle3').addClass('activeStep');
|
||||
if(stepNumber == 3 && $('#datepicker').val() !== ''){
|
||||
getAvailableTimesOfTheDay($('#datepicker').val());
|
||||
}
|
||||
$('.bookingSummaryContainer').show();
|
||||
} else if(stepNumber == 2){
|
||||
$('#stepCircle1, #stepCircle2').addClass('activeStep');
|
||||
$('.bookingResultsWrapper').hide();
|
||||
$('.bookingSummaryContainer').hide();
|
||||
} else {
|
||||
$('#stepCircle1').addClass('activeStep');
|
||||
$('.bookingResultsWrapper').hide();
|
||||
$('.bookingSummaryContainer').hide();
|
||||
}
|
||||
$('html').scrollTop(0);
|
||||
} else {
|
||||
alert('<?php echo ($lang == "no") ? "Vennligst fyll ut de påkrevde feltene!" : (($lang == "hu") ? "Kérjük töltsd ki a kötelező mezőket!" : "Please fill in the required fields!"); ?>');
|
||||
}
|
||||
}
|
||||
|
||||
function canGotoNextStep(stepNumber){
|
||||
if(stepNumber == 1 || stepNumber == 4) return 1;
|
||||
if(stepNumber == 2){
|
||||
var checked = 0;
|
||||
$('.service').each(function(){ if($(this).is(':checked')) checked = 1; });
|
||||
return checked;
|
||||
}
|
||||
if(stepNumber == 3){
|
||||
var checked = 0;
|
||||
$('.workers').each(function(){ if($(this).is(':checked')) checked = 1; });
|
||||
return checked;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
function setWorker(worker_id){
|
||||
$('#worker_id').val(worker_id);
|
||||
$('.serviceBookingWorkerContainer').hide().html('');
|
||||
}
|
||||
</script>
|
||||
|
||||
<?php
|
||||
if($subpage == 'beauty'){
|
||||
include(getcwd().'/application/views/includes/beauty-skeleton-bottom.php');
|
||||
} else {
|
||||
include(getcwd().'/application/views/includes/barber-skeleton-bottom.php');
|
||||
}
|
||||
?>
|
||||
Reference in New Issue
Block a user