refactor: redistribute main.ts logic into Astro components

This commit is contained in:
2026-05-03 21:02:25 +02:00
parent ad2a07a88e
commit e588042876
27 changed files with 1175 additions and 69 deletions

View File

@@ -1,4 +1,4 @@
<section id="checkout-view" class="hidden" style="padding: 40px 20px;">
<section id="checkout-view" style="padding: 40px 20px;">
<div class="checkout-container">
<div class="progress-bar">
<div class="step active" id="step-1-indicator">1</div>
@@ -50,3 +50,189 @@
</div>
</div>
</section>
<script>
import { currentUser, users, cart, emptyCart, occupiedSeatsData, updateCart, updateOccupiedSeats } from "../scripts/bigConstants";
function formatCheckoutEuro(value: number) {
return `${Number(value || 0).toFixed(2).replace(".", ",")} EUR`;
}
let selectedPaymentMethod = "";
function setCheckoutStep(step: number) {
const step1 = document.getElementById("checkout-step-1");
const step2 = document.getElementById("checkout-step-2");
const step3 = document.getElementById("checkout-step-3");
step1?.classList.toggle("hidden", step !== 1);
step2?.classList.toggle("hidden", step !== 2);
step3?.classList.toggle("hidden", step !== 3);
const line1 = document.getElementById("line-1");
const line2 = document.getElementById("line-2");
const indicator1 = document.getElementById("step-1-indicator");
const indicator2 = document.getElementById("step-2-indicator");
const indicator3 = document.getElementById("step-3-indicator");
indicator1?.classList.add("active");
indicator2?.classList.toggle("active", step >= 2);
indicator3?.classList.toggle("active", step >= 3);
line1?.classList.toggle("active", step >= 2);
line2?.classList.toggle("active", step >= 3);
}
function renderCheckout() {
const summaryList = document.getElementById("checkout-summary-list");
const totalDisplay = document.getElementById("checkout-total-display");
const vatDisplay = document.getElementById("checkout-vat-display");
const nextButton = document.getElementById("btn-next-step-2");
if (!summaryList) return;
summaryList.innerHTML = "";
const total = cart.reduce((sum: number, item: any) => sum + Number(item.price || 0), 0);
const vat = total - total / 1.19;
cart.forEach((item: any) => {
const row = document.createElement("div");
row.style.cssText = "display:flex; justify-content:space-between; gap:12px; margin-bottom:10px; font-size:0.95rem;";
const infoText = item.category === "movie"
? `Sitz ${item.seatId || "-"} | ${item.hall || "-"} | ${item.time || "-"} Uhr`
: `${item.time || "Standard"} | ${item.hall || "-"}`;
row.innerHTML = `<span>${item.title} (${infoText})</span><span>${formatCheckoutEuro(item.price)}</span>`;
summaryList.appendChild(row);
});
if (totalDisplay) totalDisplay.innerText = `Gesamtbetrag: ${formatCheckoutEuro(total)}`;
if (vatDisplay) vatDisplay.innerText = `inkl. 19% MwSt: ${formatCheckoutEuro(vat)}`;
selectedPaymentMethod = "";
document.querySelectorAll(".payment-method").forEach((method) => method.classList.remove("selected"));
nextButton?.classList.add("hidden");
setCheckoutStep(1);
}
function generateTicket() {
const ticketContainer = document.getElementById("ticket-container");
if (!ticketContainer) return;
const moviesInCart = cart.filter((item: any) => item.category === "movie");
if (!moviesInCart.length) {
ticketContainer.innerHTML = "<p>Danke für deinen Einkauf!</p>";
return;
}
const mainMovie = moviesInCart[0];
const matchingMovieSeats = moviesInCart
.filter((item: any) => item.title === mainMovie.title && item.time === mainMovie.time)
.map((item: any) => item.seatId)
.join(", ");
const qrData = encodeURIComponent(`EAGLE-IMAX|${mainMovie.title}|${mainMovie.hall}|${matchingMovieSeats}`);
const qrUrl = `https://api.qrserver.com/v1/create-qr-code/?size=150x150&data=${qrData}&bgcolor=ffffff`;
ticketContainer.innerHTML = `
<div class="luxury-ticket">
<div class="ticket-left">
<img src="${mainMovie.img || mainMovie.poster}" class="ticket-poster" alt="${mainMovie.title}">
</div>
<div class="ticket-right">
<div class="ticket-brand">EAGLE'S IMAX PREMIUM</div>
<h2 class="ticket-title">${mainMovie.title}</h2>
<div class="ticket-details">
<p><span>SAAL</span> <strong>${mainMovie.hall}</strong></p>
<p><span>ZEIT</span> <strong>${mainMovie.time} Uhr</strong></p>
<p><span>SITZE</span> <strong>${matchingMovieSeats || "-"}</strong></p>
</div>
<div class="ticket-footer">
<img src="${qrUrl}" class="ticket-qr" alt="QR Code">
<div class="ticket-code">#${Math.floor(Math.random() * 90000) + 10000}</div>
</div>
</div>
</div>
`;
}
function completeCheckout() {
const orderItems = [...cart];
const orderTotal = orderItems.reduce((sum, item) => sum + Number(item.price || 0), 0);
// Save order for current user
if (currentUser && Array.isArray(users)) {
const userIndex = users.findIndex((entry: any) => entry.email === currentUser.email);
if (userIndex !== -1) {
if (!Array.isArray(users[userIndex].orders)) users[userIndex].orders = [];
users[userIndex].orders.push({
date: new Date().toLocaleString("de-DE"),
items: orderItems,
total: orderTotal,
paymentMethod: selectedPaymentMethod || "-"
});
localStorage.setItem("eagleUsers", JSON.stringify(users));
}
}
// Reserve seats
orderItems.filter(item => item.category === "movie").forEach(item => {
const key = `${item.hall}-${item.time}`;
if (!occupiedSeatsData[key]) occupiedSeatsData[key] = [];
occupiedSeatsData[key].push(item.seatId);
});
updateOccupiedSeats(occupiedSeatsData);
emptyCart();
window.dispatchEvent(new CustomEvent("cart-updated"));
}
function bindCheckoutEvents() {
const nextButton = document.getElementById("btn-next-step-2");
const backButton = document.getElementById("btn-back-to-step1");
const payNowButton = document.getElementById("btn-pay-now") as HTMLButtonElement;
document.querySelectorAll(".payment-method").forEach((method) => {
method.addEventListener("click", () => {
document.querySelectorAll(".payment-method").forEach((entry) => entry.classList.remove("selected"));
method.classList.add("selected");
selectedPaymentMethod = (method as HTMLElement).dataset.method || "";
nextButton?.classList.remove("hidden");
});
});
nextButton?.addEventListener("click", () => {
if (!selectedPaymentMethod) {
alert("Bitte wähle zuerst eine Zahlungsmethode aus.");
return;
}
setCheckoutStep(2);
});
backButton?.addEventListener("click", () => setCheckoutStep(1));
payNowButton?.addEventListener("click", () => {
if (!cart.length) {
alert("Dein Warenkorb ist leer.");
return;
}
payNowButton.disabled = true;
payNowButton.innerText = "Verarbeite...";
payNowButton.style.opacity = "0.7";
setTimeout(() => {
setCheckoutStep(3);
generateTicket();
completeCheckout();
payNowButton.disabled = false;
payNowButton.innerText = "Jetzt Bezahlen";
payNowButton.style.opacity = "1";
}, 1200);
});
document.getElementById("btn-back-home")?.addEventListener("click", () => {
window.location.href = "/";
});
}
if (document.getElementById("checkout-view")) {
renderCheckout();
bindCheckoutEvents();
}
</script>