Travail sur le tunnel de reservation etape final
This commit is contained in:
98
assets/flow_reservation.js
Normal file
98
assets/flow_reservation.js
Normal 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');
|
||||
});
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user