diff options
Diffstat (limited to 'static/js/rsvp.js')
| -rw-r--r-- | static/js/rsvp.js | 206 |
1 files changed, 206 insertions, 0 deletions
diff --git a/static/js/rsvp.js b/static/js/rsvp.js new file mode 100644 index 0000000..06cdb66 --- /dev/null +++ b/static/js/rsvp.js @@ -0,0 +1,206 @@ +/* + * rsvp.js -- Simple web-based RSVP tool. + * Copyright © 2022 - 2023 Jakob L. Kreuze <zerodaysfordays@sdf.org> + * + * 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 + * <http://www.gnu.org/licenses/>. + */ + +// 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(); + } +}); |