// Product Database
const products = [
{ id: 1, name: 'Classic T-Shirt', category: 'clothes', price: 2500, emoji: '👕', description: 'Comfortable everyday t-shirt' },
{ id: 2, name: 'Designer Shirt', category: 'clothes', price: 5500, emoji: '👔', description: 'Premium quality dress shirt' },
{ id: 3, name: 'Casual Jeans', category: 'clothes', price: 6500, emoji: '👖', description: 'Stylish denim jeans' },
{ id: 4, name: 'Elegant Dress', category: 'clothes', price: 8000, emoji: '👗', description: 'Beautiful evening dress' },
{ id: 5, name: 'Leather Shoes', category: 'shoes', price: 7500, emoji: '👞', description: 'Premium leather formal shoes' },
{ id: 6, name: 'Sports Sneakers', category: 'shoes', price: 6000, emoji: '👟', description: 'Comfortable athletic sneakers' },
{ id: 7, name: 'Casual Loafers', category: 'shoes', price: 5500, emoji: '🥾', description: 'Smart casual loafers' },
{ id: 8, name: 'Elegant Heels', category: 'shoes', price: 7000, emoji: '👠', description: 'High fashion heels' },
{ id: 9, name: 'Leather Belt - Black', category: 'belts', price: 2500, emoji: '⚫', description: 'Classic black leather belt' },
{ id: 10, name: 'Leather Belt - Brown', category: 'belts', price: 2500, emoji: '🟤', description: 'Premium brown leather belt' },
{ id: 11, name: 'Designer Belt', category: 'belts', price: 4500, emoji: '✨', description: 'Luxury designer belt' },
{ id: 12, name: 'Casual Vest', category: 'vests', price: 3500, emoji: '🦺', description: 'Lightweight casual vest' },
{ id: 13, name: 'Formal Waistcoat', category: 'vests', price: 6000, emoji: '👔', description: 'Elegant formal waistcoat' },
{ id: 14, name: 'Winter Vest', category: 'vests', price: 5000, emoji: '🧥', description: 'Warm winter vest' },
{ id: 15, name: 'Silk Scarf', category: 'accessories', price: 2000, emoji: '🧣', description: 'Premium silk scarf' },
{ id: 16, name: 'Sunglasses', category: 'accessories', price: 3500, emoji: '😎', description: 'Stylish UV protection sunglasses' },
{ id: 17, name: 'Wrist Watch', category: 'accessories', price: 12000, emoji: '⌚', description: 'Elegant wrist watch' },
];
// Helpers: cart persistence
const CART_KEY = 'cart';
function loadCart() {
try {
const raw = localStorage.getItem(CART_KEY);
return raw ? JSON.parse(raw) : [];
} catch (err) {
console.warn('Failed to parse cart from localStorage, resetting cart.', err);
localStorage.removeItem(CART_KEY);
return [];
}
}
function saveCart(cart) {
try {
localStorage.setItem(CART_KEY, JSON.stringify(cart));
} catch (err) {
console.error('Failed to save cart to localStorage', err);
}
}
// Use proper currency formatting for NGN
const currencyFormatter = new Intl.NumberFormat('en-NG', {
style: 'currency',
currency: 'NGN',
minimumFractionDigits: 0
});
// App state
let cart = loadCart();
// DOM elements (defensive)
const productContainer = document.getElementById('productContainer');
const searchInput = document.getElementById('searchInput');
const categoryFilter = document.getElementById('categoryFilter');
const cartCountEl = document.getElementById('cart-count');
// Create toast container if not present
let toastContainer = document.getElementById('toast-container');
if (!toastContainer) {
toastContainer = document.createElement('div');
toastContainer.id = 'toast-container';
toastContainer.style.position = 'fixed';
toastContainer.style.right = '1rem';
toastContainer.style.bottom = '1rem';
toastContainer.style.zIndex = 9999;
document.body.appendChild(toastContainer);
}
// Create simple cart modal (if not present)
let cartModal = document.getElementById('cartModal');
if (!cartModal) {
cartModal = document.createElement('div');
cartModal.id = 'cartModal';
cartModal.style.position = 'fixed';
cartModal.style.right = '1rem';
cartModal.style.top = '4rem';
cartModal.style.width = '320px';
cartModal.style.maxHeight = '70vh';
cartModal.style.overflow = 'auto';
cartModal.style.background = '#fff';
cartModal.style.border = '1px solid #ddd';
cartModal.style.padding = '1rem';
cartModal.style.boxShadow = '0 8px 24px rgba(0,0,0,0.12)';
cartModal.style.display = 'none';
cartModal.innerHTML = '
Cart
Close';
document.body.appendChild(cartModal);
}
// Utility: show non-blocking toast
function showToast(message, ms = 2000) {
const t = document.createElement('div');
t.textContent = message;
t.style.background = '#333';
t.style.color = '#fff';
t.style.padding = '0.5rem 1rem';
t.style.marginTop = '0.5rem';
t.style.borderRadius = '6px';
t.style.opacity = '0.95';
toastContainer.appendChild(t);
setTimeout(() => {
t.style.transition = 'opacity 300ms';
t.style.opacity = '0';
setTimeout(() => toastContainer.removeChild(t), 300);
}, ms);
}
// Rendering
function displayProducts(productsToDisplay) {
if (!productContainer) return;
productContainer.innerHTML = '';
if (!productsToDisplay || productsToDisplay.length === 0) {
productContainer.innerHTML = '<p style="grid-column: 1/-1; text-align: center; padding: 2rem;">No products found</p>';
return;
}
const fragment = document.createDocumentFragment();
productsToDisplay.forEach(product => {
const card = document.createElement('div');
card.className = 'product-card';
card.dataset.productId = product.id;
// Build inner markup (keep accessible)
card.innerHTML = `
<div class="product-image" aria-hidden="true">${product.emoji}</div>
<div class="product-info">
<div class="product-name">${escapeHtml(product.name)}</div>
<div class="product-category">${escapeHtml(capitalize(product.category))}</div>
<div class="product-price">${currencyFormatter.format(product.price)}</div>
<div class="product-description">${escapeHtml(product.description)}</div>
<button class="add-to-cart-btn" data-id="${product.id}" aria-label="Add ${escapeHtml(product.name)} to cart">Add to Cart</button>
</div>
`;
fragment.appendChild(card);
});
productContainer.appendChild(fragment);
}
// Simple helpers
function capitalize(s) {
return s && typeof s === 'string' ? s.charAt(0).toUpperCase() + s.slice(1) : s;
}
function escapeHtml(str) {
if (!str) return '';
return String(str)
.replace(/&/g, '&')
.replace(/</g, '<')
.replace(/>/g, '>')
.replace(/"/g, '"')
.replace(/'/g, ''');
}
// Cart operations
function addToCart(productId) {
const product = products.find(p => p.id === Number(productId));
if (!product) {
showToast('Product not found');
return;
}
// Do not mutate original product — clone
const existing = cart.find(item => item.id === product.id);
if (existing) {
existing.quantity = (existing.quantity || 0) + 1;
} else {
cart.push({
id: product.id,
name: product.name,
price: product.price,
emoji: product.emoji,
description: product.description,
category: product.category,
quantity:`
// Product Database
const products = [
{ id: 1, name: 'Classic T-Shirt', category: 'clothes', price: 2500, emoji: '👕', description: 'Comfortable everyday t-shirt' },
{ id: 2, name: 'Designer Shirt', category: 'clothes', price: 5500, emoji: '👔', description: 'Premium quality dress shirt' },
{ id: 3, name: 'Casual Jeans', category: 'clothes', price: 6500, emoji: '👖', description: 'Stylish denim jeans' },
{ id: 4, name: 'Elegant Dress', category: 'clothes', price: 8000, emoji: '👗', description: 'Beautiful evening dress' },
];
// Helpers: cart persistence
const CART_KEY = 'cart';
function loadCart() {
try {
const raw = localStorage.getItem(CART_KEY);
return raw ? JSON.parse(raw) : [];
} catch (err) {
console.warn('Failed to parse cart from localStorage, resetting cart.', err);
localStorage.removeItem(CART_KEY);
return [];
}
}
function saveCart(cart) {
try {
localStorage.setItem(CART_KEY, JSON.stringify(cart));
} catch (err) {
console.error('Failed to save cart to localStorage', err);
}
}
// Use proper currency formatting for NGN
const currencyFormatter = new Intl.NumberFormat('en-NG', {
style: 'currency',
currency: 'NGN',
minimumFractionDigits: 0
});
// App state
let cart = loadCart();
// DOM elements (defensive)
const productContainer = document.getElementById('productContainer');
const searchInput = document.getElementById('searchInput');
const categoryFilter = document.getElementById('categoryFilter');
const cartCountEl = document.getElementById('cart-count');
// Create toast container if not present
let toastContainer = document.getElementById('toast-container');
if (!toastContainer) {
toastContainer = document.createElement('div');
toastContainer.id = 'toast-container';
toastContainer.style.position = 'fixed';
toastContainer.style.right = '1rem';
toastContainer.style.bottom = '1rem';
toastContainer.style.zIndex = 9999;
document.body.appendChild(toastContainer);
}
// Create simple cart modal (if not present)
let cartModal = document.getElementById('cartModal');
if (!cartModal) {
cartModal = document.createElement('div');
cartModal.id = 'cartModal';
cartModal.style.position = 'fixed';
cartModal.style.right = '1rem';
cartModal.style.top = '4rem';
cartModal.style.width = '320px';
cartModal.style.maxHeight = '70vh';
cartModal.style.overflow = 'auto';
cartModal.style.background = '#fff';
cartModal.style.border = '1px solid #ddd';
cartModal.style.padding = '1rem';
cartModal.style.boxShadow = '0 8px 24px rgba(0,0,0,0.12)';
cartModal.style.display = 'none';
cartModal.innerHTML = '
Cart
Close';document.body.appendChild(cartModal);
}
// Utility: show non-blocking toast
function showToast(message, ms = 2000) {
const t = document.createElement('div');
t.textContent = message;
t.style.background = '#333';
t.style.color = '#fff';
t.style.padding = '0.5rem 1rem';
t.style.marginTop = '0.5rem';
t.style.borderRadius = '6px';
t.style.opacity = '0.95';
toastContainer.appendChild(t);
setTimeout(() => {
t.style.transition = 'opacity 300ms';
t.style.opacity = '0';
setTimeout(() => toastContainer.removeChild(t), 300);
}, ms);
}
// Rendering
function displayProducts(productsToDisplay) {
if (!productContainer) return;
productContainer.innerHTML = '';
}
// Simple helpers
function capitalize(s) {
return s && typeof s === 'string' ? s.charAt(0).toUpperCase() + s.slice(1) : s;
}
function escapeHtml(str) {
if (!str) return '';
return String(str)
.replace(/&/g, '&')
.replace(/</g, '<')
.replace(/>/g, '>')
.replace(/"/g, '"')
.replace(/'/g, ''');
}
// Cart operations
function addToCart(productId) {
const product = products.find(p => p.id === Number(productId));
if (!product) {
showToast('Product not found');
return;
}