Files
Key-service-Server/Website/templates/preise.html
T

543 lines
25 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 title %}Preise{% endblock %}
{% block head %}
{{ super() }}
<style>
/* Hero & Grid Styles (Beibehalten) */
.booking-hero {
background: linear-gradient(135deg, rgba(28, 90, 99, 0.14), rgba(255, 255, 255, 0.65)),
linear-gradient(180deg, #fffefb 0%, #f2f5f2 100%);
border: 1px solid rgba(28, 90, 99, 0.16);
border-radius: 24px;
padding: 2.2rem;
margin-bottom: 1.8rem;
box-shadow: 0 18px 44px rgba(18, 49, 54, 0.08);
overflow: hidden;
position: relative;
}
.booking-hero::before {
content: "";
position: absolute;
inset: 0;
background: radial-gradient(circle at top right, rgba(34, 98, 128, 0.16), transparent 36%);
pointer-events: none;
}
.booking-hero > * { position: relative; z-index: 1; }
.booking-hero h1 { margin-bottom: 0.65rem; color: #133d4a; font-size: clamp(2rem, 3.5vw, 3.2rem); }
.booking-hero p { margin: 0.75rem 0 0; max-width: 780px; color: #3b5f69; font-size: clamp(1rem, 1.05vw, 1.1rem); }
.packages-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
gap: 1.4rem;
margin-bottom: 1.8rem;
align-items: stretch;
}
.package-card {
background: #ffffff;
border: 1px solid #dfe7e7;
border-radius: 22px;
box-shadow: 0 18px 40px rgba(23, 44, 57, 0.05);
padding: 1.8rem;
display: flex;
flex-direction: column;
height: 100%;
gap: 1.2rem;
transition: transform 0.3s ease, box-shadow 0.3s ease, border-color 0.3s ease;
}
.package-card:hover { transform: translateY(-3px); border-color: #b2d4dc; box-shadow: 0 24px 48px rgba(23, 44, 57, 0.1); }
.package-card.highlight { border-color: #106476; box-shadow: 0 18px 40px rgba(16, 100, 118, 0.15); }
.package-card__header { display: flex; flex-direction: column; gap: 1.2rem; }
.package-card__tag { display: inline-flex; align-items: center; gap: 0.35rem; padding: 0.45rem 0.8rem; border-radius: 999px; background: #e6f5f8; color: #106476; font-size: 0.9rem; font-weight: 700; margin-bottom: 0.6rem; }
.package-card__tag.highlight-tag { background: #106476; color: white; }
.package-card__name { margin: 0; color: #143f46; font-size: clamp(1.4rem, 2.5vw, 1.8rem); line-height: 1.2; }
.package-card__price { display: inline-flex; align-items: baseline; gap: 0.35rem; font-weight: 700; color: #102d37; margin-top: 0.2rem; }
.package-card__price span { font-size: clamp(1.8rem, 3vw, 2.4rem); letter-spacing: -0.04em; }
.package-card__price small { color: #57717b; font-size: 0.95rem; }
.package-card__description { margin: 0; color: #4b6a72; line-height: 1.75; }
.package-card__features { margin: 1rem 0 0; padding: 0; list-style: none; display: grid; gap: 0.75rem; flex: 1 1 auto; }
.package-card__features li { display: grid; grid-template-columns: auto 1fr; gap: 0.75rem; color: #4f6a72; font-size: 0.98rem; }
.package-card__features li::before { content: "✓"; color: #187490; font-weight: 700; }
.package-card__actions { margin-top: auto; padding-top: 0.25rem; }
.btn {
width: 100%; border: 1px solid #1c5a63; background: linear-gradient(120deg, #1d6d79 0%, #164b55 100%);
color: #ffffff; border-radius: 999px; padding: 0.95rem 1.2rem; font-weight: 700;
cursor: pointer; text-align: center; transition: all 0.2s ease;
display: inline-flex; align-items: center; justify-content: center; gap: 0.5rem;
}
.btn:hover, .btn:focus-visible { transform: translateY(-1px); box-shadow: 0 12px 24px rgba(28, 90, 99, 0.22); }
.btn.secondary { border-color: #c7dde3; background: #f7fbfb; color: #1d5f6f; }
.btn.outline { background: transparent; color: #1d6d79; }
.btn.outline:hover { background: #f0f7f8; }
.notice { padding: 1.3rem 1.35rem; border-radius: 20px; background: #ffffff; border: 1px solid #dfe7ea; color: #304f5a; box-shadow: 0 12px 24px rgba(23, 44, 57, 0.04); }
.notice strong { color: #15444c; }
/* Modals */
.custom-modal {
position: fixed; top: 0; left: 0; width: 100%; height: 100%;
display: none; align-items: center; justify-content: center; z-index: 1000; padding: 1rem;
}
.custom-modal.active { display: flex; }
.custom-modal-backdrop { position: absolute; top: 0; left: 0; width: 100%; height: 100%; background: rgba(18, 49, 54, 0.4); backdrop-filter: blur(4px); }
.custom-modal-content {
position: relative; background: #ffffff; border-radius: 20px; padding: 2.2rem;
max-width: 550px; width: 100%; box-shadow: 0 24px 54px rgba(23, 44, 57, 0.2); z-index: 101;
animation: modalEnter 0.3s cubic-bezier(0.16, 1, 0.3, 1);
}
@keyframes modalEnter { from { opacity: 0; transform: translateY(20px) scale(0.95); } to { opacity: 1; transform: translateY(0) scale(1); } }
.custom-modal-content h3 { margin-top: 0; margin-bottom: 1rem; color: #133d4a; }
.custom-modal-actions { display: flex; gap: 1rem; margin-top: 2rem; justify-content: flex-end; }
/* Cart Specific Styles */
.cart-items-list { margin: 1.5rem 0; display: flex; flex-direction: column; gap: 1rem; }
.cart-item { display: flex; justify-content: space-between; align-items: center; padding: 1rem; background: #f7fbfb; border: 1px solid #e1eced; border-radius: 12px; }
.cart-item-info { display: flex; flex-direction: column; }
.cart-item-title { font-weight: 700; color: #133d4a; }
.cart-item-price { color: #187490; font-size: 0.95rem; }
.cart-item-remove { background: none; border: none; color: #c62828; cursor: pointer; font-size: 0.9rem; font-weight: 700; padding: 0.5rem; transition: opacity 0.2s; }
.cart-item-remove:hover { opacity: 0.7; }
.cart-total-row { display: flex; justify-content: space-between; font-size: 1.2rem; font-weight: 800; color: #133d4a; margin-top: 1rem; padding-top: 1rem; border-top: 2px solid #e1eced; }
/* Floating Cart Button */
.floating-cart {
position: fixed; bottom: 2rem; right: 2rem; background: #164b55; color: white;
width: 65px; height: 65px; border-radius: 50%; display: flex; align-items: center; justify-content: center;
box-shadow: 0 10px 25px rgba(22, 75, 85, 0.4); cursor: pointer; z-index: 900;
transition: transform 0.3s cubic-bezier(0.175, 0.885, 0.32, 1.275);
display: none; /* Hidden when empty */
}
.floating-cart.visible { display: flex; animation: popIn 0.4s; }
.floating-cart:hover { transform: scale(1.08); }
.cart-badge {
position: absolute; top: -5px; right: -5px; background: #c62828; color: white;
font-size: 0.8rem; font-weight: 700; width: 24px; height: 24px; border-radius: 50%;
display: flex; align-items: center; justify-content: center; border: 2px solid white;
}
.floating-cart svg { width: 28px; height: 28px; fill: currentColor; }
@keyframes popIn { from { transform: scale(0); } to { transform: scale(1); } }
/* Upsell Highlights */
.upsell-box { background: #e6f5f8; border: 1px solid #b2d4dc; border-radius: 12px; padding: 1.2rem; margin: 1rem 0; }
.upsell-box h4 { margin: 0 0 0.5rem 0; color: #106476; }
@media (max-width: 760px) {
.custom-modal-actions { flex-direction: column; }
.custom-modal-actions button { width: 100%; }
.floating-cart { bottom: 1.5rem; right: 1.5rem; width: 55px; height: 55px; }
}
</style>
{% endblock %}
{% block content %}
<section class="booking-hero">
<h1>Preise & Module</h1>
<p>Unsere Module und Pakete sind klar strukturiert und transparent. Stellen Sie sich Ihre Lösung flexibel zusammen.</p>
<p>Nach Ihrer Anfrage meldet sich unser Admin-Team, um die Bereitstellung oder einen Termin zur Abstimmung einzuplanen. Die Server stehen in einem deutschen Rechenzentrum (Strato) DSGVO-konform und hochverfügbar.</p>
</section>
<section class="packages-grid" aria-label="Buchungspakete">
<!-- TESTVERSION -->
<article class="package-card">
<div class="package-card__header">
<div>
<span class="package-card__tag" style="background: #e8f5e9; color: #2e7d32;">Kostenlos</span>
<h2 class="package-card__name">Testversion</h2>
</div>
<div class="package-card__price">
<span>0 €</span><small> -> 14 Tage</small>
</div>
</div>
<p class="package-card__description">Testen Sie alle Module (Inventar, Bibliothek & Terminplaner) 14 Tage lang unverbindlich in Ihrer Schule.</p>
<ul class="package-card__features">
<li>Voller Zugriff auf alle Basis-Module</li>
<li>Keine automatische Verlängerung</li>
<li>Vollständige Datenübernahme bei Kauf</li>
<li>Endet automatisch nach 14 Tagen</li>
</ul>
<div class="package-card__actions">
{% if 'username' in session %}
<button class="btn add-to-cart-btn" data-id="testversion" data-name="Testversion (14 Tage)" data-price="0" onclick="handleAddToCart(this)">
Jetzt kostenlos starten
</button>
{% else %}
<a class="btn secondary" href="{{ url_for('login') }}">Zum Testen einloggen</a>
{% endif %}
</div>
</article>
<!-- INVENTARSYSTEM -->
<article class="package-card">
<div class="package-card__header">
<div>
<span class="package-card__tag">Modul</span>
<h2 class="package-card__name">Inventarsystem</h2>
</div>
<div class="package-card__price">
<span>350 €</span><small>/ Jahr</small>
</div>
</div>
<p class="package-card__description">Der stabile Einstieg in die Schulverwaltung mit Inventarverwaltung, Benutzerrechten und Berichten.</p>
<ul class="package-card__features">
<li>Inventarverwaltung mit Rollenrechten</li>
<li>Basis-Support und Ticketing</li>
<li>Schulweite Übersichten und Berichte</li>
<li>Ihre Schullehrmittel auf einen Blick</li>
</ul>
<div class="package-card__actions">
{% if 'username' in session %}
<button class="btn add-to-cart-btn" data-id="inventarsystem" data-name="Inventarsystem" data-price="350" onclick="handleAddToCart(this)">
In den Warenkorb
</button>
{% else %}
<a class="btn secondary" href="{{ url_for('login') }}">Zum Buchen einloggen</a>
{% endif %}
</div>
</article>
<!-- BIBLIOTHEKSSYSTEM -->
<article class="package-card">
<div class="package-card__header">
<div>
<span class="package-card__tag">Modul</span>
<h2 class="package-card__name">Bibliothekssystem</h2>
</div>
<div class="package-card__price">
<span>100 €</span><small>/ Jahr</small>
</div>
</div>
<p class="package-card__description">Spezialisiertes Modul für Bibliotheken und Medienzentren inkl. Ausleihprozessen und Historie.</p>
<ul class="package-card__features">
<li>Ausgabe- und Rückgabeprozesse</li>
<li>Bestandsübersichten für Medien</li>
<li>Transparente Historie pro Medium</li>
</ul>
<div class="package-card__actions">
{% if 'username' in session %}
<button class="btn add-to-cart-btn" data-id="buecherei" data-name="Bibliothekssystem" data-price="100" onclick="handleAddToCart(this)">
In den Warenkorb
</button>
{% else %}
<a class="btn secondary" href="{{ url_for('login') }}">Zum Buchen einloggen</a>
{% endif %}
</div>
</article>
<!-- TERMINPLANER -->
<article class="package-card">
<div class="package-card__header">
<div>
<span class="package-card__tag">Modul</span>
<h2 class="package-card__name">Terminplaner</h2>
</div>
<div class="package-card__price">
<span>100 €</span><small>/ Jahr</small>
</div>
</div>
<p class="package-card__description">Für flexible Terminplanung entwickelt (z.B. Elternsprechstunden), um Termine hürdenlos online anzubieten.</p>
<ul class="package-card__features">
<li>Flexible Slot- und Zeitfenster-Erstellung</li>
<li>Hürdenlose Buchung ohne Registrierung</li>
<li>Echtzeit-Aktualisierung</li>
<li>Terminvergabe per Einladungslink</li>
</ul>
<div class="package-card__actions">
{% if 'username' in session %}
<button class="btn add-to-cart-btn" data-id="terminverwaltung" data-name="Terminplaner" data-price="100" onclick="handleAddToCart(this)">
In den Warenkorb
</button>
{% else %}
<a class="btn secondary" href="{{ url_for('login') }}">Zum Buchen einloggen</a>
{% endif %}
</div>
</article>
<!-- STARTPAKET (Kombi) -->
<!--<article class="package-card highlight">
<div class="package-card__header">
<div>
<span class="package-card__tag highlight-tag">Sparpaket</span>
<h2 class="package-card__name">Startpaket</h2>
</div>
<div class="package-card__price">
<span>420 €</span><small>/ Jahr</small>
</div>
</div>
<p class="package-card__description">Enthält <strong>Inventarverwaltung</strong> und <strong>Bibliothekssystem</strong> als ideale Komplettlösung zum Vorzugspreis.</p>
<ul class="package-card__features">
<li>Beinhaltet alle Features des Inventarsystems</li>
<li>Beinhaltet alle Features des Bibliothekssystems</li>
<li>Perfekter Start für Ihre Digitalisierung</li>
<li><strong>30 € Ersparnis</strong> gegenüber Einzelkauf</li>
</ul>
<div class="package-card__actions">
{% if 'username' in session %}
<button class="btn add-to-cart-btn" data-id="startpaket" data-name="Startpaket (Inventar + Bibliothek)" data-price="420" onclick="handleAddToCart(this)">
In den Warenkorb
</button>
{% else %}
<a class="btn secondary" href="{{ url_for('login') }}">Zum Buchen einloggen</a>
{% endif %}
</div>
</article>-->
<!-- SCHULTRÄGER -->
<article class="package-card">
<div class="package-card__header">
<div>
<span class="package-card__tag">Premium</span>
<h2 class="package-card__name">Schulträger</h2>
</div>
<div class="package-card__price">
<span>Individuell</span>
</div>
</div>
<p class="package-card__description">Individuelles Angebot für Schulträger mit mehreren Schulen und speziellen Anforderungen.</p>
<ul class="package-card__features">
<li>Mandantenfähige Verwaltung</li>
<li>Zentrale Übersicht aller Schulen</li>
<li>Individuelle Anpassungen & SSO</li>
<li>Persönlicher Ansprechpartner</li>
</ul>
<div class="package-card__actions">
{% if 'username' in session %}
<button class="btn add-to-cart-btn" data-id="schultraeger" data-name="Schulträger (Individuell)" data-price="0" onclick="handleAddToCart(this)">
Auf die Liste setzen
</button>
{% else %}
<a class="btn secondary" href="{{ url_for('login') }}">Zum Anfragen einloggen</a>
{% endif %}
</div>
</article>
</section>
<!-- Floating Cart Button -->
<div class="floating-cart" id="cartFab" onclick="openCartModal()">
<svg viewBox="0 0 24 24">
<path d="M7 18c-1.1 0-1.99.9-1.99 2S5.9 22 7 22s2-.9 2-2-.9-2-2-2zM1 2v2h2l3.6 7.59-1.35 2.45c-.16.28-.25.61-.25.96 0 1.1.9 2 2 2h12v-2H7.42c-.14 0-.25-.11-.25-.25l.03-.12.9-1.63h7.45c.75 0 1.41-.41 1.75-1.03l3.58-6.49c.08-.14.12-.31.12-.48 0-.55-.45-1-1-1H5.21l-.94-2H1zm16 16c-1.1 0-1.99.9-1.99 2s.89 2 1.99 2 2-.9 2-2-.9-2-2-2z"/>
</svg>
<div class="cart-badge" id="cartBadge">0</div>
</div>
<!-- Upsell Modal -->
<div class="custom-modal" id="upsellModal" aria-hidden="true" role="dialog">
<div class="custom-modal-backdrop" onclick="closeUpsellModal()"></div>
<div class="custom-modal-content">
<h3>Tipp: Sparen Sie mit dem Startpaket!</h3>
<p>Sie sind dabei, ein Einzelmodul in den Warenkorb zu legen. Wussten Sie, dass Inventar- und Bibliothekssystem perfekt zusammenarbeiten?</p>
<div class="upsell-box">
<h4>Das Startpaket (420 € / Jahr)</h4>
<p style="font-size: 0.9rem; margin-bottom: 0;">Beinhaltet das Inventarsystem (regulär 350 €) und das Bibliothekssystem (regulär 100 €). Sie sparen 30 € jährlich!</p>
</div>
<div class="custom-modal-actions">
<button class="btn outline" type="button" onclick="declineUpsell()">Nein, beim Einzelmodul bleiben</button>
<button class="btn" type="button" onclick="acceptUpsell()">Zum Startpaket upgraden</button>
</div>
</div>
</div>
<!-- Cart Modal -->
<div class="custom-modal" id="cartModal" aria-hidden="true" role="dialog">
<div class="custom-modal-backdrop" onclick="closeCartModal()"></div>
<div class="custom-modal-content">
<h3>Ihr Warenkorb</h3>
<div id="cartEmptyMessage" style="display:none; color: #4b6a72;">Ihr Warenkorb ist noch leer.</div>
<div class="cart-items-list" id="cartItemsContainer">
<!-- Items werden per JS hier eingefügt -->
</div>
<div class="cart-total-row" id="cartTotalRow">
<span>Gesamtsumme:</span>
<span id="cartTotalPrice">0 €</span>
</div>
<div class="custom-modal-actions" id="cartActions">
<button class="btn secondary" type="button" onclick="closeCartModal()">Weiter umsehen</button>
<button class="btn outline" type="button" onclick="goToCheckout('consultation')">Beratungstermin anfragen</button>
<button class="btn" type="button" onclick="goToCheckout('payment')">Jetzt Zahlungspflichtig buchen</button>
</div>
</div>
</div>
<script>
// System Config
const bookingReviewBaseUrl = "{{ url_for('booking_payment') }}";
// Cart State
let cart = []; // Speichert {id, name, price}
let pendingItemForUpsell = null;
// Hilfsfunktion: Warenkorb UI aktualisieren
function updateCartUI() {
const fab = document.getElementById('cartFab');
const badge = document.getElementById('cartBadge');
const container = document.getElementById('cartItemsContainer');
const emptyMsg = document.getElementById('cartEmptyMessage');
const totalRow = document.getElementById('cartTotalRow');
const actions = document.getElementById('cartActions');
const totalPriceEl = document.getElementById('cartTotalPrice');
// Badge & FAB Sichtbarkeit
if (cart.length > 0) {
fab.classList.add('visible');
badge.innerText = cart.length;
emptyMsg.style.display = 'none';
totalRow.style.display = 'flex';
actions.style.display = 'flex';
} else {
fab.classList.remove('visible');
emptyMsg.style.display = 'block';
totalRow.style.display = 'none';
actions.style.display = 'none';
}
// Artikel rendern
container.innerHTML = '';
let total = 0;
let hasIndividualPrice = false;
cart.forEach(item => {
if(item.price > 0) total += item.price;
if(item.price === 0) hasIndividualPrice = true;
let priceText = `${item.price} €`;
if (item.price === 0) {
priceText = item.id === 'testversion' ? 'Kostenlos' : 'Auf Anfrage';
}
container.innerHTML += `
<div class="cart-item">
<div class="cart-item-info">
<span class="cart-item-title">${item.name}</span>
<span class="cart-item-price">${priceText}</span>
</div>
<button class="cart-item-remove" onclick="removeFromCart('${item.id}')" aria-label="Entfernen">Entfernen</button>
</div>
`;
});
// Summe formatieren
if(hasIndividualPrice && total > 0) {
totalPriceEl.innerText = `${total} € + ind. Paket`;
} else if (hasIndividualPrice && total === 0) {
totalPriceEl.innerText = "Auf Anfrage";
} else {
totalPriceEl.innerText = `${total} € / Jahr`;
}
}
// Artikel zum Warenkorb hinzufügen
function addItem(id, name, price) {
// Prüfen, ob schon drin
if(cart.find(i => i.id === id)) {
alert(`${name} ist bereits im Warenkorb.`);
return;
}
const hasTestversion = cart.find(i => i.id === 'testversion');
if (hasTestversion || (id === 'testversion' && cart.length > 0)) {
alert('Die Testversion beinhaltet bereits alle Module und kann nicht mit anderen Paketen kombiniert werden. Bitte leeren Sie Ihren Warenkorb zuerst.');
return;
}
// Konflikte mit Startpaket abfangen
const hasStartpaket = cart.find(i => i.id === 'startpaket');
if (hasStartpaket && (id === 'inventarsystem' || id === 'buecherei')) {
alert(`Das Modul ist bereits in Ihrem gewählten Startpaket enthalten!`);
return;
}
if (id === 'startpaket') {
// Wenn Startpaket hinzugefügt wird, Einzelmodule (Inventar/Bib) entfernen, um doppelte Kosten zu vermeiden
cart = cart.filter(i => i.id !== 'inventarsystem' && i.id !== 'buecherei');
}
cart.push({id, name, price: parseInt(price, 10)});
updateCartUI();
// Modal öffnen zur Bestätigung
openCartModal();
}
// Logic Klick auf "In den Warenkorb"
function handleAddToCart(btn) {
const id = btn.dataset.id;
const name = btn.dataset.name;
const price = btn.dataset.price;
// Upsell Logik triggern, wenn Inventar oder Bib einzeln gewählt wird
if ((id === 'inventarsystem' || id === 'buecherei') && !cart.find(i => i.id === 'startpaket')) {
pendingItemForUpsell = { id, name, price };
openUpsellModal();
} else {
// Normal hinzufügen
addItem(id, name, price);
}
}
// Artikel aus Warenkorb entfernen
function removeFromCart(id) {
cart = cart.filter(i => i.id !== id);
updateCartUI();
if(cart.length === 0) {
setTimeout(closeCartModal, 1500); // Modal nach kurzer Zeit schließen wenn leer
}
}
// Upsell-Entscheidungen
function acceptUpsell() {
closeUpsellModal();
addItem('startpaket', 'Startpaket (Inventar + Bibliothek)', 420);
pendingItemForUpsell = null;
}
function declineUpsell() {
closeUpsellModal();
if(pendingItemForUpsell) {
addItem(pendingItemForUpsell.id, pendingItemForUpsell.name, pendingItemForUpsell.price);
}
pendingItemForUpsell = null;
}
// Checkout Routing
function goToCheckout(flow) {
if (cart.length === 0) return;
// Alle IDs der Cart zusammenführen (z.B. "startpaket,terminverwaltung")
const packageIds = cart.map(i => i.id).join(',');
const reviewUrl = new URL(bookingReviewBaseUrl, window.location.origin);
reviewUrl.searchParams.set('packages', packageIds);
reviewUrl.searchParams.set('flow', flow);
window.location.href = reviewUrl.toString();
}
// Modal Steuerungen
function openCartModal() {
updateCartUI();
document.getElementById('cartModal').classList.add('active');
}
function closeCartModal() { document.getElementById('cartModal').classList.remove('active'); }
function openUpsellModal() { document.getElementById('upsellModal').classList.add('active'); }
function closeUpsellModal() { document.getElementById('upsellModal').classList.remove('active'); }
// Escape Key für Modals
document.addEventListener('keydown', function(event) {
if (event.key === 'Escape') {
closeCartModal();
closeUpsellModal();
}
});
</script>
{% endblock %}