Files
MSPE/calendar.html
T

922 lines
38 KiB
HTML
Executable File

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta name="description" content="Schedule a consultation with MSPE. Book an appointment at a time that works for you.">
<title>Book a Consultation | MSPE - Architects of Digital Resilience</title>
<link rel="icon" type="image/png" href="images/logo/logo.png">
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=DM+Sans:wght@400;500;600;700&family=Space+Grotesk:wght@500;600;700&display=swap" rel="stylesheet" media="print" onload="this.media='all'">
<noscript><link href="https://fonts.googleapis.com/css2?family=DM+Sans:wght@400;500;600;700&family=Space+Grotesk:wght@500;600;700&display=swap" rel="stylesheet"></noscript>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.1/css/all.min.css" integrity="sha384-t1nt8BQoYMLFN5p42tRAtuAAFQaCQODekUVeKKZrEnEyp4H2R0RHFz0KWpmj7i8g" crossorigin="anonymous" media="print" onload="this.media='all'">
<noscript><link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.1/css/all.min.css" integrity="sha384-t1nt8BQoYMLFN5p42tRAtuAAFQaCQODekUVeKKZrEnEyp4H2R0RHFz0KWpmj7i8g" crossorigin="anonymous"></noscript>
<link rel="stylesheet" href="css/variables.css">
<link rel="stylesheet" href="css/style.css">
<link rel="stylesheet" href="css/pages.css">
<link rel="stylesheet" href="css/ultimate-ui.css" media="print" onload="this.media='all'">
<noscript><link rel="stylesheet" href="css/ultimate-ui.css"></noscript>
<link rel="canonical" href="https://mspe.pro/calendar.html">
<!-- Open Graph -->
<meta property="og:type" content="website">
<meta property="og:url" content="https://mspe.pro/calendar.html">
<meta property="og:title" content="Book a Consultation | MSPE - Architects of Digital Resilience">
<meta property="og:description" content="Schedule a consultation with MSPE. Choose your preferred date and time for a free discovery meeting.">
<meta property="og:image" content="https://mspe.pro/images/logo/logo.png">
<meta property="og:site_name" content="MSPE">
<!-- Twitter Card -->
<meta name="twitter:card" content="summary_large_image">
<meta name="twitter:site" content="@mspe_pro">
<meta name="twitter:title" content="Book a Consultation with MSPE">
<meta name="twitter:description" content="Schedule a free discovery consultation at a time that works for you.">
<meta name="twitter:image" content="https://mspe.pro/images/logo/logo.png">
<style>
.calendar-wrapper {
background: linear-gradient(135deg, #0a1628 0%, #1a365d 100%);
min-height: calc(100vh - 80px);
padding: calc(80px + 2rem) 0 3rem;
}
.calendar-intro {
text-align: center;
margin-bottom: 2rem;
color: #ffffff;
}
.calendar-intro h1 {
font-size: 2.5rem;
margin-bottom: 0.5rem;
line-height: 1.15;
text-shadow: 0 4px 20px rgba(0, 0, 0, 0.35);
}
.calendar-intro p {
font-size: 1.1rem;
color: #cbd5e1;
}
.calendar-container {
max-width: 1400px;
margin: 0 auto;
padding: 0 1rem;
}
.calendar-grid {
display: grid;
grid-template-columns: 1fr 400px;
gap: 2rem;
}
.calendar-main {
background: rgba(255, 255, 255, 0.03);
backdrop-filter: blur(20px);
border: 1px solid rgba(255, 255, 255, 0.1);
border-radius: 20px;
padding: 2rem;
box-shadow: 0 20px 40px rgba(0,0,0,0.3);
}
.calendar-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 2rem;
padding-bottom: 1rem;
border-bottom: 1px solid rgba(255, 255, 255, 0.1);
}
.calendar-header h2 {
font-size: 1.75rem;
color: #ffffff;
margin: 0;
}
.calendar-nav {
display: flex;
gap: 0.5rem;
}
.calendar-nav button {
padding: 0.5rem 1rem;
border: 1px solid rgba(255, 255, 255, 0.2);
background: rgba(255, 255, 255, 0.05);
border-radius: 8px;
cursor: pointer;
font-weight: 600;
color: #94a3b8;
transition: all 0.3s ease;
}
.calendar-nav button:hover {
border-color: #0ea5e9;
color: #0ea5e9;
background: rgba(14, 165, 233, 0.1);
}
.calendar-days {
display: grid;
grid-template-columns: repeat(7, 1fr);
gap: 0.5rem;
margin-bottom: 2rem;
}
.calendar-day-header {
text-align: center;
font-weight: 600;
color: #94a3b8;
padding: 0.75rem;
font-size: 0.875rem;
}
.calendar-day {
aspect-ratio: 1;
border: 1px solid rgba(255, 255, 255, 0.1);
border-radius: 10px;
padding: 0.5rem;
cursor: pointer;
transition: all 0.3s ease;
background: rgba(255, 255, 255, 0.02);
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
position: relative;
color: #e2e8f0;
}
.calendar-day:hover:not(.disabled) {
border-color: #0ea5e9;
background: rgba(14, 165, 233, 0.1);
}
.calendar-day.selected {
background: linear-gradient(135deg, #0ea5e9 0%, #0d9488 100%);
color: white;
border-color: #0ea5e9;
}
.calendar-day.disabled {
opacity: 0.48;
cursor: not-allowed;
}
.calendar-day .day-number {
font-size: 1.25rem;
font-weight: 700;
}
.calendar-day .day-month {
font-size: 0.75rem;
opacity: 0.8;
}
.calendar-day .availability-indicator {
width: 6px;
height: 6px;
border-radius: 50%;
margin-top: 0.25rem;
}
.calendar-day.has-slots .availability-indicator {
background: #10b981;
}
.calendar-day.no-slots .availability-indicator {
background: #ef4444;
}
.time-slots {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(100px, 1fr));
gap: 0.75rem;
}
.time-slot {
padding: 0.75rem 1rem;
border: 1px solid rgba(255, 255, 255, 0.15);
border-radius: 10px;
text-align: center;
cursor: pointer;
transition: all 0.3s ease;
background: rgba(255, 255, 255, 0.05);
font-weight: 600;
color: #e2e8f0;
}
.time-slot:hover:not(.booked):not(.disabled) {
border-color: #0ea5e9;
color: #0ea5e9;
background: rgba(14, 165, 233, 0.15);
}
.time-slot.selected {
background: linear-gradient(135deg, #0ea5e9 0%, #0d9488 100%);
color: white;
border-color: #0ea5e9;
}
.time-slot.booked {
background: rgba(239, 68, 68, 0.1);
border-color: rgba(239, 68, 68, 0.3);
color: #f87171;
cursor: not-allowed;
}
.time-slot.booked::after {
content: 'Not Available';
display: block;
font-size: 0.7rem;
font-weight: 500;
margin-top: 0.25rem;
color: #f87171;
}
.time-slot.disabled {
opacity: 0.3;
cursor: not-allowed;
}
.booking-form {
background: rgba(255, 255, 255, 0.03);
backdrop-filter: blur(20px);
border: 1px solid rgba(255, 255, 255, 0.1);
border-radius: 20px;
padding: 2rem;
box-shadow: 0 20px 40px rgba(0,0,0,0.3);
height: fit-content;
}
.booking-form-header {
text-align: center;
margin-bottom: 2rem;
}
.booking-form-header h3 {
font-size: 1.5rem;
color: #ffffff;
margin-bottom: 0.5rem;
}
.selected-slot-display {
background: linear-gradient(135deg, rgba(14, 165, 233, 0.15) 0%, rgba(13, 148, 136, 0.15) 100%);
border: 1px solid rgba(14, 165, 233, 0.3);
border-radius: 12px;
padding: 1rem;
margin-bottom: 1.5rem;
text-align: center;
}
.selected-slot-display p {
margin: 0;
color: #ffffff;
font-weight: 600;
}
.selected-slot-display .slot-date {
font-size: 1.1rem;
margin-bottom: 0.25rem;
}
.selected-slot-display .slot-time {
font-size: 1.25rem;
color: #0ea5e9;
}
.form-group {
margin-bottom: 1.25rem;
}
.form-group label {
display: block;
font-weight: 600;
color: #94a3b8;
margin-bottom: 0.5rem;
}
.form-group input,
.form-group textarea,
.form-group select {
width: 100%;
padding: 0.875rem 1rem;
border: 1px solid rgba(255, 255, 255, 0.15);
border-radius: 10px;
font-size: 1rem;
transition: all 0.3s ease;
font-family: 'DM Sans', sans-serif;
background: rgba(255, 255, 255, 0.05);
color: #ffffff;
}
.form-group input::placeholder,
.form-group textarea::placeholder {
color: #64748b;
}
.form-group select option {
background: #1a365d;
color: #ffffff;
}
.form-group input:focus,
.form-group textarea:focus,
.form-group select:focus {
outline: none;
border-color: #0ea5e9;
box-shadow: 0 0 0 4px rgba(14, 165, 233, 0.15);
background: rgba(255, 255, 255, 0.08);
}
.btn-book {
width: 100%;
padding: 1rem;
background: linear-gradient(135deg, #0ea5e9 0%, #0d9488 100%);
color: white;
border: none;
border-radius: 10px;
font-size: 1.1rem;
font-weight: 700;
cursor: pointer;
transition: all 0.3s ease;
}
.btn-book:hover:not(:disabled) {
transform: translateY(-2px);
box-shadow: 0 10px 20px rgba(14, 165, 233, 0.3);
}
.btn-book:disabled {
opacity: 0.5;
cursor: not-allowed;
}
.info-box {
background: rgba(251, 191, 36, 0.1);
border-left: 4px solid #f59e0b;
padding: 1rem;
border-radius: 8px;
margin-bottom: 1.5rem;
font-size: 0.9rem;
color: #fbbf24;
}
.loading {
display: flex;
justify-content: center;
align-items: center;
padding: 3rem;
}
.loading-spinner {
width: 50px;
height: 50px;
border: 4px solid rgba(255, 255, 255, 0.1);
border-top-color: #0ea5e9;
border-radius: 50%;
animation: spin 1s linear infinite;
}
#time-slots-section h3 {
color: #ffffff;
}
#booking-placeholder {
color: #94a3b8 !important;
}
#booking-placeholder i {
color: rgba(255, 255, 255, 0.2) !important;
}
@keyframes spin {
to { transform: rotate(360deg); }
}
@media (max-width: 1024px) {
.calendar-grid {
grid-template-columns: 1fr;
}
.calendar-wrapper {
padding-top: calc(80px + 1.25rem);
}
.calendar-container {
padding: 0;
}
.calendar-main,
.booking-form {
border-radius: 0;
}
}
</style>
</head>
<body class="has-promo">
<!-- Skip to Content (Accessibility) -->
<a href="#main-content" class="skip-to-content">Skip to main content</a>
<!-- Promo Announcement Bar -->
<div class="promo-bar" id="promo-bar">
<span class="promo-icon"><i class="fas fa-shield-alt"></i></span>
<span>🔒 <strong>Free Infrastructure Audit</strong> — Limited availability. <a href="calendar.html">Book your spot →</a></span>
<button class="promo-close" aria-label="Close promotion"><i class="fas fa-times"></i></button>
</div>
<header class="header" id="header">
<nav class="nav container">
<a href="index.html" class="nav-logo">
<img src="images/logo/logo.png" alt="MSPE PRO" class="logo-image" width="200" height="50">
</a>
<div class="nav-menu" id="nav-menu">
<ul class="nav-list">
<li class="nav-item"><a href="index.html" class="nav-link">Home</a></li>
<li class="nav-item"><a href="about.html" class="nav-link">About Us</a></li>
<li class="nav-item dropdown">
<a href="services.html" class="nav-link">Services <i class="fas fa-chevron-down"></i></a>
<ul class="dropdown-menu">
<li><a href="services.html#it-support">IT Support & Maintenance</a></li>
<li><a href="services.html#cybersecurity">Cybersecurity Solutions</a></li>
<li><a href="services.html#cloud">Cloud Services</a></li>
<li><a href="services.html#consulting">Business Consulting</a></li>
</ul>
</li>
<li class="nav-item"><a href="portfolio.html" class="nav-link">Portfolio</a></li>
<li class="nav-item"><a href="news.html" class="nav-link">News & Events</a></li>
<li class="nav-item"><a href="contact.html" class="nav-link">Contact</a></li>
</ul>
</div>
<div class="nav-actions">
<a href="contact.html" class="btn btn-primary">Contact Us</a>
<button class="nav-toggle" id="nav-toggle" aria-label="Toggle navigation menu" aria-expanded="false">
<span></span>
<span></span>
<span></span>
</button>
</div>
</nav>
</header>
<section class="calendar-wrapper">
<div class="calendar-container">
<div class="calendar-intro">
<h1>Book Your Consultation</h1>
<p>Select a date and time that works for you</p>
</div>
<div class="calendar-grid">
<div class="calendar-main">
<div class="calendar-header">
<h2 id="current-month">January 2026</h2>
<div class="calendar-nav">
<button onclick="changeMonth(-1)"><i class="fas fa-chevron-left"></i></button>
<button onclick="changeMonth(0)">Today</button>
<button onclick="changeMonth(1)"><i class="fas fa-chevron-right"></i></button>
</div>
</div>
<div class="calendar-days">
<div class="calendar-day-header">Sun</div>
<div class="calendar-day-header">Mon</div>
<div class="calendar-day-header">Tue</div>
<div class="calendar-day-header">Wed</div>
<div class="calendar-day-header">Thu</div>
<div class="calendar-day-header">Fri</div>
<div class="calendar-day-header">Sat</div>
</div>
<div id="calendar-days" class="calendar-days" style="grid-template-rows: repeat(6, 1fr);">
<div class="loading" style="grid-column: 1 / -1;">
<div class="loading-spinner"></div>
</div>
</div>
<div id="time-slots-section" style="display: none;">
<h3 style="margin: 2rem 0 1rem; color: #ffffff;">Available Time Slots</h3>
<div id="time-slots" class="time-slots"></div>
</div>
</div>
<div class="booking-form">
<div class="booking-form-header">
<h3>Complete Your Booking</h3>
<p style="color: #94a3b8; font-size: 0.9rem;">Fill in your details to confirm your appointment</p>
</div>
<div class="info-box">
<i class="fas fa-info-circle"></i>
All times shown in UTC. We'll send you a confirmation email with your selected time.
</div>
<div style="background: rgba(255, 255, 255, 0.03); border: 1px solid rgba(255, 255, 255, 0.1); border-radius: 8px; padding: 1rem; margin-bottom: 1.5rem; font-size: 0.875rem;">
<div style="font-weight: 600; margin-bottom: 0.5rem; color: #ffffff;"><i class="fas fa-question-circle" style="margin-right: 0.5rem; color: #94a3b8;"></i>Calendar Legend</div>
<div style="display: flex; align-items: center; margin-bottom: 0.25rem;">
<div style="width: 10px; height: 10px; border-radius: 50%; background: #10b981; margin-right: 0.5rem;"></div>
<span style="color: #94a3b8;">Available - time slots open for booking</span>
</div>
<div style="display: flex; align-items: center; margin-bottom: 0.25rem;">
<div style="width: 10px; height: 10px; border-radius: 50%; background: #ef4444; margin-right: 0.5rem;"></div>
<span style="color: #94a3b8;">Unavailable - all slots booked or blocked</span>
</div>
<div style="display: flex; align-items: center;">
<div style="width: 10px; height: 10px; border-radius: 50%; background: rgba(255, 255, 255, 0.2); margin-right: 0.5rem;"></div>
<span style="color: #94a3b8;">No slots - no times scheduled for this day</span>
</div>
</div>
<div id="selected-slot-display" class="selected-slot-display" style="display: none;">
<p class="slot-date">Select a date and time</p>
<p class="slot-time"></p>
</div>
<form id="booking-form" style="display: none;">
<div class="form-group">
<label for="first-name">First Name *</label>
<input type="text" id="first-name" name="first_name" required placeholder="John">
</div>
<div class="form-group">
<label for="last-name">Last Name *</label>
<input type="text" id="last-name" name="last_name" required placeholder="Doe">
</div>
<div class="form-group">
<label for="email">Email Address *</label>
<input type="email" id="email" name="email" required placeholder="john@example.com">
</div>
<div class="form-group">
<label for="phone">Phone Number</label>
<input type="tel" id="phone" name="phone" placeholder="+1 (234) 567-890">
</div>
<div class="form-group">
<label for="company">Company Name</label>
<input type="text" id="company" name="company" placeholder="Your Company">
</div>
<div class="form-group">
<label for="service">Service Interest</label>
<select id="service" name="service_interest">
<option value="">Select a service</option>
<option value="it-support">IT Support & Maintenance</option>
<option value="cybersecurity">Cybersecurity Solutions</option>
<option value="cloud">Cloud Services</option>
<option value="consulting">Business Consulting</option>
<option value="general">General Consultation</option>
</select>
</div>
<div class="form-group">
<label for="message">Additional Notes</label>
<textarea id="message" name="message" rows="4" placeholder="Tell us what you'd like to discuss..."></textarea>
</div>
<button type="submit" class="btn-book" id="submit-btn">
Confirm Booking <i class="fas fa-check"></i>
</button>
</form>
<div id="booking-placeholder" style="text-align: center; color: #94a3b8; padding: 2rem;">
<i class="fas fa-calendar-alt" style="font-size: 3rem; margin-bottom: 1rem; opacity: 0.3;"></i>
<p>Select a date and time from the calendar to begin</p>
</div>
</div>
</div>
</div>
</section>
<footer class="footer">
<div class="footer-main">
<div class="container">
<div class="footer-grid">
<div class="footer-brand">
<a href="index.html" class="footer-logo">
<img src="images/logo/logo.png" alt="MSPE PRO" class="logo-image" width="200" height="50">
</a>
<p class="footer-description">We engineer possibilities. Transforming complexity into competitive advantage through innovative technology solutions and uncompromising security.</p>
<div class="footer-social">
<a href="https://www.facebook.com/mspe.pro" class="social-link" title="Facebook" target="_blank" rel="noopener noreferrer"><i class="fab fa-facebook-f"></i></a>
<a href="https://www.linkedin.com/company/mspe-pro" class="social-link" title="LinkedIn" target="_blank" rel="noopener noreferrer"><i class="fab fa-linkedin-in"></i></a>
<a href="https://x.com/mspe_pro" class="social-link" title="X (Twitter)" target="_blank" rel="noopener noreferrer"><i class="fab fa-twitter"></i></a>
<a href="https://www.instagram.com/mspe.pro" class="social-link" title="Instagram" target="_blank" rel="noopener noreferrer"><i class="fab fa-instagram"></i></a>
</div>
</div>
<div class="footer-links">
<h4 class="footer-title">Quick Links</h4>
<ul>
<li><a href="about.html">About Us</a></li>
<li><a href="services.html">Our Services</a></li>
<li><a href="portfolio.html">Portfolio</a></li>
<li><a href="news.html">News &amp; Events</a></li>
<li><a href="contact.html">Contact Us</a></li>
</ul>
</div>
<div class="footer-links">
<h4 class="footer-title">Services</h4>
<ul>
<li><a href="services.html#it-support">IT Support &amp; Maintenance</a></li>
<li><a href="services.html#cybersecurity">Cybersecurity Solutions</a></li>
<li><a href="services.html#cloud">Cloud Services</a></li>
<li><a href="services.html#consulting">Business Consulting</a></li>
</ul>
</div>
<div class="footer-contact">
<h4 class="footer-title">Contact Info</h4>
<ul class="contact-list">
<li>
<i class="fas fa-envelope"></i>
<span data-site-email>info@mspe.pro</span>
</li>
<li>
<i class="fas fa-phone"></i>
<a href="tel:+96178782023" data-site-phone style="color:inherit;">+961 78 782 023</a>
</li>
<li>
<i class="fas fa-clock"></i>
<span>Available for consultations</span>
</li>
<li>
<i class="fas fa-map-marker-alt"></i>
<span>Beirut, Lebanon</span>
</li>
</ul>
<div class="footer-newsletter">
<p>Get expert insights delivered to your inbox</p>
<form class="newsletter-form" id="footer-newsletter-form">
<input type="email" placeholder="Your email address" required aria-label="Email for newsletter">
<button type="submit" class="btn-newsletter">Subscribe</button>
</form>
</div>
</div>
</div>
</div>
</div>
<div class="footer-bottom">
<div class="container">
<p>&copy; 2026 MSPE - Architects of Digital Resilience. All Rights Reserved.</p>
<div class="footer-bottom-links">
<a href="privacy.html">Privacy Policy</a>
<a href="terms.html">Terms of Service</a>
</div>
</div>
</div>
</footer>
<!-- Mobile Sticky CTA -->
<div class="mobile-sticky-cta">
<a href="calendar.html" class="btn btn-primary"><i class="fas fa-calendar-check"></i> Book Free Consultation</a>
</div>
<script src="js/main.js" defer></script>
<script>
let currentDate = new Date();
let selectedDate = null;
let selectedTime = null;
let availability = {};
document.addEventListener('DOMContentLoaded', function() {
initCalendar();
loadAvailability();
});
async function loadAvailability() {
const dateFrom = formatDate(new Date(currentDate.getFullYear(), currentDate.getMonth(), 1));
const dateTo = formatDate(new Date(currentDate.getFullYear(), currentDate.getMonth() + 2, 0));
try {
// Use public-availability endpoint - only shows available/not available status
// Does not expose any booking details or personal information
const response = await fetch(`api/bookings.php?action=public-availability&date_from=${dateFrom}&date_to=${dateTo}`);
const result = await response.json();
if (result.success) {
// Clear previous data for this range
availability = {};
result.data.forEach(slot => {
if (!availability[slot.date]) {
availability[slot.date] = [];
}
availability[slot.date].push({
time: slot.time,
available: slot.available
});
});
renderCalendar();
}
} catch (error) {
console.error('Error loading availability:', error);
}
}
function initCalendar() {
document.getElementById('nav-toggle').addEventListener('click', function() {
document.getElementById('nav-menu').classList.toggle('active');
});
}
function changeMonth(delta) {
if (delta === 0) {
currentDate = new Date();
} else {
currentDate.setMonth(currentDate.getMonth() + delta);
}
loadAvailability();
}
function formatDate(date) {
return date.toISOString().split('T')[0];
}
function renderCalendar() {
const year = currentDate.getFullYear();
const month = currentDate.getMonth();
const monthNames = ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'];
document.getElementById('current-month').textContent = `${monthNames[month]} ${year}`;
const firstDay = new Date(year, month, 1);
const lastDay = new Date(year, month + 1, 0);
const startingDay = firstDay.getDay();
const totalDays = lastDay.getDate();
const calendarDays = document.getElementById('calendar-days');
let html = '';
for (let i = 0; i < startingDay; i++) {
html += '<div class="calendar-day disabled"></div>';
}
const today = new Date();
today.setHours(0, 0, 0, 0);
for (let day = 1; day <= totalDays; day++) {
const dateStr = formatDate(new Date(year, month, day));
const dateObj = new Date(year, month, day);
const isPast = dateObj < today;
const slots = availability[dateStr] || [];
const hasAvailableSlots = slots.some(s => s.available);
const hasAnySlots = slots.length > 0;
const selectedClass = selectedDate === dateStr ? 'selected' : '';
const disabledClass = isPast ? 'disabled' : '';
const slotsClass = hasAnySlots ? (hasAvailableSlots ? 'has-slots' : 'no-slots') : '';
html += `
<div class="calendar-day ${selectedClass} ${disabledClass} ${slotsClass}"
onclick="${isPast ? '' : `selectDate('${dateStr}')`}">
<span class="day-number">${day}</span>
<span class="day-month">${monthNames[month].substring(0, 3)}</span>
${hasAnySlots ? '<div class="availability-indicator"></div>' : ''}
</div>
`;
}
const remainingSlots = 42 - startingDay - totalDays;
for (let i = 0; i < remainingSlots; i++) {
html += '<div class="calendar-day disabled"></div>';
}
calendarDays.innerHTML = html;
if (selectedDate) {
renderTimeSlots(selectedDate);
}
}
function selectDate(dateStr) {
selectedDate = dateStr;
selectedTime = null;
document.querySelectorAll('.calendar-day').forEach(day => day.classList.remove('selected'));
event.target.closest('.calendar-day').classList.add('selected');
renderTimeSlots(dateStr);
}
function renderTimeSlots(dateStr) {
const slots = availability[dateStr] || [];
const container = document.getElementById('time-slots');
const section = document.getElementById('time-slots-section');
if (slots.length === 0) {
section.style.display = 'block';
container.innerHTML = '<p style="grid-column: 1/-1; text-align: center; color: #94a3b8; padding: 1rem;">No time slots available for this date. Please select another day.</p>';
document.getElementById('booking-form').style.display = 'none';
document.getElementById('booking-placeholder').style.display = 'block';
document.getElementById('selected-slot-display').style.display = 'none';
return;
}
section.style.display = 'block';
let html = '';
slots.forEach(slot => {
const isAvailable = slot.available;
const bookedClass = !isAvailable ? 'booked' : '';
const selectedClass = selectedTime === slot.time && isAvailable ? 'selected' : '';
html += `
<div class="time-slot ${bookedClass} ${selectedClass}"
onclick="${isAvailable ? `selectTime('${slot.time}')` : ''}">
${formatTime(slot.time)}
</div>
`;
});
container.innerHTML = html;
}
function formatTime(timeStr) {
const [hours, minutes] = timeStr.split(':');
const date = new Date();
date.setHours(parseInt(hours), parseInt(minutes), 0);
return date.toLocaleTimeString('en-US', { hour: 'numeric', minute: '2-digit', hour12: true });
}
function selectTime(time) {
selectedTime = time;
document.querySelectorAll('.time-slot').forEach(slot => slot.classList.remove('selected'));
event.target.closest('.time-slot').classList.add('selected');
updateBookingForm();
}
function updateBookingForm() {
const display = document.getElementById('selected-slot-display');
const form = document.getElementById('booking-form');
const placeholder = document.getElementById('booking-placeholder');
const dateObj = new Date(selectedDate);
const dateStr = dateObj.toLocaleDateString('en-US', { weekday: 'long', year: 'numeric', month: 'long', day: 'numeric' });
const timeStr = formatTime(selectedTime);
display.style.display = 'block';
display.querySelector('.slot-date').textContent = dateStr;
display.querySelector('.slot-time').textContent = timeStr;
form.style.display = 'block';
placeholder.style.display = 'none';
}
document.getElementById('booking-form').addEventListener('submit', async function(e) {
e.preventDefault();
if (!selectedDate || !selectedTime) {
alert('Please select a date and time');
return;
}
const submitBtn = document.getElementById('submit-btn');
submitBtn.disabled = true;
submitBtn.innerHTML = '<i class="fas fa-spinner fa-spin"></i> Booking...';
const formData = new FormData(this);
const data = Object.fromEntries(formData);
data.booking_date = selectedDate;
data.booking_time = selectedTime;
data.duration = 60;
try {
const response = await fetch('api/bookings.php?action=book', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify(data)
});
const result = await response.json();
if (result.success) {
alert('Booking request submitted successfully! We will send you a confirmation email shortly.');
this.reset();
document.getElementById('booking-form').style.display = 'none';
document.getElementById('selected-slot-display').style.display = 'none';
document.getElementById('booking-placeholder').style.display = 'block';
selectedDate = null;
selectedTime = null;
loadAvailability();
} else {
alert(result.message || 'Failed to submit booking. Please try again.');
}
} catch (error) {
console.error('Booking error:', error);
alert('An error occurred. Please try again.');
} finally {
submitBtn.disabled = false;
submitBtn.innerHTML = 'Confirm Booking <i class="fas fa-check"></i>';
}
});
</script>
</body>
</html>