// App JS moved from index.html // Global variables let cart = []; let products = []; const CART_KEY = 'blue_mobile_cart_v1'; // Load products from products.json async function loadProducts() { const loading = document.getElementById('loading'); const container = document.getElementById('productsContainer'); loading.style.display = 'block'; try { // Fetch local JSON file (simulate API response) const res = await fetch('./products.json', {cache: 'no-store'}); const json = await res.json(); // Support both plain array and API-style response { status, data: { products: [...] } } if (Array.isArray(json)) { products = json; } else if (json && json.data && Array.isArray(json.data.products)) { products = json.data.products; // optional: use metadata for logging or pagination UI later console.info('Products loaded from API-style response', {total: json.data.total || products.length, meta: json.meta || null}); } else if (json && Array.isArray(json.products)) { products = json.products; // another possible shape } else { throw new Error('Unexpected products.json format'); } // Optional small delay for UX await new Promise(resolve => setTimeout(resolve, 500)); loading.style.display = 'none'; displayProducts(); // Load cart from localStorage if present const saved = localStorage.getItem(CART_KEY); if (saved) { try { cart = JSON.parse(saved) || []; } catch (e) { cart = []; } updateCartDisplay(); } } catch (err) { loading.style.display = 'none'; container.innerHTML = '

เกิดข้อผิดพลาดในการโหลดสินค้า

'; console.error(err); } } function displayProducts() { const container = document.getElementById('productsContainer'); container.innerHTML = ''; products.forEach(product => { const discountPercent = Math.round(((product.originalPrice - product.price) / product.originalPrice) * 100); // Prefer local preprocessed WebP images when available; otherwise build WebP URLs for remote images const isLocal = !!product.image; let webpSmall, webpLarge; if (isLocal) { const imgBase = product.image; // e.g. images/product-1 webpSmall = `${imgBase}-400.webp`; webpLarge = `${imgBase}-800.webp`; } else { // Build responsive WebP URLs (Unsplash supports fm=webp) const imgBase = product.image; webpSmall = imgBase.replace(/(\?)/, '&') + '&w=400&fm=webp'; webpLarge = imgBase.replace(/(\?)/, '&') + '&w=800&fm=webp'; } const productCard = `
${product.name}
${product.name}

${product.description}

