const ProductManager = {
init() {
this.loadProducts();
this.setupFilterButtons();
this.setupSearch();
this.setupCartButtons();
},
async loadProducts() {
try {
Utils.showLoading();
const response = await fetch('data/products.json');
if (!response.ok) throw new Error('ไม่สามารถโหลดข้อมูลสินค้าได้');
const data = await response.json();
State.products = data.products;
State.categories = data.categories;
State.tags = data.tags;
this.renderCategories();
this.renderProducts();
} catch (error) {
console.error('Error loading products:', error);
NotificationManager.showError('ไม่สามารถโหลดข้อมูลสินค้าได้');
} finally {
Utils.hideLoading();
}
},
setupSearch() {
const searchInput = document.getElementById('searchInput');
if (!searchInput) return;
let debounceTimeout;
searchInput.addEventListener('input', (e) => {
clearTimeout(debounceTimeout);
debounceTimeout = setTimeout(() => {
const searchTerm = e.target.value.toLowerCase().trim();
this.filterProducts('all', searchTerm);
}, 300);
});
},
setupFilterButtons() {
const filterContainer = document.getElementById('categoryFilters');
if (!filterContainer) return;
filterContainer.addEventListener('click', (e) => {
const button = e.target.closest('.category-filter');
if (!button) return;
const searchTerm = document.getElementById('searchInput')?.value.toLowerCase().trim() || '';
filterContainer.querySelectorAll('.category-filter').forEach(btn => {
btn.classList.remove('active');
});
button.classList.add('active');
const category = button.dataset.category;
this.filterProducts(category, searchTerm);
});
document.getElementById('productGrid')?.addEventListener('click', (e) => {
const tag = e.target.closest('.product-tag');
if (!tag) return;
const tagId = tag.dataset.tag;
if (tagId) {
document.getElementById('searchInput').value = '';
filterContainer.querySelectorAll('.category-filter').forEach(btn => {
btn.classList.remove('active');
});
filterContainer.querySelector('[data-category="all"]').classList.add('active');
this.filterByTag(tagId);
}
});
},
renderCategories() {
const filterContainer = document.getElementById('categoryFilters');
if (!filterContainer) return;
filterContainer.innerHTML = `
<button class="category-filter active" data-category="all">
<i class="fas fa-th"></i> ทั้งหมด
</button>
`;
State.categories
.sort((a, b) => a.order - b.order)
.forEach(category => {
filterContainer.innerHTML += `
<button class="category-filter" data-category="${category.id}">
<i class="fas ${category.icon}"></i> ${category.name}
</button>
`;
});
},
filterProducts(category, searchTerm = '') {
let filteredProducts = category === 'all'
? [...State.products]
: State.products.filter(p => p.category === category);
if (searchTerm) {
filteredProducts = filteredProducts.filter(p =>
p.name.toLowerCase().includes(searchTerm) ||
p.description.toLowerCase().includes(searchTerm) ||
p.tags.some(tag => State.tags[tag]?.name.toLowerCase().includes(searchTerm))
);
}
this.renderProducts(filteredProducts);
this.updateProductCount(filteredProducts.length);
},
filterByTag(tagId) {
const filteredProducts = State.products.filter(p => p.tags.includes(tagId));
this.renderProducts(filteredProducts);
this.updateProductCount(filteredProducts.length);
},
updateProductCount(count) {
const countElement = document.getElementById('productCount');
if (countElement) {
countElement.textContent = `${count} รายการ`;
}
},
renderProducts(products = State.products) {
const productGrid = document.getElementById('productGrid');
if (!productGrid) return;
productGrid.innerHTML = '';
if (products.length === 0) {
productGrid.innerHTML = `
<div class="no-products">
<i class="fas fa-search"></i>
<p>ไม่พบสินค้าที่คุณค้นหา</p>
</div>
`;
return;
}
products
.filter(product => product.available)
.forEach(product => {
const productElement = this.createProductCard(product);
productGrid.appendChild(productElement);
});
},
createProductTags(tags) {
return tags
.map(tag => {
const tagInfo = State.tags[tag];
if (!tagInfo) return '';
return `
<span class="product-tag"
data-tag="${tag}"
style="background-color: ${tagInfo.color}">
<i class="fas ${tagInfo.icon}"></i>
${tagInfo.name}
</span>
`;
})
.join('');
},
createNutritionInfo(nutrition) {
return `
<div class="nutrition-info">
<div class="nutrition-item">
<span class="label">แคลอรี่</span>
<span class="value">${nutrition.calories}</span>
</div>
<div class="nutrition-item">
<span class="label">โปรตีน</span>
<span class="value">${nutrition.protein}g</span>
</div>
<div class="nutrition-item">
<span class="label">คาร์บ</span>
<span class="value">${nutrition.carbs}g</span>
</div>
<div class="nutrition-item">
<span class="label">ไขมัน</span>
<span class="value">${nutrition.fat}g</span>
</div>
</div>
`;
},
createProductCard(product) {
const card = document.createElement('div');
card.className = 'product-card';
const category = State.categories.find(c => c.id === product.category);
const inStock = product.stock > 0;
card.innerHTML = `
<div class="product-image-container">
<img src="${product.image}" alt="${product.name}" loading="lazy">
<div class="product-tags">
${this.createProductTags(product.tags)}
<span class="product-tag category-tag" data-tag="${product.category}">
<i class="fas ${category?.icon || 'fa-tag'}"></i>
${category?.name || 'ทั่วไป'}
</span>
</div>
${product.stock <= 10 && product.stock > 0 ?
`<div class="stock-warning">เหลือเพียง ${product.stock} ชิ้น</div>` : ''}
</div>
<div class="product-content">
<h3 class="product-title">${product.name}</h3>
<p class="product-description">${product.description}</p>
${product.nutrition ? this.createNutritionInfo(product.nutrition) : ''}
<div class="product-allergens">
<small>แจ้งเตือนสารก่อภูมิแพ้: ${product.allergens.join(', ')}</small>
</div>
<div class="product-footer">
<div class="product-price">${Utils.formatPrice(product.price)}</div>
<button class="add-to-cart-btn"
data-product-id="${product.id}"
${!inStock ? 'disabled' : ''}>
<i class="fas ${inStock ? 'fa-cart-plus' : 'fa-times'}"></i>
${inStock ? 'เพิ่มลงตะกร้า' : 'สินค้าหมด'}
</button>
</div>
</div>
`;
return card;
},
setupCartButtons() {
document.addEventListener('click', (e) => {
const addToCartBtn = e.target.closest('.add-to-cart-btn');
if (!addToCartBtn) return;
e.preventDefault();
e.stopPropagation();
const productId = addToCartBtn.dataset.productId;
if (!productId) return;
const product = State.products.find(p => p.id === productId);
if (!product) return;
this.addToCart(product);
});
},
addToCart(product) {
if (!product.available || product.stock <= 0) {
NotificationManager.showError('ขออภัย สินค้าหมด');
return;
}
try {
CartManager.addToCart({
id: product.id,
name: product.name,
price: product.price,
image: product.image,
stock: product.stock
});
// อัพเดทจำนวนสินค้าคงเหลือ
const updatedProduct = State.products.find(p => p.id === product.id);
if (updatedProduct) {
updatedProduct.stock -= 1;
if (updatedProduct.stock <= 0) {
updatedProduct.available = false;
}
this.updateProductCard(updatedProduct);
}
} catch (error) {
console.error('Error adding to cart:', error);
NotificationManager.showError('เกิดข้อผิดพลาดในการเพิ่มสินค้าลงตะกร้า');
}
},
updateProductCard(product) {
const productCard = document.querySelector(`[data-product-id="${product.id}"]`)?.closest('.product-card');
if (!productCard) return;
const addToCartBtn = productCard.querySelector('.add-to-cart-btn');
const stockWarning = productCard.querySelector('.stock-warning');
if (product.stock <= 0) {
addToCartBtn.disabled = true;
addToCartBtn.innerHTML = '<i class="fas fa-times"></i> สินค้าหมด';
if (stockWarning) stockWarning.remove();
} else if (product.stock <= 10) {
addToCartBtn.disabled = false;
if (!stockWarning) {
const warning = document.createElement('div');
warning.className = 'stock-warning';
warning.textContent = `เหลือเพียง ${product.stock} ชิ้น`;
productCard.querySelector('.product-image-container').appendChild(warning);
} else {
stockWarning.textContent = `เหลือเพียง ${product.stock} ชิ้น`;
}
}
}
};