diff --git a/app/agenda/agenda.tsx b/app/agenda/agenda.tsx index e7149d0..c257079 100644 --- a/app/agenda/agenda.tsx +++ b/app/agenda/agenda.tsx @@ -14,6 +14,8 @@ import { Tracks, Speaker, } from "@/components/service/contentStrapi_static"; +import Link from "next/link"; +import { DownloadIcon } from "lucide-react"; type AgendaProps = { sessions: Session[]; speakers: Speaker[] }; @@ -252,6 +254,19 @@ export const Agenda: React.FC = ({ sessions, speakers }) => { +
+ + Venue + + + + View Venue Map (PDF) + +
diff --git a/app/now/now.tsx b/app/now/now.tsx index 6151a7c..06d079a 100644 --- a/app/now/now.tsx +++ b/app/now/now.tsx @@ -23,24 +23,26 @@ const stageDisplayNames: Record = { "Lab Lounge": "Lab Lounge", }; -// --- Custom Hook for simulated time --- +// --- Custom Hook for simulated time (keeps the page updating) --- const useSimulatedTime = (initialTime: Date) => { const [simulatedTime, setSimulatedTime] = useState(initialTime); - useEffect(() => { const intervalId = setInterval(() => { - setSimulatedTime((prevTime) => new Date(prevTime.getTime() + 60000)); // advance 1 min + setSimulatedTime((prev) => new Date(prev.getTime() + 60000)); // +1 min per second }, 1000); - return () => clearInterval(intervalId); }, []); - return simulatedTime; }; -// --- Helper to always get NOW in Europe/Berlin --- -const getBerlinNow = (): Date => { - const formatter = new Intl.DateTimeFormat("en-CA", { +// ===== Time helpers (robust & simple) ===== + +// "Now" as an actual instant (UTC under the hood, as JS always does) +const getBerlinNow = (): Date => new Date(); + +// Format any Date as Munich/Berlin wall clock for DISPLAY/logging +const fmtBerlinDateTime = (d: Date) => + d.toLocaleString("de-DE", { timeZone: "Europe/Berlin", year: "numeric", month: "2-digit", @@ -50,17 +52,14 @@ const getBerlinNow = (): Date => { second: "2-digit", }); - const parts = formatter.formatToParts(new Date()); - const values: any = {}; - parts.forEach((p) => { - if (p.type !== "literal") values[p.type] = p.value; +const fmtBerlinTime = (d: Date, withTZ = false) => + d.toLocaleTimeString("de-DE", { + timeZone: "Europe/Berlin", + hour: "2-digit", + minute: "2-digit", + ...(withTZ ? { timeZoneName: "short" } : {}), }); - // Build an ISO string in Berlin local time (no timezone offset) - const iso = `${values.year}-${values.month}-${values.day}T${values.hour}:${values.minute}:${values.second}`; - return new Date(iso); -}; - export type NowProps = { sessions: Session[]; speakers: Speaker[]; @@ -69,15 +68,40 @@ export type NowProps = { const Now: React.FC = ({ sessions, speakers, simulatedDate }) => { const initialTime = simulatedDate || new Date(); - const currentTime = useSimulatedTime(initialTime); + // This state change forces re-renders so "now" updates on screen. + useSimulatedTime(initialTime); + const newVersionAvailable = useVersionCheck(); + useEffect(() => { + if (newVersionAvailable) window.location.reload(); + }, [newVersionAvailable]); - // Handle refresh on new version + // ⏱️ Auto-refresh exactly every new minute 60000 - (now.getSeconds() * 1000 + now.getMilliseconds()); useEffect(() => { - if (newVersionAvailable) { + const now = new Date(); + const msUntilNextMinute = + 300_000 - + ((now.getMinutes() * 60_000 + + now.getSeconds() * 1000 + + now.getMilliseconds()) % + 300_000); + + console.log( + "[AutoReload] scheduling reload in", + msUntilNextMinute, + "ms at", + new Date(Date.now() + msUntilNextMinute).toLocaleTimeString("de-DE", { + timeZone: "Europe/Berlin", + }), + ); + + const timeout = setTimeout(() => { + console.log("[AutoReload] Reloading now!"); window.location.reload(); - } - }, [newVersionAvailable]); + }, msUntilNextMinute); + + return () => clearTimeout(timeout); + }, []); // Speaker lookup const speakerMap = new Map( @@ -91,17 +115,15 @@ const Now: React.FC = ({ sessions, speakers, simulatedDate }) => { .filter((sp): sp is Speaker => !!sp); }; - // --- Utility to compare days in Europe/Berlin --- + // --- Utility to compare days in Europe/Berlin (for filtering "today") --- const toBerlinDateString = (d: Date) => d.toLocaleDateString("en-CA", { timeZone: "Europe/Berlin" }); - const todayBerlin = toBerlinDateString(new Date()); const getCurrentAndNextSessions = ( sessionsInStage: Session[], ): { currentSession: Session | null; nextSession: Session | null } => { - const now = getBerlinNow(); - + const now = getBerlinNow(); // real "now" let currentSession: Session | null = null; let nextSession: Session | null = null; @@ -114,7 +136,14 @@ const Now: React.FC = ({ sessions, speakers, simulatedDate }) => { const startTime = new Date(session.startTime); const endTime = new Date(session.endTime); - // console.log("NOW (Berlin)", now, "START", startTime, "END", endTime); + console.log( + "NOW (Munich)", + fmtBerlinDateTime(now), + "START", + fmtBerlinDateTime(startTime), + "END", + fmtBerlinDateTime(endTime), + ); if (now >= startTime && now < endTime) { currentSession = session; @@ -132,7 +161,7 @@ const Now: React.FC = ({ sessions, speakers, simulatedDate }) => { {/* Header */}
-
+
Now @@ -179,22 +208,14 @@ const Now: React.FC = ({ sessions, speakers, simulatedDate }) => { {currentSession.title} - {new Date( - currentSession.startTime, - ).toLocaleTimeString("en-DE", { - hour: "2-digit", - minute: "2-digit", - timeZone: "Europe/Berlin", - })}{" "} + {fmtBerlinTime( + new Date(currentSession.startTime), + )}{" "} -{" "} - {new Date( - currentSession.endTime, - ).toLocaleTimeString("en-DE", { - hour: "2-digit", - minute: "2-digit", - timeZone: "Europe/Berlin", - timeZoneName: "short", - })} + {fmtBerlinTime( + new Date(currentSession.endTime), + true, + )}
@@ -250,22 +271,10 @@ const Now: React.FC = ({ sessions, speakers, simulatedDate }) => { {nextSession.title} - {new Date( - nextSession.startTime, - ).toLocaleTimeString("en-DE", { - hour: "2-digit", - minute: "2-digit", - timeZone: "Europe/Berlin", - })}{" "} - -{" "} - {new Date(nextSession.endTime).toLocaleTimeString( - "en-DE", - { - hour: "2-digit", - minute: "2-digit", - timeZone: "Europe/Berlin", - timeZoneName: "short", - }, + {fmtBerlinTime(new Date(nextSession.startTime))} -{" "} + {fmtBerlinTime( + new Date(nextSession.endTime), + true, )}
diff --git a/public/map/TBC_25_venue_map.pdf b/public/map/TBC_25_venue_map.pdf new file mode 100644 index 0000000..3991bfe Binary files /dev/null and b/public/map/TBC_25_venue_map.pdf differ diff --git a/sections/Venue.tsx b/sections/Venue.tsx index 7bdabc7..f326c8c 100644 --- a/sections/Venue.tsx +++ b/sections/Venue.tsx @@ -3,6 +3,8 @@ import { Text } from "@/components/text"; import { VenueImage } from "@/components/venue/VenueImage"; import { useEffect, useRef, useState } from "react"; +import Link from "next/link"; +import { DownloadIcon } from "lucide-react"; const Venue = () => { const [slide, setSlide] = useState(1); @@ -33,7 +35,9 @@ const Venue = () => { Venue +
+ {/* Venue slideshow */}
{ ref={timerRef} >
+ {
+ + + Looking for the venue layout? + + + View Map (PDF) + +
);