Skip to content

E-COMMERCE #1

Description

@Tovian5050

// 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:`

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions