✨ feat(reservation): Ajoute le panier et sélection de date globale
Ajoute un composant de panier accessible depuis toutes les pages de réservation et un sélecteur de date global.
```
174 lines
8.3 KiB
JavaScript
174 lines
8.3 KiB
JavaScript
export class FlowDatePicker extends HTMLElement {
|
|
constructor() {
|
|
super();
|
|
this.modalId = 'flow-datepicker-modal';
|
|
}
|
|
|
|
connectedCallback() {
|
|
// Find the button inside this element and attach click listener
|
|
const btn = this.querySelector('button');
|
|
if (btn) {
|
|
btn.addEventListener('click', (e) => {
|
|
e.preventDefault();
|
|
this.openModal();
|
|
});
|
|
}
|
|
|
|
// Listen for global open event
|
|
document.addEventListener('open-date-picker', () => this.openModal());
|
|
|
|
// Update header if dates exist in localStorage
|
|
const storedDates = JSON.parse(localStorage.getItem('reservation_dates') || '{}');
|
|
if (storedDates.start && storedDates.end) {
|
|
const headerDisplay = document.getElementById('header-date-display');
|
|
if (headerDisplay) {
|
|
const formatDate = (dateStr) => {
|
|
if (!dateStr) return '';
|
|
const [y, m, d] = dateStr.split('-');
|
|
return `${d}/${m}/${y}`;
|
|
};
|
|
headerDisplay.textContent = `${formatDate(storedDates.start)} au ${formatDate(storedDates.end)}`;
|
|
}
|
|
}
|
|
}
|
|
|
|
openModal() {
|
|
this.ensureModalExists();
|
|
const modal = document.getElementById(this.modalId);
|
|
const backdrop = modal.querySelector('.backdrop');
|
|
const panel = modal.querySelector('.panel');
|
|
|
|
modal.classList.remove('pointer-events-none');
|
|
backdrop.classList.remove('opacity-0');
|
|
panel.classList.remove('translate-y-full', 'opacity-0');
|
|
panel.classList.add('translate-y-0', 'opacity-100');
|
|
}
|
|
|
|
closeModal() {
|
|
const modal = document.getElementById(this.modalId);
|
|
if (!modal) return;
|
|
|
|
const backdrop = modal.querySelector('.backdrop');
|
|
const panel = modal.querySelector('.panel');
|
|
|
|
backdrop.classList.add('opacity-0');
|
|
panel.classList.remove('translate-y-0', 'opacity-100');
|
|
panel.classList.add('translate-y-full', 'opacity-0');
|
|
|
|
setTimeout(() => {
|
|
modal.classList.add('pointer-events-none');
|
|
}, 300);
|
|
}
|
|
|
|
ensureModalExists() {
|
|
if (document.getElementById(this.modalId)) return;
|
|
|
|
// Recuperation des dates du localStorage
|
|
const storedDates = JSON.parse(localStorage.getItem('reservation_dates') || '{}');
|
|
const defaultStart = storedDates.start || '';
|
|
const defaultEnd = storedDates.end || '';
|
|
|
|
// Calculer la date minimum (Aujourd'hui + 7 jours)
|
|
const minDate = new Date();
|
|
minDate.setDate(minDate.getDate() + 7);
|
|
const minDateString = minDate.toISOString().split('T')[0];
|
|
|
|
const template = `
|
|
<div id="${this.modalId}" class="fixed inset-0 z-[110] flex items-end sm:items-center justify-center pointer-events-none px-4 pb-4 sm:p-0">
|
|
<!-- Backdrop -->
|
|
<div class="backdrop absolute inset-0 bg-slate-900/80 backdrop-blur-sm opacity-0 transition-opacity duration-300"></div>
|
|
|
|
<!-- Panel -->
|
|
<div class="panel w-full max-w-lg bg-white rounded-3xl shadow-2xl transform translate-y-full opacity-0 transition-all duration-300 relative z-10 overflow-hidden">
|
|
|
|
<div class="p-8">
|
|
<div class="flex items-center justify-between mb-8">
|
|
<h3 class="text-2xl font-black text-slate-900 uppercase italic tracking-tighter">Vos dates <span class="text-[#f39e36]">d'événement</span></h3>
|
|
<button id="datepicker-close" class="p-2 hover:bg-slate-100 rounded-full transition-colors">
|
|
<svg class="w-6 h-6 text-slate-400" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12"/></svg>
|
|
</button>
|
|
</div>
|
|
|
|
<div class="mb-6 p-4 bg-blue-50 border border-blue-100 rounded-xl">
|
|
<p class="text-sm text-blue-800 font-medium">
|
|
<svg class="w-5 h-5 inline-block mr-1 -mt-0.5 text-blue-600" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M13 16h-1v-4h-1m1-4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z"></path></svg>
|
|
Pour les réservations urgentes (moins de 7 jours), merci de <a href="/contact" class="underline font-bold hover:text-blue-900">nous contacter directement</a>.
|
|
</p>
|
|
</div>
|
|
|
|
<form action="/reservation/dates/update" method="POST" class="space-y-6" data-turbo="false">
|
|
<div class="grid grid-cols-2 gap-4">
|
|
<div class="space-y-2">
|
|
<label for="start_date" class="block text-xs font-bold uppercase tracking-widest text-slate-500">Du</label>
|
|
<input type="date" name="start" id="start_date" required
|
|
value="${defaultStart}"
|
|
class="w-full bg-slate-50 border border-slate-200 text-slate-900 text-sm rounded-xl focus:ring-[#f39e36] focus:border-[#f39e36] block p-3 font-bold"
|
|
min="${minDateString}">
|
|
</div>
|
|
<div class="space-y-2">
|
|
<label for="end_date" class="block text-xs font-bold uppercase tracking-widest text-slate-500">Au</label>
|
|
<input type="date" name="end" id="end_date" required
|
|
value="${defaultEnd}"
|
|
class="w-full bg-slate-50 border border-slate-200 text-slate-900 text-sm rounded-xl focus:ring-[#f39e36] focus:border-[#f39e36] block p-3 font-bold"
|
|
min="${minDateString}">
|
|
</div>
|
|
</div>
|
|
|
|
<button type="submit" class="w-full py-4 bg-[#f39e36] hover:bg-slate-900 text-white rounded-xl font-black uppercase text-sm tracking-widest transition-all shadow-lg shadow-orange-500/20">
|
|
Valider ces dates
|
|
</button>
|
|
</form>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
`;
|
|
document.body.insertAdjacentHTML('beforeend', template);
|
|
|
|
// Bind Close Events
|
|
const modal = document.getElementById(this.modalId);
|
|
modal.querySelector('.backdrop').addEventListener('click', () => this.closeModal());
|
|
modal.querySelector('#datepicker-close').addEventListener('click', () => this.closeModal());
|
|
|
|
// Basic Logic: Ensure End Date >= Start Date & Save to LocalStorage
|
|
const startInput = modal.querySelector('#start_date');
|
|
const endInput = modal.querySelector('#end_date');
|
|
|
|
const saveToLocalStorage = () => {
|
|
localStorage.setItem('reservation_dates', JSON.stringify({
|
|
start: startInput.value,
|
|
end: endInput.value
|
|
}));
|
|
};
|
|
|
|
modal.querySelector('form').addEventListener('submit', (evt) => {
|
|
evt.preventDefault();
|
|
saveToLocalStorage();
|
|
|
|
// Update Header Display
|
|
const headerDisplay = document.getElementById('header-date-display');
|
|
if (headerDisplay) {
|
|
const formatDate = (dateStr) => {
|
|
if (!dateStr) return '';
|
|
const [y, m, d] = dateStr.split('-');
|
|
return `${d}/${m}/${y}`;
|
|
};
|
|
headerDisplay.textContent = `${formatDate(startInput.value)} au ${formatDate(endInput.value)}`;
|
|
}
|
|
|
|
this.closeModal();
|
|
});
|
|
|
|
startInput.addEventListener('change', () => {
|
|
if (endInput.value < startInput.value) {
|
|
endInput.value = startInput.value;
|
|
}
|
|
endInput.min = startInput.value;
|
|
saveToLocalStorage();
|
|
});
|
|
|
|
endInput.addEventListener('change', () => {
|
|
saveToLocalStorage();
|
|
});
|
|
}
|
|
}
|