Travail sur le tunnel de reservation etape final

This commit is contained in:
Serreau Jovann
2026-02-01 10:28:09 +01:00
parent 2790be518b
commit aadf05d5bb
11 changed files with 81294 additions and 16 deletions

View File

@@ -0,0 +1,98 @@
class ZipCodeCityUpdater {
constructor(zipCodeInputSelector, citySelectSelector, apiUrl) {
this.zipCodeInput = document.querySelector(zipCodeInputSelector);
this.citySelect = document.querySelector(citySelectSelector); // Changed to citySelect
this.apiUrl = apiUrl;
this.timer = null;
this.debounceTime = 500; // ms
// Store initial value from the select element (if any was pre-selected by Twig)
this.initialCityValue = this.citySelect ? this.citySelect.value : '';
if (this.zipCodeInput && this.citySelect) {
this.zipCodeInput.addEventListener('input', this.debounce(this.handleZipCodeChange.bind(this)));
// Trigger on page load if a zip code is already present
if (this.zipCodeInput.value) {
this.handleZipCodeChange();
}
}
}
debounce(func) {
return function(...args) {
const context = this;
clearTimeout(context.timer);
context.timer = setTimeout(() => func.apply(context, args), context.debounceTime);
};
}
async handleZipCodeChange() {
const zipCode = this.zipCodeInput.value.trim();
// Save current city selection if any, before clearing
const currentlySelectedCity = this.citySelect.value;
// Clear existing options, but keep the default placeholder if any
this.citySelect.innerHTML = '<option value="">Sélectionnez une ville</option>';
this.citySelect.value = '';
this.citySelect.disabled = true; // Disable until cities are loaded or cleared
if (zipCode.length !== 5 || !/^\d+$/.test(zipCode)) {
// If zip code is invalid or empty, disable and reset select
this.citySelect.disabled = false; // Re-enable for placeholder
return;
}
try {
const response = await fetch(this.apiUrl, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({ zipCode: zipCode }),
});
if (!response.ok) {
console.error(`HTTP error! status: ${response.status}`);
this.citySelect.disabled = false; // Re-enable for placeholder
return;
}
const data = await response.json();
if (data.cities && data.cities.length > 0) {
data.cities.forEach(city => {
const option = document.createElement('option');
option.value = city;
option.textContent = city;
this.citySelect.appendChild(option);
});
// Attempt to re-select the city that was previously selected, or the initial one
if (data.cities.includes(currentlySelectedCity)) {
this.citySelect.value = currentlySelectedCity;
} else if (data.cities.includes(this.initialCityValue)) {
this.citySelect.value = this.initialCityValue;
} else if (data.cities.length === 1) {
// Automatically select if only one city is returned and no previous match
this.citySelect.value = data.cities[0];
}
this.citySelect.disabled = false; // Enable once options are loaded
} else {
// If no cities found, ensure select is enabled but shows only placeholder
this.citySelect.disabled = false;
}
} catch (error) {
console.error('Error fetching city:', error);
this.citySelect.disabled = false; // Re-enable on error
}
}
}
// Global initialization - run when the DOM is fully loaded or Turbo loads a new page
document.addEventListener('turbo:load', () => {
// Note: Use CSS selectors for querySelector
new ZipCodeCityUpdater('input[name="billingZipCode"]', '#billingTownSelect', '/cities/lookup');
new ZipCodeCityUpdater('input[name="zipCodeEvent"]', '#townEventSelect', '/cities/lookup');
});

View File

@@ -5,7 +5,9 @@ export class FlowReserve extends HTMLAnchorElement {
this.sidebarId = 'flow-reserve-sidebar';
this.storageKey = 'pl_list';
this.apiUrl = '/basket/json';
this.checkAvailabilityUrl = '/produit/check/basket';
this.isOpen = false;
this.productsAvailable = true;
}
connectedCallback() {
@@ -15,10 +17,14 @@ export class FlowReserve extends HTMLAnchorElement {
});
// Listen for updates to the cart from other components
window.addEventListener('cart:updated', () => this.updateBadge());
window.addEventListener('cart:updated', () => {
this.updateBadge();
this._checkProductAvailability(); // Re-check on cart update
});
// Initial badge update
this.updateBadge();
this._checkProductAvailability();
}
/**
@@ -92,6 +98,42 @@ export class FlowReserve extends HTMLAnchorElement {
this.isOpen = false;
}
async _checkProductAvailability() {
const ids = this.getList();
if (ids.length === 0) {
this.productsAvailable = true;
return;
}
let dates = { start: null, end: null };
try {
dates = JSON.parse(localStorage.getItem('reservation_dates') || '{}');
} catch (e) {
console.warn('Invalid reservation dates in localStorage for availability check');
}
try {
const response = await fetch(this.checkAvailabilityUrl, {
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 lors de la vérification de disponibilité');
const data = await response.json();
this.productsAvailable = data.available;
} catch (error) {
console.error('Erreur lors de la vérification de disponibilité:', error);
this.productsAvailable = false;
}
}
ensureSidebarExists() {
if (document.getElementById(this.sidebarId)) return;
@@ -165,6 +207,23 @@ export class FlowReserve extends HTMLAnchorElement {
if (ids.length === 0) {
this.renderEmpty(container, footer);
this.productsAvailable = true;
return;
}
// Display warning if products are not available
if (!this.productsAvailable) {
container.innerHTML = `
<div class="text-center py-10 bg-red-100 border border-red-200 text-red-700 rounded-xl">
<p class="font-bold mb-2">Attention :</p>
<p>Certains produits de votre panier ne sont plus disponibles. Veuillez vérifier votre sélection.</p>
</div>
`;
footer.innerHTML = `
<button disabled class="block w-full py-4 bg-gray-300 text-gray-500 text-center rounded-2xl font-black uppercase italic tracking-widest cursor-not-allowed">
Valider ma demande (Produits indisponibles)
</button>
`;
return;
}