/** * Main Application JavaScript * Handles global state management, API integration, and core functionality */ (function () { "use strict"; // Global state management window.AppState = { cart: [], wishlist: [], products: [], settings: null, user: null, // Initialize state from localStorage init() { this.loadCart(); this.loadWishlist(); this.updateUI(); }, // Cart management loadCart() { try { const saved = localStorage.getItem("cart"); this.cart = saved ? JSON.parse(saved) : []; } catch (error) { console.error("Error loading cart:", error); this.cart = []; } }, saveCart() { try { localStorage.setItem("cart", JSON.stringify(this.cart)); this.updateUI(); } catch (error) { console.error("Error saving cart:", error); } }, addToCart(product, quantity = 1) { const existing = this.cart.find((item) => item.id === product.id); if (existing) { existing.quantity += quantity; } else { this.cart.push({ ...product, quantity }); } this.saveCart(); this.showNotification("Added to cart", "success"); }, removeFromCart(productId) { this.cart = this.cart.filter((item) => item.id !== productId); this.saveCart(); this.showNotification("Removed from cart", "info"); }, updateCartQuantity(productId, quantity) { const item = this.cart.find((item) => item.id === productId); if (item) { item.quantity = Math.max(1, quantity); this.saveCart(); } }, getCartTotal() { return this.cart.reduce( (sum, item) => sum + item.price * item.quantity, 0 ); }, getCartCount() { return this.cart.reduce((sum, item) => sum + item.quantity, 0); }, // Wishlist management loadWishlist() { try { const saved = localStorage.getItem("wishlist"); this.wishlist = saved ? JSON.parse(saved) : []; } catch (error) { console.error("Error loading wishlist:", error); this.wishlist = []; } }, saveWishlist() { try { localStorage.setItem("wishlist", JSON.stringify(this.wishlist)); this.updateUI(); } catch (error) { console.error("Error saving wishlist:", error); } }, addToWishlist(product) { if (!this.wishlist.find((item) => item.id === product.id)) { this.wishlist.push(product); this.saveWishlist(); this.showNotification("Added to wishlist", "success"); } }, removeFromWishlist(productId) { this.wishlist = this.wishlist.filter((item) => item.id !== productId); this.saveWishlist(); this.showNotification("Removed from wishlist", "info"); }, isInWishlist(productId) { return this.wishlist.some((item) => item.id === productId); }, // UI updates updateUI() { this.updateCartUI(); this.updateWishlistUI(); }, updateCartUI() { const count = this.getCartCount(); const badge = document.getElementById("cartCount"); if (badge) { badge.textContent = count; badge.style.display = count > 0 ? "flex" : "none"; } }, updateWishlistUI() { const count = this.wishlist.length; const badge = document.getElementById("wishlistCount"); if (badge) { badge.textContent = count; badge.style.display = count > 0 ? "flex" : "none"; } }, // Notifications showNotification(message, type = "info") { const notification = document.createElement("div"); notification.className = `notification notification-${type}`; notification.textContent = message; notification.setAttribute("role", "alert"); notification.setAttribute("aria-live", "polite"); document.body.appendChild(notification); setTimeout(() => notification.classList.add("show"), 10); setTimeout(() => { notification.classList.remove("show"); setTimeout(() => notification.remove(), 300); }, 3000); }, }; // API Client window.API = { baseURL: "/api", async request(endpoint, options = {}) { try { const response = await fetch(this.baseURL + endpoint, { ...options, headers: { "Content-Type": "application/json", ...options.headers, }, }); if (!response.ok) { throw new Error(`HTTP error! status: ${response.status}`); } return await response.json(); } catch (error) { console.error("API request failed:", error); throw error; } }, // Product endpoints async getProducts(filters = {}) { const params = new URLSearchParams(filters); return this.request(`/products?${params}`); }, async getProduct(id) { return this.request(`/products/${id}`); }, async getFeaturedProducts() { return this.request("/products/featured"); }, // Settings endpoint async getSettings() { return this.request("/settings"); }, // Homepage endpoint async getHomepageSettings() { return this.request("/homepage/settings"); }, // Menu endpoint async getMenu() { return this.request("/menu"); }, // Blog endpoints async getBlogPosts() { return this.request("/blog"); }, async getBlogPost(id) { return this.request(`/blog/${id}`); }, // Portfolio endpoints async getPortfolioProjects() { return this.request("/portfolio"); }, async getPortfolioProject(id) { return this.request(`/portfolio/${id}`); }, // Pages endpoints async getPages() { return this.request("/pages"); }, async getPage(slug) { return this.request(`/pages/${slug}`); }, }; // Utility functions window.Utils = { // Format currency formatCurrency(amount) { return new Intl.NumberFormat("en-US", { style: "currency", currency: "USD", }).format(amount); }, // Format date formatDate(date) { return new Intl.DateTimeFormat("en-US", { year: "numeric", month: "long", day: "numeric", }).format(new Date(date)); }, // Debounce function debounce(func, wait) { let timeout; return function executedFunction(...args) { const later = () => { clearTimeout(timeout); func(...args); }; clearTimeout(timeout); timeout = setTimeout(later, wait); }; }, // Get URL parameter getUrlParameter(name) { const params = new URLSearchParams(window.location.search); return params.get(name); }, // Safe HTML encode escapeHtml(text) { const div = document.createElement("div"); div.textContent = text; return div.innerHTML; }, // Show loading state showLoading(element) { if (element) { element.classList.add("loading"); element.setAttribute("aria-busy", "true"); } }, hideLoading(element) { if (element) { element.classList.remove("loading"); element.setAttribute("aria-busy", "false"); } }, }; // Initialize on DOM ready if (document.readyState === "loading") { document.addEventListener("DOMContentLoaded", () => { window.AppState.init(); }); } else { window.AppState.init(); } // Add notification styles if not exists if (!document.getElementById("notification-styles")) { const style = document.createElement("style"); style.id = "notification-styles"; style.textContent = ` .notification { position: fixed; top: 20px; right: 20px; padding: 15px 20px; background: white; border-radius: 8px; box-shadow: 0 4px 12px rgba(0,0,0,0.15); z-index: 10000; opacity: 0; transform: translateX(400px); transition: all 0.3s ease; max-width: 300px; } .notification.show { opacity: 1; transform: translateX(0); } .notification-success { border-left: 4px solid #28a745; } .notification-error { border-left: 4px solid #dc3545; } .notification-info { border-left: 4px solid #17a2b8; } .notification-warning { border-left: 4px solid #ffc107; } `; document.head.appendChild(style); } })();