903 lines
37 KiB
HTML
Executable File
903 lines
37 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=Playfair+Display:wght@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=Playfair+Display:wght@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/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="stylesheet" href="css/header-fix.css">
|
|
<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>
|
|
<!-- Skip to Content (Accessibility) -->
|
|
<a href="#main-content" class="skip-to-content">Skip to main content</a>
|
|
|
|
<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 & 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 & 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>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="footer-bottom">
|
|
<div class="container">
|
|
<p>© 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>
|
|
|
|
<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>
|