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").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").classList.add("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}

`; document.body.appendChild(errorDiv); requestAnimationFrame(() => { errorDiv.classList.remove('opacity-0', 'translate-x-4'); }); setTimeout(() => { errorDiv.classList.add('opacity-0', 'translate-x-4'); setTimeout(() => errorDiv.remove(), 500); }, 5000); } getTicketData(tickets) { return Array.from(tickets).map(ticket => this.extractTicketData(ticket)); } getPersonalData() { return { firstname: this.firstnameTarget.value.trim(), lastname: this.lastnameTarget.value.trim(), email: this.emailTarget.value.trim(), phone: this.phoneTarget.value.trim(), }; } extractTicketData(ticket) { return { ticket: parseInt(ticket.querySelector('select[name="ticket"]').value), food: parseInt(ticket.querySelector('select[name="food"]').value), note: ticket.querySelector('input[name="note"]').value.trim(), }; } }