/* * rsvp.js -- Simple web-based RSVP tool. * Copyright © 2022 - 2023 Jakob L. Kreuze * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 3 of the * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see * . */ // Common nodes. const guestView = document.getElementById("guest-view"); const addEntry = document.getElementById("add-entry"); const removeEntry = document.getElementById("remove-entry"); const submitButton = document.getElementById("submit-form"); const form = document.getElementById("rsvp-input"); // Parse out the HTML form into something we can send to the backend. function submitForm() { let data = new FormData(form); if (data.get("name").trim().length == 0) { alert("You have to provide something for \"Name\"."); return; } else if (data.get("rsvp") === null) { alert("You have to choose an option for \"RSVP Status\"."); return; } let res = { guests: [] }; if (urlParams.get("i")) { res["id"] = urlParams.get("i"); } else if (urlParams.get("r")) { res["update"] = urlParams.get("r"); } for (let pair of data.entries()) { if (pair[0].startsWith("guest-")) { res.guests.push(pair[1]); } else if (pair[0] === "rsvp") { const radioButtons = document.querySelectorAll('input[name="rsvp"]'); for (const radioButton of radioButtons) { if (radioButton.checked) { res.rsvp = radioButton.id; break; } } } else { res[pair[0]] = pair[1]; } } res.guests = res.guests.join(","); let xhr = new XMLHttpRequest(); xhr.open("POST", `${location.protocol}//${location.host}/api/rsvp`); xhr.send(JSON.stringify(res)); xhr.onload = function(data) { if (xhr.status != 200) { alert("Failed to submit form."); } else { document.getElementById("rsvp").innerHTML = ""; let resp = JSON.parse(xhr.response); let elem = document.createElement("p"); elem.innerHTML = "Thanks for registering! Please bookmark or save the following link:"; document.getElementById("rsvp").appendChild(elem); elem = document.createElement("a"); elem.href = [location.protocol, '//', location.host, location.pathname].join('') + `?r=${resp.receipt}`; elem.textContent = elem.href; document.getElementById("rsvp").appendChild(elem); elem = document.createElement("p"); elem.innerHTML = "This will enable you to edit your RSVP later."; document.getElementById("rsvp").appendChild(elem); } } xhr.onerror = function(error) { throw new Error(`Request failed: ${error}`); } } // Immediately send off an XHR to load info from the backend. const urlParams = new URLSearchParams(window.location.search); if (!urlParams.get("i") && !urlParams.get("r")) { document.getElementById("loading").remove(); let elem = document.createElement("p"); elem.innerHTML = "No invitation code provided."; document.getElementById("rsvp").appendChild(elem); } else { let xhr = new XMLHttpRequest(); if (urlParams.get("i")) { xhr.open("GET", `${location.protocol}//${location.host}/api/rsvp/event-info?i=${urlParams.get("i")}`); } else { xhr.open("GET", `${location.protocol}//${location.host}/api/rsvp/event-info?r=${urlParams.get("r")}`); } xhr.send(); xhr.onload = function(data) { document.getElementById("loading").remove(); if (xhr.status != 200) { let elem = document.createElement("p"); elem.innerHTML = "Invalid invitation code."; document.getElementById("rsvp").appendChild(elem); } else { document.getElementById("rsvp-input").hidden = false; let response = JSON.parse(xhr.response); let elem = document.createElement("h1"); elem.innerHTML = response.title; document.getElementById("event-info").appendChild(elem); if (response.image !== "#f") { elem = document.createElement("img"); elem.src = `data:image/png;base64,${response.image}`; elem.style = "float: right; max-size: 200px; margin: 16px;"; document.getElementById("event-info").appendChild(elem); } elem = document.createElement("p"); elem.innerHTML = `Where: ${response.location}`; document.getElementById("event-info").appendChild(elem); elem = document.createElement("p"); elem.innerHTML = `When: ${response.date}`; document.getElementById("event-info").appendChild(elem); elem = document.createElement("p"); elem.innerHTML = response.description; document.getElementById("event-info").appendChild(elem); if (response.hasOwnProperty("rsvps")) { elem = document.createElement("h2"); elem.innerHTML = "Current RSVPs"; document.getElementById("rsvp-global").appendChild(elem); elem = document.createElement("table"); document.getElementById("rsvp-global").appendChild(elem); for (let rsvp of response.rsvps) { let container = document.createElement("tr"); let field = document.createElement("td"); field.textContent = rsvp.name; container.append(field); field = document.createElement("td"); field.textContent = rsvp.email; container.append(field); field = document.createElement("td"); field.textContent = rsvp.guests.replaceAll(',', ', '); container.append(field); field = document.createElement("td"); field.textContent = rsvp.attending; container.append(field); elem.appendChild(container); } } // Pre-filled info if this is an edit. if (response.hasOwnProperty("name")) { document.getElementById("name").value = response.name; } if (response.hasOwnProperty("email")) { document.getElementById("email").value = response.email; } if (response.hasOwnProperty("attending")) { document.getElementById(response.attending).checked = true; } if (response.hasOwnProperty("guests") && response.guests.trim() != "") { let i = 0; for (let guest of response.guests.split(",")) { let elem = document.createElement("input"); elem.type = "text"; elem.name = `guest-${i}`; elem.value = guest; guestView.appendChild(elem); i++; } } } } xhr.onerror = function(error) { throw new Error(`Request failed: ${error}`); } } // Attach event listeners to the UI. submitButton.addEventListener("click", submitForm); submitButton.addEventListener("submit", submitForm); addEntry.addEventListener("click", () => { let i = guestView.childNodes.length; let elem = document.createElement("input"); elem.type = "text"; elem.name = `guest-${i}`; guestView.appendChild(elem); }); removeEntry.addEventListener("click", () => { if (guestView.lastChild) { guestView.lastChild.remove(); } });