Files
Hellas-Wawi/index.html
Bjoern Welker 832aaf2b05 feat: add email notifications, order references, stock badges, and sale flags
- Add customer email field and PayPal payment reminder emails with order reference (HEL-YEAR-ID format)
- Display stock availability with color-coded badges (available/low/unavailable)
- Add sale/clearance flag with animated red badge overlay
- Implement automatic fallback placeholder for missing/broken product images
- Add email column to order management view

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2026-02-09 13:56:16 +01:00

779 lines
27 KiB
HTML
Executable File
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<!doctype html>
<html lang="de">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width,initial-scale=1" />
<title>Hellas Shop</title>
<style>
:root {
--bg: #0a2036;
--card: #0f2236;
--muted: #9fb1c8;
--text: #f1f4f8;
--line: rgba(255,255,255,.12);
--accent: #f3d52a;
--teal: #2a8a8a;
--ok: #7bd58d;
--bad: #ff6b7d;
--warn: #f0c04a;
--shadow: 0 12px 28px rgba(0,0,0,.28);
--radius: 14px;
--surface: #0f2236;
}
* { box-sizing: border-box; }
body {
margin: 0;
font-family: ui-sans-serif, system-ui, -apple-system, Segoe UI, Roboto, Arial, "Noto Sans", "Liberation Sans", sans-serif;
background:
radial-gradient(900px 520px at 50% -10%, rgba(255,255,255,.10), transparent 60%),
radial-gradient(900px 600px at 50% 20%, rgba(16,44,70,.85), transparent 65%),
radial-gradient(1200px 700px at 50% 80%, rgba(7,26,44,.95), transparent 70%),
linear-gradient(180deg, #0a2036 0%, #0b243b 45%, #092135 100%);
color: var(--text);
line-height: 1.35;
}
header {
position: sticky;
top: 0;
z-index: 10;
background: rgba(9,24,40,.9);
border-bottom: 1px solid var(--line);
box-shadow: 0 8px 22px rgba(0,0,0,.35);
}
header::before {
content: "";
display: block;
height: 3px;
background: linear-gradient(90deg, var(--teal), rgba(42,138,138,.0));
}
.wrap {
max-width: 1100px;
margin: 0 auto;
padding: 18px 16px;
}
.top {
display: flex;
gap: 12px;
align-items: center;
justify-content: space-between;
flex-wrap: wrap;
}
.brand {
display: flex;
align-items: center;
gap: 12px;
}
.brand img {
height: 42px;
width: auto;
display: block;
filter: drop-shadow(0 2px 6px rgba(0,0,0,.4));
}
h1 {
font-family: "Arial Narrow", "Helvetica Neue Condensed", Impact, "Franklin Gothic Medium", "Arial Black", sans-serif;
font-size: 24px;
margin: 0;
letter-spacing: 1px;
text-transform: uppercase;
}
.meta { color: var(--muted); font-size: 12px; letter-spacing: .3px; }
.controls { display: flex; gap: 10px; align-items: center; flex-wrap: wrap; }
.search {
min-width: 240px; max-width: 460px; flex: 1;
display: flex; align-items: center; gap: 10px;
padding: 10px 12px; border-radius: 999px;
background: rgba(255,255,255,.06);
border: 1px solid var(--line);
box-shadow: 0 1px 0 rgba(255,255,255,.06) inset;
}
.search input {
width: 100%; border: 0; outline: 0; background: transparent;
color: var(--text); font-size: 14px;
}
.pill {
display: inline-flex; align-items: center; gap: 8px;
padding: 10px 12px; border-radius: 999px;
background: rgba(255,255,255,.06);
border: 1px solid var(--line);
user-select: none; cursor: pointer;
font-size: 13px; color: var(--text);
box-shadow: 0 2px 0 rgba(0,0,0,.18);
}
.pill input { accent-color: var(--accent); }
main .wrap { padding-top: 14px; padding-bottom: 28px; }
.grid { display: grid; gap: 16px; grid-template-columns: repeat(auto-fill, minmax(220px, 1fr)); }
.card-tile {
border: 1px solid rgba(255,255,255,.08);
border-radius: 16px;
background: rgba(12,31,51,.92);
box-shadow: 0 10px 22px rgba(0,0,0,.28);
overflow: hidden;
display: flex;
flex-direction: column;
transition: transform .12s ease, box-shadow .12s ease;
}
.card-tile:hover { transform: translateY(-1px); box-shadow: 0 14px 26px rgba(0,0,0,.32); }
.card-media {
width: 100%;
aspect-ratio: 1 / 1;
background: rgba(0,0,0,.2);
display: flex;
align-items: center;
justify-content: center;
color: var(--muted);
font-size: 12px;
text-transform: uppercase;
letter-spacing: .6px;
}
.card-media img { width: 100%; height: 100%; object-fit: cover; display: block; }
.card-body { padding: 12px 12px 10px; display: grid; gap: 6px; }
.card-title {
font-family: "Arial Narrow", "Helvetica Neue Condensed", Impact, "Franklin Gothic Medium", "Arial Black", sans-serif;
font-size: 16px; font-weight: 600; letter-spacing: .6px;
}
.card-price { color: var(--accent); font-weight: 800; font-size: 14px; }
.card-sub { color: var(--muted); font-size: 12px; }
.stock-badge {
display: inline-block;
padding: 4px 8px;
border-radius: 6px;
font-size: 11px;
font-weight: 600;
margin-top: 6px;
}
.stock-badge.available {
background: rgba(123, 213, 141, 0.15);
color: var(--ok);
border: 1px solid rgba(123, 213, 141, 0.3);
}
.stock-badge.low {
background: rgba(243, 213, 42, 0.15);
color: var(--accent);
border: 1px solid rgba(243, 213, 42, 0.3);
}
.stock-badge.unavailable {
background: rgba(255, 107, 125, 0.15);
color: var(--bad);
border: 1px solid rgba(255, 107, 125, 0.3);
}
.sale-badge {
position: absolute;
top: 8px;
left: 8px;
background: linear-gradient(135deg, #ff0000, #cc0000);
color: #fff;
padding: 6px 12px;
border-radius: 6px;
font-size: 13px;
font-weight: 800;
letter-spacing: 1px;
text-transform: uppercase;
box-shadow: 0 4px 12px rgba(255, 0, 0, 0.4);
z-index: 10;
animation: pulse 2s ease-in-out infinite;
}
@keyframes pulse {
0%, 100% { transform: scale(1); }
50% { transform: scale(1.05); }
}
.card-tile { position: relative; }
.card-actions { padding: 0 12px 12px; display: flex; justify-content: flex-end; }
.detail-btn { width: 100%; }
.size-list { display: grid; gap: 8px; padding: 10px 2px 2px; }
.size-row { display: grid; grid-template-columns: 1fr auto; gap: 8px; align-items: center; padding: 8px 10px; border-radius: 10px; }
.size-row:nth-child(odd) { background: rgba(255,255,255,.04); }
.size-meta { font-size: 13px; color: var(--text); }
.size-meta strong { font-weight: 700; letter-spacing: .2px; }
.art { display: flex; flex-direction: column; gap: 4px; min-width: 0; }
.art .name {
font-family: "Arial Narrow", "Helvetica Neue Condensed", Impact, "Franklin Gothic Medium", "Arial Black", sans-serif;
font-size: 18px; font-weight: 600; letter-spacing: .6px;
white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.art .sub { font-size: 12px; color: var(--muted); }
.badges { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; justify-content: flex-end; }
.badge {
font-size: 12px; padding: 6px 10px; border-radius: 10px;
border: 1px solid rgba(255,255,255,.12);
background: rgba(255,255,255,.05);
color: var(--text);
white-space: nowrap;
font-weight: 700;
letter-spacing: .2px;
}
.thumb {
width: 64px;
height: 64px;
border-radius: 12px;
background:
linear-gradient(135deg, rgba(255,255,255,.08), rgba(0,0,0,.2)),
radial-gradient(circle at 30% 30%, rgba(255,255,255,.25), transparent 40%);
border: 1px solid rgba(255,255,255,.12);
display: inline-flex;
align-items: center;
justify-content: center;
font-size: 11px;
color: var(--muted);
text-transform: uppercase;
letter-spacing: .6px;
flex: 0 0 auto;
}
.price {
margin-top: 4px;
font-size: 12px;
color: var(--accent);
font-weight: 700;
letter-spacing: .2px;
}
.content {
border-top: 1px solid rgba(255,255,255,.08);
padding: 10px 12px 12px 12px;
background: rgba(6,16,28,.3);
}
.table-wrap { overflow-x: auto; }
.table-wrap table { min-width: 520px; }
table { width: 100%; border-collapse: collapse; font-size: 13px; overflow: hidden; }
th, td { padding: 10px 8px; border-bottom: 1px solid rgba(255,255,255,.06); text-align: right; vertical-align: middle; font-variant-numeric: tabular-nums; }
th:first-child, td:first-child { text-align: left; }
th { color: var(--muted); font-weight: 600; }
tr:last-child td { border-bottom: 0; }
thead th { background: rgba(0,0,0,.12); }
tbody tr:nth-child(odd) { background: rgba(255,255,255,.02); }
.muted { color: var(--muted); }
.small { font-size: 12px; }
.footer {
margin-top: 14px; color: var(--muted); font-size: 12px;
display: flex; gap: 10px; flex-wrap: wrap; justify-content: space-between;
border-top: 1px dashed rgba(255,255,255,.12);
padding-top: 12px;
}
.empty, .error {
border: 1px dashed rgba(255,255,255,.2);
border-radius: var(--radius);
padding: 16px;
color: var(--muted);
text-align: center;
}
.error { color: #ffd6de; border-color: rgba(255,107,125,.4); }
.order-btn {
display: inline-flex;
align-items: center;
gap: 6px;
padding: 6px 10px;
border-radius: 10px;
border: 1px solid var(--line);
background: rgba(255,255,255,.06);
color: var(--text);
cursor: pointer;
font-size: 12px;
}
.modal {
position: fixed;
inset: 0;
background: rgba(5,12,20,.6);
display: none;
align-items: flex-start;
justify-content: center;
padding: 84px 16px 24px;
z-index: 50;
opacity: 0;
transition: opacity .18s ease;
}
.modal.open { display: flex; opacity: 1; }
.modal-card {
width: 100%;
max-width: 520px;
border: 1px solid var(--line);
border-radius: 14px;
background: linear-gradient(180deg, rgba(18,45,70,.92), rgba(12,31,51,.98));
box-shadow: 0 16px 28px rgba(0,0,0,.35);
padding: 14px;
max-height: calc(100vh - 80px);
overflow: auto;
transform: scale(.98);
transition: transform .18s ease;
}
.modal.open .modal-card { transform: scale(1); }
.modal-card h3 { margin: 0 0 10px; }
.detail-header { display: grid; gap: 8px; }
.detail-title { font-size: 20px; font-weight: 700; letter-spacing: .4px; }
.detail-price { color: var(--accent); font-weight: 800; }
.detail-media {
width: 100%;
aspect-ratio: 4 / 3;
border-radius: 12px;
overflow: hidden;
background: rgba(0,0,0,.2);
}
.detail-media img { width: 100%; height: 100%; object-fit: cover; display: block; }
.modal-card { position: relative; }
.close-x {
position: absolute;
top: 8px;
right: 8px;
width: 28px;
height: 28px;
border-radius: 8px;
border: 1px solid rgba(0,0,0,.35);
background: rgba(8,16,28,.85);
color: var(--text);
font-size: 16px;
line-height: 1;
cursor: pointer;
box-shadow: 0 4px 10px rgba(0,0,0,.35);
}
.form-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
gap: 10px;
}
.form-grid label { display: grid; gap: 6px; font-size: 12px; color: var(--muted); }
.form-grid input, .form-grid textarea {
background: rgba(255,255,255,.06);
border: 1px solid var(--line);
color: var(--text);
padding: 8px 10px;
border-radius: 10px;
font-size: 13px;
}
.form-actions { margin-top: 12px; display: flex; gap: 10px; justify-content: flex-end; }
.btn {
display: inline-flex; align-items: center; gap: 8px;
padding: 8px 12px; border-radius: 999px;
border: 1px solid var(--line);
background: rgba(255,255,255,.06);
color: var(--text); cursor: pointer;
}
.btn.accent { background: var(--accent); color: #071320; border-color: transparent; font-weight: 700; }
.img-modal .modal-card { max-width: 720px; padding: 10px; }
.img-modal img { width: 100%; height: auto; border-radius: 12px; display: block; }
.order-modal { z-index: 60; }
@media (max-width: 700px) {
.top { align-items: flex-start; }
.brand { width: 100%; }
.controls { width: 100%; }
.search { min-width: 100%; }
.card-media { aspect-ratio: 4 / 3; }
.order-btn { width: 100%; justify-content: center; }
}
@media (max-width: 640px) { .grid { grid-template-columns: 1fr; } }
/* Toast Notifications */
.toast-container {
position: fixed;
top: 20px;
right: 20px;
z-index: 9999;
display: flex;
flex-direction: column;
gap: 12px;
pointer-events: none;
}
.toast {
min-width: 300px;
max-width: 400px;
padding: 16px 20px;
border-radius: 12px;
background: rgba(12, 31, 51, 0.98);
border: 1px solid rgba(255, 255, 255, 0.15);
box-shadow: 0 12px 28px rgba(0, 0, 0, 0.4), 0 0 1px rgba(255, 255, 255, 0.3);
color: var(--text);
font-size: 14px;
line-height: 1.5;
pointer-events: all;
transform: translateX(400px);
opacity: 0;
transition: all 0.3s cubic-bezier(0.68, -0.55, 0.265, 1.55);
}
.toast.show {
transform: translateX(0);
opacity: 1;
}
.toast.success {
border-left: 4px solid var(--ok);
background: linear-gradient(90deg, rgba(123, 213, 141, 0.15), rgba(12, 31, 51, 0.98));
}
.toast.error {
border-left: 4px solid var(--bad);
background: linear-gradient(90deg, rgba(255, 107, 125, 0.15), rgba(12, 31, 51, 0.98));
}
.toast.info {
border-left: 4px solid var(--accent);
background: linear-gradient(90deg, rgba(243, 213, 42, 0.15), rgba(12, 31, 51, 0.98));
}
@media (max-width: 640px) {
.toast-container {
top: auto;
bottom: 20px;
right: 16px;
left: 16px;
}
.toast {
min-width: 100%;
max-width: 100%;
}
}
</style>
</head>
<body>
<header>
<div class="wrap">
<div class="top">
<div class="brand">
<img src="logo.png" alt="Hellas 1899 Logo" />
<div>
<h1>Shop</h1>
<div class="meta" id="meta">Stand: </div>
</div>
</div>
<div class="controls">
<div class="search" role="search">
<span aria-hidden="true">🔎</span>
<input id="q" type="search" placeholder="Artikel suchen… (z.B. Badehose, Hoodie, Kappe)" />
</div>
</div>
</div>
</div>
</header>
<main>
<div class="wrap">
<div id="grid" class="grid" aria-live="polite"></div>
<div class="footer">
<div>Tip: Auf einen Artikel klicken, um die GrößenTabelle zu öffnen.</div>
</div>
</div>
</main>
<div id="orderModal" class="modal order-modal" role="dialog" aria-modal="true">
<div class="modal-card">
<button class="close-x" id="orderCloseX" aria-label="Schließen">×</button>
<h3>Bestellung</h3>
<form id="orderForm">
<div class="form-grid">
<label>Artikel
<input id="fArtikel" name="artikel" readonly />
</label>
<label>Größe
<input id="fGroesse" name="groesse" readonly />
</label>
<label>Menge
<input id="fMenge" name="menge" type="number" min="1" value="1" required />
</label>
<label>Name
<input id="fName" name="name" required />
</label>
<label>Handy
<input id="fHandy" name="handy" required />
</label>
<label>E-Mail
<input id="fEmail" name="email" type="email" required />
</label>
<label>Mannschaft
<input id="fMannschaft" name="mannschaft" placeholder="z. B. U12" required />
</label>
<label style="grid-column: 1 / -1;">Notiz
<textarea id="fNotiz" name="notiz" rows="3"></textarea>
</label>
<div style="grid-column: 1 / -1; padding: 12px; background: #f0f9ff; border: 1px solid #bfdbfe; border-radius: 4px; margin-top: 8px;">
<strong>Zahlungsart wählen:</strong>
<div style="margin-top: 8px;">
<label style="display: flex; align-items: center; margin-bottom: 8px;">
<input type="radio" name="payment_method" value="paypal" checked style="margin-right: 8px;" />
<span><strong>PayPal (Familie & Freunde)</strong></span>
</label>
<div id="paypalInfo" style="margin-left: 28px; margin-bottom: 12px; font-size: 0.95em; color: #1e40af;">
Bitte sende den Betrag über PayPal an: <strong id="paypalAccount"></strong>
</div>
<div style="margin-left: 28px; margin-bottom: 12px; padding: 10px; background: #fef3c7; border: 2px solid #f59e0b; border-radius: 6px; font-size: 0.9em; color: #92400e;">
<strong>⚠️ WICHTIG:</strong> Bitte unbedingt die Option <strong>"Familie & Freunde"</strong> wählen!<br>
Bei normalen PayPal-Zahlungen fallen zusätzliche Gebühren an.
</div>
<label style="display: flex; align-items: center;">
<input type="radio" name="payment_method" value="bar" style="margin-right: 8px;" />
<span><strong>Bar bei Abholung</strong></span>
</label>
</div>
</div>
</div>
<div class="form-actions">
<button type="button" class="btn" id="orderCancel">Abbrechen</button>
<button type="submit" class="btn accent">Bestellen</button>
</div>
</form>
</div>
</div>
<div id="imgModal" class="modal img-modal" role="dialog" aria-modal="true">
<div class="modal-card">
<img id="imgPreview" src="" alt="Artikelbild" />
</div>
</div>
<div id="detailModal" class="modal" role="dialog" aria-modal="true">
<div class="modal-card">
<button class="close-x" id="detailCloseX" aria-label="Schließen">×</button>
<div class="detail-header">
<div id="detailMedia" class="detail-media"></div>
<div class="detail-title" id="detailTitle"></div>
<div class="detail-price" id="detailPrice"></div>
<div class="card-sub" id="detailSizes"></div>
</div>
<div class="size-list" id="detailSizeList"></div>
<div class="form-actions">
<button type="button" class="btn" id="detailClose">Schließen</button>
</div>
</div>
</div>
<div id="toastContainer" class="toast-container"></div>
<script>
// Toast Notification System
function showToast(message, type = 'info') {
const container = document.getElementById('toastContainer');
const toast = document.createElement('div');
toast.className = `toast ${type}`;
toast.textContent = message;
container.appendChild(toast);
// Trigger animation
setTimeout(() => toast.classList.add('show'), 10);
// Auto-remove after 4 seconds
setTimeout(() => {
toast.classList.remove('show');
setTimeout(() => container.removeChild(toast), 300);
}, 4000);
}
// Proxy der WaWiApp (kein APIKey im Browser nötig).
const API_URL = "/wawi/proxy/bestand";
let DATA = [];
const DATA_MAP = new Map();
function fmt(v) {
if (v === null || v === undefined || Number.isNaN(v)) return "";
return String(v);
}
function badge(label, value, cls="") {
if (value === null || value === undefined) return "";
return `<span class="badge ${cls}">${label}: <strong>${fmt(value)}</strong></span>`;
}
function render(items) {
const grid = document.getElementById("grid");
if (!items.length) {
grid.innerHTML = `<div class="empty">Keine Treffer. (Suchbegriff anpassen)</div>`;
return;
}
grid.innerHTML = items.map((item, idx) => {
const t = item.totals || {};
const diff = t.abweichung ?? 0;
const fb = t.fehlbestand ?? null;
let statusCls = "ok";
if ((diff ?? 0) !== 0) statusCls = "bad";
else if ((fb ?? 0) !== 0) statusCls = "warn";
const statusText = ((diff ?? 0) === 0 && (fb ?? 0) === 0) ? "OK" : "Prüfen";
const price = Number(item.preis) || 0;
const priceText = price > 0 ? `${price.toFixed(2)}` : "Preis auf Anfrage";
const img = (item.bild_url || "").trim();
// Verfügbarkeit prüfen
const totalStock = Number(t.gezaehlt) || 0;
let stockBadge = '';
let stockClass = '';
if (totalStock === 0) {
stockBadge = '<div class="stock-badge unavailable">⛔ Nicht verfügbar</div>';
stockClass = 'unavailable';
} else if (totalStock <= 5) {
stockBadge = `<div class="stock-badge low">⚠️ Nur noch ${totalStock} verfügbar</div>`;
stockClass = 'low';
} else {
stockBadge = `<div class="stock-badge available">✓ Verfügbar (${totalStock})</div>`;
stockClass = 'available';
}
// Sale-Badge anzeigen
const saleBadge = item.sale ? '<div class="sale-badge">SALE 🔥</div>' : '';
return `
<div class="card-tile">
${saleBadge}
<div class="card-media">
${img ? `<button class="thumb-btn" data-img="${img}" aria-label="Bild vergrößern" title="Bild vergrößern" style="width:100%;height:100%;border:0;cursor:pointer;padding:0;position:relative;overflow:hidden;"><img src="${img}" onerror="this.style.display='none';this.nextElementSibling.style.display='flex';" style="width:100%;height:100%;object-fit:cover;display:block;"><div style="display:none;position:absolute;inset:0;align-items:center;justify-content:center;background:linear-gradient(135deg, rgba(42,138,138,.15), rgba(18,45,70,.2));font-size:40px;opacity:0.5;">📦</div></button>` : `<div style="width:100%;height:100%;display:flex;align-items:center;justify-content:center;background:linear-gradient(135deg, rgba(42,138,138,.15), rgba(18,45,70,.2));font-size:40px;opacity:0.5;">📦</div>`}
</div>
<div class="card-body">
<div class="card-title">${item.artikel}</div>
<div class="card-price">${priceText}</div>
<div class="card-sub">${item.rows.length} Größen</div>
${stockBadge}
</div>
<div class="card-actions">
<button class="order-btn detail-btn" data-artikel="${item.artikel}" data-preis="${priceText}" data-img="${img}" ${totalStock === 0 ? 'disabled style="opacity: 0.5; cursor: not-allowed;"' : ''}>
${totalStock === 0 ? 'Nicht verfügbar' : 'Bestellen / Details'}
</button>
</div>
</div>
`;
}).join("");
}
function applyFilters() {
const q = (document.getElementById("q").value || "").trim().toLowerCase();
let items = DATA.slice();
if (q) {
items = items.filter(it => (it.artikel || "").toLowerCase().includes(q));
}
render(items);
}
async function loadData() {
const res = await fetch(API_URL);
if (!res.ok) {
const grid = document.getElementById("grid");
grid.innerHTML = `<div class="error">API Fehler (${res.status}). Bitte APIKey prüfen.</div>`;
return;
}
DATA = await res.json();
DATA_MAP.clear();
DATA.forEach(item => DATA_MAP.set(item.artikel, item));
document.getElementById("meta").textContent = `Stand: ${new Date().toLocaleString("de-DE")}`;
applyFilters();
}
document.getElementById("q").addEventListener("input", applyFilters);
const modal = document.getElementById("orderModal");
const form = document.getElementById("orderForm");
const setField = (id, v) => document.getElementById(id).value = v || "";
const ORDER_KEY = "";
// PayPal-Konto vom Backend laden
fetch("/wawi/config")
.then(res => res.json())
.then(config => {
if (config.paypal_account) {
document.getElementById("paypalAccount").textContent = config.paypal_account;
} else {
document.getElementById("paypalAccount").textContent = "Nicht konfiguriert";
}
})
.catch(() => {
document.getElementById("paypalAccount").textContent = "Fehler beim Laden";
});
document.addEventListener("click", (e) => {
const imgBtn = e.target.closest(".thumb-btn");
if (imgBtn) {
document.getElementById("imgPreview").src = imgBtn.dataset.img;
document.getElementById("imgModal").classList.add("open");
return;
}
const detailBtn = e.target.closest(".detail-btn");
if (detailBtn) {
// Verhindere Klick auf disabled Button
if (detailBtn.disabled) return;
const artikel = detailBtn.dataset.artikel;
const item = DATA_MAP.get(artikel);
if (!item) return;
const img = (detailBtn.dataset.img || "").trim();
const media = document.getElementById("detailMedia");
media.innerHTML = img ? `<img src="${img}" alt="${artikel}">` : "";
document.getElementById("detailTitle").textContent = artikel;
document.getElementById("detailPrice").textContent = detailBtn.dataset.preis || "Preis auf Anfrage";
document.getElementById("detailSizes").textContent = `${item.rows.length} Größen`;
const list = item.rows.map(r => {
const stock = Number(r.gezaehlt) || 0;
let stockInfo = '';
if (stock === 0) {
stockInfo = '<span class="stock-badge unavailable">Nicht verfügbar</span>';
} else if (stock <= 3) {
stockInfo = `<span class="stock-badge low">Nur noch ${stock} verfügbar</span>`;
} else {
stockInfo = `<span class="stock-badge available">Verfügbar (${stock})</span>`;
}
return `
<div class="size-row">
<div class="size-meta">
<strong>${fmt(r.groesse)}</strong> · ${stockInfo}
</div>
${stock > 0 ? `<button class="order-btn" data-artikel="${item.artikel}" data-groesse="${fmt(r.groesse)}">Bestellen</button>` : '<span style="color: var(--muted); font-size: 11px;"></span>'}
</div>
`;
}).join("");
document.getElementById("detailSizeList").innerHTML = list;
document.getElementById("detailModal").classList.add("open");
return;
}
const btn = e.target.closest(".order-btn");
if (!btn) return;
setField("fArtikel", btn.dataset.artikel);
setField("fGroesse", btn.dataset.groesse);
setField("fMenge", 1);
modal.classList.add("open");
});
document.getElementById("orderCancel").addEventListener("click", () => {
modal.classList.remove("open");
if (document.getElementById("detailModal").classList.contains("open")) {
document.getElementById("detailModal").querySelector(".size-row")?.scrollIntoView({ block: "nearest" });
}
});
document.getElementById("orderCloseX").addEventListener("click", () => {
modal.classList.remove("open");
});
modal.addEventListener("click", (e) => {
if (e.target === modal) modal.classList.remove("open");
});
document.getElementById("imgModal").addEventListener("click", (e) => {
if (e.target.id === "imgModal") e.currentTarget.classList.remove("open");
});
document.getElementById("detailClose").addEventListener("click", () => {
document.getElementById("detailModal").classList.remove("open");
});
document.getElementById("detailCloseX").addEventListener("click", () => {
document.getElementById("detailModal").classList.remove("open");
});
document.getElementById("detailModal").addEventListener("click", (e) => {
if (e.target.id === "detailModal") e.currentTarget.classList.remove("open");
});
form.addEventListener("submit", async (e) => {
e.preventDefault();
const payload = Object.fromEntries(new FormData(form).entries());
const key = ORDER_KEY || "";
const headers = { "Content-Type": "application/json" };
if (key) headers["X-Order-Key"] = key;
const res = await fetch("/wawi/order", {
method: "POST",
headers,
body: JSON.stringify(payload)
});
if (res.ok) {
showToast("Bestellung erfolgreich gesendet! Wir melden uns bei dir.", "success");
modal.classList.remove("open");
document.getElementById("detailModal").classList.remove("open");
form.reset();
setField("fMenge", 1);
} else {
showToast("Fehler beim Senden der Bestellung. Bitte versuche es erneut.", "error");
}
});
loadData();
</script>
</body>
</html>