Chowder / templates /index.html
WillemVH's picture
Update templates/index.html
14bd9ee verified
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>ShopEasy - One Page E-Commerce</title>
<!-- Bootstrap 5 CSS -->
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0-alpha1/dist/css/bootstrap.min.css" rel="stylesheet">
<!-- Font Awesome for icons -->
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0/css/all.min.css">
<style>
.section {
display: none;
animation: fadeIn 0.5s;
}
.active-section {
display: block;
}
.nav-item {
cursor: pointer;
}
.nav-link.active {
background-color: #0d6efd;
color: white !important;
}
.card {
transition: transform 0.3s;
height: 100%;
}
.card:hover {
transform: translateY(-5px);
box-shadow: 0 5px 15px rgba(0,0,0,0.1);
}
.cart-item {
border-bottom: 1px solid #eee;
padding: 10px 0;
}
.quantity-control {
display: flex;
align-items: center;
gap: 10px;
}
.product-img {
height: 200px;
object-fit: cover;
width: 100%;
}
.badge-notification {
position: absolute;
top: -5px;
right: -5px;
}
@keyframes fadeIn {
from { opacity: 0; }
to { opacity: 1; }
}
.checkout-step {
display: none;
}
.checkout-step.active {
display: block;
}
.order-summary {
background-color: #f8f9fa;
border-radius: 10px;
padding: 20px;
}
</style>
</head>
<body>
<!-- Navigation -->
<nav class="navbar navbar-expand-lg navbar-dark bg-primary sticky-top">
<div class="container">
<a class="navbar-brand" href="#" onclick="showSection('home')">
<i class="fas fa-shopping-bag me-2"></i>ShopEasy
</a>
<div class="d-flex align-items-center">
<!-- Cart Icon with Badge -->
<div class="position-relative me-3" onclick="showSection('cart')" style="cursor: pointer;">
<i class="fas fa-shopping-cart fa-lg text-white"></i>
<span id="cartBadge" class="badge bg-danger badge-notification">0</span>
</div>
<!-- Navigation Tabs -->
<ul class="navbar-nav">
<li class="nav-item">
<a class="nav-link" onclick="showSection('home')">Home</a>
</li>
<li class="nav-item">
<a class="nav-link" onclick="showSection('products')">Products</a>
</li>
<li class="nav-item">
<a class="nav-link" onclick="showSection('cart')">Cart</a>
</li>
<li class="nav-item">
<a class="nav-link" onclick="showSection('checkout')">Checkout</a>
</li>
</ul>
</div>
</div>
</nav>
<!-- Main Content -->
<div class="container mt-4">
<!-- Home Section -->
<div id="home" class="section active-section">
<div class="jumbotron bg-light p-5 rounded">
<h1 class="display-4">Welcome to ShopEasy!</h1>
<p class="lead">Your one-stop shop for all your needs. Browse our products, add them to cart, and checkout securely.</p>
<hr class="my-4">
<p>We offer high-quality products with fast delivery and excellent customer service.</p>
<button class="btn btn-primary btn-lg" onclick="showSection('products')">
Start Shopping <i class="fas fa-arrow-right ms-2"></i>
</button>
</div>
<div class="row mt-5">
<div class="col-md-4">
<div class="card text-center">
<div class="card-body">
<i class="fas fa-shipping-fast fa-3x text-primary mb-3"></i>
<h5 class="card-title">Fast Delivery</h5>
<p class="card-text">Get your orders delivered within 2-3 business days.</p>
</div>
</div>
</div>
<div class="col-md-4">
<div class="card text-center">
<div class="card-body">
<i class="fas fa-shield-alt fa-3x text-success mb-3"></i>
<h5 class="card-title">Secure Payment</h5>
<p class="card-text">100% secure payment processing with encryption.</p>
</div>
</div>
</div>
<div class="col-md-4">
<div class="card text-center">
<div class="card-body">
<i class="fas fa-headset fa-3x text-warning mb-3"></i>
<h5 class="card-title">24/7 Support</h5>
<p class="card-text">Our support team is always ready to help you.</p>
</div>
</div>
</div>
</div>
</div>
<!-- Products Section -->
<div id="products" class="section">
<h2 class="mb-4">Our Products</h2>
<div class="row" id="productsGrid">
<!-- Products will be loaded here -->
</div>
</div>
<!-- Cart Section -->
<div id="cart" class="section">
<h2 class="mb-4">Your Shopping Cart</h2>
<div class="row">
<div class="col-md-8">
<div id="cartItems">
<!-- Cart items will be loaded here -->
<p class="text-muted" id="emptyCartMessage">Your cart is empty. <a href="#" onclick="showSection('products')">Browse products</a></p>
</div>
</div>
<div class="col-md-4">
<div class="order-summary">
<h5>Order Summary</h5>
<table class="table">
<tr>
<td>Subtotal:</td>
<td class="text-end">$<span id="subtotal">0.00</span></td>
</tr>
<tr>
<td>Shipping:</td>
<td class="text-end">$<span id="shipping">5.00</span></td>
</tr>
<tr>
<td>Tax:</td>
<td class="text-end">$<span id="tax">0.00</span></td>
</tr>
<tr class="table-active">
<th>Total:</th>
<th class="text-end">$<span id="total">5.00</span></th>
</tr>
</table>
<button class="btn btn-primary w-100" onclick="showSection('checkout')" id="checkoutBtn" disabled>
Proceed to Checkout
</button>
<button class="btn btn-outline-secondary w-100 mt-2" onclick="clearCart()">
Clear Cart
</button>
</div>
</div>
</div>
</div>
<!-- Checkout Section -->
<div id="checkout" class="section">
<h2 class="mb-4">Checkout</h2>
<div class="row">
<div class="col-md-8">
<div id="checkoutSteps">
<!-- Step 1: Shipping Info -->
<div id="step1" class="checkout-step active">
<h4>Shipping Information</h4>
<form id="shippingForm">
<div class="row mb-3">
<div class="col-md-6">
<label class="form-label">First Name *</label>
<input type="text" class="form-control" required>
</div>
<div class="col-md-6">
<label class="form-label">Last Name *</label>
<input type="text" class="form-control" required>
</div>
</div>
<div class="mb-3">
<label class="form-label">Address *</label>
<input type="text" class="form-control" required>
</div>
<div class="row mb-3">
<div class="col-md-6">
<label class="form-label">City *</label>
<input type="text" class="form-control" required>
</div>
<div class="col-md-6">
<label class="form-label">ZIP Code *</label>
<input type="text" class="form-control" required>
</div>
</div>
<div class="mb-3">
<label class="form-label">Email *</label>
<input type="email" class="form-control" required>
</div>
<button type="button" class="btn btn-primary" onclick="nextStep(2)">Continue to Payment</button>
</form>
</div>
<!-- Step 2: Payment Info -->
<div id="step2" class="checkout-step">
<h4>Payment Information</h4>
<form id="paymentForm">
<div class="mb-3">
<label class="form-label">Card Number *</label>
<input type="text" class="form-control" placeholder="1234 5678 9012 3456" required>
</div>
<div class="row mb-3">
<div class="col-md-6">
<label class="form-label">Expiry Date *</label>
<input type="text" class="form-control" placeholder="MM/YY" required>
</div>
<div class="col-md-6">
<label class="form-label">CVV *</label>
<input type="text" class="form-control" required>
</div>
</div>
<div class="mb-3">
<label class="form-label">Name on Card *</label>
<input type="text" class="form-control" required>
</div>
<button type="button" class="btn btn-secondary" onclick="prevStep(1)">Back</button>
<button type="button" class="btn btn-primary" onclick="nextStep(3)">Review Order</button>
</form>
</div>
<!-- Step 3: Review Order -->
<div id="step3" class="checkout-step">
<h4>Review Your Order</h4>
<div id="reviewOrderItems" class="mb-4">
<!-- Order items will be shown here -->
</div>
<div class="order-summary mb-4">
<h5>Order Total: $<span id="reviewTotal">0.00</span></h5>
</div>
<div class="mb-3">
<h5>Shipping Address:</h5>
<p id="reviewAddress">Not provided yet</p>
</div>
<button type="button" class="btn btn-secondary" onclick="prevStep(2)">Back</button>
<button type="button" class="btn btn-success" onclick="placeOrder()">
<i class="fas fa-lock me-2"></i>Place Order
</button>
</div>
<!-- Step 4: Confirmation -->
<div id="step4" class="checkout-step">
<div class="text-center py-5">
<i class="fas fa-check-circle fa-5x text-success mb-4"></i>
<h3>Order Confirmed!</h3>
<p class="lead">Thank you for your purchase.</p>
<p>Your order number is: <strong>ORD-<span id="orderNumber">0000</span></strong></p>
<p>You will receive a confirmation email shortly.</p>
<button class="btn btn-primary" onclick="showSection('home')">
Return to Home
</button>
</div>
</div>
</div>
</div>
<div class="col-md-4">
<div class="order-summary">
<h5>Order Summary</h5>
<div id="checkoutCartItems">
<!-- Checkout cart items -->
</div>
<table class="table">
<tr>
<td>Subtotal:</td>
<td class="text-end">$<span id="checkoutSubtotal">0.00</span></td>
</tr>
<tr>
<td>Shipping:</td>
<td class="text-end">$<span id="checkoutShipping">5.00</span></td>
</tr>
<tr>
<td>Tax:</td>
<td class="text-end">$<span id="checkoutTax">0.00</span></td>
</tr>
<tr class="table-active">
<th>Total:</th>
<th class="text-end">$<span id="checkoutTotal">5.00</span></th>
</tr>
</table>
</div>
</div>
</div>
</div>
</div>
<!-- Footer -->
<footer class="bg-dark text-white mt-5 py-4">
<div class="container text-center">
<p>&copy; 2024 ShopEasy. All rights reserved.</p>
<p class="mb-0">
<a href="#" onclick="showSection('home')" class="text-white me-3">Home</a> |
<a href="#" onclick="showSection('products')" class="text-white me-3">Products</a> |
<a href="#" onclick="showSection('cart')" class="text-white me-3">Cart</a> |
<a href="#" onclick="showSection('checkout')" class="text-white">Checkout</a>
</p>
</div>
</footer>
<!-- JavaScript -->
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0-alpha1/dist/js/bootstrap.bundle.min.js"></script>
<script>
// Sample product data
const products = [
{ id: 1, name: "Wireless Headphones", price: 99.99, image: "https://images.unsplash.com/photo-1505740420928-5e560c06d30e?w=400&h=300&fit=crop", category: "Electronics" },
{ id: 2, name: "Smart Watch", price: 199.99, image: "https://images.unsplash.com/photo-1523275335684-37898b6baf30?w=400&h=300&fit=crop", category: "Electronics" },
{ id: 3, name: "Running Shoes", price: 89.99, image: "https://images.unsplash.com/photo-1542291026-7eec264c27ff?w=400&h=300&fit=crop", category: "Fashion" },
{ id: 4, name: "Coffee Maker", price: 49.99, image: "https://images.unsplash.com/photo-1495474472287-4d71bcdd2085?w=400&h=300&fit=crop", category: "Home" },
{ id: 5, name: "Backpack", price: 39.99, image: "https://images.unsplash.com/photo-1553062407-98eeb64c6a62?w=400&h=300&fit=crop", category: "Fashion" },
{ id: 6, name: "Desk Lamp", price: 29.99, image: "https://images.unsplash.com/photo-1507473885765-e6ed057f782c?w=400&h=300&fit=crop", category: "Home" }
];
// Cart state
let cart = JSON.parse(localStorage.getItem('cart')) || [];
let currentStep = 1;
// Initialize the page
document.addEventListener('DOMContentLoaded', function() {
loadProducts();
updateCartBadge();
updateNav();
});
// Navigation functions
function showSection(sectionId) {
// Hide all sections
document.querySelectorAll('.section').forEach(section => {
section.classList.remove('active-section');
});
// Show selected section
document.getElementById(sectionId).classList.add('active-section');
// Update navigation highlighting
updateNav();
// Special handling for each section
if (sectionId === 'products') {
loadProducts();
} else if (sectionId === 'cart') {
updateCartDisplay(); // FIXED: Only update cart display when on cart section
} else if (sectionId === 'checkout') {
resetCheckoutSteps();
updateCheckoutDisplay(); // FIXED: Use checkout-specific update function
}
}
function updateNav() {
const navLinks = document.querySelectorAll('.nav-link');
navLinks.forEach(link => link.classList.remove('active'));
const activeSection = document.querySelector('.section.active-section');
if (activeSection) {
const sectionId = activeSection.id;
const activeLink = document.querySelector(`.nav-link[onclick="showSection('${sectionId}')"]`);
if (activeLink) {
activeLink.classList.add('active');
}
}
}
// Product functions
function loadProducts() {
const productsGrid = document.getElementById('productsGrid');
productsGrid.innerHTML = '';
products.forEach(product => {
const productCard = `
<div class="col-md-4 col-lg-4 mb-4">
<div class="card">
<img src="${product.image}" class="card-img-top product-img" alt="${product.name}">
<div class="card-body">
<h5 class="card-title">${product.name}</h5>
<p class="card-text">${product.category}</p>
<p class="card-text"><strong>$${product.price.toFixed(2)}</strong></p>
<button class="btn btn-primary" onclick="addToCart(${product.id})">
<i class="fas fa-cart-plus me-2"></i>Add to Cart
</button>
</div>
</div>
</div>
`;
productsGrid.innerHTML += productCard;
});
}
// Cart functions
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({
id: product.id,
name: product.name,
price: product.price,
image: product.image,
quantity: 1
});
}
saveCart();
updateCartBadge();
showToast(`${product.name} added to cart!`);
// Update cart display only if we're on the cart page
if (document.getElementById('cart').classList.contains('active-section')) {
updateCartDisplay();
}
}
function removeFromCart(productId) {
cart = cart.filter(item => item.id !== productId);
saveCart();
updateCartBadge();
updateCartDisplay();
}
function updateQuantity(productId, change) {
const item = cart.find(item => item.id === productId);
if (item) {
item.quantity += change;
if (item.quantity <= 0) {
removeFromCart(productId);
} else {
saveCart();
updateCartBadge();
updateCartDisplay();
}
}
}
function clearCart() {
cart = [];
saveCart();
updateCartBadge();
// Update cart display if on cart page
if (document.getElementById('cart').classList.contains('active-section')) {
updateCartDisplay();
}
// Update checkout display if on checkout page
if (document.getElementById('checkout').classList.contains('active-section')) {
updateCheckoutDisplay();
}
showToast('Cart cleared!');
}
function saveCart() {
localStorage.setItem('cart', JSON.stringify(cart));
updateCartBadge();
}
function updateCartBadge() {
const totalItems = cart.reduce((sum, item) => sum + item.quantity, 0);
document.getElementById('cartBadge').textContent = totalItems;
// Update checkout button state
const checkoutBtn = document.getElementById('checkoutBtn');
if (checkoutBtn) {
checkoutBtn.disabled = totalItems === 0;
}
}
function updateCartDisplay() {
const cartItemsDiv = document.getElementById('cartItems');
const emptyCartMessage = document.getElementById('emptyCartMessage');
// FIXED: Check if elements exist before using them
if (!cartItemsDiv || !emptyCartMessage) return;
if (cart.length === 0) {
cartItemsDiv.innerHTML = '<p class="text-muted">Your cart is empty. <a href="#" onclick="showSection(\'products\')">Browse products</a></p>';
emptyCartMessage.style.display = 'block';
} else {
emptyCartMessage.style.display = 'none';
let cartHTML = '';
let subtotal = 0;
cart.forEach(item => {
const itemTotal = item.price * item.quantity;
subtotal += itemTotal;
cartHTML += `
<div class="cart-item">
<div class="row align-items-center">
<div class="col-2">
<img src="${item.image}" class="img-fluid rounded" alt="${item.name}">
</div>
<div class="col-4">
<h6 class="mb-0">${item.name}</h6>
<p class="mb-0 text-muted">$${item.price.toFixed(2)}</p>
</div>
<div class="col-4">
<div class="quantity-control">
<button class="btn btn-sm btn-outline-secondary" onclick="updateQuantity(${item.id}, -1)">-</button>
<span class="mx-2">${item.quantity}</span>
<button class="btn btn-sm btn-outline-secondary" onclick="updateQuantity(${item.id}, 1)">+</button>
</div>
</div>
<div class="col-2 text-end">
<h6 class="mb-0">$${itemTotal.toFixed(2)}</h6>
<button class="btn btn-sm btn-danger mt-1" onclick="removeFromCart(${item.id})">
<i class="fas fa-trash"></i>
</button>
</div>
</div>
</div>
`;
});
cartItemsDiv.innerHTML = cartHTML;
const shipping = 5.00;
const tax = subtotal * 0.08; // 8% tax
const total = subtotal + shipping + tax;
// FIXED: Check if elements exist before updating
const subtotalEl = document.getElementById('subtotal');
const taxEl = document.getElementById('tax');
const totalEl = document.getElementById('total');
if (subtotalEl) subtotalEl.textContent = subtotal.toFixed(2);
if (taxEl) taxEl.textContent = tax.toFixed(2);
if (totalEl) totalEl.textContent = total.toFixed(2);
}
}
// Checkout functions
function resetCheckoutSteps() {
currentStep = 1;
document.querySelectorAll('.checkout-step').forEach(step => {
step.classList.remove('active');
});
document.getElementById('step1').classList.add('active');
}
function nextStep(stepNumber) {
if (stepNumber === 2) {
// Validate shipping form
const shippingForm = document.getElementById('shippingForm');
if (!shippingForm.checkValidity()) {
shippingForm.reportValidity();
return;
}
} else if (stepNumber === 3) {
// Validate payment form
const paymentForm = document.getElementById('paymentForm');
if (!paymentForm.checkValidity()) {
paymentForm.reportValidity();
return;
}
updateReviewSection();
}
currentStep = stepNumber;
document.querySelectorAll('.checkout-step').forEach(step => {
step.classList.remove('active');
});
document.getElementById(`step${stepNumber}`).classList.add('active');
}
function prevStep(stepNumber) {
currentStep = stepNumber;
document.querySelectorAll('.checkout-step').forEach(step => {
step.classList.remove('active');
});
document.getElementById(`step${stepNumber}`).classList.add('active');
}
function updateCheckoutDisplay() {
const checkoutCartItems = document.getElementById('checkoutCartItems');
if (!checkoutCartItems) return;
let itemsHTML = '';
let subtotal = 0;
cart.forEach(item => {
const itemTotal = item.price * item.quantity;
subtotal += itemTotal;
itemsHTML += `
<div class="d-flex justify-content-between mb-2">
<div>
<span>${item.name} x ${item.quantity}</span>
</div>
<div>$${itemTotal.toFixed(2)}</div>
</div>
`;
});
checkoutCartItems.innerHTML = itemsHTML || '<p class="text-muted">No items in cart</p>';
const shipping = 5.00;
const tax = subtotal * 0.08;
const total = subtotal + shipping + tax;
// FIXED: Update checkout summary
document.getElementById('checkoutSubtotal').textContent = subtotal.toFixed(2);
document.getElementById('checkoutTax').textContent = tax.toFixed(2);
document.getElementById('checkoutTotal').textContent = total.toFixed(2);
document.getElementById('reviewTotal').textContent = total.toFixed(2);
}
function updateReviewSection() {
const reviewOrderItems = document.getElementById('reviewOrderItems');
if (!reviewOrderItems) return;
let itemsHTML = '<h5>Items:</h5>';
cart.forEach(item => {
itemsHTML += `
<div class="d-flex justify-content-between mb-2">
<div>
<span>${item.name} x ${item.quantity}</span>
</div>
<div>$${(item.price * item.quantity).toFixed(2)}</div>
</div>
`;
});
reviewOrderItems.innerHTML = itemsHTML;
// Get shipping address from form (simplified)
const addressInput = document.querySelector('#shippingForm input[type="text"]');
const address = addressInput ? addressInput.value : '';
document.getElementById('reviewAddress').textContent = address || "Not provided";
}
function placeOrder() {
if (cart.length === 0) {
showToast('Your cart is empty!');
return;
}
// Generate random order number
const orderNumber = Math.floor(1000 + Math.random() * 9000);
document.getElementById('orderNumber').textContent = orderNumber;
// Clear cart
cart = [];
saveCart();
updateCartBadge();
// Show confirmation
nextStep(4);
// In a real app, you would send order to server here
console.log('Order placed:', orderNumber);
showToast('Order placed successfully!');
}
// Utility function
function showToast(message) {
// Create toast element
const toast = document.createElement('div');
toast.className = 'position-fixed bottom-0 end-0 p-3';
toast.style.zIndex = '1050';
toast.innerHTML = `
<div class="toast show" role="alert">
<div class="toast-header">
<strong class="me-auto">ShopEasy</strong>
<button type="button" class="btn-close" onclick="this.parentElement.parentElement.parentElement.remove()"></button>
</div>
<div class="toast-body">
${message}
</div>
</div>
`;
document.body.appendChild(toast);
// Auto-remove after 3 seconds
setTimeout(() => {
if (toast.parentNode) {
toast.parentNode.removeChild(toast);
}
}, 3000);
}
</script>
</body>
</html>