The main purpose of the code below is for a booking session. Each time I click on the book a session button on the pop-up modal window I get Server Error The booking service is currently unavailable. Please try again later or contact support.
–booking.php–
<?php
// booking.php
require_once 'config.php';
use PHPMailerPHPMailerPHPMailer;
use PHPMailerPHPMailerException;
require __DIR__ . '/../assets/vendor/autoload.php';
header('Content-Type: application/json; charset=UTF-8');
header('Access-Control-Allow-Origin: *');
header('Access-Control-Allow-Methods: POST, OPTIONS');
header('Access-Control-Allow-Headers: Content-Type, X-Requested-With');
header('Access-Control-Allow-Credentials: true');
// Handle preflight OPTIONS
if ($_SERVER['REQUEST_METHOD'] === 'OPTIONS') {
http_response_code(200);
exit;
}
if ($_SERVER['REQUEST_METHOD'] !== 'POST') {
echo json_encode(["status" => "error", "message" => "Invalid request method"]);
exit;
}
// Parse JSON
$raw = file_get_contents("php://input");
$input = json_decode($raw, true);
if (!$input) {
echo json_encode([
"status" => "error",
"message" => "Invalid or empty JSON",
"debug" => (APP_ENV === 'development' ? $raw : null)
]);
exit;
}
// Required fields
$required = ['full_name', 'email', 'phone', 'subject', 'session_type', 'date', 'time', 'details'];
foreach ($required as $field) {
if (empty($input[$field])) {
echo json_encode([
"status" => "error",
"message" => "Missing required field: $field",
"debug" => (APP_ENV === 'development' ? $input : null)
]);
exit;
}
}
// Core fields
$full_name = trim($input['full_name']);
$email = filter_var($input['email'], FILTER_VALIDATE_EMAIL);
$phone = trim($input['phone']);
$subject = trim($input['subject']);
$session_type = trim($input['session_type']);
$date = $input['date'];
$time = $input['time'];
$details = trim($input['details']);
$role = $input['role'] ?? null;
if (!$email) {
echo json_encode(["status" => "error", "message" => "Invalid email address"]);
exit;
}
// Optional fields (set null if missing)
$optionalFields = [
'current_challenges','personal_goals','group_size','group_type','group_objectives',
'institution_type','institution_name','educational_goals','org_size','org_sector',
'dev_focus','leadership_level','leadership_challenges','dev_areas','transformation_scope',
'current_state','desired_outcome','timeline'
];
foreach ($optionalFields as $field) {
$$field = $input[$field] ?? null;
}
try {
// Save booking
$stmt = $pdo->prepare("INSERT INTO bookings
(full_name,email,phone,subject,session_type,date,time,details,role,
current_challenges,personal_goals,group_size,group_type,group_objectives,
institution_type,institution_name,educational_goals,
org_size,org_sector,dev_focus,
leadership_level,leadership_challenges,dev_areas,
transformation_scope,current_state,desired_outcome,timeline)
VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)");
$stmt->execute([
$full_name, $email, $phone, $subject, $session_type, $date, $time, $details, $role,
$current_challenges,$personal_goals,$group_size,$group_type,$group_objectives,
$institution_type,$institution_name,$educational_goals,
$org_size,$org_sector,$dev_focus,
$leadership_level,$leadership_challenges,$dev_areas,
$transformation_scope,$current_state,$desired_outcome,$timeline
]);
$booking_id = $pdo->lastInsertId();
// Send Admin Email
try {
$mail = new PHPMailer(true);
$mail->isSMTP();
$mail->Host = 'smtp.gmail.com';
$mail->SMTPAuth = true;
$mail->Username = MAIL_FROM;
$mail->Password = MAIL_PASS;
$mail->SMTPSecure = PHPMailer::ENCRYPTION_STARTTLS;
$mail->Port = 587;
$mail->setFrom(MAIL_FROM, 'Booking System');
$mail->addAddress(MAIL_TO);
$mail->isHTML(true);
$mail->Subject = "New Booking (#$booking_id): $session_type by $full_name";
$mail->Body = "
<h2>New Booking Received</h2>
<p><strong>Name:</strong> $full_name</p>
<p><strong>Email:</strong> $email</p>
<p><strong>Phone:</strong> $phone</p>
<p><strong>Subject:</strong> $subject</p>
<p><strong>Session:</strong> $session_type</p>
<p><strong>Date:</strong> $date</p>
<p><strong>Time:</strong> $time</p>
<p><strong>Details:</strong><br>" . nl2br($details) . "</p>";
$mail->send();
} catch (Exception $e) {
error_log("Email Error (Admin): " . $e->getMessage());
echo json_encode(["status"=>"error","message"=>"Email error (admin)","debug"=>(APP_ENV==='development'?$e->getMessage():null)]);
exit;
}
// Send Customer Confirmation
try {
$mail = new PHPMailer(true);
$mail->isSMTP();
$mail->Host = 'smtp.gmail.com';
$mail->SMTPAuth = true;
$mail->Username = MAIL_FROM;
$mail->Password = MAIL_PASS;
$mail->SMTPSecure = PHPMailer::ENCRYPTION_STARTTLS;
$mail->Port = 587;
$mail->setFrom(MAIL_FROM, '360 Sages');
$mail->addAddress($email);
$mail->isHTML(true);
$mail->Subject = "Booking Confirmation - $session_type";
$mail->Body = "
<h2>Hello $full_name,</h2>
<p>Thank you for booking a <strong>$session_type</strong> session with us.</p>
<p><strong>Date:</strong> $date</p>
<p><strong>Time:</strong> $time</p>
<p>We’ll contact you soon with further details.</p>
<br>
<p>Best regards,<br>360 Sages Team</p>";
$mail->send();
} catch (Exception $e) {
error_log("Email Error (Customer): " . $e->getMessage());
echo json_encode(["status"=>"error","message"=>"Email error (customer)","debug"=>(APP_ENV==='development'?$e->getMessage():null)]);
exit;
}
echo json_encode(["status"=>"success","message"=>"Booking submitted successfully!"]);
} catch (PDOException $e) {
error_log("Database Error: " . $e->getMessage());
echo json_encode([
"status" => "error",
"message" => "Database error while saving booking",
"debug" => (APP_ENV === 'development' ? $e->getMessage() : null)
]);
exit;
}
--script.js--
document.addEventListener("DOMContentLoaded", function () {
const bookingForm = document.getElementById("bookingForm");
const sessionTypeSelect = document.getElementById("session_type");
// Inject CSS for shake + label highlight + SweetAlert error color + success glow
if (!document.getElementById("error-style")) {
const style = document.createElement("style");
style.id = "error-style";
style.textContent = `
.field-error {
border: 2px solid red !important;
animation: shake 0.3s ease-in-out;
}
.label-error {
color: red !important;
font-weight: bold;
}
.form-success {
animation: glowSuccess 1s ease-in-out;
}
.swal2-popup.swal2-toast .swal2-title,
.swal2-popup .swal2-title,
.swal2-popup .swal2-html-container {
color: red !important;
}
@keyframes shake {
0% { transform: translateX(0); }
25% { transform: translateX(-5px); }
50% { transform: translateX(5px); }
75% { transform: translateX(-5px); }
100% { transform: translateX(0); }
}
@keyframes glowSuccess {
0% { box-shadow: 0 0 0px rgba(0,255,0,0); }
50% { box-shadow: 0 0 15px rgba(0,255,0,0.7); }
100% { box-shadow: 0 0 0px rgba(0,255,0,0); }
}
`;
document.head.appendChild(style);
}
if (bookingForm) {
bookingForm.addEventListener("submit", async (e) => {
e.preventDefault();
const formDataObj = {};
const invalidFields = [];
function getFieldLabel(el) {
const label = bookingForm.querySelector(`label[for="${el.id}"]`);
return label ? label.textContent.trim() : el.name.replace("_", " ");
}
bookingForm.querySelectorAll("input, textarea, select").forEach((el) => {
if (el.name) {
const value = el.value.trim();
formDataObj[el.name] = value;
const label = bookingForm.querySelector(`label[for="${el.id}"]`);
if (label) label.classList.remove("label-error");
el.classList.remove("field-error");
if (el.hasAttribute("required") && !value) {
invalidFields.push({ field: el, message: `${getFieldLabel(el)} is required.` });
}
if (el.type === "email" && value) {
const emailRegex = /^[^s@]+@[^s@]+.[^s@]+$/;
if (!emailRegex.test(value)) {
invalidFields.push({ field: el, message: `Please enter a valid ${getFieldLabel(el)}.` });
}
}
if (el.type === "tel" && value) {
const phoneDigits = value.replace(/D/g, "");
if (phoneDigits.length < 7) {
invalidFields.push({ field: el, message: `${getFieldLabel(el)} must have at least 7 digits.` });
}
}
}
});
formDataObj.session_type = sessionTypeSelect.value;
for (const invalid of invalidFields) {
const field = invalid.field;
const label = bookingForm.querySelector(`label[for="${field.id}"]`);
field.classList.add("field-error");
if (label) label.classList.add("label-error");
field.scrollIntoView({ behavior: "smooth", block: "center" });
await Swal.fire({
icon: "error",
title: "Invalid Field",
html: `<span style="color:red; font-weight:bold;">⚠️ ${invalid.message}</span>`,
confirmButtonColor: "#152942",
didClose: () => {
field.focus();
field.classList.remove("field-error");
if (label) label.classList.remove("label-error");
},
});
}
if (invalidFields.length > 0) return;
Swal.fire({
title: "Submitting...",
text: "Please wait while we process your booking.",
allowOutsideClick: false,
didOpen: () => Swal.showLoading(),
});
try {
const apiUrl = new URL(
"includes/booking.php",
window.location.origin + window.location.pathname
).href;
const response = await fetch(apiUrl, {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify(formDataObj),
});
const result = await response.json();
if (result.status === "success") {
window.scrollTo({ top: 0, behavior: "smooth" });
// Add subtle green glow animation
bookingForm.classList.add("form-success");
setTimeout(() => bookingForm.classList.remove("form-success"), 1000);
Swal.fire({
icon: "success",
title: "Booking Confirmed",
text: result.message,
confirmButtonColor: "#152942",
});
bookingForm.reset();
if (typeof closeModal === "function") closeModal();
} else {
let errorMsg = "Booking failed. Please try again.";
if (result.message.includes("Database")) errorMsg = "Database Error: Unable to save your booking.";
else if (result.message.includes("Email error (admin)")) errorMsg = "Email Error: Failed to notify admin.";
else if (result.message.includes("Email error (customer)")) errorMsg = "Email Error: Failed to send confirmation to your email.";
Swal.fire({
icon: "error",
title: "Error",
html: `<span style="color:red; font-weight:bold;">${errorMsg}</span>`,
confirmButtonColor: "#152942",
});
if (result.debug) console.error("Debug Info:", result.debug);
}
} catch (error) {
console.error("Error:", error);
Swal.fire({
icon: "error",
title: "Server Error",
html: `<span style="color:red; font-weight:bold;">⚠️ The booking service is unavailable.</span>`,
confirmButtonColor: "#152942",
});
}
});
}
}
);