File size: 6,053 Bytes
c910874 fd40a84 c910874 fd40a84 de9919b fd40a84 de9919b fd40a84 c910874 de9919b fd40a84 c910874 fd40a84 de9919b fd40a84 c910874 fd40a84 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 | <!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<title>Book a meeting with SumUp</title>
<link rel="stylesheet" href="style.css" />
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;600&display=swap" rel="stylesheet" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
</head>
<body>
<div class="container">
<h2>Book a meeting with SumUp</h2>
<form id="booking-form" aria-labelledby="form-heading">
<input type="text" id="name" placeholder="Your First Name" required />
<input type="email" id="email" placeholder="Your Email" required />
<button type="submit">Check availability</button>
<select id="slots" style="display:none;" aria-label="Available Time Slots"></select>
<button type="button" id="bookBtn" style="display:none;" aria-label="Confirm Booking">Confirm booking</button>
</form>
<div id="spinner" aria-live="polite"></div>
<p id="status" aria-live="polite"></p>
<div id="confirmation" class="hidden" aria-live="polite">
<h3>✅ Meeting confirmed with SumUp</h3>
<p><strong>Name:</strong> <span id="conf-name"></span></p>
<p><strong>Email:</strong> <span id="conf-email"></span></p>
<p><strong>Time:</strong> <span id="conf-slot"></span></p>
</div>
</div>
<img src="sumup-logo.png" alt="SumUp logo" class="logo" />
<script>
let repEmail = "";
const slotsDropdown = document.getElementById("slots");
const bookBtn = document.getElementById("bookBtn");
const statusEl = document.getElementById("status");
const spinner = document.getElementById("spinner");
function showSpinner() { spinner.style.display = "block"; }
function hideSpinner() { spinner.style.display = "none"; }
function setStatus(message, type="info") {
statusEl.className = "";
statusEl.classList.add(`status-${type}`);
statusEl.innerText = message;
statusEl.style.display = "block";
}
// -------------------------------
// Auto-fill form from query params
// -------------------------------
const urlParams = new URLSearchParams(window.location.search);
const leadName = urlParams.get("ln") || "";
const leadEmail = urlParams.get("le") || "";
const salesRepEmailParam = urlParams.get("oe") || "";
document.getElementById("name").value = leadName;
document.getElementById("email").value = leadEmail;
async function fetchSlots(name, email, repEmailParam) {
showSpinner();
setStatus("Loading available slots...", "info");
try {
const res = await fetch(`/available?name=${encodeURIComponent(name)}&email=${encodeURIComponent(email)}&salesRepEmail=${encodeURIComponent(repEmailParam)}`);
const data = await res.json();
hideSpinner();
if (data.error) {
setStatus(data.error, "error");
return;
}
repEmail = data.repEmail;
const slots = data.slots;
slotsDropdown.innerHTML = "";
if (!slots || slots.length === 0) {
setStatus("No available time slots found.", "error");
return;
}
slots.forEach(slot => {
const option = document.createElement("option");
option.value = slot.start;
option.text = new Date(slot.start).toLocaleString();
slotsDropdown.appendChild(option);
});
slotsDropdown.style.display = "block";
bookBtn.style.display = "inline-block";
setStatus("Select a time slot to book.", "success");
} catch (error) {
hideSpinner();
setStatus("Failed to fetch available slots.", "error");
}
}
// Auto-fetch slots if all query params are present
if (leadName && leadEmail && salesRepEmailParam) {
fetchSlots(leadName, leadEmail, salesRepEmailParam);
}
// -------------------------------
// Form submit manually (optional)
// -------------------------------
const form = document.getElementById("booking-form");
form.addEventListener("submit", async (e) => {
e.preventDefault();
const name = document.getElementById("name").value;
const email = document.getElementById("email").value;
if (!name || !email) {
setStatus("Please enter your name and email.", "error");
return;
}
fetchSlots(name, email, salesRepEmailParam || repEmail);
});
// -------------------------------
// Booking
// -------------------------------
bookBtn.addEventListener("click", async () => {
const name = document.getElementById("name").value;
const email = document.getElementById("email").value;
const selectedSlot = slotsDropdown.value;
if (!selectedSlot || !repEmail) {
setStatus("Please select a time slot first.", "error");
return;
}
showSpinner();
setStatus("Booking your meeting...", "info");
try {
const res = await fetch("/book", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
name,
email,
salesRepEmail: repEmail,
selectedSlot
})
});
const result = await res.json();
hideSpinner();
if (result.message) setStatus(result.message, "success");
const confirmationPanel = document.getElementById("confirmation");
confirmationPanel.classList.add("visible");
document.getElementById("conf-name").innerText = name;
document.getElementById("conf-email").innerText = email;
document.getElementById("conf-slot").innerText = new Date(selectedSlot).toLocaleString();
slotsDropdown.style.display = "none";
bookBtn.style.display = "none";
form.reset();
setTimeout(() => { statusEl.style.display = "none"; }, 3000);
} catch (error) {
hideSpinner();
setStatus("Booking failed. Please try again.", "error");
}
});
</script>
</body>
</html> |