summaryrefslogtreecommitdiff
path: root/static/js/rsvp.js
diff options
context:
space:
mode:
Diffstat (limited to 'static/js/rsvp.js')
-rw-r--r--static/js/rsvp.js206
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();
+ }
+});