master #9
@@ -1,5 +1,45 @@
|
|||||||
---
|
---
|
||||||
import { movieCatalog, timePatterns, hallRotation, weekdayShort } from "../scripts/bigConstants";
|
import {
|
||||||
|
timePatterns,
|
||||||
|
hallRotation,
|
||||||
|
weekdayShort,
|
||||||
|
type MovieInterface,
|
||||||
|
type ITMDBResponse,
|
||||||
|
} from "../scripts/bigConstants";
|
||||||
|
|
||||||
|
async function getTopMovies(): Promise<MovieInterface[]> {
|
||||||
|
const API_KEY = import.meta.env.TMDB_API_KEY;
|
||||||
|
console.log("Fetching with Key:", API_KEY ? "Key found" : "KEY MISSING!");
|
||||||
|
|
||||||
|
const IMAGE_BASE_URL = "https://image.tmdb.org/t/p/w500";
|
||||||
|
|
||||||
|
// 1. Corrected "discover" spelling
|
||||||
|
const response = await fetch(
|
||||||
|
`https://api.themoviedb.org/3/discover/movie?api_key=${API_KEY}&language=de-DE&sort_by=popularity.desc`,
|
||||||
|
);
|
||||||
|
console.log("Response Status:", response.status);
|
||||||
|
|
||||||
|
const data: ITMDBResponse = await response.json();
|
||||||
|
console.log("Results found:", data.results?.length);
|
||||||
|
|
||||||
|
if (!data.results) return [];
|
||||||
|
|
||||||
|
return data.results?.map((movie) => ({
|
||||||
|
id: movie.id,
|
||||||
|
title: movie.title || "Unknown Title",
|
||||||
|
poster: movie.poster_path
|
||||||
|
? `${IMAGE_BASE_URL}${movie.poster_path}`
|
||||||
|
: "/placeholder.jpg",
|
||||||
|
rating: movie.vote_average || 0,
|
||||||
|
// Add optional chaining (?.) and a fallback
|
||||||
|
year: movie.release_date?.split("-")[0] || "N/A",
|
||||||
|
genre: "Movie", // Discover doesn't provide the name, only an ID
|
||||||
|
duration: 120, // Discover doesn't provide duration
|
||||||
|
fsk: "12",
|
||||||
|
description: movie.overview || "No description available.",
|
||||||
|
backdrop: movie.backdrop_path,
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
const formatDateShort = (dateObj: Date) => {
|
const formatDateShort = (dateObj: Date) => {
|
||||||
const day = String(dateObj.getDate()).padStart(2, "0");
|
const day = String(dateObj.getDate()).padStart(2, "0");
|
||||||
@@ -15,78 +55,142 @@ const buildDayMeta = (offset: number) => {
|
|||||||
const weekday = weekdayShort[date.getDay()];
|
const weekday = weekdayShort[date.getDay()];
|
||||||
const formattedDate = formatDateShort(date);
|
const formattedDate = formatDateShort(date);
|
||||||
|
|
||||||
if (offset === 0) return { offset, date, short: "Heute", long: `Heute, ${formattedDate}` };
|
if (offset === 0)
|
||||||
if (offset === 1) return { offset, date, short: "Morgen", long: `Morgen, ${formattedDate}` };
|
return {
|
||||||
return { offset, date, short: weekday, long: `${weekday}, ${formattedDate}` };
|
offset,
|
||||||
|
date,
|
||||||
|
short: "Heute",
|
||||||
|
long: `Heute, ${formattedDate}`,
|
||||||
|
};
|
||||||
|
if (offset === 1)
|
||||||
|
return {
|
||||||
|
offset,
|
||||||
|
date,
|
||||||
|
short: "Morgen",
|
||||||
|
long: `Morgen, ${formattedDate}`,
|
||||||
|
};
|
||||||
|
return {
|
||||||
|
offset,
|
||||||
|
date,
|
||||||
|
short: weekday,
|
||||||
|
long: `${weekday}, ${formattedDate}`,
|
||||||
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
const buildScheduleForMovie = (movieIndex: number) => {
|
const buildScheduleForMovie = (movieIndex: number) => {
|
||||||
return Array.from({ length: 7 }, (_, dayOffset) => {
|
return Array.from({ length: 7 }, (_, dayOffset) => {
|
||||||
const dayMeta = buildDayMeta(dayOffset);
|
const dayMeta = buildDayMeta(dayOffset);
|
||||||
const pattern = timePatterns[(movieIndex + dayOffset) % timePatterns.length];
|
const pattern =
|
||||||
|
timePatterns[(movieIndex + dayOffset) % timePatterns.length];
|
||||||
const desiredCount = 4 + ((movieIndex + dayOffset) % 2);
|
const desiredCount = 4 + ((movieIndex + dayOffset) % 2);
|
||||||
const showCount = Math.min(pattern.length, desiredCount);
|
const showCount = Math.min(pattern.length, desiredCount);
|
||||||
|
|
||||||
const showings = pattern.slice(0, showCount).map((time: string, slotIndex: number) => {
|
const showings = pattern
|
||||||
const hall = hallRotation[(movieIndex + dayOffset + slotIndex) % hallRotation.length];
|
.slice(0, showCount)
|
||||||
return { time, hall };
|
.map((time: string, slotIndex: number) => {
|
||||||
});
|
const hall =
|
||||||
|
hallRotation[
|
||||||
|
(movieIndex + dayOffset + slotIndex) %
|
||||||
|
hallRotation.length
|
||||||
|
];
|
||||||
|
return { time, hall };
|
||||||
|
});
|
||||||
|
|
||||||
return { ...dayMeta, showings };
|
return { ...dayMeta, showings };
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
const movieProgram = movieCatalog.map((movie, movieIndex) => ({
|
let movieCatalog = await getTopMovies();
|
||||||
|
const movieProgram = movieCatalog?.map((movie, movieIndex) => ({
|
||||||
...movie,
|
...movie,
|
||||||
schedule: buildScheduleForMovie(movieIndex)
|
schedule: buildScheduleForMovie(movieIndex),
|
||||||
}));
|
}));
|
||||||
---
|
---
|
||||||
|
|
||||||
<section id="movie-list-view">
|
<section id="movie-list-view">
|
||||||
<div class="container movie-list-shell">
|
<div class="container movie-list-shell">
|
||||||
<h1 class="list-title">Aktuelle Filme & Spielzeiten</h1>
|
<h1 class="list-title">Aktuelle Filme & Spielzeiten</h1>
|
||||||
<p class="list-subtitle">Alle Filme mit 7 Tagen Spielplan. Erste Vorstellung täglich ab 13:00 Uhr.</p>
|
<p class="list-subtitle">
|
||||||
|
Alle Filme mit 7 Tagen Spielplan. Erste Vorstellung täglich ab 13:00
|
||||||
|
Uhr.
|
||||||
|
</p>
|
||||||
|
|
||||||
<div id="movie-program-list" class="movie-program-list">
|
<div id="movie-program-list" class="movie-program-list">
|
||||||
{movieProgram.map((movie, programIndex) => (
|
{
|
||||||
<article class="detailed-card program-card reveal-on-scroll" data-program-index={programIndex}>
|
movieProgram?.map((movie, programIndex) => (
|
||||||
<div class="card-left">
|
<article
|
||||||
<img src={movie.poster} alt={movie.title} />
|
class="detailed-card program-card"
|
||||||
<span class={`fsk fsk-${movie.fsk}`}>{movie.fsk}</span>
|
data-program-index={programIndex}
|
||||||
</div>
|
data-schedule={JSON.stringify(movie.schedule)}
|
||||||
<div class="card-right">
|
>
|
||||||
<div class="card-header">
|
<div class="card-left">
|
||||||
<h2>{movie.title}</h2>
|
<img src={movie.poster} alt={movie.title} />
|
||||||
<span class="duration">{movie.duration} Min. | {movie.genre} | FSK: {movie.fsk}</span>
|
<span class={`fsk fsk-${movie.fsk}`}>
|
||||||
|
{movie.fsk}
|
||||||
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<p class="description">{movie.description}</p>
|
<div class="card-right">
|
||||||
|
<div class="card-header">
|
||||||
<div class="program-day-tabs">
|
<h2>{movie.title}</h2>
|
||||||
{movie.schedule.map((day, dayIndex) => (
|
<span class="duration">
|
||||||
<button type="button" class={`program-day-tab ${dayIndex === 0 ? "active" : ""}`} data-program-index={programIndex} data-day-index={dayIndex}>
|
{movie.duration} Min. | {movie.genre} | FSK:{" "}
|
||||||
<span>{day.short}</span>
|
{movie.fsk}
|
||||||
<small>{formatDateShort(day.date)}</small>
|
</span>
|
||||||
</button>
|
|
||||||
))}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="schedule-container program-schedule-shell">
|
|
||||||
<div class="schedule-header">
|
|
||||||
<span>Tag</span><span>Kinosaal</span><span>Uhrzeit</span>
|
|
||||||
</div>
|
</div>
|
||||||
<div id={`schedule-body-${programIndex}`} class="program-schedule-body">
|
<p class="description">{movie.description}</p>
|
||||||
{movie.schedule[0].showings.map((showing) => (
|
|
||||||
<button class="schedule-row time-chip program-time-row" data-movie={movie.title} data-hall={showing.hall} data-time={showing.time}>
|
<div class="program-day-tabs">
|
||||||
<span>{movie.schedule[0].long}</span>
|
{movie.schedule.map((day, dayIndex) => (
|
||||||
<span class="hall-pill">{showing.hall}</span>
|
<button
|
||||||
<span class="time-btn">{showing.time}</span>
|
type="button"
|
||||||
|
class={`program-day-tab ${dayIndex === 0 ? "active" : ""}`}
|
||||||
|
data-program-index={programIndex}
|
||||||
|
data-day-index={dayIndex}
|
||||||
|
>
|
||||||
|
<span>{day.short}</span>
|
||||||
|
<small>
|
||||||
|
{formatDateShort(day.date)}
|
||||||
|
</small>
|
||||||
</button>
|
</button>
|
||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div class="schedule-container program-schedule-shell">
|
||||||
|
<div class="schedule-header">
|
||||||
|
<span>Tag</span>
|
||||||
|
<span>Kinosaal</span>
|
||||||
|
<span>Uhrzeit</span>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
id={`schedule-body-${programIndex}`}
|
||||||
|
class="program-schedule-body"
|
||||||
|
>
|
||||||
|
{movie.schedule[0].showings.map(
|
||||||
|
(showing) => (
|
||||||
|
<button
|
||||||
|
class="schedule-row time-chip program-time-row"
|
||||||
|
data-movie={movie.title}
|
||||||
|
data-hall={showing.hall}
|
||||||
|
data-time={showing.time}
|
||||||
|
>
|
||||||
|
<span>
|
||||||
|
{movie.schedule[0].long}
|
||||||
|
</span>
|
||||||
|
<span class="hall-pill">
|
||||||
|
{showing.hall}
|
||||||
|
</span>
|
||||||
|
<span class="time-btn">
|
||||||
|
{showing.time}
|
||||||
|
</span>
|
||||||
|
</button>
|
||||||
|
),
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</article>
|
||||||
</article>
|
))
|
||||||
))}
|
}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
@@ -97,19 +201,27 @@ const movieProgram = movieCatalog.map((movie, movieIndex) => ({
|
|||||||
movieProgramList?.addEventListener("click", (event: any) => {
|
movieProgramList?.addEventListener("click", (event: any) => {
|
||||||
const dayButton = event.target.closest(".program-day-tab");
|
const dayButton = event.target.closest(".program-day-tab");
|
||||||
if (dayButton) {
|
if (dayButton) {
|
||||||
const tabs = dayButton.closest(".program-day-tabs");
|
const programIndex = dayButton.getAttribute("data-program-index");
|
||||||
tabs?.querySelectorAll(".program-day-tab").forEach((t: any) => t.classList.remove("active"));
|
const dayIndex = parseInt(dayButton.getAttribute("data-day-index"));
|
||||||
dayButton.classList.add("active");
|
const card = dayButton.closest(".detailed-card");
|
||||||
}
|
const scheduleData = JSON.parse(card.getAttribute("data-schedule"));
|
||||||
|
const selectedDay = scheduleData[dayIndex];
|
||||||
|
|
||||||
const chip = event.target.closest(".time-chip");
|
// Update the schedule body HTML
|
||||||
if (chip) {
|
const body:any = document.getElementById(
|
||||||
const movie = chip.getAttribute("data-movie");
|
`schedule-body-${programIndex}`,
|
||||||
const hall = chip.getAttribute("data-hall");
|
);
|
||||||
const time = chip.getAttribute("data-time");
|
body.innerHTML = selectedDay.showings
|
||||||
if (movie && hall && time && (window as any).openBooking) {
|
.map(
|
||||||
(window as any).openBooking(movie, hall, time);
|
(showing:any) => `
|
||||||
}
|
<button class="schedule-row time-chip" data-movie="${card.querySelector("h2").innerText}" data-hall="${showing.hall}" data-time="${showing.time}">
|
||||||
|
<span>${selectedDay.long}</span>
|
||||||
|
<span class="hall-pill">${showing.hall}</span>
|
||||||
|
<span class="time-btn">${showing.time}</span>
|
||||||
|
</button>
|
||||||
|
`,
|
||||||
|
)
|
||||||
|
.join("");
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -117,7 +229,9 @@ const movieProgram = movieCatalog.map((movie, movieIndex) => ({
|
|||||||
const params = new URLSearchParams(window.location.search);
|
const params = new URLSearchParams(window.location.search);
|
||||||
const focusIndex = params.get("focus");
|
const focusIndex = params.get("focus");
|
||||||
if (focusIndex !== null) {
|
if (focusIndex !== null) {
|
||||||
const target = document.querySelector(`[data-program-index="${focusIndex}"]`);
|
const target = document.querySelector(
|
||||||
|
`[data-program-index="${focusIndex}"]`,
|
||||||
|
);
|
||||||
if (target) {
|
if (target) {
|
||||||
target.scrollIntoView({ behavior: "smooth", block: "start" });
|
target.scrollIntoView({ behavior: "smooth", block: "start" });
|
||||||
target.classList.add("flash-focus");
|
target.classList.add("flash-focus");
|
||||||
|
|||||||
@@ -1,8 +0,0 @@
|
|||||||
export default function topbar() {
|
|
||||||
return (
|
|
||||||
<div className="navbar bg-[rgba(29, 29, 31, 0.75)]">
|
|
||||||
<div className="leftButtonArray">Hallo</div>
|
|
||||||
<div className="rightButtonArray"></div>
|
|
||||||
</div>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
@@ -74,7 +74,7 @@ export interface User {
|
|||||||
paymentMethods: any[];
|
paymentMethods: any[];
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface MovieCatalog {
|
export interface MovieInterface {
|
||||||
id: number;
|
id: number;
|
||||||
title: string;
|
title: string;
|
||||||
genre: string;
|
genre: string;
|
||||||
|
|||||||
Reference in New Issue
Block a user