/** * Shopping/Products Component * Handles product display, filtering, and interactions */ (function () { "use strict"; class ShoppingPage { constructor() { this.productsContainer = document.getElementById("productsContainer"); this.loadingIndicator = document.getElementById("loadingIndicator"); this.errorContainer = document.getElementById("errorContainer"); this.currentCategory = window.Utils.getUrlParameter("category") || "all"; this.currentSort = "newest"; this.products = []; this.init(); } async init() { this.setupEventListeners(); await this.loadProducts(); } setupEventListeners() { // Category filters document.querySelectorAll("[data-category]").forEach((btn) => { btn.addEventListener("click", (e) => { e.preventDefault(); this.currentCategory = e.currentTarget.dataset.category; this.filterProducts(); }); }); // Sort dropdown const sortSelect = document.getElementById("sortSelect"); if (sortSelect) { sortSelect.addEventListener("change", (e) => { this.currentSort = e.target.value; this.filterProducts(); }); } // Search const searchInput = document.getElementById("productSearch"); if (searchInput) { searchInput.addEventListener( "input", window.Utils.debounce((e) => { this.searchProducts(e.target.value); }, 300) ); } } async loadProducts() { if (!this.productsContainer) return; try { this.showLoading(); const response = await window.API.getProducts(); this.products = response.products || response.data || []; this.renderProducts(this.products); this.hideLoading(); } catch (error) { console.error("Error loading products:", error); this.showError("Failed to load products. Please try again later."); this.hideLoading(); } } filterProducts() { let filtered = [...this.products]; // Filter by category if (this.currentCategory && this.currentCategory !== "all") { filtered = filtered.filter( (p) => p.category?.toLowerCase() === this.currentCategory.toLowerCase() ); } // Sort products filtered = this.sortProducts(filtered); this.renderProducts(filtered); } sortProducts(products) { switch (this.currentSort) { case "price-low": return products.sort((a, b) => (a.price || 0) - (b.price || 0)); case "price-high": return products.sort((a, b) => (b.price || 0) - (a.price || 0)); case "name": return products.sort((a, b) => (a.title || a.name || "").localeCompare(b.title || b.name || "") ); case "newest": default: return products.sort( (a, b) => new Date(b.created_at || 0) - new Date(a.created_at || 0) ); } } searchProducts(query) { if (!query.trim()) { this.filterProducts(); return; } const searchTerm = query.toLowerCase(); const filtered = this.products.filter((p) => { const title = (p.title || p.name || "").toLowerCase(); const description = (p.description || "").toLowerCase(); const category = (p.category || "").toLowerCase(); return ( title.includes(searchTerm) || description.includes(searchTerm) || category.includes(searchTerm) ); }); this.renderProducts(filtered); } renderProducts(products) { if (!this.productsContainer) return; if (products.length === 0) { this.productsContainer.innerHTML = `
No products found