feat(ReserverController): Gère les options de produits au panier et en session.

Ajoute la gestion des options de produits lors de l'ajout au panier et dans la session de réservation. Inclut des corrections pour les options orphelines.
```
This commit is contained in:
Serreau Jovann
2026-02-04 11:58:07 +01:00
parent d23e75034c
commit 900b55c07b
8 changed files with 361 additions and 55 deletions

View File

@@ -43,15 +43,30 @@ export class FlowAddToCart extends HTMLElement {
if (!response.ok) throw new Error('Network error');
const data = await response.json();
if (data.dispo) {
// 4. Add to Cart
const list = JSON.parse(localStorage.getItem('pl_list') || '[]');
if (data.dispo) {
// 4. Add to Cart
const list = JSON.parse(localStorage.getItem('pl_list') || '[]');
// --- Save Options ---
const selectedOptions = Array.from(document.querySelectorAll('.product-option-checkbox:checked'))
.map(cb => cb.value);
const allOptions = JSON.parse(localStorage.getItem('pl_options') || '{}'); console.log(selectedOptions);
if (selectedOptions.length > 0) {
allOptions[this.productId] = selectedOptions;
} else {
delete allOptions[this.productId];
}
localStorage.setItem('pl_options', JSON.stringify(allOptions));
// --------------------
if (!list.includes(this.productId)) {
list.push(this.productId);
localStorage.setItem('pl_list', JSON.stringify(list));
window.dispatchEvent(new CustomEvent('cart:updated'));
}
// Open Cart
const cart = document.querySelector('[is="flow-reserve"]');
if (cart) cart.open();

View File

@@ -51,10 +51,26 @@ export class FlowReserve extends HTMLAnchorElement {
}
}
getOptions() {
try {
return JSON.parse(localStorage.getItem('pl_options') || '{}');
} catch (e) {
return {};
}
}
removeFromList(id) {
let list = this.getList();
list = list.filter(itemId => itemId.toString() !== id.toString());
localStorage.setItem(this.storageKey, JSON.stringify(list));
// Remove options for this product
const options = this.getOptions();
if (options[id]) {
delete options[id];
localStorage.setItem('pl_options', JSON.stringify(options));
}
window.dispatchEvent(new CustomEvent('cart:updated'));
this.refreshContent(); // Re-fetch and render
}
@@ -211,6 +227,7 @@ export class FlowReserve extends HTMLAnchorElement {
footer.innerHTML = '';
const ids = this.getList();
const options = this.getOptions();
// Retrieve dates from localStorage
let dates = { start: null, end: null };
@@ -248,6 +265,7 @@ export class FlowReserve extends HTMLAnchorElement {
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
ids,
options,
start: dates.start,
end: dates.end
})
@@ -323,8 +341,22 @@ export class FlowReserve extends HTMLAnchorElement {
`;
}
// --- RENDER PRODUCTS ---
const productsHtml = data.products.map(product => `
const productsHtml = data.products.map(product => {
let optionsHtml = '';
if (product.options && product.options.length > 0) {
optionsHtml = '<div class="mt-1 space-y-1 bg-slate-50 p-2 rounded-lg">';
product.options.forEach(opt => {
optionsHtml += `
<div class="flex justify-between text-[9px] text-slate-500 font-medium">
<span>+ ${opt.name}</span>
<span>${this.formatPrice(opt.price)}</span>
</div>
`;
});
optionsHtml += '</div>';
}
return `
<div class="flex gap-4 bg-white p-3 rounded-2xl shadow-sm border border-gray-100">
<div class="w-20 h-20 bg-gray-100 rounded-xl flex-shrink-0 overflow-hidden">
<img src="${product.image || '/provider/images/favicon.png'}" class="w-full h-full object-cover" alt="${product.name}">
@@ -336,6 +368,7 @@ export class FlowReserve extends HTMLAnchorElement {
<span>1J: ${this.formatPrice(product.priceHt1Day)} HT</span>
${product.priceHTSupDay ? `<span class="text-slate-300">|</span><span>Sup: ${this.formatPrice(product.priceHTSupDay)} HT</span>` : ''}
</div>
${optionsHtml}
</div>
<div class="flex justify-between items-end mt-2">
<span class="text-[#0782bc] font-black text-sm">${this.formatPrice(product.totalPriceTTC || product.totalPriceHT)} <span class="text-[9px] text-slate-400 font-bold">Total</span></span>
@@ -345,7 +378,8 @@ export class FlowReserve extends HTMLAnchorElement {
</div>
</div>
</div>
`).join('');
`;
}).join('');
container.innerHTML = `<div class="space-y-3">${datesHtml}${productsHtml}</div>`;
@@ -396,6 +430,7 @@ export class FlowReserve extends HTMLAnchorElement {
e.preventDefault();
const ids = this.getList();
const options = this.getOptions();
let dates = { start: null, end: null };
try {
dates = JSON.parse(localStorage.getItem('reservation_dates') || '{}');
@@ -409,6 +444,7 @@ export class FlowReserve extends HTMLAnchorElement {
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
ids,
options,
start: dates.start,
end: dates.end
})