diff --git a/app/live/page.tsx b/app/live/page.tsx new file mode 100644 index 0000000..2bdf97a --- /dev/null +++ b/app/live/page.tsx @@ -0,0 +1,250 @@ +"use client"; + +import Image from "next/image"; +import { useState, useEffect } from "react"; +import FadeInView from "@/components/FadeInView"; + +interface EventData { + time: string; + endTime?: string; + title: string; + venue: string; + type: "Internal" | "Public" | "Everyone"; + dateObj: Date; +} + +// Fixed timeline data mapped to actual Date objects for accurate tracking +const flattenedEvents: EventData[] = [ + { time: "2:30 PM", endTime: "5:00 PM", title: "Entry Begins", venue: "Main Gate", type: "Public" as const, dateObj: new Date("2026-04-03T14:30:00") }, + { time: "2:30 PM", endTime: "5:30 PM", title: "Registration and Reporting", venue: "Front of LHTC", type: "Public" as const, dateObj: new Date("2026-04-03T14:30:00") }, + { time: "5:00 PM", endTime: "6:45 PM", title: "Inauguration Ceremony", venue: "Auditorium, LHTC", type: "Everyone" as const, dateObj: new Date("2026-04-03T17:00:00") }, + { time: "6:45 PM", endTime: "7:00 PM", title: "Participants Move to Venue", venue: "L104/L105", type: "Public" as const, dateObj: new Date("2026-04-03T18:45:00") }, + { time: "7:00 PM", title: "Hacking Begins", venue: "L104/L105", type: "Public" as const, dateObj: new Date("2026-04-03T19:00:00") }, + { time: "9:00 PM", endTime: "10:00 PM", title: "Dinner", venue: "Mess", type: "Everyone" as const, dateObj: new Date("2026-04-03T21:00:00") }, + + { time: "12:00 AM", endTime: "1:30 AM", title: "Mentorship Round 1", venue: "L104/L105", type: "Public" as const, dateObj: new Date("2026-04-04T00:00:00") }, + { time: "1:45 AM", endTime: "2:30 AM", title: "Fun Event with Prizes!", venue: "L104/L105", type: "Public" as const, dateObj: new Date("2026-04-04T01:45:00") }, + { time: "2:45 AM", title: "Midnight Snack", venue: "LHTC", type: "Public" as const, dateObj: new Date("2026-04-04T02:45:00") }, + { time: "4:30 AM", title: "Checkpoint 1 / 3", venue: "L104/L105", type: "Public" as const, dateObj: new Date("2026-04-04T04:30:00") }, + { time: "7:30 AM", endTime: "8:30 AM", title: "Breakfast Break", venue: "Mess", type: "Everyone" as const, dateObj: new Date("2026-04-04T07:30:00") }, + { time: "10:30 AM", endTime: "11:30 AM", title: "Fireside Chat", venue: "L104/L105", type: "Everyone" as const, dateObj: new Date("2026-04-04T10:30:00") }, + { time: "12:00 PM", endTime: "1:00 PM", title: "Lunch Break", venue: "Mess", type: "Everyone" as const, dateObj: new Date("2026-04-04T12:00:00") }, + { time: "2:00 PM", title: "Checkpoint 2 / 3", venue: "L104/L105", type: "Public" as const, dateObj: new Date("2026-04-04T14:00:00") }, + { time: "2:00 PM", endTime: "4:00 PM", title: "Judging Round 1", venue: "L104/L105", type: "Public" as const, dateObj: new Date("2026-04-04T14:00:00") }, + { time: "4:45 PM", title: "Evening Snacks", venue: "L104/L105", type: "Public" as const, dateObj: new Date("2026-04-04T16:45:00") }, + { time: "6:00 PM", endTime: "8:00 PM", title: "GitHub + MLH Workshop", venue: "L104/L105", type: "Public" as const, dateObj: new Date("2026-04-04T18:00:00") }, + { time: "9:00 PM", endTime: "10:00 PM", title: "Dinner Break", venue: "Mess", type: "Everyone" as const, dateObj: new Date("2026-04-04T21:00:00") }, + + { time: "12:00 AM", endTime: "1:30 AM", title: "Mentorship Round 2", venue: "L104/L105", type: "Public" as const, dateObj: new Date("2026-04-05T00:00:00") }, + { time: "1:45 AM", endTime: "2:30 AM", title: "Fun Event with Prizes!", venue: "L104/L105", type: "Public" as const, dateObj: new Date("2026-04-05T01:45:00") }, + { time: "2:45 AM", title: "Midnight Snack", venue: "L104/L105", type: "Public" as const, dateObj: new Date("2026-04-05T02:45:00") }, + { time: "4:00 AM", title: "Checkpoint 3 / 3", venue: "L104/L105", type: "Public" as const, dateObj: new Date("2026-04-05T04:00:00") }, + { time: "6:00 AM", title: "Soft Deadline", venue: "Online", type: "Public" as const, dateObj: new Date("2026-04-05T06:00:00") }, + { time: "7:00 AM", title: "Hard Deadline — Coding Ends", venue: "Online", type: "Public" as const, dateObj: new Date("2026-04-05T07:00:00") }, + { time: "7:30 AM", endTime: "8:30 AM", title: "Breakfast Break", venue: "Mess", type: "Everyone" as const, dateObj: new Date("2026-04-05T07:30:00") }, + { time: "9:30 AM", title: "Judging Round 2", venue: "L104/L105", type: "Public" as const, dateObj: new Date("2026-04-05T09:30:00") }, + { time: "12:00 PM", endTime: "1:00 PM", title: "Lunch Break", venue: "Mess", type: "Everyone" as const, dateObj: new Date("2026-04-05T12:00:00") }, + { time: "2:30 PM", endTime: "4:00 PM", title: "Closing Ceremony", venue: "Auditorium, LHTC", type: "Everyone" as const, dateObj: new Date("2026-04-05T14:30:00") }, +]; // sorted chronologically + +const HACKATHON_START = new Date("2026-04-03T19:00:00"); +const HACKATHON_END = new Date("2026-04-05T07:00:00"); + +// --- TIME MACHINE FOR TESTING --- +// Change this value to simulate jumping forward in time (in milliseconds) +// e.g., To jump ahead to April 3rd at 7:00 PM: new Date("2026-04-03T19:00:00").getTime() - Date.now() +const TEST_OFFSET_MS = 0; +// -------------------------------- + +function formatTimeLeft(ms: number) { + if (ms <= 0) return "00 : 00 : 00"; + const hours = Math.floor(ms / (1000 * 60 * 60)); + const mins = Math.floor((ms % (1000 * 60 * 60)) / (1000 * 60)); + const secs = Math.floor((ms % (1000 * 60)) / 1000); + return `${hours.toString().padStart(2, "0")} : ${mins.toString().padStart(2, "0")} : ${secs.toString().padStart(2, "0")}`; +} + +export default function LiveProjectorPage() { + const [now, setNow] = useState(new Date(Date.now() + TEST_OFFSET_MS)); + + useEffect(() => { + const interval = setInterval(() => setNow(new Date(Date.now() + TEST_OFFSET_MS)), 1000); + return () => clearInterval(interval); + }, []); + + const timeLeftToHack = HACKATHON_END.getTime() - now.getTime(); + const hackIsOver = timeLeftToHack <= 0; + + const timeElapsed = now.getTime() - HACKATHON_START.getTime(); + const hasHackingStarted = timeElapsed > 0; + + // Find next event + const nextEventIndex = flattenedEvents.findIndex(e => e.dateObj.getTime() > now.getTime()); + const nextEvent = nextEventIndex !== -1 ? flattenedEvents[nextEventIndex] : null; + const timeToNextEvent = nextEvent ? nextEvent.dateObj.getTime() - now.getTime() : 0; + + // Find current event + // Automatically gets the event right before the 'next' event, or the last event if all are passed + const currentEvent = nextEventIndex > 0 + ? flattenedEvents[nextEventIndex - 1] + : nextEventIndex === -1 + ? flattenedEvents[flattenedEvents.length - 1] + : null; + + return ( +