export class FlowReserve extends HTMLAnchorElement { constructor() { super(); this.sidebarId = 'flow-reserve-sidebar'; this.storageKey = 'pl_list'; this.apiUrl = '/basket/json'; this.isOpen = false; } connectedCallback() { this.addEventListener('click', (e) => { e.preventDefault(); this.toggleSidebar(); }); // Listen for updates to the cart from other components window.addEventListener('cart:updated', () => this.updateBadge()); // Initial badge update this.updateBadge(); } /** * Updates the notification badge on the icon */ updateBadge() { const list = this.getList(); const badge = this.querySelector('[data-count]'); if (badge) { badge.innerText = list.length; if (list.length > 0) { badge.classList.remove('hidden'); } else { badge.classList.add('hidden'); } } } getList() { try { return JSON.parse(localStorage.getItem(this.storageKey) || '[]'); } catch (e) { return []; } } removeFromList(id) { let list = this.getList(); list = list.filter(itemId => itemId.toString() !== id.toString()); localStorage.setItem(this.storageKey, JSON.stringify(list)); window.dispatchEvent(new CustomEvent('cart:updated')); this.refreshContent(); // Re-fetch and render } toggleSidebar() { if (this.isOpen) { this.close(); } else { this.open(); } } open() { this.ensureSidebarExists(); const sidebar = document.getElementById(this.sidebarId); const backdrop = sidebar.querySelector('.backdrop'); const panel = sidebar.querySelector('.panel'); sidebar.classList.remove('pointer-events-none'); backdrop.classList.remove('opacity-0'); panel.classList.remove('translate-x-full'); this.isOpen = true; this.refreshContent(); } close() { const sidebar = document.getElementById(this.sidebarId); if (!sidebar) return; const backdrop = sidebar.querySelector('.backdrop'); const panel = sidebar.querySelector('.panel'); backdrop.classList.add('opacity-0'); panel.classList.add('translate-x-full'); setTimeout(() => { sidebar.classList.add('pointer-events-none'); }, 300); // Match transition duration this.isOpen = false; } ensureSidebarExists() { if (document.getElementById(this.sidebarId)) return; const template = `

Ma Super
Future Réservation

`; document.body.insertAdjacentHTML('beforeend', template); // Bind events const sidebar = document.getElementById(this.sidebarId); const closeHandler = (e) => { if (e) { e.preventDefault(); e.stopPropagation(); } this.close(); }; sidebar.querySelector('.backdrop').addEventListener('click', closeHandler); sidebar.querySelector('#flow-reserve-close').addEventListener('click', closeHandler); } async refreshContent() { const container = document.getElementById('flow-reserve-content'); const footer = document.getElementById('flow-reserve-footer'); // Loader container.innerHTML = `
`; footer.innerHTML = ''; const ids = this.getList(); // Retrieve dates from localStorage let dates = { start: null, end: null }; try { dates = JSON.parse(localStorage.getItem('reservation_dates') || '{}'); } catch (e) { console.warn('Invalid reservation dates in localStorage'); } if (ids.length === 0) { this.renderEmpty(container, footer); return; } try { const response = await fetch(this.apiUrl, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ ids, start: dates.start, end: dates.end }) }); if (!response.ok) throw new Error('Erreur réseau'); const data = await response.json(); // Merge client-side dates if server didn't return them (or to prioritize client choice) if (!data.start_date && dates.start) data.start_date = this.formatDate(dates.start); if (!data.end_date && dates.end) data.end_date = this.formatDate(dates.end); // Fallback: if server returns dates in a format we can use directly, fine. // If we just want to display what is in local storage: if (dates.start) data.start_date = this.formatDate(dates.start); if (dates.end) data.end_date = this.formatDate(dates.end); this.renderList(container, footer, data); } catch (error) { console.error(error); container.innerHTML = `

Une erreur est survenue lors du chargement de votre panier.

`; } } renderEmpty(container, footer) { container.innerHTML = `

Votre panier est vide

Ajoutez du bonheur à votre événement !

Voir le catalogue
`; footer.innerHTML = ''; container.querySelector('#flow-empty-catalog-link').addEventListener('click', () => this.close()); } renderList(container, footer, data) { // --- HEADER DATES --- let datesHtml = ''; if (data.start_date && data.end_date) { datesHtml = `

Votre période

${data.start_date} ${data.end_date}
`; } // --- RENDER PRODUCTS --- const productsHtml = data.products.map(product => `
${product.name}

${product.name}

1J: ${this.formatPrice(product.priceHt1Day)} HT ${product.priceHTSupDay ? `|Sup: ${this.formatPrice(product.priceHTSupDay)} HT` : ''}
${this.formatPrice(product.totalPriceTTC || product.totalPriceHT)} Total
`).join(''); container.innerHTML = `
${datesHtml}${productsHtml}
`; // Attach event listeners container.querySelectorAll('.remove-btn').forEach(btn => { btn.addEventListener('click', (e) => { e.preventDefault(); e.stopPropagation(); this.removeFromList(btn.dataset.removeId); }); }); // --- RENDER FOOTER (TOTALS) --- const total = data.total || {}; const hasTva = total.totalTva > 0; footer.innerHTML = `
Total HT ${this.formatPrice(total.totalHT)}
${hasTva ? `
TVA ${this.formatPrice(total.totalTva)}
` : ''}
Total ${hasTva ? 'TTC' : 'HT'} ${this.formatPrice(total.totalTTC || total.totalHT)}
Valider ma demande `; const validateBtn = footer.querySelector('#flow-validate-btn'); if (validateBtn) { validateBtn.addEventListener('click', (e) => { this.validateBasket(e); }); } } async validateBasket(e) { e.preventDefault(); const ids = this.getList(); let dates = { start: null, end: null }; try { dates = JSON.parse(localStorage.getItem('reservation_dates') || '{}'); } catch (error) { console.warn('Invalid reservation dates in localStorage'); } try { const response = await fetch('/reservation/session', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ ids, start: dates.start, end: dates.end }) }); if (!response.ok) throw new Error('Erreur réseau'); const data = await response.json(); if (data.flowUrl) { window.location.href = data.flowUrl; } } catch (error) { console.error('Erreur lors de la validation du panier', error); } } formatDate(dateString) { if (!dateString) return ''; try { const date = new Date(dateString); return new Intl.DateTimeFormat('fr-FR').format(date); } catch (e) { return dateString; } } formatPrice(amount) { if (amount === undefined || amount === null) return '-'; return new Intl.NumberFormat('fr-FR', { style: 'currency', currency: 'EUR' }).format(amount); } }