import { seatLayouts, occupiedSeatsData, prices, cart } from "./main" import { renderCart, saveCart } from "./cart"; import { renderCheckout } from "./checkout"; let currentBookingContext: any = null; let currentHallLayout: any = null; export function openBooking(movie: string, hall: string, time: any) { 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: number) { return String(rowIndex + 1); } function buildHallLayout(hallName: string, baseConfig:any) { 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: number, startCol: number, width: number) => { 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: number, section: any) => 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: any) => { 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: any, rowNumber: number, colNumber: number) { 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 }:any) { 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: string, time: any) { const seatGrid = document.getElementById("seat-grid"); if (!seatGrid) { return; } seatGrid.innerHTML = ""; const arrIndex = hallName as keyof typeof seatLayouts; const baseConfig: any = seatLayouts[arrIndex]; 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) => `