Files
Kino-Website/booking.js
Jannis Heydemann 9e599e496c Aarons Erster Commit
2026-04-29 09:35:10 +02:00

353 lines
11 KiB
JavaScript

let currentBookingContext = null;
let currentHallLayout = null;
function openBooking(movie, hall, time) {
const titleEl = document.getElementById("modal-movie-title");
const infoEl = document.getElementById("modal-info-text");
if (titleEl) {
titleEl.innerText = movie;
}
if (infoEl) {
infoEl.innerText = `${hall}${time} Uhr`;
}
currentBookingContext = { movie, hall, time };
createSeats(hall, time);
renderBookingLegend();
updateBookingSummary();
document.getElementById("booking-modal")?.classList.remove("hidden");
}
function getRowLabel(rowIndex) {
return String(rowIndex + 1);
}
function buildHallLayout(hallName, baseConfig) {
const rows = Number(baseConfig.rows || 0);
const totalCols = Number(baseConfig.left || 0) + Number(baseConfig.right || 0);
const isDeluxe = /deluxe/i.test(hallName);
const left = isDeluxe
? Math.max(3, Number(baseConfig.left || 0) - 1)
: Number(baseConfig.left || 0);
const right = Math.max(0, totalCols - left);
const vipRows = rows > 0 ? [rows] : [];
const dboxMap = new Set();
const markDboxRange = (rowNumber, startCol, width) => {
if (!rowNumber || width <= 0) {
return;
}
const maxCol = Math.min(totalCols, startCol + width - 1);
for (let col = startCol; col <= maxCol; col++) {
dboxMap.add(`${rowNumber}-${col}`);
}
};
if (isDeluxe) {
const configuredDboxSeats = Array.isArray(baseConfig.dbox)
? baseConfig.dbox.reduce((sum, section) => sum + Number(section.w || 0), 0)
: 0;
const totalDboxSeats = Math.max(4, configuredDboxSeats || 0);
const firstRow = Math.max(1, rows - 2);
const secondRow = Math.max(1, rows - 1);
const targetRows = [firstRow, secondRow]
.filter((rowNumber, index, arr) => arr.indexOf(rowNumber) === index)
.filter((rowNumber) => !vipRows.includes(rowNumber));
const rowCount = Math.max(1, targetRows.length);
const seatsPerFirstRows = Math.ceil(totalDboxSeats / rowCount);
let remaining = totalDboxSeats;
targetRows.forEach((rowNumber, index) => {
const seatsForRow = index === targetRows.length - 1
? remaining
: Math.min(seatsPerFirstRows, remaining);
remaining -= seatsForRow;
const startCol = left + Math.max(1, Math.floor((right - seatsForRow) / 2) + 1);
markDboxRange(rowNumber, startCol, seatsForRow);
});
} else if (Array.isArray(baseConfig.dbox)) {
baseConfig.dbox.forEach((section) => {
const rowNumber = Number(section.r || 0);
const width = Number(section.w || 0);
const startCol = Number(section.c || 0);
markDboxRange(rowNumber, startCol, width);
});
}
return {
rows,
left,
right,
totalCols,
vipRows,
dboxMap,
isImax: Boolean(baseConfig.isImax)
};
}
function getSeatType(layout, rowNumber, colNumber) {
if (layout.dboxMap.has(`${rowNumber}-${colNumber}`)) {
return "dbox";
}
if (layout.vipRows.includes(rowNumber)) {
return "vip";
}
if (layout.isImax) {
return "imax";
}
return "normal";
}
function createSeatElement({ seatId, seatType, occupiedSeats }) {
const seat = document.createElement("button");
seat.type = "button";
seat.classList.add("seat", seatType);
seat.dataset.seatId = seatId;
seat.dataset.type = seatType;
seat.title = `${seatId} (${seatType.toUpperCase()})`;
if (occupiedSeats.has(seatId)) {
seat.classList.add("occupied");
seat.disabled = true;
seat.setAttribute("aria-label", `${seatId} belegt`);
return seat;
}
seat.setAttribute("aria-label", `${seatId} frei`);
seat.addEventListener("click", () => {
seat.classList.toggle("selected");
updateBookingSummary();
});
return seat;
}
function createSeats(hallName, time) {
const seatGrid = document.getElementById("seat-grid");
if (!seatGrid) {
return;
}
seatGrid.innerHTML = "";
const baseConfig = seatLayouts[hallName];
if (!baseConfig) {
currentHallLayout = null;
return;
}
currentHallLayout = buildHallLayout(hallName, baseConfig);
const occupiedKey = `${hallName}-${time}`;
const occupiedSeats = new Set(Array.isArray(occupiedSeatsData?.[occupiedKey]) ? occupiedSeatsData[occupiedKey] : []);
for (let rowIndex = 0; rowIndex < currentHallLayout.rows; rowIndex++) {
const rowNumber = rowIndex + 1;
const rowLabel = getRowLabel(rowIndex);
const perspectiveFactor = (currentHallLayout.rows - rowNumber) / Math.max(currentHallLayout.rows - 1, 1);
const rowIndent = Math.round(18 * perspectiveFactor);
const row = document.createElement("div");
row.className = "seat-row cinema-row";
row.style.setProperty("--row-indent", `${rowIndent}px`);
const leftLabel = document.createElement("div");
leftLabel.className = "row-label";
leftLabel.textContent = rowLabel;
const rightLabel = document.createElement("div");
rightLabel.className = "row-label row-label-right";
rightLabel.textContent = rowLabel;
const leftBlock = document.createElement("div");
leftBlock.className = "row-seat-block left-block";
const rightBlock = document.createElement("div");
rightBlock.className = "row-seat-block right-block";
for (let col = 1; col <= currentHallLayout.totalCols; col++) {
const seatId = `R${rowNumber}-P${col}`;
const seatType = getSeatType(currentHallLayout, rowNumber, col);
const seat = createSeatElement({ seatId, seatType, occupiedSeats });
if (col <= currentHallLayout.left) {
leftBlock.appendChild(seat);
} else {
rightBlock.appendChild(seat);
}
}
const aisle = document.createElement("div");
aisle.className = "aisle-gap";
row.append(leftLabel, leftBlock, aisle, rightBlock, rightLabel);
seatGrid.appendChild(row);
}
}
function renderBookingLegend() {
const legend = document.getElementById("dynamic-legend");
if (!legend || !currentHallLayout) {
return;
}
const legendItems = [
{ type: "normal", label: "Standard" },
{ type: "selected", label: "Ausgewählt" },
{ type: "occupied", label: "Belegt" }
];
if (currentHallLayout.isImax) {
legendItems.unshift({ type: "imax", label: "IMAX" });
}
if (currentHallLayout.vipRows.length > 0) {
legendItems.unshift({ type: "vip", label: "VIP" });
}
if (currentHallLayout.dboxMap.size > 0) {
legendItems.unshift({ type: "dbox", label: "D-BOX" });
}
legend.innerHTML = legendItems
.map((item) => `
<div class="item">
<span class="seat ${item.type}"></span>
<span>${item.label}</span>
</div>
`)
.join("");
}
function updateBookingSummary() {
const selectedSeats = Array.from(document.querySelectorAll("#seat-grid .seat.selected"));
const summaryPanel = document.getElementById("booking-summary");
const summaryItems = document.getElementById("summary-items");
const totalEl = document.getElementById("total-price");
let total = 0;
if (summaryItems) {
summaryItems.innerHTML = selectedSeats
.map((seat) => {
const type = seat.dataset.type || "normal";
const seatPrice = Number(prices?.[type] ?? prices?.normal ?? 11);
total += seatPrice;
return `
<div class="summary-row">
<span>${seat.dataset.seatId}</span>
<span>${seatPrice.toFixed(2).replace(".", ",")} EUR</span>
</div>
`;
})
.join("");
} else {
selectedSeats.forEach((seat) => {
const type = seat.dataset.type || "normal";
const seatPrice = Number(prices?.[type] ?? prices?.normal ?? 11);
total += seatPrice;
});
}
if (totalEl) {
totalEl.innerText = `${total.toFixed(2).replace(".", ",")} EUR`;
}
summaryPanel?.classList.toggle("hidden", selectedSeats.length === 0);
}
function findMoviePoster(movieTitle) {
const cards = Array.from(document.querySelectorAll(".movie-card, .detailed-card"));
const normalizedTarget = String(movieTitle || "").trim().toLowerCase();
for (const card of cards) {
const title = card.querySelector("h2, h3")?.innerText?.trim().toLowerCase();
if (title === normalizedTarget) {
const imageSrc = card.querySelector("img")?.src;
if (imageSrc) {
return imageSrc;
}
}
}
return "";
}
function confirmSelectedSeats() {
const selectedSeats = Array.from(document.querySelectorAll("#seat-grid .seat.selected"));
if (!currentBookingContext || selectedSeats.length === 0) {
alert("Bitte waehle mindestens einen Platz aus.");
return;
}
const moviePoster = findMoviePoster(currentBookingContext.movie);
const addedSeats = [];
selectedSeats.forEach((seat) => {
const seatId = seat.dataset.seatId;
const seatType = seat.dataset.type || "normal";
const alreadyInCart = cart.some((item) =>
item.category === "movie" &&
item.title === currentBookingContext.movie &&
item.hall === currentBookingContext.hall &&
item.time === currentBookingContext.time &&
item.seatId === seatId
);
if (alreadyInCart) {
return;
}
cart.push({
id: Date.now() + Math.random(),
category: "movie",
title: currentBookingContext.movie,
hall: currentBookingContext.hall,
time: currentBookingContext.time,
seatId,
type: seatType.toUpperCase(),
price: Number(prices?.[seatType] ?? prices?.normal ?? 11),
img: moviePoster
});
addedSeats.push(seatId);
});
if (!addedSeats.length) {
alert("Diese Plaetze sind bereits im Warenkorb.");
return;
}
saveCart?.();
renderCart?.();
renderCheckout?.();
document.getElementById("booking-modal")?.classList.add("hidden");
const snackOverlay = document.getElementById("snack-prompt-overlay");
snackOverlay?.classList.remove("hidden");
document.body.style.overflow = "hidden";
}
document.addEventListener("DOMContentLoaded", () => {
document.getElementById("btn-confirm-seats")?.addEventListener("click", confirmSelectedSeats);
});