class RsvReservationSummary extends HTMLElement { // ---- Lifecycle ---------------------------------------------------------- connectedCallback() { this._all_slots = new Map(); // name → { slots, price_per_block } this._form = this.closest('form'); this._build(); if (this._form) { this._handler = e => { this._all_slots.set(e.detail.name, { slots: e.detail.slots, price_per_block: e.detail.price_per_block, }); this._render(); }; this._form.addEventListener('rsv:slots-changed', this._handler); } } disconnectedCallback() { if (this._form && this._handler) { this._form.removeEventListener('rsv:slots-changed', this._handler); } } // ---- Public API --------------------------------------------------------- // Detached, static copy of the current selection for the success message. // Mirrors the live layout minus the interactive "clear all" control. snapshot() { const s = ReservairStrings.summary; const list = this.querySelector('.rsv-summary-list'); const count = this.querySelector('.rsv-summary-count'); const price = this.querySelector('.rsv-summary-price'); const node = document.createElement('div'); node.className = 'rsv-summary rsv-summary-snapshot'; node.innerHTML = `
${s.title}
`; return node; } // ---- Private ------------------------------------------------------------ _build() { const s = ReservairStrings.summary; this.innerHTML = `
${s.title}
`; this.hidden = true; this.querySelector('.rsv-summary-clear').addEventListener('click', () => { this._form?.querySelectorAll('rsv-reservation-selector').forEach(sel => sel.clear()); }); } _render() { const all_slots = [...this._all_slots.values()].flatMap(({ slots, price_per_block }) => slots.map(s => ({ ...s, price_per_block })) ); const n = all_slots.length; const list = this.querySelector('.rsv-summary-list'); const count_el = this.querySelector('.rsv-summary-count'); const price_el = this.querySelector('.rsv-summary-price'); const s = ReservairStrings.summary; const locale = navigator.language; this.hidden = n === 0; if (n === 0) { list.replaceChildren(); count_el.textContent = ''; price_el.textContent = ''; return; } const time_opts = { hour: '2-digit', minute: '2-digit' }; list.replaceChildren(...all_slots.map(slot => { const start = new Date(slot.start_utc); const end = new Date(slot.end_utc); const li = document.createElement('li'); li.className = 'rsv-summary-item'; li.innerHTML = `
${start.toLocaleDateString(locale, { weekday: 'long', day: 'numeric', month: 'long' })} ${start.toLocaleTimeString(locale, time_opts)} – ${end.toLocaleTimeString(locale, time_opts)}
${slot.price_per_block > 0 ? `${slot.price_per_block} ${s.currency}` : ''} `; return li; })); const total = all_slots.reduce((sum, slot) => sum + slot.price_per_block, 0); count_el.textContent = this._fmt_count(n); price_el.textContent = total > 0 ? `${total} ${s.currency}` : ''; } _fmt_count(n) { const s = ReservairStrings.summary; if (n === 1) return s.count_one; if (n < 5) return s.count_few.replace('%d', n); return s.count_many.replace('%d', n); } } customElements.define('rsv-reservation-summary', RsvReservationSummary);