· 4 months ago · May 20, 2025, 04:05 PM
1 const colorKeyMap = {
2 'Noir': 'color_black',
3 'Blanc': 'color_white',
4 'Bleu Ciel': 'color_lightblue',
5 'Bleu': 'color_blue',
6 'Gris': 'color_grey',
7 'Rose': 'color_pink',
8 'Vert': 'color_green',
9 'Beige': 'color_beige',
10 'Violet': 'color_purple',
11 'Bleu Marine': 'color_navy',
12 'Rose Floral': 'color_rose_floral',
13 'Jaune Moutarde': 'color_mustard',
14 'Bleu Délavé': 'color_fadedblue',
15 'Rouge': 'color_red',
16 'Bleu foncé': 'color_darkblue'
17 };
18
19 const sizeKeyMap = {
20 'S': 'size_s',
21 'M': 'size_m',
22 'L': 'size_l',
23 'XL': 'size_xl',
24 'XXL': 'size_xxl',
25 '36': 'size_36',
26 '38': 'size_38',
27 '40': 'size_40',
28 '42': 'size_42',
29 '44': 'size_44'
30 };
31
32 function getTranslatedColorName(color) {
33 const lang = getLanguage();
34 return getTranslation(colorKeyMap[color] || 'color_custom', lang)?.replace('{value}', color) || color;
35 }
36
37 function getTranslatedSize(size) {
38 const lang = getLanguage();
39 const sizeKey = sizeKeyMap[size];
40 return sizeKey ? getTranslation(sizeKey, lang) || size : size;
41 }
42
43 function applyLanguage(lang) {
44 console.log('Application de la langue:', lang);
45 document.querySelectorAll('[data-lang]').forEach(elem => {
46 const key = elem.getAttribute('data-lang');
47 const translation = getTranslation(key, lang);
48 if (translation && translation !== key) {
49 elem.textContent = translation;
50 } else {
51 console.warn(`Traduction manquante pour ${key} dans ${lang}`);
52 }
53 });
54 document.querySelectorAll('[data-color]').forEach(elem => {
55 const color = elem.getAttribute('data-color');
56 elem.textContent = getTranslatedColorName(color);
57 });
58 const currentFlag = document.querySelector('.current-lang-flag');
59 const currentLangName = document.querySelector('.current-lang-name');
60 if (currentFlag && currentLangName) {
61 currentFlag.src = `assets/images/${lang === 'ar' ? 'algeria' : 'france'}.png`;
62 currentFlag.alt = getTranslation(lang === 'ar' ? 'country_algeria' : 'country_france', lang);
63 currentLangName.textContent = getTranslation(lang === 'ar' ? 'country_algeria' : 'country_france', lang);
64 }
65 }
66
67 function setLanguage(lang) {
68 console.log('Changement de langue vers:', lang);
69 localStorage.setItem('aminaShopLanguage', lang);
70 document.documentElement.lang = lang;
71 document.body.classList.toggle('font-arabic', lang === 'ar');
72 document.body.classList.toggle('font-latin', lang !== 'ar');
73 document.body.classList.toggle('rtl', lang === 'ar');
74 applyLanguage(lang);
75 loadFeaturedProducts();
76 loadProducts();
77 loadCategories();
78 loadCart();
79 }
80
81 function positionCartDropdown() {
82 const cartDropdown = document.getElementById('cart-dropdown');
83 const cartToggle = document.getElementById('cart-toggle');
84 if (cartDropdown && cartToggle) {
85 cartDropdown.style.display = 'block';
86 cartDropdown.style.display = '';
87 }
88 }
89
90/* essai carrousell */
91 fetch('api/products.php?action=get_products')
92 .then(response => response.json())
93 .then(data => {
94 const products = data.products; // Récupère les produits correctement
95 generateNewProductsSlider(products);
96 })
97 .catch(error => console.error("Erreur lors de la récupération des produits:", error));
98
99function generateNewProductsSlider(products) {
100 if (!Array.isArray(products) || products.length === 0) {
101 console.error("Aucun produit trouvé ou format incorrect.", products);
102 return;
103 }
104
105 const newProductsContainer = document.getElementById('new-products');
106
107 products.forEach(product => {
108 if (!product.new) return;
109
110 let images = [];
111 try {
112 images = JSON.parse(product.images || '[]').filter(img => img && typeof img === 'string');
113 } catch (error) {
114 console.error("Erreur de parsing des images pour le produit:", product.id, error);
115 }
116
117 const imageSrc = images.length > 0 ? images[0] : "default.jpg";
118 const name = (document.documentElement.lang === "ar" && product.name_ar ? product.name_ar : product.name) || 'Produit sans nom';
119
120 const slideHtml = `
121 <li class="splide__slide">
122 <div class="product-card bg-white rounded-lg shadow-lg overflow-hidden hover:shadow-xl transition">
123 <a href="single-product.html?id=${product.id}">
124 <img src="${imageSrc}" alt="${name}" class="w-full h-48 object-cover lazyload transition-transform transform hover:scale-105">
125 <div class="p-4">
126 <h3 class="text-lg font-semibold text-gray-800">${name}</h3>
127 <p class="text-gray-600 mt-2">
128 ${product.originalPrice > product.price ? `<span class="line-through text-sm text-gray-500">${product.originalPrice} DZD</span> ` : ''}
129 <span class="text-lg font-bold text-red-600">${product.price} DZD</span>
130 </p>
131 </div>
132 </a>
133 </div>
134 </li>
135 `;
136
137 newProductsContainer.insertAdjacentHTML('beforeend', slideHtml);
138 });
139
140 // Initialisation du carrousel Splide.js avec correction RTL
141 new Splide('#new-products-slider', {
142 type: 'loop',
143 perPage: 3,
144 focus: 'center',
145 gap: '1rem',
146 autoplay: true,
147 interval: 3000,
148 pagination: true,
149 arrows: true,
150 direction: document.documentElement.lang === "ar" ? "rtl" : "ltr", // Détection automatique de la langue
151 breakpoints: {
152 640: { perPage: 1 }, // Mobile : 1 produit visible
153 768: { perPage: 2 }, // Tablette : 2 produits visibles
154 1024: { perPage: 3 }, // Bureau : 3 produits visibles
155 }
156 }).mount();
157}
158
159/* fin essai carrousell */
160 async function loadFeaturedProducts() {
161 console.log('Chargement produits phares...');
162 const featuredGrid = document.getElementById('featured-products');
163 if (!featuredGrid) {
164 console.error('Erreur: #featured-products introuvable');
165 return;
166 }
167 try {
168 const lang = getLanguage();
169 const response = await fetch('api/products.php?action=get_products');
170 if (!response.ok) {
171 throw new Error(`Erreur HTTP: ${response.status}`);
172 }
173 const data = await response.json();
174 console.log('Réponse API produits phares:', data);
175 featuredGrid.innerHTML = '';
176 if (data.success && data.products) {
177 const featured = data.products.filter(p => p.promotion || p.new).slice(0, 4);
178 if (featured.length) {
179 featured.forEach(product => {
180 const name = (lang === 'ar' && product.name_ar ? product.name_ar : product.name) || 'Produit sans nom';
181 const images = JSON.parse(product.images || '[]').filter(img => img && typeof img === 'string');
182 const imageSrc = images.length > 0 ? images[0] : '';
183 const price = parseFloat(product.price || 0);
184 const originalPrice = parseFloat(product.original_price || price);
185 const colors = JSON.parse(product.colors || '[]').filter(c => c && typeof c === 'string');
186 const sizes = JSON.parse(product.sizes || '[]').filter(s => s && typeof s === 'string');
187 const cardHtml = `
188 <div class="product-card relative bg-white rounded-lg shadow-lg overflow-hidden hover:shadow-xl transition">
189 <a href="single-product.html?id=${product.id}" class="block">
190 ${imageSrc ? `<img src="${imageSrc}" alt="${name}" class="w-full h-48 object-cover lazyload transition-transform transform hover:scale-105">` : ''}
191 <div class="p-4">
192 <h3 class="text-lg font-semibold text-gray-800">${name}</h3>
193 <p class="text-gray-600 mt-2">
194 ${originalPrice > price ? `<span class="line-through text-sm text-gray-500">${getTranslation('price_dzd', lang, { price: originalPrice.toFixed(2) })}</span> ` : ''}
195 <span class="text-lg font-bold text-red-600">${getTranslation('price_dzd', lang, { price: price.toFixed(2) })}</span>
196 </p>
197 </div>
198 </a>
199 <div class="p-4 pt-0">
200 <label class="block text-sm font-medium mb-1 text-gray-700" data-lang="color">Couleur:</label>
201 <select class="w-full p-2 border rounded-md bg-gray-100 focus:ring-2 focus:ring-blue-500 transition" data-color-select data-product-id="${product.id}">
202 ${colors.map(color => `<option value="${color}">${getTranslatedColorName(color)}</option>`).join('')}
203 </select>
204
205 <label class="block text-sm font-medium mt-2 mb-1 text-gray-700" data-lang="size">Taille:</label>
206 <select class="w-full p-2 border rounded-md bg-gray-100 focus:ring-2 focus:ring-blue-500 transition" data-size-select data-product-id="${product.id}">
207 ${sizes.map(size => `<option value="${size}">${size}</option>`).join('')}
208 </select>
209
210 <button class="add-to-cart-btn mt-2 bg-blue-600 text-white py-2 px-3 rounded-lg hover:bg-blue-700 transition w-full" data-product-id="${product.id}" disabled>
211 ${getTranslation('add_to_cart', lang)}
212 </button>
213 </div>
214
215 <div class="badges absolute top-2 left-2 space-y-1 z-10 rtl:left-auto rtl:right-2">
216 <span class="badge bg-red-500 text-white px-2 py-1 rounded-full text-xs ${product.promotion ? '' : 'hidden'}" data-lang="promo_badge">🔥 Promo</span>
217 <span class="badge bg-green-500 text-white px-2 py-1 rounded-full text-xs ${product.new ? '' : 'hidden'}" data-lang="new_badge">🆕 Nouveau</span>
218 </div>
219</div>
220`;
221 featuredGrid.insertAdjacentHTML('beforeend', cardHtml);
222 });
223 } else {
224 featuredGrid.innerHTML = `<p class="col-span-full text-center text-gray-600">${getTranslation('no_featured_products', lang)}</p>`;
225 }
226 } else {
227 console.warn('Aucun produit phare:', data);
228 featuredGrid.innerHTML = `<p class="col-span-full text-center text-gray-600">${getTranslation('no_featured_products', lang)}</p>`;
229 }
230 applyLanguage(lang);
231 } catch (error) {
232 console.error('Erreur chargement produits phares:', error);
233 featuredGrid.innerHTML = `<p class="col-span-full text-center text-gray-600">${getTranslation('error_loading', lang)}</p>`;
234 }
235 }
236
237 async function loadCategories() {
238 console.log('Chargement catégories...');
239 const categoryFilters = document.getElementById('category-filters');
240 if (!categoryFilters) {
241 console.error('Erreur: #category-filters introuvable');
242 return;
243 }
244 try {
245 const lang = getLanguage();
246 const response = await fetch('api/categories.php?action=get_categories');
247 if (!response.ok) {
248 throw new Error(`Erreur HTTP: ${response.status}`);
249 }
250 const data = await response.json();
251 console.log('Réponse API catégories:', data);
252 categoryFilters.innerHTML = '';
253 if (data.success && data.categories) {
254 data.categories.forEach(category => {
255 const categoryName = lang === 'ar' ? category.name_ar : category.name;
256 const btnHtml = `
257 <button class="category-filter bg-gray-200 text-gray-700 py-2 px-4 rounded-lg hover:bg-green-600 hover:text-white transition" data-category="${category.id}">
258 ${categoryName}
259 </button>
260 `;
261 categoryFilters.insertAdjacentHTML('beforeend', btnHtml);
262 });
263 } else {
264 console.warn('Aucune catégorie:', data);
265 categoryFilters.innerHTML = `<p class="text-gray-600">${getTranslation('no_categories', lang)}</p>`;
266 }
267 applyLanguage(lang);
268 } catch (error) {
269 console.error('Erreur chargement catégories:', error);
270 categoryFilters.innerHTML = `<p class="text-gray-600">${getTranslation('error_loading', lang)}</p>`;
271 }
272 }
273
274 async function loadProducts(categoryId = 'all') {
275 console.log('Chargement produits, catégorie:', categoryId);
276 const productGrid = document.getElementById('product-grid');
277 if (!productGrid) {
278 console.error('Erreur: #product-grid introuvable');
279 return;
280 }
281 try {
282 const lang = getLanguage();
283 const response = await fetch('api/products.php?action=get_products');
284 if (!response.ok) {
285 throw new Error(`Erreur HTTP: ${response.status}`);
286 }
287 const data = await response.json();
288 console.log('Réponse API produits:', data);
289 productGrid.innerHTML = '';
290 if (data.success && data.products) {
291 const products = categoryId === 'all' ? data.products : data.products.filter(p => p.category_id == categoryId);
292 if (products.length) {
293 products.slice(0, 8).forEach(product => {
294 const name = (lang === 'ar' && product.name_ar ? product.name_ar : product.name) || 'Produit sans nom';
295 const images = JSON.parse(product.images || '[]').filter(img => img && typeof img === 'string');
296 const imageSrc = images.length > 0 ? images[0] : '';
297 const price = parseFloat(product.price || 0);
298 const originalPrice = parseFloat(product.original_price || price);
299 const colors = JSON.parse(product.colors || '[]').filter(c => c && typeof c === 'string');
300 const sizes = JSON.parse(product.sizes || '[]').filter(s => s && typeof s === 'string');
301 const cardHtml = `
302 <div class="product-card relative">
303 <a href="single-product.html?id=${product.id}" class="block">
304 ${imageSrc ? `<img src="${imageSrc}" alt="${name}" class="w-full h-48 object-cover lazyload">` : ''}
305 <div class="p-4">
306 <h3 class="text-base font-semibold">${name}</h3>
307 <p class="text-gray-600 mt-2">
308 ${originalPrice > price ? `<span class="line-through text-sm">${getTranslation('price_dzd', lang, { price: originalPrice.toFixed(2) })}</span> ` : ''}
309 <span class="font-semibold">${getTranslation('price_dzd', lang, { price: price.toFixed(2) })}</span>
310 </p>
311 </div>
312 </a>
313 <div class="p-4 pt-0">
314 <label class="block text-sm font-medium mb-1" data-lang="color">Couleur:</label>
315 <select class="w-full p-1 border rounded" data-color-select data-product-id="${product.id}">
316 ${colors.map(color => `<option value="${color}">${getTranslatedColorName(color)}</option>`).join('')}
317 </select>
318 <label class="block text-sm font-medium mt-2 mb-1" data-lang="size">Taille:</label>
319 <select class="w-full p-1 border rounded" data-size-select data-product-id="${product.id}">
320 ${sizes.map(size => `<option value="${size}">${size}</option>`).join('')}
321 </select>
322 <button class="add-to-cart-btn mt-2 bg-green-600 text-white py-1 px-3 rounded-lg hover:bg-green-700 transition w-full" data-product-id="${product.id}" disabled>
323 ${getTranslation('add_to_cart', lang)}
324 </button>
325 </div>
326 <div class="badges absolute top-2 left-2 space-y-1 z-10 rtl:left-auto rtl:right-2">
327 <span class="badge bg-red-600 text-white ${product.promotion ? '' : 'hidden'}" data-lang="promo_badge">Promotion</span>
328 <span class="badge bg-green-600 text-white ${product.new ? '' : 'hidden'}" data-lang="new_badge">Nouveau</span>
329 </div>
330 </div>
331 `;
332 productGrid.insertAdjacentHTML('beforeend', cardHtml);
333 });
334 } else {
335 productGrid.innerHTML = `<p class="col-span-full text-center text-gray-600">${getTranslation('no_products', lang)}</p>`;
336 }
337 } else {
338 console.warn('Aucun produit:', data);
339 productGrid.innerHTML = `<p class="col-span-full text-center text-gray-600">${getTranslation('no_products', lang)}</p>`;
340 }
341 applyLanguage(lang);
342 } catch (error) {
343 console.error('Erreur chargement produits:', error);
344 productGrid.innerHTML = `<p class="col-span-full text-center text-gray-600">${getTranslation('error_loading', lang)}</p>`;
345 }
346 }
347
348 async function addToCart(productId, size, color) {
349 const lang = getLanguage();
350 if (!productId || isNaN(productId)) {
351 console.error('ID produit invalide:', productId);
352 showNotification('invalid_product_id', 'error', {}, 'error_title');
353 return;
354 }
355 const payload = {
356 action: 'add_to_cart',
357 product_id: parseInt(productId),
358 quantity: 1,
359 size: size || null,
360 color: color || null
361 };
362 console.log('Envoi payload:', payload);
363 try {
364 const response = await fetch('api/cart.php', {
365 method: 'POST',
366 headers: { 'Content-Type': 'application/json' },
367 body: JSON.stringify(payload)
368 });
369 const data = await response.json();
370 console.log('Réponse API ajout:', data);
371 if (data.success) {
372 showNotification('item_added_to_cart', 'success', {}, 'success_title');
373 const cartCount = document.getElementById('cart-count');
374 if (cartCount) {
375 cartCount.textContent = parseInt(cartCount.textContent) + 1;
376 }
377 const cartIcon = document.getElementById('cart-icon');
378 if (cartIcon) {
379 cartIcon.classList.remove('text-blue-600');
380 cartIcon.classList.add('text-red-600');
381 }
382 loadCart();
383 } else {
384 console.error('Erreur API:', data.error);
385 showNotification('error_adding_to_cart', 'error', { error: data.error || 'Unknown' }, 'error_title');
386 }
387 } catch (error) {
388 console.error('Erreur réseau:', error);
389 showNotification('error_adding_to_cart', 'error', { error: error.message }, 'error_title');
390 }
391 }
392
393 async function loadCart() {
394 try {
395 const lang = getLanguage();
396 console.log('Chargement chariot, langue:', lang);
397 const response = await fetch(`api/cart.php?lang=${lang}`, {
398 credentials: 'same-origin'
399 });
400 if (!response.ok) {
401 throw new Error(`Erreur HTTP: ${response.status}`);
402 }
403 const data = await response.json();
404 console.log('Réponse API chariot:', data);
405 const cartCount = document.getElementById('cart-count');
406 const cartItems = document.getElementById('cart-items');
407 const cartIcon = document.getElementById('cart-icon');
408 if (!cartItems) {
409 console.error('Élément DOM #cart-items introuvable');
410 showNotification('error_loading_cart', 'error', { error: 'Éléments chariot introuvables' }, 'error_title');
411 return;
412 }
413 if (data.success) {
414 if (cartCount) {
415 cartCount.textContent = data.items?.length || 0;
416 }
417 if (cartIcon) {
418 cartIcon.classList.toggle('text-red-600', data.items?.length > 0);
419 cartIcon.classList.toggle('text-blue-600', data.items?.length === 0);
420 }
421 cartItems.innerHTML = '';
422 if (data.items?.length) {
423 data.items.forEach(item => {
424 const itemName = item.name || getTranslation('missing_name', lang, { id: item.product_id });
425 const itemPrice = parseFloat(item.price || 0);
426 const colorTranslated = item.color ? getTranslatedColorName(item.color) : '';
427 const sizeTranslated = item.size ? item.size : '';
428 const itemHtml = `
429 <div class="flex items-center space-x-4 rtl:space-x-reverse border-b py-1">
430 ${item.image ? `<img src="${item.image}" alt="${itemName}" class="w-12 h-12 object-cover rounded-lg lazyload">` : ''}
431 <div class="flex-1">
432 <p class="text-sm font-semibold text-gray-800">${itemName}</p>
433 <p class="text-xs text-gray-500">${item.size ? getTranslation('size', lang) + ': ' + sizeTranslated : ''} ${item.color ? getTranslation('color', lang) + ': ' + colorTranslated : ''}</p>
434 <p class="text-xs text-gray-600" data-price="${itemPrice}">${getTranslation('price_dzd', lang, { price: itemPrice.toFixed(2) })} x ${item.quantity}</p>
435 </div>
436 <button class="remove-cart-item text-red-500 hover:text-red-700" data-key="${item.key}">
437 <i class="fas fa-trash"></i>
438 </button>
439 </div>
440 `;
441 cartItems.insertAdjacentHTML('beforeend', itemHtml);
442 });
443 } else {
444 cartItems.innerHTML = `<p class="text-center text-gray-600">${getTranslation('cart_empty', lang)}</p>`;
445 }
446 applyLanguage(lang);
447 } else {
448 console.error('Erreur API chariot:', data.error);
449 showNotification('error_loading_cart', 'error', { error: data.error || 'Unknown' }, 'error_title');
450 cartItems.innerHTML = `<p class="text-center text-gray-600">${getTranslation('cart_empty', lang)}</p>`;
451 if (cartCount) cartCount.textContent = 0;
452 }
453 } catch (error) {
454 console.error('Erreur réseau:', error);
455 showNotification('error_loading_cart', 'error', { error: error.message }, 'error_title');
456 }
457 }
458
459 async function removeFromCart(key) {
460 try {
461 const payload = { key };
462 console.log('Envoi payload suppression:', payload);
463 const response = await fetch('api/cart.php', {
464 method: 'DELETE',
465 headers: { 'Content-Type': 'application/json' },
466 body: JSON.stringify(payload)
467 });
468 const data = await response.json();
469 console.log('Réponse API suppression:', data);
470 if (data.success) {
471 showNotification('item_removed_from_cart', 'success', {}, 'success_title');
472 loadCart();
473 } else {
474 console.error('Erreur API:', data.error);
475 showNotification('error_deleting_cart', 'error', { error: data.error || 'Unknown' }, 'error_title');
476 }
477 } catch (error) {
478 console.error('Erreur réseau:', error);
479 showNotification('error_deleting_cart', 'error', { error: error.message }, 'error_title');
480 }
481 }
482
483 function showNotification(key, type, params, titleKey) {
484 const notificationArea = document.getElementById('notification-area');
485 if (!notificationArea) {
486 console.error('Élément #notification-area introuvable');
487 return;
488 }
489 const message = getTranslation(key, getLanguage(), params);
490 const title = getTranslation(titleKey, getLanguage());
491 const notification = document.createElement('div');
492 notification.className = `notification p-3 rounded-lg shadow-lg text-white ${type === 'success' ? 'bg-green-500' : 'bg-red-500'}`;
493 notification.innerHTML = `
494 <h4 class="font-semibold">${title}</h4>
495 <p>${message}</p>
496 `;
497 notificationArea.appendChild(notification);
498 setTimeout(() => notification.remove(), 3000);
499 }
500
501 document.addEventListener('DOMContentLoaded', () => {
502 console.log('DOM chargé pour index.html');
503 const initialLang = localStorage.getItem('aminaShopLanguage') || 'fr';
504 setLanguage(initialLang);
505
506 const hamburger = document.querySelector('.hamburger');
507 const navLinks = document.querySelector('.nav-links');
508 if (hamburger && navLinks) {
509 hamburger.addEventListener('click', () => {
510 console.log('Clic hamburger');
511 navLinks.classList.toggle('hidden');
512 });
513 }
514
515 const langToggle = document.querySelector('.lang-toggle');
516 const langDropdown = document.querySelector('.lang-dropdown');
517 if (langToggle && langDropdown) {
518 langToggle.addEventListener('click', (e) => {
519 e.preventDefault();
520 langDropdown.classList.toggle('hidden');
521 });
522 document.querySelectorAll('.lang-option').forEach(option => {
523 option.addEventListener('click', () => {
524 const lang = option.getAttribute('data-lang');
525 setLanguage(lang);
526 langDropdown.classList.add('hidden');
527 });
528 });
529 }
530
531 const cartToggle = document.getElementById('cart-toggle');
532 const cartDropdown = document.getElementById('cart-dropdown');
533 if (cartToggle && cartDropdown) {
534 cartToggle.addEventListener('mouseenter', () => {
535 cartDropdown.classList.remove('hidden');
536 positionCartDropdown();
537 });
538 cartToggle.addEventListener('mouseleave', () => {
539 setTimeout(() => {
540 if (!cartDropdown.matches(':hover')) {
541 cartDropdown.classList.add('hidden');
542 }
543 }, 100);
544 });
545 cartDropdown.addEventListener('mouseenter', () => {
546 cartDropdown.classList.remove('hidden');
547 });
548 cartDropdown.addEventListener('mouseleave', () => {
549 cartDropdown.classList.add('hidden');
550 });
551 cartToggle.addEventListener('click', (e) => {
552 e.preventDefault();
553 cartDropdown.classList.toggle('hidden');
554 if (!cartDropdown.classList.contains('hidden')) {
555 positionCartDropdown();
556 }
557 });
558 }
559
560 if (document.getElementById('cart-items')) {
561 document.getElementById('cart-items').addEventListener('click', (e) => {
562 if (e.target.closest('.remove-cart-item')) {
563 const button = e.target.closest('.remove-cart-item');
564 const key = button.dataset.key;
565 removeFromCart(key);
566 }
567 });
568 }
569
570 document.addEventListener('change', (e) => {
571 if (e.target.matches('[data-color-select]') || e.target.matches('[data-size-select]')) {
572 const productId = e.target.dataset.productId;
573 const card = document.querySelector(`.product-card [data-product-id="${productId}"]`).closest('.product-card');
574 const colorSelect = card.querySelector('[data-color-select]');
575 const sizeSelect = card.querySelector('[data-size-select]');
576 const button = card.querySelector('.add-to-cart-btn');
577 const hasColors = colorSelect.options.length > 0;
578 const hasSizes = sizeSelect.options.length > 0;
579 const colorSelected = hasColors ? colorSelect.value !== '' : true;
580 const sizeSelected = hasSizes ? sizeSelect.value !== '' : true;
581 button.disabled = !(colorSelected && sizeSelected);
582 if (colorSelected) card.dataset.selectedColor = colorSelect.value;
583 if (sizeSelected) card.dataset.selectedSize = sizeSelect.value;
584 }
585 });
586
587 document.addEventListener('click', (e) => {
588 if (e.target.classList.contains('category-filter')) {
589 const categoryId = e.target.getAttribute('data-category');
590 loadProducts(categoryId);
591 document.querySelectorAll('.category-filter').forEach(btn => btn.classList.remove('bg-green-600', 'text-white'));
592 e.target.classList.add('bg-green-600', 'text-white');
593 }
594
595 if (e.target.classList.contains('add-to-cart-btn')) {
596 const productId = e.target.dataset.productId;
597 const card = e.target.closest('.product-card');
598 const color = card.dataset.selectedColor || null;
599 const size = card.dataset.selectedSize || null;
600 addToCart(productId, size, color);
601 }
602 });
603 });