Files
schmankerl/app/templates/index.html
T

322 lines
13 KiB
HTML
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.
{% extends "base.html" %}
{% block content %}
<div class="container">
{% if success %}
<div class="alert-success" style="margin-bottom: 20px;">
✓ {{ success }}
</div>
{% endif %}
{% if error %}
<div class="alert-error" style="margin-bottom: 20px;">
⚠️ {{ error }}
</div>
{% endif %}
<!-- Multi-Event Picker (wenn mehrere anstehende Runden offen sind) -->
{% if open_events|length > 1 %}
<div class="multi-event-banner">
<span>📅 Weitere offene Termine:</span>
<div class="multi-event-chips">
{% for ev in open_events %}
<a href="/?event_id={{ ev.id }}{% if is_valid_guest %}&token={{ guest_token }}{% endif %}" class="mini-chip {% if event and event.id == ev.id %}active{% endif %}">
{{ ev.event_date.strftime('%d.%m.') }} – {{ ev.title }}
</a>
{% endfor %}
</div>
</div>
{% endif %}
<!-- Header Banner -->
{% if event %}
<div class="banner {% if is_closed %}banner-closed{% endif %}">
<div class="banner-top-row">
<div class="banner-badge {% if is_closed %}closed{% endif %}">
{% if is_closed %}🔴 Runde geschlossen{% else %}🟢 Runde geöffnet{% endif %}
</div>
<div class="countdown-container" id="countdownContainer">
<span class="countdown-label">Frist:</span>
<span class="countdown-timer" id="countdownTimer">Berechne...</span>
</div>
</div>
<h1>{{ event.title }}</h1>
<p class="banner-sub">
Brotzeit-Tag: <strong>{{ event.event_date.strftime('%d.%m.%Y') }}</strong> &nbsp;|&nbsp;
Bestellschluss: <strong>{{ event.deadline.strftime('%d.%m.%Y um %H:%M Uhr') }}</strong>
</p>
{% if event.sponsor_name %}
<div class="sponsor-badge-banner">
🎉 <strong>Runde gesponsert:</strong> Die Brotzeit geht heute auf <strong>{{ event.sponsor_name }}</strong>!
</div>
{% endif %}
<div class="banner-stats">
<span>👥 Bereits <strong>{{ order_count }}</strong> Bestellungen von Kollegen eingegangen</span>
</div>
</div>
{% if is_closed %}
<div class="closed-notice-bar">
🔒 <strong>Bestellschluss erreicht:</strong> Diese Bestellrunde ist geschlossen. Änderungen oder neue Bestellungen sind nicht mehr möglich. Wende dich bei Notfällen direkt an den Organisator.
</div>
{% endif %}
{% set is_locked = is_closed or (existing_order and existing_order.is_paid) %}
<!-- Order Form -->
<form action="/order" method="POST" class="order-form" id="orderForm">
<input type="hidden" name="event_id" value="{{ event.id }}">
<input type="hidden" name="guest_token" value="{{ guest_token }}">
<div class="form-grid">
<!-- Left: Products -->
<div class="products-section">
<h2>1. Brotzeit auswählen</h2>
<div class="product-list">
{% for product in products %}
{% set current_qty = user_items.get(product.id, 0) %}
<div class="product-card {% if is_locked %}disabled{% endif %}" data-price="{{ product.price }}" data-id="{{ product.id }}">
<div class="product-info">
<h3>{{ product.name }}</h3>
<p class="product-desc">{{ product.description }}</p>
<div class="product-price">
{% if event.sponsor_name %}
<span style="text-decoration: line-through; opacity: 0.6; font-size: 0.9rem;">{{ "%.2f"|format(product.price) }} €</span>
<span style="color: var(--accent-gold); font-weight: 700;"> 0,00 € (Gesponsert)</span>
{% else %}
{{ "%.2f"|format(product.price) }} € <small>/ {{ product.unit }}</small>
{% endif %}
</div>
</div>
<div class="quantity-control">
<button type="button" class="qty-btn" onclick="changeQty({{ product.id }}, -1)" {% if is_locked %}disabled{% endif %}>-</button>
<input type="number" id="qty_{{ product.id }}" name="qty_{{ product.id }}" value="{{ current_qty }}" min="0" max="50" class="qty-input" onchange="updateTotal()" {% if is_locked %}disabled{% endif %}>
<button type="button" class="qty-btn" onclick="changeQty({{ product.id }}, 1)" {% if is_locked %}disabled{% endif %}>+</button>
</div>
</div>
{% endfor %}
</div>
</div>
<!-- Right: User Details & Summary -->
<div class="summary-section">
<div class="summary-card">
<h2>2. Angaben & Übersicht</h2>
{% if current_user %}
<div class="logged-in-badge">
<div class="user-avatar">👤</div>
<div>
<strong>{{ current_user.first_name }} {{ current_user.last_name }}</strong>
{% if current_user.role == 'guest' %}<small>(Gast)</small>{% endif %}
<br>
<small class="text-muted">{{ current_user.email }}</small>
</div>
</div>
{% else %}
<!-- Gast Angaben -->
<div class="guest-order-box">
<div class="privacy-note" style="margin-bottom: 12px;">
👋 <strong>Gast- & Dienstleister-Bestellung:</strong><br>
Du bestellst ohne dauerhaftes Konto für diesen Termin ({{ event.event_date.strftime('%d.%m.') }}) mit.
</div>
<div class="input-group">
<label for="g_first_name">Vorname / Name *</label>
<input type="text" id="g_first_name" name="guest_first_name" required placeholder="z. B. Tobias">
</div>
<div class="input-group">
<label for="g_last_name">Firma / Abteilung (optional)</label>
<input type="text" id="g_last_name" name="guest_last_name" placeholder="z. B. IT-Service Müller">
</div>
<div class="input-group">
<label for="g_email">E-Mail (optional)</label>
<input type="email" id="g_email" name="guest_email" placeholder="name@firma.de">
</div>
</div>
{% endif %}
{% set is_locked = is_closed or (existing_order and existing_order.is_paid) %}
{% if existing_order %}
{% if existing_order.is_paid %}
<div class="alert-success" style="margin-bottom: 16px; border-left: 4px solid var(--success); font-size: 0.88rem; line-height: 1.4;">
🔒 <strong>Bestellung bereits bezahlt ({{ "%.2f"|format(existing_order.total_price) }} €)</strong><br>
Deine Bestellung wurde vom Organisator bereits als bezahlt verbucht
({% if existing_order.payment_method == 'balance' %}Guthaben abgebucht{% else %}Barzahlung vermerkt{% endif %}).
Änderungen sind gesperrt. Wende dich an deinen Organisator für Anpassungen.
</div>
{% else %}
<div class="notice-box" style="margin-bottom: 14px;">
ℹ️ Du hast bereits für diese Runde bestellt (Status: <strong>Noch offen</strong>).
{% if not is_closed %}Du kannst deine Mengen bis zum Fristende anpassen oder die Bestellung stornieren.{% endif %}
</div>
{% endif %}
{% endif %}
<hr class="divider">
<div class="order-total-box">
<div class="total-label">Gesamtsumme:</div>
<div class="total-amount" id="totalAmount">0,00 €</div>
</div>
{% if event.sponsor_name %}
<div style="font-size: 0.85rem; color: var(--accent-gold); margin-bottom: 14px; text-align: center;">
🎁 Die Rechnung wird von <strong>{{ event.sponsor_name }}</strong> übernommen!
</div>
{% endif %}
<button type="submit" class="btn-submit" id="submitBtn" {% if is_locked %}disabled{% endif %}>
{% if existing_order and existing_order.is_paid %}
🔒 Bestellung bereits bezahlt & gesperrt
{% elif is_closed %}
🔒 Bestellschluss vorüber
{% elif existing_order %}
🥨 Bestellung aktualisieren
{% else %}
🥨 Bestellung verbindlich abschicken
{% endif %}
</button>
{% if existing_order and not existing_order.is_paid and not is_closed %}
<div style="margin-top: 10px;">
<button type="button" onclick="cancelMyOrder()" class="btn-secondary" style="width: 100%; border-color: var(--danger); color: var(--danger); font-size: 0.85rem; padding: 8px 12px; cursor: pointer;">
✕ Bestellung komplett stornieren
</button>
</div>
{% endif %}
{% if not is_closed and not (existing_order and existing_order.is_paid) %}
<small class="form-hint">Du kannst deine Bestellung bis zum Bestellschluss jederzeit hier anpassen.</small>
{% elif existing_order and existing_order.is_paid %}
<small class="form-hint">Bereits abgerechnet – Änderungen nur über den Organisator.</small>
{% else %}
<small class="form-hint text-warning">Die Frist ist abgelaufen.</small>
{% endif %}
</div>
</div>
</div>
</form>
{% else %}
<div class="empty-state">
<div class="empty-icon">🏖️</div>
<h2>Aktuell keine offene Bestellrunde</h2>
<p>Für dieses Team ist im Moment keine Brotzeit geplant.</p>
{% if current_user and current_user.role == 'admin' %}
<a href="/admin?tab=event" class="btn-primary" style="margin-top: 1rem;">Neue Bestellrunde im Cockpit anlegen</a>
{% endif %}
</div>
{% endif %}
</div>
<script>
function changeQty(productId, delta) {
const input = document.getElementById('qty_' + productId);
if (!input || input.disabled) return;
let val = parseInt(input.value) || 0;
val = Math.max(0, val + delta);
input.value = val;
updateTotal();
}
function updateTotal() {
let total = 0;
const cards = document.querySelectorAll('.product-card');
cards.forEach(card => {
const price = parseFloat(card.dataset.price) || 0;
const id = card.dataset.id;
const qtyInput = document.getElementById('qty_' + id);
const qty = parseInt(qtyInput ? qtyInput.value : 0) || 0;
total += price * qty;
});
const totalEl = document.getElementById('totalAmount');
if (totalEl) {
totalEl.innerText = total.toFixed(2).replace('.', ',') + ' €';
}
}
// --- LIVE COUNTDOWN TIMER ---
{% if event and not is_closed %}
const deadlineMs = new Date("{{ event.deadline.isoformat() }}").getTime();
function updateCountdown() {
const nowMs = new Date().getTime();
const diffMs = deadlineMs - nowMs;
const timerEl = document.getElementById('countdownTimer');
const containerEl = document.getElementById('countdownContainer');
const submitBtn = document.getElementById('submitBtn');
if (diffMs <= 0) {
if (timerEl) timerEl.innerText = "Abgelaufen (geschlossen)";
if (containerEl) {
containerEl.classList.add('expired');
}
if (submitBtn) {
submitBtn.disabled = true;
submitBtn.innerText = "🔒 Bestellschluss vorüber";
}
document.querySelectorAll('.qty-btn').forEach(btn => btn.disabled = true);
document.querySelectorAll('.qty-input').forEach(inp => inp.disabled = true);
return;
}
const totalSeconds = Math.floor(diffMs / 1000);
const days = Math.floor(totalSeconds / 86400);
const hours = Math.floor((totalSeconds % 86400) / 3600);
const minutes = Math.floor((totalSeconds % 3600) / 60);
const seconds = totalSeconds % 60;
let text = "";
if (days > 0) {
text = `${days}T ${pad(hours)}:${pad(minutes)}:${pad(seconds)}`;
} else {
text = `${pad(hours)}:${pad(minutes)}:${pad(seconds)}`;
}
if (timerEl) timerEl.innerText = `⏳ Noch ${text}`;
if (totalSeconds < 3600 && containerEl) {
containerEl.classList.add('urgent');
}
}
function pad(num) {
return num.toString().padStart(2, '0');
}
setInterval(updateCountdown, 1000);
updateCountdown();
{% elif is_closed %}
const timerEl = document.getElementById('countdownTimer');
if (timerEl) timerEl.innerText = "Frist beendet";
{% endif %}
function cancelMyOrder() {
if (!confirm('Möchtest du deine Bestellung für diese Runde wirklich komplett stornieren?')) {
return;
}
const form = document.createElement('form');
form.method = 'POST';
form.action = '/order/cancel';
const evInput = document.createElement('input');
evInput.type = 'hidden';
evInput.name = 'event_id';
evInput.value = '{{ event.id if event else "" }}';
form.appendChild(evInput);
document.body.appendChild(form);
form.submit();
}
document.addEventListener('DOMContentLoaded', updateTotal);
</script>
{% endblock %}