Download index.html from Sumup/scheduler: direct link, hf CLI and curl.
- Browser
- Download file 6.05 kB
-
https://huggingface.co/spaces/Sumup/scheduler/resolve/main/index.html
- Command line
-
hf download hf://spaces/Sumup/scheduler/index.html
-
curl -L -o index.html https://huggingface.co/spaces/Sumup/scheduler/resolve/main/index.html
6.05 kB
| <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> |