import "vanilla-hcaptcha"; import fetch from "unfetch"; // don't continue if there isn't a contact form on this page // TODO: be better and only do any of this on /contact/ const contactForm = document.querySelector("form#contact-form"); if (contactForm) { contactForm.addEventListener("submit", (event) => { // immediately prevent
from actually submitting to a new page event.preventDefault(); // feedback s for later const successSpan = document.querySelector("span#contact-form-result-success"); const errorSpan = document.querySelector("span#contact-form-result-error"); // disable the whole form if the button has been disabled below (on success) const submitButton = document.querySelector("button#contact-form-btn-submit"); if (submitButton.disabled === true) { return; } // change button appearance between click and server response submitButton.textContent = "Sending..."; submitButton.disabled = true; // prevent accidental multiple submissions submitButton.style.cursor = "default"; try { // https://simonplend.com/how-to-use-fetch-to-post-form-data-as-json-to-your-api/ const formData = Object.fromEntries(new FormData(event.currentTarget).entries()); // some client-side validation. these are all also checked on the server to be safe but we can save some // unnecessary requests here. // we throw identical error messages to the server's so they're caught in the same way below. if (!formData.name || !formData.email || !formData.message) { throw new Error("USER_MISSING_DATA"); } if (!formData["h-captcha-response"]) { throw new Error("USER_INVALID_CAPTCHA"); } // post JSONified form input to /api/contact/ fetch(contactForm.action, { method: "POST", headers: { "Content-Type": "application/json", Accept: "application/json", }, body: JSON.stringify(formData), }) .then((response) => response.json()) .then((data) => { if (data.success === true) { // handle successful submission // we can disable submissions & hide the send button now submitButton.disabled = true; submitButton.style.display = "none"; // just in case there *was* a PEBCAK error and it was corrected errorSpan.style.display = "none"; // let user know we were successful successSpan.textContent = "Success! You should hear from me soon. :)"; } else { // pass on an error sent by the server throw new Error(data.message); } }); } catch (error) { const message = error instanceof Error ? error.message : "UNKNOWN_EXCEPTION"; // give user feedback based on the error message returned if (message === "USER_INVALID_CAPTCHA") { errorSpan.textContent = "Did you complete the CAPTCHA? (If you're human, that is...)"; } else if (message === "USER_MISSING_DATA") { errorSpan.textContent = "Please make sure that all fields are filled in."; } else { // something else went wrong, and it's probably my fault... errorSpan.textContent = "Internal server error. Try again later?"; } // reset submit button to let user try again submitButton.textContent = "Try Again"; submitButton.disabled = false; submitButton.style.cursor = "pointer"; submitButton.blur(); // remove keyboard focus from the button } }); }