import { Controller } from "@hotwired/stimulus" export default class extends Controller { static targets = ["quantity", "cartCount", "cartTotal", "checkoutButton"] static values = { eventId: String } connect() { this.cart = {} this.updateCartDisplay() // Check for pending cart in session storage (after login) this.checkForPendingCart() } increaseQuantity(event) { const ticketTypeId = event.params.ticketTypeId const max = parseInt(event.params.max) const input = this.quantityTargetFor(ticketTypeId) const current = parseInt(input.value) || 0 if (current < max) { input.value = current + 1 this.updateCartItem(ticketTypeId, input) } } decreaseQuantity(event) { const ticketTypeId = event.params.ticketTypeId const input = this.quantityTargetFor(ticketTypeId) const current = parseInt(input.value) || 0 if (current > 0) { input.value = current - 1 this.updateCartItem(ticketTypeId, input) } } updateQuantityFromInput(event) { const input = event.target const ticketTypeId = input.dataset.ticketTypeId const max = parseInt(input.max) const quantity = parseInt(input.value) || 0 // Validate input if (quantity < 0) { input.value = 0 } else if (quantity > max) { input.value = max } this.updateCartItem(ticketTypeId, input) } updateCartItem(ticketTypeId, input) { const name = input.dataset.name const price = parseInt(input.dataset.price) const quantity = parseInt(input.value) || 0 if (quantity > 0) { this.cart[ticketTypeId] = { name: name, price: price, quantity: quantity } } else { delete this.cart[ticketTypeId] } this.updateCartDisplay() } updateCartDisplay() { let totalTickets = 0 let totalPrice = 0 for (let ticketTypeId in this.cart) { totalTickets += this.cart[ticketTypeId].quantity totalPrice += (this.cart[ticketTypeId].price * this.cart[ticketTypeId].quantity) / 100 } // Update cart count and total if (this.hasCartCountTarget) { this.cartCountTarget.textContent = totalTickets } if (this.hasCartTotalTarget) { this.cartTotalTarget.textContent = totalPrice.toFixed(2) } // Update checkout button state if (this.hasCheckoutButtonTarget) { const checkoutBtn = this.checkoutButtonTarget if (totalTickets > 0) { checkoutBtn.disabled = false checkoutBtn.classList.remove('opacity-50', 'cursor-not-allowed') } else { checkoutBtn.disabled = true checkoutBtn.classList.add('opacity-50', 'cursor-not-allowed') } } } proceedToCheckout() { if (Object.keys(this.cart).length === 0) { this.showNotification('Veuillez sélectionner au moins un billet', 'warning') return } // Validate cart contents if (!this.validateCartAvailability()) { return } // Check if user is authenticated const isAuthenticated = document.body.dataset.userAuthenticated === "true" if (!isAuthenticated) { this.showLoginModal() return } // Show loading state this.setCheckoutLoading(true) // Create form and submit to checkout const form = document.createElement('form') form.method = 'POST' form.action = `/events/${document.body.dataset.eventSlug}.${this.eventIdValue}/checkout` // Add CSRF token const csrfToken = document.querySelector('meta[name="csrf-token"]').content const csrfInput = document.createElement('input') csrfInput.type = 'hidden' csrfInput.name = 'authenticity_token' csrfInput.value = csrfToken form.appendChild(csrfInput) // Add cart data const cartInput = document.createElement('input') cartInput.type = 'hidden' cartInput.name = 'cart' cartInput.value = JSON.stringify(this.cart) form.appendChild(cartInput) document.body.appendChild(form) form.submit() } validateCartAvailability() { // Check each ticket type availability before checkout for (let ticketTypeId in this.cart) { const input = this.quantityTargetFor(ticketTypeId) if (input) { const maxAvailable = parseInt(input.max) const requested = this.cart[ticketTypeId].quantity if (requested > maxAvailable) { this.showNotification(`Seulement ${maxAvailable} billets disponibles pour ${this.cart[ticketTypeId].name}`, 'error') // Adjust cart to maximum available input.value = maxAvailable this.updateCartItem(ticketTypeId, input) return false } } } return true } showLoginModal() { // Create and show modern login modal const modal = document.createElement('div') modal.className = 'fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center z-50' modal.innerHTML = `
Vous devez être connecté pour acheter des billets. Votre panier sera conservé.
${message}