diff --git a/application/controllers/Pages.php b/application/controllers/Pages.php index 68f9662..1b2a9b7 100755 --- a/application/controllers/Pages.php +++ b/application/controllers/Pages.php @@ -315,7 +315,7 @@ class Pages extends CI_Controller { * form is a normal full-page POST, so whatever this outputs is what the * customer actually sees in their browser. */ - private function _booking_error($errorCode, $statusCode = 409){ + private function _booking_error($errorCode, $statusCode = 409, $backUrl = ''){ $this->load->helper('url'); $lang = vertical_lang(isset($_POST['lang']) ? $_POST['lang'] : ''); @@ -332,7 +332,10 @@ class Pages extends CI_Controller { 'selectedLang' => $lang, 'subpage' => $vertical['slug'], 'vertical' => $vertical, - 'bookingErrorCode' => $errorCode + 'bookingErrorCode' => $errorCode, + // Manage-booking errors must return the guest to their own manage page, + // not to a fresh booking form. Empty = the new-booking default. + 'bookingBackUrl' => $backUrl ); $this->output->set_status_header($statusCode); @@ -854,10 +857,14 @@ class Pages extends CI_Controller { // wrong vertical's branding. $serviceIds = unserialize($booking->service_ids); $subpage = 'barber'; + $firstService = NULL; if(is_array($serviceIds)){ foreach($serviceIds as $serviceIdItem){ $resolvedService = $this->Service_model->getServiceById($serviceIdItem); if($resolvedService && $resolvedService->service_type !== ''){ + // Kept for the worker filter below: the category (and therefore the + // capability check) is derived from this same resolved service. + $firstService = $resolvedService; $subpage = $resolvedService->service_type; break; } @@ -893,7 +900,7 @@ class Pages extends CI_Controller { // Filter workers to those qualified for the booking's service category, // so the guest can't switch to a worker who doesn't perform these services. $categorySlug = ''; - if(isset($firstService) && $firstService){ + if($firstService){ $category = $this->Service_model->getServiceCategoryById($firstService->service_category_id); if($category){ $categorySlug = $category->serv_cat_slug; @@ -928,11 +935,17 @@ class Pages extends CI_Controller { return; } + // This form is a normal POST, not AJAX, so every rejection below is rendered + // as the shared booking error page. Returning raw JSON showed the guest an + // unstyled {"error":...} blob after they had filled the whole form in. + // Use the stored token, not the posted one: it is echoed straight into the + // error page's back link. + $manageBackUrl = SITEURL.vertical_lang(isset($_POST['lang']) ? $_POST['lang'] : '').'/manage-booking/'.$booking->manage_token; + $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.'])); + $this->_booking_error('cutoff_passed', 403, $manageBackUrl); return; } @@ -963,8 +976,7 @@ class Pages extends CI_Controller { if(!empty($selectedServiceArray) && $submittedWorker){ $firstSelectedService = $this->Service_model->getServiceById($selectedServiceArray[0]); if($firstSelectedService && $firstSelectedService->service_category_id != $submittedWorker->service_category_id){ - $this->output->set_status_header(403)->set_content_type('application/json') - ->set_output(json_encode(['error' => 'Selected worker does not perform the chosen services.'])); + $this->_booking_error('category_mismatch', 403, $manageBackUrl); return; } } @@ -973,26 +985,22 @@ class Pages extends CI_Controller { // category check proves only that the services belong to the worker's // category, not that this worker performs them. if(!$this->Service_model->workerCanPerformServices($newWorkerId, $selectedServiceArray)){ - $this->output->set_status_header(403)->set_content_type('application/json') - ->set_output(json_encode(['error' => 'Selected worker does not perform the chosen services.'])); + $this->_booking_error('service_not_offered', 403, $manageBackUrl); return; } // Schedule check $schedule = $this->Service_model->getWorkerScheduleForDate($newWorkerId, $newBookingDate); 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.'])); + $this->_booking_error('worker_unavailable', 403, $manageBackUrl); 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.'])); + $this->_booking_error('outside_schedule', 403, $manageBackUrl); 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.'])); + $this->_booking_error('alternate_week', 403, $manageBackUrl); return; } @@ -1000,8 +1008,7 @@ class Pages extends CI_Controller { $available = $this->Service_model->getAvailableTimes($newWorkerId, $newBookingDate, $servicelength, $booking->booking_id); 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.'])); + $this->_booking_error('slot_taken', 409, $manageBackUrl); return; } @@ -1010,8 +1017,7 @@ class Pages extends CI_Controller { $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.'])); + $this->_booking_error('too_far', 403, $manageBackUrl); return; } @@ -1023,8 +1029,7 @@ class Pages extends CI_Controller { $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.'])); + $this->_booking_error('after_hours', 403, $manageBackUrl); return; } $finishTime = $bookingEnd->format('H:i:s'); @@ -1186,8 +1191,7 @@ class Pages extends CI_Controller { $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.'])); + $this->_booking_error('cutoff_passed', 403, SITEURL.vertical_lang($lang).'/manage-booking/'.$booking->manage_token); return; } diff --git a/application/views/pages/includes/booking-error-form-en.php b/application/views/pages/includes/booking-error-form-en.php index 5d942a5..0608a0d 100755 --- a/application/views/pages/includes/booking-error-form-en.php +++ b/application/views/pages/includes/booking-error-form-en.php @@ -10,6 +10,7 @@ 'service_not_offered' => 'The selected staff member does not perform all of the chosen treatments. Please pick another staff member or change the treatments.', 'single_service_only' => 'Only one treatment can be booked at a time. Please select just one.', 'invalid_email' => 'That e-mail address does not look valid. Please check it - your confirmation and the link to manage your booking are sent there.', + 'cutoff_passed' => 'Your booking is within 24 hours and can no longer be changed or cancelled. Please contact the salon.', 'no_service' => 'No service was selected. Please choose at least one service.', 'default' => 'Something went wrong with your booking. Please try again.', ); @@ -19,12 +20,24 @@ : $bookingErrorMessages['default']; $backSubpage = isset($subpage) && $subpage != '' ? $subpage : 'barber'; - $backUrl = SITEURL.'en/booking/'.$backSubpage; + + // _booking_error() passes a back URL when the error came from the + // manage-booking flow; that guest must return to their own booking page + // rather than being dropped into an empty new-booking form. + $isManageError = isset($bookingBackUrl) && $bookingBackUrl !== ''; + $backUrl = $isManageError ? $bookingBackUrl : SITEURL.'en/booking/'.$backSubpage; + $backLabel = $isManageError ? 'Back to your booking' : 'Back to booking'; + + if(isset($bookingErrorCode) && $bookingErrorCode === 'slot_taken'){ + $errorTitle = 'This time is no longer available'; + } else { + $errorTitle = $isManageError ? 'Your booking could not be changed' : 'Your booking could not be completed'; + } ?>
-
This time is no longer available
+
- Back to booking +
diff --git a/application/views/pages/includes/booking-error-form-hu.php b/application/views/pages/includes/booking-error-form-hu.php index 84d67a6..bd35bc8 100755 --- a/application/views/pages/includes/booking-error-form-hu.php +++ b/application/views/pages/includes/booking-error-form-hu.php @@ -10,6 +10,7 @@ 'service_not_offered' => 'A kiválasztott kolléga nem végzi el az összes kiválasztott szolgáltatást. Kérjük, válasszon másik kollégát, vagy módosítsa a szolgáltatásokat.', 'single_service_only' => 'Egyszerre csak egy kezelés foglalható. Kérjük, csak egyet válasszon.', 'invalid_email' => 'Az e-mail cím nem tűnik érvényesnek. Kérjük, ellenőrizze - a visszaigazolást és a foglalás kezelésére szolgáló linket erre a címre küldjük.', + 'cutoff_passed' => 'A foglalás 24 órán belül van, ezért már nem módosítható és nem törölhető. Kérjük, vedd fel a kapcsolatot a szalonnal.', 'no_service' => 'Nem választott ki szolgáltatást. Kérjük, válasszon legalább egyet.', 'default' => 'Hiba történt a foglalás során. Kérjük, próbálja újra.', ); @@ -19,12 +20,24 @@ : $bookingErrorMessages['default']; $backSubpage = isset($subpage) && $subpage != '' ? $subpage : 'barber'; - $backUrl = SITEURL.'hu/booking/'.$backSubpage; + + // _booking_error() passes a back URL when the error came from the + // manage-booking flow; that guest must return to their own booking page + // rather than being dropped into an empty new-booking form. + $isManageError = isset($bookingBackUrl) && $bookingBackUrl !== ''; + $backUrl = $isManageError ? $bookingBackUrl : SITEURL.'hu/booking/'.$backSubpage; + $backLabel = $isManageError ? 'Vissza a foglalásodhoz' : 'Vissza a foglaláshoz'; + + if(isset($bookingErrorCode) && $bookingErrorCode === 'slot_taken'){ + $errorTitle = 'Ez az időpont már nem foglalható'; + } else { + $errorTitle = $isManageError ? 'A foglalást nem sikerült módosítani' : 'A foglalást nem sikerült véglegesíteni'; + } ?>
-
Ez az időpont már nem foglalható
+
- Vissza a foglaláshoz +
diff --git a/application/views/pages/includes/booking-error-form-no.php b/application/views/pages/includes/booking-error-form-no.php index ef8e172..22eeae3 100755 --- a/application/views/pages/includes/booking-error-form-no.php +++ b/application/views/pages/includes/booking-error-form-no.php @@ -10,6 +10,7 @@ 'service_not_offered' => 'Den valgte medarbeideren utfører ikke alle de valgte behandlingene. Vennligst velg en annen medarbeider eller endre behandlingene.', 'single_service_only' => 'Du kan kun bestille én behandling om gangen. Vennligst velg kun én.', 'invalid_email' => 'E-postadressen ser ikke ut til å være gyldig. Vennligst kontroller den - bekreftelsen og lenken for å endre bestillingen sendes dit.', + 'cutoff_passed' => 'Bestillingen er innen 24 timer og kan ikke lenger endres eller avbestilles. Vennligst ta kontakt med salongen.', 'no_service' => 'Du har ikke valgt noen tjeneste. Vennligst velg minst én tjeneste.', 'default' => 'Noe gikk galt med bestillingen. Vennligst prøv igjen.', ); @@ -19,12 +20,24 @@ : $bookingErrorMessages['default']; $backSubpage = isset($subpage) && $subpage != '' ? $subpage : 'barber'; - $backUrl = SITEURL.'no/booking/'.$backSubpage; + + // _booking_error() passes a back URL when the error came from the + // manage-booking flow; that guest must return to their own booking page + // rather than being dropped into an empty new-booking form. + $isManageError = isset($bookingBackUrl) && $bookingBackUrl !== ''; + $backUrl = $isManageError ? $bookingBackUrl : SITEURL.'no/booking/'.$backSubpage; + $backLabel = $isManageError ? 'Tilbake til bestillingen din' : 'Tilbake til bestilling'; + + if(isset($bookingErrorCode) && $bookingErrorCode === 'slot_taken'){ + $errorTitle = 'Tidspunktet er ikke lenger tilgjengelig'; + } else { + $errorTitle = $isManageError ? 'Bestillingen kunne ikke endres' : 'Bestillingen kunne ikke fullføres'; + } ?>
-
Tidspunktet er ikke lenger tilgjengelig
+
- Tilbake til bestilling +
diff --git a/application/views/pages/manage-booking.php b/application/views/pages/manage-booking.php index d0b1dd9..fee2d8d 100755 --- a/application/views/pages/manage-booking.php +++ b/application/views/pages/manage-booking.php @@ -30,6 +30,7 @@ 'back' => 'Tilbake', 'send' => 'Bekreft endring', 'no_times' => 'Ingen ledige tider denne dagen!', + 'no_workers' => 'Ingen medarbeidere utfører alle de valgte tjenestene.', 'expired_msg' => 'Denne bestillingen er allerede passert og kan ikke endres.', 'cutoff_msg' => 'Bestillingen er innen 24 timer og kan ikke endres eller avbestilles.', ), @@ -53,6 +54,7 @@ 'back' => 'Vissza', 'send' => 'Módosítás megerősítése', 'no_times' => 'Ezen a napon nincs szabad időpont!', + 'no_workers' => 'Egyik kolléga sem végzi el az összes kiválasztott szolgáltatást.', '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ő.', ), @@ -76,6 +78,7 @@ 'back' => 'Back', 'send' => 'Confirm changes', 'no_times' => 'There is no available time on this day!', + 'no_workers' => 'No staff member performs all of the selected services.', '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.', ), @@ -246,6 +249,7 @@ onsubmit="return confirm('');"> + @@ -445,6 +449,7 @@