pull/1/head
parent
92ca0e870b
commit
d9d2b2c917
|
|
@ -0,0 +1,94 @@
|
||||||
|
// State management
|
||||||
|
let products = [];
|
||||||
|
let cart = [];
|
||||||
|
|
||||||
|
// DOM Elements
|
||||||
|
const productsContainer = document.getElementById('products-container');
|
||||||
|
const cartItems = document.getElementById('cart-items');
|
||||||
|
const cartTotal = document.getElementById('cart-total');
|
||||||
|
const cartCount = document.getElementById('cart-count');
|
||||||
|
|
||||||
|
// Fetch products from API
|
||||||
|
async function fetchProducts() {
|
||||||
|
const response = await fetch('/api/products');
|
||||||
|
products = await response.json();
|
||||||
|
renderProducts();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Render products
|
||||||
|
function renderProducts() {
|
||||||
|
productsContainer.innerHTML = products.map(product => `
|
||||||
|
<div class="product-card">
|
||||||
|
<img src="${product.image}" alt="${product.name}">
|
||||||
|
<h3>${product.name}</h3>
|
||||||
|
<p>${product.description}</p>
|
||||||
|
<p class="price">€${product.price.toFixed(2)}</p>
|
||||||
|
<button onclick="addToCart(${product.id})">In den Warenkorb</button>
|
||||||
|
</div>
|
||||||
|
`).join('');
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add to cart
|
||||||
|
async function addToCart(productId) {
|
||||||
|
const response = await fetch('/api/cart', {
|
||||||
|
method: 'POST',
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/json'
|
||||||
|
},
|
||||||
|
body: JSON.stringify({ productId })
|
||||||
|
});
|
||||||
|
cart = await response.json();
|
||||||
|
updateCart();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Remove from cart
|
||||||
|
async function removeFromCart(productId) {
|
||||||
|
const response = await fetch(`/api/cart/${productId}`, {
|
||||||
|
method: 'DELETE'
|
||||||
|
});
|
||||||
|
cart = await response.json();
|
||||||
|
updateCart();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update quantity
|
||||||
|
async function updateQuantity(productId, quantity) {
|
||||||
|
if (quantity < 1) return;
|
||||||
|
|
||||||
|
const response = await fetch(`/api/cart/${productId}`, {
|
||||||
|
method: 'PUT',
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/json'
|
||||||
|
},
|
||||||
|
body: JSON.stringify({ quantity })
|
||||||
|
});
|
||||||
|
cart = await response.json();
|
||||||
|
updateCart();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update cart display
|
||||||
|
function updateCart() {
|
||||||
|
cartItems.innerHTML = cart.map(item => `
|
||||||
|
<div class="cart-item">
|
||||||
|
<div>
|
||||||
|
<h4>${item.product.name}</h4>
|
||||||
|
<div class="quantity-controls">
|
||||||
|
<button onclick="updateQuantity(${item.productId}, ${item.quantity - 1})">-</button>
|
||||||
|
<span>${item.quantity}</span>
|
||||||
|
<button onclick="updateQuantity(${item.productId}, ${item.quantity + 1})">+</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<p>€${(item.product.price * item.quantity).toFixed(2)}</p>
|
||||||
|
<button onclick="removeFromCart(${item.productId})">Entfernen</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
`).join('');
|
||||||
|
|
||||||
|
const total = cart.reduce((sum, item) => sum + (item.product.price * item.quantity), 0);
|
||||||
|
cartTotal.innerHTML = `Gesamt: €${total.toFixed(2)}`;
|
||||||
|
cartCount.innerHTML = cart.reduce((sum, item) => sum + item.quantity, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Initialize
|
||||||
|
fetchProducts();
|
||||||
|
updateCart();
|
||||||
|
|
@ -0,0 +1,28 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="de">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
|
<title>Online Shop</title>
|
||||||
|
<link rel="stylesheet" href="styles.css">
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<header>
|
||||||
|
<h1>Online Shop</h1>
|
||||||
|
<div id="cart-icon">
|
||||||
|
🛒 <span id="cart-count">0</span>
|
||||||
|
</div>
|
||||||
|
</header>
|
||||||
|
|
||||||
|
<main>
|
||||||
|
<div id="products-container"></div>
|
||||||
|
<div id="cart-container">
|
||||||
|
<h2>Warenkorb</h2>
|
||||||
|
<div id="cart-items"></div>
|
||||||
|
<div id="cart-total"></div>
|
||||||
|
</div>
|
||||||
|
</main>
|
||||||
|
|
||||||
|
<script src="app.js"></script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
|
@ -0,0 +1,90 @@
|
||||||
|
* {
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
box-sizing: border-box;
|
||||||
|
}
|
||||||
|
|
||||||
|
body {
|
||||||
|
font-family: Arial, sans-serif;
|
||||||
|
line-height: 1.6;
|
||||||
|
background-color: #f4f4f4;
|
||||||
|
}
|
||||||
|
|
||||||
|
header {
|
||||||
|
background-color: #333;
|
||||||
|
color: white;
|
||||||
|
padding: 1rem;
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
#cart-icon {
|
||||||
|
cursor: pointer;
|
||||||
|
font-size: 1.2rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
main {
|
||||||
|
max-width: 1200px;
|
||||||
|
margin: 2rem auto;
|
||||||
|
padding: 0 1rem;
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: 3fr 1fr;
|
||||||
|
gap: 2rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
#products-container {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: repeat(auto-fill, minmax(250px, 1fr));
|
||||||
|
gap: 1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.product-card {
|
||||||
|
background: white;
|
||||||
|
padding: 1rem;
|
||||||
|
border-radius: 8px;
|
||||||
|
box-shadow: 0 2px 5px rgba(0,0,0,0.1);
|
||||||
|
}
|
||||||
|
|
||||||
|
.product-card img {
|
||||||
|
width: 100%;
|
||||||
|
height: 200px;
|
||||||
|
object-fit: cover;
|
||||||
|
border-radius: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.product-card button {
|
||||||
|
width: 100%;
|
||||||
|
padding: 0.5rem;
|
||||||
|
background-color: #007bff;
|
||||||
|
color: white;
|
||||||
|
border: none;
|
||||||
|
border-radius: 4px;
|
||||||
|
cursor: pointer;
|
||||||
|
margin-top: 1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.product-card button:hover {
|
||||||
|
background-color: #0056b3;
|
||||||
|
}
|
||||||
|
|
||||||
|
#cart-container {
|
||||||
|
background: white;
|
||||||
|
padding: 1rem;
|
||||||
|
border-radius: 8px;
|
||||||
|
box-shadow: 0 2px 5px rgba(0,0,0,0.1);
|
||||||
|
}
|
||||||
|
|
||||||
|
.cart-item {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
padding: 0.5rem 0;
|
||||||
|
border-bottom: 1px solid #eee;
|
||||||
|
}
|
||||||
|
|
||||||
|
#cart-total {
|
||||||
|
margin-top: 1rem;
|
||||||
|
font-weight: bold;
|
||||||
|
text-align: right;
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,14 @@
|
||||||
|
/* Add basic styles */
|
||||||
|
.product-grid {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: repeat(auto-fill, minmax(250px, 1fr));
|
||||||
|
gap: 2rem;
|
||||||
|
padding: 2rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.product-card {
|
||||||
|
background: white;
|
||||||
|
border-radius: 8px;
|
||||||
|
padding: 1rem;
|
||||||
|
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,41 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="de">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
|
<title>Einfacher Online-Shop</title>
|
||||||
|
<script src="https://cdn.tailwindcss.com"></script>
|
||||||
|
<link rel="stylesheet" href="{{ url_for('static', filename='styles.css') }}">
|
||||||
|
</head>
|
||||||
|
<body class="bg-gray-100 min-h-screen">
|
||||||
|
<header class="bg-white shadow-sm mb-8">
|
||||||
|
<div class="container mx-auto px-4 py-6">
|
||||||
|
<h1 class="text-3xl font-bold text-gray-900">Unser Shop</h1>
|
||||||
|
</div>
|
||||||
|
</header>
|
||||||
|
|
||||||
|
<main class="container mx-auto px-4">
|
||||||
|
<div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6">
|
||||||
|
{% for product in products %}
|
||||||
|
<div class="bg-white rounded-lg shadow-md overflow-hidden">
|
||||||
|
<img
|
||||||
|
src="{{ product.image }}"
|
||||||
|
alt="{{ product.name }}"
|
||||||
|
class="w-full h-48 object-cover"
|
||||||
|
>
|
||||||
|
<div class="p-4">
|
||||||
|
<h2 class="text-xl font-semibold mb-2">{{ product.name }}</h2>
|
||||||
|
<p class="text-gray-600 text-lg mb-4">€{{ "%.2f"|format(product.price) }}</p>
|
||||||
|
<button
|
||||||
|
onclick="alert('Produkt wurde zum Warenkorb hinzugefügt!')"
|
||||||
|
class="w-full bg-blue-500 text-white py-2 px-4 rounded hover:bg-blue-600 transition-colors"
|
||||||
|
>
|
||||||
|
In den Warenkorb
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{% endfor %}
|
||||||
|
</div>
|
||||||
|
</main>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
Loading…
Reference in New Issue