function formatEur(value) { return value.toFixed(2).replace('.', ',') + ' \u20AC' } export function initCart() { const billetterie = document.getElementById('billetterie') if (!billetterie) return const items = billetterie.querySelectorAll('[data-cart-item]') const totalEl = document.getElementById('cart-total') const countEl = document.getElementById('cart-count') const checkoutBtn = document.getElementById('cart-checkout') const errorEl = document.getElementById('cart-error') const errorText = document.getElementById('cart-error-text') if (!totalEl || !countEl) return function updateTotals() { let total = 0 let count = 0 for (const item of items) { const price = Number.parseFloat(item.dataset.price) || 0 const qtyInput = item.querySelector('[data-cart-qty]') const lineTotalEl = item.querySelector('[data-cart-line-total]') const qty = Number.parseInt(qtyInput.value, 10) || 0 const lineTotal = price * qty total += lineTotal count += qty lineTotalEl.textContent = formatEur(lineTotal) } totalEl.textContent = formatEur(total) countEl.textContent = String(count) if (checkoutBtn) { checkoutBtn.disabled = count === 0 } } for (const item of items) { const qtyInput = item.querySelector('[data-cart-qty]') const minusBtn = item.querySelector('[data-cart-minus]') const plusBtn = item.querySelector('[data-cart-plus]') const max = Number.parseInt(item.dataset.max, 10) || 0 minusBtn.addEventListener('click', () => { const current = Number.parseInt(qtyInput.value, 10) || 0 if (current > 0) { qtyInput.value = current - 1 updateTotals() } }) plusBtn.addEventListener('click', () => { const current = Number.parseInt(qtyInput.value, 10) || 0 if (max === 0 || current < max) { qtyInput.value = current + 1 updateTotals() } }) } if (checkoutBtn) { checkoutBtn.addEventListener('click', () => { const cart = [] for (const item of items) { const qty = Number.parseInt(item.querySelector('[data-cart-qty]').value, 10) || 0 if (qty > 0) { cart.push({ billetId: item.dataset.billetId, qty }) } } if (cart.length === 0) return const orderUrl = checkoutBtn.dataset.orderUrl if (!orderUrl) return checkoutBtn.disabled = true checkoutBtn.textContent = 'Chargement...' if (errorEl) errorEl.classList.add('hidden') globalThis.fetch(orderUrl, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(cart), }) .then(r => { if (!r.ok) throw new Error(r.status) return r.json() }) .then(data => { if (data.redirect) { globalThis.location.href = data.redirect } }) .catch(() => { checkoutBtn.disabled = false checkoutBtn.textContent = 'Commander' if (errorEl && errorText) { errorText.textContent = 'Une erreur est survenue. Veuillez reessayer.' errorEl.classList.remove('hidden') } }) }) } updateTotals() const stockUrl = billetterie.dataset.stockUrl if (stockUrl) { setInterval(() => { globalThis.fetch(stockUrl) .then(r => r.json()) .then(stock => { for (const item of items) { const billetId = item.dataset.billetId const qty = stock[billetId] if (qty === undefined || qty === null) continue const max = qty item.dataset.max = String(max) const qtyInput = item.querySelector('[data-cart-qty]') qtyInput.max = max const current = Number.parseInt(qtyInput.value, 10) || 0 if (max > 0 && current > max) { qtyInput.value = max } const label = item.querySelector('[data-stock-label]') if (label) { if (max === 0) { label.innerHTML = 'Rupture de stock' if (current > 0) { qtyInput.value = 0 } } else if (max <= 10) { label.innerHTML = 'Plus que ' + max + ' place' + (max > 1 ? 's' : '') + ' !' } else { label.innerHTML = '' + max + ' place' + (max > 1 ? 's' : '') + ' disponible' + (max > 1 ? 's' : '') + '' } } } updateTotals() }) .catch(() => {}) }, 30000) } }