${product.price.toLocaleString()} บาท
${product.originalPrice.toLocaleString()} บาท
ลด ${discountPercent}%
`; container.innerHTML += productCard; }); } function addToCart(productId) { const product = products.find(p => p.id === productId); const existingItem = cart.find(item => item.id === productId); if (existingItem) { existingItem.quantity += 1; } else { cart.push({...product, quantity: 1}); } updateCartDisplay(); saveCart(); // Success animation const buttons = document.querySelectorAll(`button[onclick="addToCart(${productId})"]`); buttons.forEach(button => { button.classList.add('success-animation'); button.innerHTML = ' เพิ่มแล้ว'; setTimeout(() => { button.classList.remove('success-animation'); button.innerHTML = ' เพิ่มในตะกร้า'; }, 1000); }); } function updateCartDisplay() { const cartCount = document.getElementById('cartCount'); const cartItems = document.getElementById('cartItems'); const cartTotal = document.getElementById('cartTotal'); const checkoutBtn = document.getElementById('checkoutBtn'); const totalItems = cart.reduce((sum, item) => sum + item.quantity, 0); const totalPrice = cart.reduce((sum, item) => sum + (item.price * item.quantity), 0); cartCount.textContent = totalItems; cartTotal.textContent = totalPrice.toLocaleString(); if (cart.length === 0) { cartItems.innerHTML = '

ตะกร้าสินค้าว่างเปล่า

'; checkoutBtn.disabled = true; } else { cartItems.innerHTML = cart.map(item => `
${item.name}
${item.name}
${item.price.toLocaleString()} บาท
${item.quantity}
`).join(''); checkoutBtn.disabled = false; } } function changeQuantity(productId, change) { const item = cart.find(item => item.id === productId); if (item) { item.quantity += change; if (item.quantity <= 0) { removeFromCart(productId); } else { updateCartDisplay(); saveCart(); } } } function removeFromCart(productId) { cart = cart.filter(item => item.id !== productId); updateCartDisplay(); saveCart(); } function proceedToCheckout() { if (cart.length === 0) return; const cartModal = bootstrap.Modal.getInstance(document.getElementById('cartModal')); if (cartModal) cartModal.hide(); setTimeout(() => { updateOrderSummary(); const checkoutModal = new bootstrap.Modal(document.getElementById('checkoutModal')); checkoutModal.show(); }, 500); } function updateOrderSummary() { const orderSummary = document.getElementById('orderSummary'); const orderTotal = document.getElementById('orderTotal'); const totalPrice = cart.reduce((sum, item) => sum + (item.price * item.quantity), 0); const shipping = totalPrice >= 1000 ? 0 : 100; // ส่งฟรีเมื่อซื้อมากกว่า 1000 บาท const finalTotal = totalPrice + shipping; orderSummary.innerHTML = cart.map(item => `
${item.name} x${item.quantity} ${(item.price * item.quantity).toLocaleString()} บาท
`).join('') + `
ค่าจัดส่ง ${shipping === 0 ? 'ฟรี' : shipping + ' บาท'}
`; orderTotal.textContent = finalTotal.toLocaleString() + ' บาท'; } async function processPayment() { const form = document.getElementById('checkoutForm'); const formData = new FormData(form); // Validate required fields if (!form.checkValidity()) { form.reportValidity(); return; } // Show loading state const paymentBtn = document.getElementById('processPaymentBtn'); const originalText = paymentBtn.innerHTML; paymentBtn.disabled = true; paymentBtn.innerHTML = 'กำลังดำเนินการ...'; // Simulate payment processing await new Promise(resolve => setTimeout(resolve, 3000)); // Simulate successful payment paymentBtn.innerHTML = ' ชำระเงินสำเร็จ'; setTimeout(() => { const checkoutModal = bootstrap.Modal.getInstance(document.getElementById('checkoutModal')); if (checkoutModal) checkoutModal.hide(); // Show success message alert('ชำระเงินสำเร็จ! ขอบคุณสำหรับการสั่งซื้อ เราจะจัดส่งสินค้าให้คุณในเร็วๆ นี้'); // Clear cart cart = []; updateCartDisplay(); saveCart(); // Reset button paymentBtn.disabled = false; paymentBtn.innerHTML = originalText; }, 1500); } function saveCart() { try { localStorage.setItem(CART_KEY, JSON.stringify(cart)); } catch (e) { console.warn('Failed to save cart', e); } } function scrollToProducts() { document.getElementById('products').scrollIntoView({behavior: 'smooth'}); } // Payment method toggle & helpers function initUI() { const paymentRadios = document.querySelectorAll('input[name="payment"]'); const creditCardForm = document.getElementById('creditCardForm'); paymentRadios.forEach(radio => { radio.addEventListener('change', function() { if (this.value === 'credit') { creditCardForm.style.display = 'block'; } else { creditCardForm.style.display = 'none'; } }); }); // Credit card number formatting const cardNumberInput = document.querySelector('input[placeholder*="หมายเลขบัตร"]'); if (cardNumberInput) { cardNumberInput.addEventListener('input', function() { let value = this.value.replace(/\s+/g, '').replace(/[^0-9]/gi, ''); let formattedValue = value.match(/.{1,4}/g)?.join(' ') || value; if (formattedValue !== this.value) { this.value = formattedValue; } }); } // Expiry date formatting const expiryInput = document.querySelector('input[placeholder="MM/YY"]'); if (expiryInput) { expiryInput.addEventListener('input', function() { let value = this.value.replace(/\D/g, ''); if (value.length >= 2) { value = value.substring(0, 2) + '/' + value.substring(2, 4); } this.value = value; }); } // Smooth scrolling for navigation links document.querySelectorAll('a[href^="#"]').forEach(anchor => { anchor.addEventListener('click', function(e) { e.preventDefault(); const target = document.querySelector(this.getAttribute('href')); if (target) { const offsetTop = target.offsetTop - 80; // Account for fixed navbar window.scrollTo({ top: offsetTop, behavior: 'smooth' }); } }); }); // Navbar scroll effect window.addEventListener('scroll', function() { const navbar = document.querySelector('.navbar'); if (window.scrollY > 50) { navbar.style.background = 'rgba(26, 26, 26, 0.98)'; } else { navbar.style.background = 'rgba(26, 26, 26, 0.95)'; } }); } // Initialize on DOM ready document.addEventListener('DOMContentLoaded', function() { initUI(); loadProducts(); registerServiceWorker(); }); // Register service worker function registerServiceWorker() { if ('serviceWorker' in navigator) { navigator.serviceWorker.register('./sw.js').then(reg => { console.info('Service worker registered', reg.scope); }).catch(err => { console.warn('Service worker registration failed', err); }); } } // PWA install prompt handling let deferredPrompt = null; function setupPWAInstall() { const installModalEl = document.getElementById('installModal'); const installConfirm = document.getElementById('installConfirm'); const installCancel = document.getElementById('installCancel'); const bsModal = installModalEl ? new bootstrap.Modal(installModalEl) : null; window.addEventListener('beforeinstallprompt', (e) => { e.preventDefault(); deferredPrompt = e; // show modal if (bsModal) bsModal.show(); }); installConfirm && installConfirm.addEventListener('click', async () => { if (!deferredPrompt) return; deferredPrompt.prompt(); const choice = await deferredPrompt.userChoice; deferredPrompt = null; if (bsModal) bsModal.hide(); console.info('PWA install choice', choice); }); installCancel && installCancel.addEventListener('click', () => { if (bsModal) bsModal.hide(); }); window.addEventListener('appinstalled', () => { if (bsModal) bsModal.hide(); console.info('App installed'); }); }