import { Controller } from "@hotwired/stimulus"; import { loadStripe } from "@stripe/stripe-js"; export default class extends Controller { static targets = [ "key", "submit", "firstname", "lastname", "email", "phone", "ticketType", "foodType", "note", ]; stripe; async connect() { this.stripe = await loadStripe(this.keyTarget.textContent); } addEntry(event) { event.preventDefault(); const template = this.element .querySelector(".forms") .firstElementChild.cloneNode(true); template.querySelectorAll("select, input").forEach((element) => { element.value = ""; if (element.id) { element.id = `${element.id}_${Date.now()}`; } }); template.querySelectorAll("label").forEach((label) => { const forAttribute = label.getAttribute("for"); if (forAttribute) { label.setAttribute("for", `${forAttribute}_${Date.now()}`); } }); template.classList.add("opacity-0"); this.element.querySelector(".forms").appendChild(template); requestAnimationFrame(() => { template.classList.remove("opacity-0"); template.classList.add("transition-all", "duration-300"); }); } removeEntry(event) { event.preventDefault(); const forms = this.element.querySelector(".forms"); if (forms.childElementCount <= 1) { return; } const ticketElement = event.currentTarget.closest(".bg-white\\/80"); if (!ticketElement) return; ticketElement.classList.add("opacity-0", "transition-all", "duration-300"); setTimeout(() => { ticketElement.remove(); }, 300); } submit(event) { event.preventDefault(); if (!this.validateForm()) { return; } this.submitTarget.querySelector("span").classList.add("hidden"); this.submitTarget.querySelector("svg.arrow").classList.add("hidden"); this.submitTarget.querySelector("svg.loader").classList.remove("hidden"); const tickets = this.element.querySelectorAll(".forms > div"); const personalData = this.getPersonalData(); const ticketData = this.getTicketData(tickets); const formData = { personal: personalData, tickets: ticketData, }; fetch("/ticket/submit", { method: "POST", body: JSON.stringify(formData), headers: { "Content-Type": "application/json", }, }).then((response) => { if (!response.ok) { this.submitTarget.querySelector("svg.error").classList.add("hidden"); this.submitTarget .querySelector("svg.loader") .classList.remove("hidden"); this.submitTarget.querySelector("span").classList.remove("hidden"); this.showError( "Ein Fehler ist aufgetreten. Bitte versuchen Sie es erneut.", ); } else { response.json().then((data) => { this.stripe.redirectToCheckout({ sessionId: data.id, }); }); } }); } validateForm() { let isValid = true; ["firstname", "lastname", "email"].forEach((field) => { const target = this[`${field}Target`]; if (!target.value.trim()) { this.showFieldError(target); isValid = false; } }); this.element.querySelectorAll(".forms > div").forEach((ticket) => { const selects = ticket.querySelectorAll("select[required]"); selects.forEach((select) => { if (!select.value) { this.showFieldError(select); isValid = false; } }); }); return isValid; } showFieldError(element) { element.classList.add( "border-red-500", "focus:border-red-500", "focus:ring-red-200", ); element.addEventListener( "input", () => { element.classList.remove( "border-red-500", "focus:border-red-500", "focus:ring-red-200", ); }, { once: true }, ); } showError(message) { const errorDiv = document.createElement("div"); errorDiv.className = "fixed top-4 right-4 bg-red-50 border-l-4 border-red-500 p-4 rounded shadow-lg transform transition-all duration-500 opacity-0 translate-x-4"; errorDiv.innerHTML = `
${message}