diff --git a/app/now/now.tsx b/app/now/now.tsx index 673ec53..6151a7c 100644 --- a/app/now/now.tsx +++ b/app/now/now.tsx @@ -4,19 +4,33 @@ import { useVersionCheck } from "@/hooks/useVersion"; import React, { useEffect, useState } from "react"; import { Container } from "@/components/container"; import { Text } from "@/components/text"; -import Session, { Stages } from "@/model/session"; +import { + Session, + Stages, + Speaker, +} from "@/components/service/contentStrapi_static"; import Image from "next/image"; import { contentfulImageLoader } from "@/util/contentfulImageLoader"; import { Link } from "@/components/link"; -// New custom hook for simulated time +// Stage display names +const stageDisplayNames: Record = { + "Stage 1": "Turing Stage", + "Stage 2": "Hopper Stage", + "Stage 3": "Nakamoto Stage", + "Workshop Room": "Lovelace Room", + Gern: "Gern", + "Lab Lounge": "Lab Lounge", +}; + +// --- Custom Hook for simulated time --- const useSimulatedTime = (initialTime: Date) => { const [simulatedTime, setSimulatedTime] = useState(initialTime); useEffect(() => { const intervalId = setInterval(() => { - setSimulatedTime((prevTime) => new Date(prevTime.getTime() + 60000)); // Advance by 1 minute - }, 1000); // Update every second for smoother simulation + setSimulatedTime((prevTime) => new Date(prevTime.getTime() + 60000)); // advance 1 min + }, 1000); return () => clearInterval(intervalId); }, []); @@ -24,42 +38,72 @@ const useSimulatedTime = (initialTime: Date) => { return simulatedTime; }; +// --- Helper to always get NOW in Europe/Berlin --- +const getBerlinNow = (): Date => { + const formatter = new Intl.DateTimeFormat("en-CA", { + timeZone: "Europe/Berlin", + year: "numeric", + month: "2-digit", + day: "2-digit", + hour: "2-digit", + minute: "2-digit", + second: "2-digit", + }); + + const parts = formatter.formatToParts(new Date()); + const values: any = {}; + parts.forEach((p) => { + if (p.type !== "literal") values[p.type] = p.value; + }); + + // 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[]; - simulatedDate?: Date; // New prop for simulated date + speakers: Speaker[]; + simulatedDate?: Date; }; -const Now: React.FC = ({ sessions, simulatedDate }) => { +const Now: React.FC = ({ sessions, speakers, simulatedDate }) => { const initialTime = simulatedDate || new Date(); const currentTime = useSimulatedTime(initialTime); const newVersionAvailable = useVersionCheck(); + // Handle refresh on new version useEffect(() => { if (newVersionAvailable) { - handleRefresh(); + window.location.reload(); } }, [newVersionAvailable]); - const handleRefresh = () => { - window.location.reload(); + // Speaker lookup + const speakerMap = new Map( + speakers.map((sp) => [sp.name.toLowerCase().trim(), sp]), + ); + + const resolveSpeakers = (session: Session): Speaker[] => { + if (!session.speakers) return []; + return Object.values(session.speakers) + .map((name) => speakerMap.get(name.toLowerCase().trim())) + .filter((sp): sp is Speaker => !!sp); }; - // Re-render the page every minute - useEffect(() => { - const intervalId = setInterval(() => {}, 60000); + // --- Utility to compare days in Europe/Berlin --- + const toBerlinDateString = (d: Date) => + d.toLocaleDateString("en-CA", { timeZone: "Europe/Berlin" }); - return () => clearInterval(intervalId); - }, []); + const todayBerlin = toBerlinDateString(new Date()); const getCurrentAndNextSessions = ( sessionsInStage: Session[], ): { currentSession: Session | null; nextSession: Session | null } => { - const now = - simulatedDate && process.env.NEXT_PUBLIC_PRODUCTION !== "1" - ? currentTime - : new Date(); - let currentSession = null; - let nextSession = null; + const now = getBerlinNow(); + + let currentSession: Session | null = null; + let nextSession: Session | null = null; sessionsInStage.sort( (a, b) => @@ -70,11 +114,12 @@ const Now: React.FC = ({ sessions, simulatedDate }) => { const startTime = new Date(session.startTime); const endTime = new Date(session.endTime); + // console.log("NOW (Berlin)", now, "START", startTime, "END", endTime); + if (now >= startTime && now < endTime) { currentSession = session; - } else if (now < startTime) { + } else if (now < startTime && !nextSession) { nextSession = session; - break; } } @@ -82,42 +127,37 @@ const Now: React.FC = ({ sessions, simulatedDate }) => { }; return ( -
-
- -
+
+
+ + {/* Header */} +
- + Now - + Grab it on your phone:{" "} https://conference.tum-blockchain.com/now
-
-
+ + {/* Sessions Grid */} +
+
{Stages.map((stage, key) => { - const sessionsInThisStage = sessions.filter( - (session) => - session.room === stage && - new Date(session.startTime).getDate() === - new Date().getDate(), - ); + const sessionsInThisStage = sessions.filter((session) => { + const sessionDay = toBerlinDateString( + new Date(session.startTime), + ); + return session.room === stage && sessionDay === todayBerlin; + }); const { currentSession, nextSession } = getCurrentAndNextSessions(sessionsInThisStage); @@ -127,14 +167,15 @@ const Now: React.FC = ({ sessions, simulatedDate }) => { className="flex md:min-h-[500px] flex-1 border p-4 flex-col gap-16" key={key} > + {/* Current Session */}

- {stage} + {stageDisplayNames[stage] || stage}

- {currentSession !== null && ( + {currentSession ? (
- + {currentSession.title} @@ -157,50 +198,54 @@ const Now: React.FC = ({ sessions, simulatedDate }) => {
- {currentSession.speakers && - currentSession.speakers.map((speaker, index) => ( - <> -
- {speaker.profilePhoto && ( - {speaker.name} - )} -
- {speaker.name} - - {speaker.description} + {resolveSpeakers(currentSession).map( + (speaker, index) => ( +
+ {speaker.profile_photo?.url && ( + {speaker.name} + )} +
+ + {speaker.name} + + {speaker.position && ( + + {speaker.position} + {speaker.company_name + ? `, ${speaker.company_name}` + : ""} -
+ )}
- - ))} +
+ ), + )}
- )} - {currentSession === null && ( + ) : ( There is currently no active session. )}
+ + {/* Next Session */}

Up Next

- {nextSession !== null && ( + {nextSession ? (
{nextSession.title} @@ -224,38 +269,40 @@ const Now: React.FC = ({ sessions, simulatedDate }) => { )}
- {nextSession.speakers && - nextSession.speakers.map((speaker, index) => ( - <> -
- {speaker.profilePhoto && ( - {speaker.name} - )} -
- {speaker.name} - - {speaker.description} + {resolveSpeakers(nextSession).map( + (speaker, index) => ( +
+ {speaker.profile_photo?.url && ( + {speaker.name} + )} +
+ + {speaker.name} + + {speaker.position && ( + + {speaker.position} + {speaker.company_name + ? `, ${speaker.company_name}` + : ""} -
+ )}
- - ))} +
+ ), + )}
- )} - {nextSession === null && ( + ) : ( There is no next event in this room. )}
diff --git a/app/now/page.tsx b/app/now/page.tsx index f2803d6..d29e600 100644 --- a/app/now/page.tsx +++ b/app/now/page.tsx @@ -1,12 +1,16 @@ import { useSession } from "@/hooks/useSession"; import Now from "@/app/now/now"; +import { fetchSessions } from "@/components/service/contentStrapi_static"; +import { fetchSpeakers } from "@/components/service/contentStrapi"; export default async function NowPage() { - const sessions = await useSession(); + const sessions = await fetchSessions(); + const speakers = await fetchSpeakers(); return ( ); diff --git a/components/service/contentStrapi_static.ts b/components/service/contentStrapi_static.ts index 5c1f67d..1350301 100644 --- a/components/service/contentStrapi_static.ts +++ b/components/service/contentStrapi_static.ts @@ -64,8 +64,6 @@ export const Tracks = [ "Workshop", "TBC'25", "Academic Forum", - // "Sub Events", - // "TUM Blockchain Club", ] as const; export const Stages = [