Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 15 additions & 0 deletions app/agenda/agenda.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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[] };

Expand Down Expand Up @@ -252,6 +254,19 @@ export const Agenda: React.FC<AgendaProps> = ({ sessions, speakers }) => {
</div>
</div>
</div>
<div className="mt-6 pt-4 border-t border-gray-700">
<Text textType={"paragraph"} className="font-bold text-left" as="p">
Venue
</Text>
<Link
href="/map/TBC_25_venue_map.pdf"
download
className="mt-2 inline-flex items-center gap-2 text-sm font-medium text-blue-400 hover:underline"
>
<DownloadIcon className="h-4 w-4" />
View Venue Map (PDF)
</Link>
</div>
</div>
<div id="sessions" className="flex w-full flex-col gap-y-4">
<div className="flex w-full flex-col items-center md:items-start">
Expand Down
127 changes: 68 additions & 59 deletions app/now/now.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -23,24 +23,26 @@ const stageDisplayNames: Record<string, string> = {
"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",
Expand All @@ -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[];
Expand All @@ -69,15 +68,40 @@ export type NowProps = {

const Now: React.FC<NowProps> = ({ 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(
Expand All @@ -91,17 +115,15 @@ const Now: React.FC<NowProps> = ({ 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;

Expand All @@ -114,7 +136,14 @@ const Now: React.FC<NowProps> = ({ 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;
Expand All @@ -132,7 +161,7 @@ const Now: React.FC<NowProps> = ({ sessions, speakers, simulatedDate }) => {
<Container className="flex flex-col min-h-full">
{/* Header */}
<div className="mt-[100px] md:mt-[20vh] z-10 max-w-3xl">
<div className="flex flex-col items-start">
<div className="flex flex-col items-start gap-8">
<Text textType="sub_hero" className="text-gradient text-left">
Now
</Text>
Expand Down Expand Up @@ -179,22 +208,14 @@ const Now: React.FC<NowProps> = ({ sessions, speakers, simulatedDate }) => {
{currentSession.title}
</Text>
<Text>
{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,
)}
</Text>
</div>
<div className="flex flex-col gap-4">
Expand Down Expand Up @@ -250,22 +271,10 @@ const Now: React.FC<NowProps> = ({ sessions, speakers, simulatedDate }) => {
{nextSession.title}
</Text>
<Text>
{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,
)}
</Text>
</div>
Expand Down
Binary file added public/map/TBC_25_venue_map.pdf
Binary file not shown.
21 changes: 21 additions & 0 deletions sections/Venue.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down Expand Up @@ -33,7 +35,9 @@ const Venue = () => {
<Text textType={"sub_hero"} className="text-gradient text-center">
Venue
</Text>

<div className="mt-20">
{/* Venue slideshow */}
<div className="overflow-x-hidden w-[280px] sm:w-[600px] xl:w-[800px]">
<div
className="flex relative duration-500 ease-in-out"
Expand Down Expand Up @@ -66,6 +70,7 @@ const Venue = () => {
ref={timerRef}
></div>
</div>

<a
href="https://maps.app.goo.gl/rLirPeQoSCjxYL1u5"
target="_blank"
Expand All @@ -81,6 +86,22 @@ const Venue = () => {
</Text>
</div>
</a>

<Text
as="p"
textType={"paragraph"}
className="flex justify-center items-center gap-2 text-gray-300"
>
Looking for the venue layout?
<Link
href="/map/TBC_25_venue_map.pdf"
download
className="inline-flex items-center gap-2 px-3 py-1.5 rounded-md border border-gray-600 bg-black/40 text-sm font-medium text-gray-100 hover:bg-gray-800 hover:text-white transition-colors"
>
<DownloadIcon className="h-4 w-4" />
View Map (PDF)
</Link>
</Text>
</div>
</section>
);
Expand Down