From 0082df91403dff02cd743e07ab9aed6f3e5e1ca9 Mon Sep 17 00:00:00 2001 From: Afifah Hadi Date: Tue, 7 Apr 2026 12:01:26 -0700 Subject: [PATCH 1/8] copied over and refactored schedule sneak peak from hub. now works from hardcoded json instead of mongodb --- .../ScheduleSneakPeak/CalendarItem.tsx | 126 ++++++ .../ScheduleSneakPeak/ScheduleSneakPeek.tsx | 236 ++++++++++ .../ScheduleSneakPeak/scheduleEventStyles.ts | 40 ++ .../ScheduleSneakPeak/scheduleTime.ts | 52 +++ app/(pages)/(index-page)/page.tsx | 2 + app/(pages)/_data/event.ts | 21 + .../_data/hub-2026-staging.events.json | 404 ++++++++++++++++++ public/schedule/arrow-right.svg | 3 + public/schedule/attendee.svg | 17 + public/schedule/check.svg | 3 + public/schedule/cucumber_cow.svg | 80 ++++ public/schedule/duck+bunny.svg | 44 ++ public/schedule/duck+frog.svg | 34 ++ public/schedule/header_grass.svg | 15 + public/schedule/location.svg | 3 + public/schedule/plus.svg | 3 + public/schedule/sleeping_cow.svg | 37 ++ public/schedule/vocal_angel_cow.svg | 99 +++++ 18 files changed, 1219 insertions(+) create mode 100644 app/(pages)/(index-page)/_components/ScheduleSneakPeak/CalendarItem.tsx create mode 100644 app/(pages)/(index-page)/_components/ScheduleSneakPeak/ScheduleSneakPeek.tsx create mode 100644 app/(pages)/(index-page)/_components/ScheduleSneakPeak/scheduleEventStyles.ts create mode 100644 app/(pages)/(index-page)/_components/ScheduleSneakPeak/scheduleTime.ts create mode 100644 app/(pages)/_data/event.ts create mode 100644 app/(pages)/_data/hub-2026-staging.events.json create mode 100644 public/schedule/arrow-right.svg create mode 100644 public/schedule/attendee.svg create mode 100644 public/schedule/check.svg create mode 100644 public/schedule/cucumber_cow.svg create mode 100644 public/schedule/duck+bunny.svg create mode 100644 public/schedule/duck+frog.svg create mode 100644 public/schedule/header_grass.svg create mode 100644 public/schedule/location.svg create mode 100644 public/schedule/plus.svg create mode 100644 public/schedule/sleeping_cow.svg create mode 100644 public/schedule/vocal_angel_cow.svg diff --git a/app/(pages)/(index-page)/_components/ScheduleSneakPeak/CalendarItem.tsx b/app/(pages)/(index-page)/_components/ScheduleSneakPeak/CalendarItem.tsx new file mode 100644 index 0000000..9e196c0 --- /dev/null +++ b/app/(pages)/(index-page)/_components/ScheduleSneakPeak/CalendarItem.tsx @@ -0,0 +1,126 @@ +import Image from 'next/image'; +import Event, { EventTag, EventType } from '@data/event'; +import { SCHEDULE_EVENT_STYLES } from './scheduleEventStyles'; +import { formatScheduleTimeRange } from './scheduleTime'; + +import locationIcon from '@public/schedule/location.svg'; +import attendeeIcon from '@public/schedule/attendee.svg'; + +interface CalendarItemProps { + event: Event; + attendeeCount?: number; +} + +const isEventType = (value: string): value is EventType => { + return value in SCHEDULE_EVENT_STYLES; +}; + +const normalizeTag = (tag: EventTag) => tag.toUpperCase().replace('_', ' '); + +const toHostLines = (host?: string) => + host + ? host + .split(/,|\n/) + .map((line) => line.trim()) + .filter(Boolean) + .slice(0, 3) + : []; + +export function CalendarItem({ event, attendeeCount }: CalendarItemProps) { + const { name, type, location, start_time, end_time, tags, host } = event; + const rawType = type ?? ''; + const normalizedType = rawType.toUpperCase(); + const displayType: EventType = isEventType(normalizedType) + ? normalizedType + : 'GENERAL'; + const eventStyle = SCHEDULE_EVENT_STYLES[displayType]; + const hostLines = toHostLines(host); + const showAttendees = displayType === 'WORKSHOPS' && (attendeeCount ?? 0) > 0; + const hasMeta = + hostLines.length > 0 || (tags?.length ?? 0) > 0 || showAttendees; + + const timeDisplay = formatScheduleTimeRange( + new Date(start_time), + end_time ? new Date(end_time) : undefined + ); + + return ( +
+
+
+
+

+ {name} +

+
+ {timeDisplay} + {location && ( + + + {location} + + )} +
+
+ {hostLines.length > 0 && ( +
+ {hostLines.map((line) => ( +

{line}

+ ))} +
+ )} +
+ + {hasMeta && ( +
+ {(tags?.length ?? 0) > 0 && ( +
+ {tags?.map((tag) => ( + + {normalizeTag(tag)} + + ))} +
+ )} + + {showAttendees && ( +
+ + + {attendeeCount} Hacker{attendeeCount === 1 ? ' is' : 's are'}{' '} + attending this event + +
+ )} +
+ )} +
+
+ ); +} + +export default CalendarItem; diff --git a/app/(pages)/(index-page)/_components/ScheduleSneakPeak/ScheduleSneakPeek.tsx b/app/(pages)/(index-page)/_components/ScheduleSneakPeak/ScheduleSneakPeek.tsx new file mode 100644 index 0000000..4e9c6d4 --- /dev/null +++ b/app/(pages)/(index-page)/_components/ScheduleSneakPeak/ScheduleSneakPeek.tsx @@ -0,0 +1,236 @@ +'use client'; + +import { useEffect, useMemo, useState } from 'react'; +import Image from 'next/image'; +import rawScheduleEvents from '@data/hub-2026-staging.events.json'; +import Event, { EventTag, EventType } from '@data/event'; +import CalendarItem from './CalendarItem'; +import { + formatCountdown, + getScheduleEventEndTime, + isScheduleEventLive, +} from './scheduleTime'; + +import duckBunny from '@public/schedule/duck+bunny.svg'; +import duckFrog from '@public/schedule/duck+frog.svg'; + +interface ScheduleSneakPeekProps { + className?: string; +} + +interface RawScheduleEvent { + name: string; + host?: string; + type: string; + location?: string; + start_time: { $date: string }; + end_time?: { $date: string }; + tags?: string[]; +} + +const VALID_EVENT_TYPES: EventType[] = [ + 'GENERAL', + 'ACTIVITIES', + 'WORKSHOPS', + 'MEALS', + 'RECOMMENDED', +]; +const DISPLAY_TYPES = new Set(['ACTIVITIES', 'WORKSHOPS', 'MEALS']); +const VALID_TAGS: EventTag[] = [ + 'developer', + 'designer', + 'pm', + 'other', + 'beginner', +]; + +const isEventType = (value: string): value is EventType => + VALID_EVENT_TYPES.includes(value as EventType); + +const isEventTag = (value: string): value is EventTag => + VALID_TAGS.includes(value as EventTag); + +const normalizeScheduleEvent = ( + event: RawScheduleEvent, + index: number +): Event => { + const start = new Date(event.start_time.$date); + const end = event.end_time ? new Date(event.end_time.$date) : undefined; + const normalizedType = (event.type || 'GENERAL').toUpperCase(); + const type = isEventType(normalizedType) ? normalizedType : 'GENERAL'; + const tags = event.tags?.filter(isEventTag); + const eventId = `${index}-${event.name}-${start.getTime()}`; + + return { + _id: eventId, + name: event.name, + host: event.host, + type, + location: event.location, + start_time: start, + end_time: end, + tags, + }; +}; + +const normalizedEvents = (rawScheduleEvents as RawScheduleEvent[]) + .map((event, index) => normalizeScheduleEvent(event, index)) + .sort( + (a, b) => + new Date(a.start_time).getTime() - new Date(b.start_time).getTime() + ); + +const displayableEvents = normalizedEvents.filter((event) => + DISPLAY_TYPES.has(event.type) +); + +const estimateAttendeeCount = (event: Event): number | undefined => { + if (event.type !== 'WORKSHOPS') return undefined; + const seedSource = event._id ?? event.name; + const hash = Array.from(seedSource).reduce( + (total, character) => total + character.charCodeAt(0), + 0 + ); + return 8 + (hash % 19); +}; + +function EmptyState({ + title, + description, + imageSrc, + imageAlt, +}: { + title: string; + description: string; + imageSrc: React.ComponentProps['src']; + imageAlt: string; +}) { + return ( +
+ {imageAlt} +

+ {title} +

+

+ {description} +

+
+ ); +} + +export default function ScheduleSneakPeek({ + className, +}: ScheduleSneakPeekProps) { + const [nowMs, setNowMs] = useState(() => Date.now()); + + useEffect(() => { + const interval = window.setInterval(() => { + setNowMs(Date.now()); + }, 1000); + return () => window.clearInterval(interval); + }, []); + + const displayNowMs = nowMs; + const displayNow = useMemo(() => new Date(displayNowMs), [displayNowMs]); + + const liveEvents = useMemo( + () => + displayableEvents + .filter((event) => isScheduleEventLive(event, displayNow)) + .sort( + (a, b) => + getScheduleEventEndTime(a).getTime() - + getScheduleEventEndTime(b).getTime() + ) + .slice(0, 3), + [displayNow] + ); + + const upcomingEvents = useMemo( + () => + displayableEvents + .filter((event) => new Date(event.start_time).getTime() > displayNowMs) + .slice(0, 3), + [displayNowMs] + ); + + const liveLabel = + liveEvents.length > 0 + ? `UNTIL ${formatCountdown( + Math.min( + ...liveEvents.map((event) => + getScheduleEventEndTime(event).getTime() + ) + ) - displayNowMs + )}` + : 'NO LIVE EVENTS'; + const upcomingLabel = + upcomingEvents.length > 0 + ? `IN ${formatCountdown( + new Date(upcomingEvents[0].start_time).getTime() - displayNowMs + )}` + : 'NO UPCOMING EVENTS'; + + return ( +
+
+
+
+

+ {liveLabel} +

+

+ Happening now +

+
+
+ {liveEvents.length > 0 ? ( + liveEvents.map((event) => ( + + )) + ) : ( + + )} +
+
+ +
+

+ {upcomingLabel} +

+

+ Upcoming Events +

+
+
+ {upcomingEvents.length > 0 ? ( + upcomingEvents.map((event) => ( + + )) + ) : ( + + )} +
+
+
+
+
+ ); +} diff --git a/app/(pages)/(index-page)/_components/ScheduleSneakPeak/scheduleEventStyles.ts b/app/(pages)/(index-page)/_components/ScheduleSneakPeak/scheduleEventStyles.ts new file mode 100644 index 0000000..66042fb --- /dev/null +++ b/app/(pages)/(index-page)/_components/ScheduleSneakPeak/scheduleEventStyles.ts @@ -0,0 +1,40 @@ +import { EventType } from '@data/event'; + +export interface ScheduleEventStyle { + bgColor: string; + textColor: string; + mutedTextColor: string; + chipBorderColor?: string; +} + +export const SCHEDULE_EVENT_STYLES: Record = { + GENERAL: { + bgColor: '#D9F2F4', + textColor: '#2B3A3B', + mutedTextColor: '#5F686A', + }, + ACTIVITIES: { + bgColor: '#FFE2D5', + textColor: '#3F3F46', + mutedTextColor: '#65656E', + chipBorderColor: 'rgba(63, 63, 70, 0.35)', + }, + WORKSHOPS: { + bgColor: '#D7E8AB', + textColor: '#202020', + mutedTextColor: '#606060', + chipBorderColor: 'rgba(32, 32, 32, 0.35)', + }, + MEALS: { + bgColor: '#CFF3F2', + textColor: '#2E3D3F', + mutedTextColor: '#5F6C6E', + chipBorderColor: 'rgba(46, 61, 63, 0.35)', + }, + RECOMMENDED: { + bgColor: '#D6C8E8', + textColor: '#2B3A3B', + mutedTextColor: '#596A6C', + chipBorderColor: 'rgba(43, 58, 59, 0.35)', + }, +}; diff --git a/app/(pages)/(index-page)/_components/ScheduleSneakPeak/scheduleTime.ts b/app/(pages)/(index-page)/_components/ScheduleSneakPeak/scheduleTime.ts new file mode 100644 index 0000000..3fe35fb --- /dev/null +++ b/app/(pages)/(index-page)/_components/ScheduleSneakPeak/scheduleTime.ts @@ -0,0 +1,52 @@ +import Event from '@data/event'; + +export const formatScheduleTime = (date: Date): string => + date.toLocaleString('en-US', { + hour: 'numeric', + minute: '2-digit', + hour12: true, + }); + +export const formatScheduleTimeRange = (start: Date, end?: Date): string => { + if (!end || start.getTime() === end.getTime()) { + return formatScheduleTime(start); + } + + const startTimeStr = formatScheduleTime(start); + const endTimeStr = formatScheduleTime(end); + + const startAMPM = startTimeStr.slice(-2); + const endAMPM = endTimeStr.slice(-2); + + if (startAMPM === endAMPM) { + return `${startTimeStr.slice(0, -2)} - ${endTimeStr}`; + } + + return `${startTimeStr} - ${endTimeStr}`; +}; + +export const getScheduleEventEndTime = (event: Event): Date => { + if (event.end_time) return new Date(event.end_time); + const fallback = new Date(event.start_time); + fallback.setMinutes(fallback.getMinutes() + 60); + return fallback; +}; + +export const isScheduleEventLive = ( + event: Event, + now: Date = new Date() +): boolean => { + const start = new Date(event.start_time); + const end = getScheduleEventEndTime(event); + return start <= now && now < end; +}; + +export const formatCountdown = (milliseconds: number): string => { + const clamped = Math.max(0, milliseconds); + const hours = Math.floor(clamped / 3600000); + const minutes = Math.floor((clamped % 3600000) / 60000); + const seconds = Math.floor((clamped % 60000) / 1000); + return `${hours.toString().padStart(2, '0')}:${minutes + .toString() + .padStart(2, '0')}:${seconds.toString().padStart(2, '0')}`; +}; diff --git a/app/(pages)/(index-page)/page.tsx b/app/(pages)/(index-page)/page.tsx index 73a3142..75eb9ef 100644 --- a/app/(pages)/(index-page)/page.tsx +++ b/app/(pages)/(index-page)/page.tsx @@ -5,11 +5,13 @@ import AccordionFAQ from './_components/FAQ/faq'; import Create from './_components/Create/create'; import DonorScroll from './_components/DonorScroll/DonorScroll'; import Sponsers from './_components/Sponsers/Sponsers'; +import ScheduleSneakPeek from './_components/ScheduleSneakPeak/ScheduleSneakPeek'; export default function Home() { return (
+ diff --git a/app/(pages)/_data/event.ts b/app/(pages)/_data/event.ts new file mode 100644 index 0000000..27b32f5 --- /dev/null +++ b/app/(pages)/_data/event.ts @@ -0,0 +1,21 @@ +type EventType = + | 'GENERAL' + | 'ACTIVITIES' + | 'WORKSHOPS' + | 'MEALS' + | 'RECOMMENDED'; +type EventTag = 'developer' | 'designer' | 'pm' | 'other' | 'beginner'; + +interface Event { + _id?: string; + name: string; + host?: string; + type: EventType; + location?: string; + start_time: Date; + end_time?: Date; + tags?: EventTag[]; +} + +export default Event; +export type { EventType, EventTag }; diff --git a/app/(pages)/_data/hub-2026-staging.events.json b/app/(pages)/_data/hub-2026-staging.events.json new file mode 100644 index 0000000..f86694e --- /dev/null +++ b/app/(pages)/_data/hub-2026-staging.events.json @@ -0,0 +1,404 @@ +[{ + "_id": { + "$oid": "67f7a4153eaf1040a69ac6a7" + }, + "name": "Lunch Starts", + "type": "MEALS", + "start_time": { + "$date": "2026-05-09T20:00:00.000Z" + } +}, +{ + "_id": { + "$oid": "67f7a60f3eaf1040a69ac6ae" + }, + "name": "Therapy Dogs", + "type": "ACTIVITIES", + "start_time": { + "$date": "2026-05-09T22:30:00.000Z" + }, + "end_time": { + "$date": "2026-05-10T00:00:00.000Z" + }, + "location": "South Wing" +}, +{ + "_id": { + "$oid": "680027589d521a51759d7e86" + }, + "name": "Tech Together Meetup", + "type": "WORKSHOPS", + "start_time": { + "$date": "2026-05-09T23:00:00.000Z" + }, + "end_time": { + "$date": "2026-05-10T00:00:00.000Z" + }, + "host": "Major League Hacking", + "tags": [ + "beginner", + "developer", + "pm", + "designer", + "other" + ], + "location": "ARC Ballroom A" +}, +{ + "_id": { + "$oid": "680076779d521a51759d7e8c" + }, + "name": "Break", + "type": "GENERAL", + "start_time": { + "$date": "2026-05-10T18:00:00.000Z" + }, + "end_time": { + "$date": "2026-05-10T19:00:00.000Z" + } +}, +{ + "_id": { + "$oid": "680026b09d521a51759d7e83" + }, + "name": "GitHub Copilot Workshop", + "type": "WORKSHOPS", + "start_time": { + "$date": "2026-05-09T22:00:00.000Z" + }, + "end_time": { + "$date": "2026-05-09T23:00:00.000Z" + }, + "host": "Major League Hacking", + "tags": [ + "beginner", + "developer", + "pm" + ], + "location": "ARC Ballroom A" +}, +{ + "_id": { + "$oid": "67e62cf95f285b9f3db580f1" + }, + "name": "Check-in Starts", + "type": "GENERAL", + "start_time": { + "$date": "2026-05-09T14:30:00.000Z" + } +}, +{ + "_id": { + "$oid": "67f7a5de3eaf1040a69ac6ad" + }, + "name": "Bracelet Making", + "type": "ACTIVITIES", + "start_time": { + "$date": "2026-05-09T22:30:00.000Z" + }, + "end_time": { + "$date": "2026-05-10T00:30:00.000Z" + }, + "location": "North Wing" +}, +{ + "_id": { + "$oid": "67f7ab113eaf1040a69ac6b2" + }, + "name": "Getting Started with Git & GitHub", + "type": "WORKSHOPS", + "start_time": { + "$date": "2026-05-09T20:00:00.000Z" + }, + "end_time": { + "$date": "2026-05-09T22:00:00.000Z" + }, + "host": "UC Davis DataLab", + "tags": [ + "beginner", + "developer" + ], + "location": "ARC Ballroom A" +}, +{ + "_id": { + "$oid": "680027f49d521a51759d7e89" + }, + "name": "Intro to Freepik AI Suite", + "type": "WORKSHOPS", + "start_time": { + "$date": "2026-05-10T00:00:00.000Z" + }, + "end_time": { + "$date": "2026-05-10T01:00:00.000Z" + }, + "host": "Freepik", + "tags": [ + "developer", + "pm", + "designer", + "other" + ], + "location": "ARC Ballroom B" +}, +{ + "_id": { + "$oid": "67eb840248055efb36b62324" + }, + "name": "Closing Ceremony", + "type": "GENERAL", + "start_time": { + "$date": "2026-05-10T22:00:00.000Z" + }, + "end_time": { + "$date": "2026-05-10T23:00:00.000Z" + } +}, +{ + "_id": { + "$oid": "67f7ad173eaf1040a69ac6b3" + }, + "name": "Software Development", + "type": "WORKSHOPS", + "start_time": { + "$date": "2026-05-09T20:00:00.000Z" + }, + "end_time": { + "$date": "2026-05-09T21:00:00.000Z" + }, + "host": "CodeLab", + "tags": [ + "beginner", + "developer", + "pm" + ], + "location": "ARC Ballroom B" +}, +{ + "_id": { + "$oid": "67f7a43f3eaf1040a69ac6a8" + }, + "name": "Dinner Starts", + "type": "MEALS", + "start_time": { + "$date": "2026-05-10T02:00:00.000Z" + } +}, +{ + "_id": { + "$oid": "67f7a5a93eaf1040a69ac6ac" + }, + "name": "Spaghetti & Marshmallow", + "type": "ACTIVITIES", + "start_time": { + "$date": "2026-05-09T21:00:00.000Z" + }, + "end_time": { + "$date": "2026-05-09T22:00:00.000Z" + }, + "location": "North Wing" +}, +{ + "_id": { + "$oid": "67f7aa013eaf1040a69ac6b0" + }, + "name": "Hackathons 101", + "type": "WORKSHOPS", + "start_time": { + "$date": "2026-05-09T18:30:00.000Z" + }, + "end_time": { + "$date": "2026-05-09T20:00:00.000Z" + }, + "host": "HackDavis", + "tags": [ + "beginner" + ], + "location": "ARC Ballroom A" +}, +{ + "_id": { + "$oid": "6800265c9d521a51759d7e82" + }, + "name": "Hacking with LLMs", + "type": "WORKSHOPS", + "start_time": { + "$date": "2026-05-09T21:00:00.000Z" + }, + "end_time": { + "$date": "2026-05-09T22:00:00.000Z" + }, + "host": "Miguel Avecedo, Founder @ Marble", + "tags": [ + "beginner", + "developer", + "pm" + ], + "location": "ARC Ballroom B" +}, +{ + "_id": { + "$oid": "67eb83a648055efb36b62323" + }, + "name": "Check-in closes", + "type": "GENERAL", + "start_time": { + "$date": "2026-05-09T23:00:00.000Z" + } +}, +{ + "_id": { + "$oid": "67f7a4ef3eaf1040a69ac6ab" + }, + "name": "Panel Judging", + "type": "GENERAL", + "start_time": { + "$date": "2026-05-10T21:00:00.000Z" + }, + "end_time": { + "$date": "2026-05-10T22:00:00.000Z" + } +}, +{ + "_id": { + "$oid": "67f7a9773eaf1040a69ac6af" + }, + "name": "Jeopardy/Kahoot", + "type": "ACTIVITIES", + "start_time": { + "$date": "2026-05-10T04:30:00.000Z" + }, + "end_time": { + "$date": "2026-05-10T05:30:00.000Z" + }, + "location": "ARC Ballroom B" +}, +{ + "_id": { + "$oid": "680027d19d521a51759d7e88" + }, + "name": "Intro to Letta AI Agents Framework", + "type": "WORKSHOPS", + "start_time": { + "$date": "2026-05-10T00:00:00.000Z" + }, + "end_time": { + "$date": "2026-05-10T01:00:00.000Z" + }, + "host": "Letta", + "tags": [ + "developer" + ], + "location": "ARC Ballroom A" +}, +{ + "_id": { + "$oid": "67eb834a48055efb36b62320" + }, + "name": "Team Mixer", + "type": "ACTIVITIES", + "start_time": { + "$date": "2026-05-09T15:30:00.000Z" + }, + "end_time": { + "$date": "2026-05-09T17:00:00.000Z" + }, + "location": "ARC Ballroom A" +}, +{ + "_id": { + "$oid": "67eb837948055efb36b62321" + }, + "name": "Opening Ceremony", + "type": "GENERAL", + "start_time": { + "$date": "2026-05-09T17:00:00.000Z" + }, + "end_time": { + "$date": "2026-05-09T18:00:00.000Z" + } +}, +{ + "_id": { + "$oid": "67f21f0a3c0ba318b4930cfc" + }, + "name": "Hacking Ends", + "type": "GENERAL", + "start_time": { + "$date": "2026-05-10T18:00:00.000Z" + } +}, +{ + "_id": { + "$oid": "6800279a9d521a51759d7e87" + }, + "name": "Surprise Mini-Event!", + "type": "WORKSHOPS", + "start_time": { + "$date": "2026-05-10T03:00:00.000Z" + }, + "end_time": { + "$date": "2026-05-10T04:00:00.000Z" + }, + "host": "Major League Hacking", + "tags": [ + "beginner", + "developer", + "pm", + "designer", + "other" + ], + "location": "ARC Ballroom A" +}, +{ + "_id": { + "$oid": "67eb839548055efb36b62322" + }, + "name": "Hacking Begins", + "type": "GENERAL", + "start_time": { + "$date": "2026-05-09T18:00:00.000Z" + } +}, +{ + "_id": { + "$oid": "67f7a46d3eaf1040a69ac6a9" + }, + "name": "Brunch Starts", + "type": "MEALS", + "start_time": { + "$date": "2026-05-10T16:30:00.000Z" + } +}, +{ + "_id": { + "$oid": "67f7a4db3eaf1040a69ac6aa" + }, + "name": "Demos", + "type": "GENERAL", + "start_time": { + "$date": "2026-05-10T19:00:00.000Z" + }, + "end_time": { + "$date": "2026-05-10T21:00:00.000Z" + } +}, +{ + "_id": { + "$oid": "680028219d521a51759d7e8a" + }, + "name": "Intro to UI/UX", + "type": "WORKSHOPS", + "start_time": { + "$date": "2026-05-09T23:00:00.000Z" + }, + "end_time": { + "$date": "2026-05-10T00:00:00.000Z" + }, + "host": "Design Interactive", + "tags": [ + "beginner", + "designer" + ], + "location": "ARC Ballroom B" +}] \ No newline at end of file diff --git a/public/schedule/arrow-right.svg b/public/schedule/arrow-right.svg new file mode 100644 index 0000000..6a58aac --- /dev/null +++ b/public/schedule/arrow-right.svg @@ -0,0 +1,3 @@ + + + diff --git a/public/schedule/attendee.svg b/public/schedule/attendee.svg new file mode 100644 index 0000000..6f7ea58 --- /dev/null +++ b/public/schedule/attendee.svg @@ -0,0 +1,17 @@ + + + + + + + + + + + + + + + + + diff --git a/public/schedule/check.svg b/public/schedule/check.svg new file mode 100644 index 0000000..0aee042 --- /dev/null +++ b/public/schedule/check.svg @@ -0,0 +1,3 @@ + + + diff --git a/public/schedule/cucumber_cow.svg b/public/schedule/cucumber_cow.svg new file mode 100644 index 0000000..745e361 --- /dev/null +++ b/public/schedule/cucumber_cow.svg @@ -0,0 +1,80 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/public/schedule/duck+bunny.svg b/public/schedule/duck+bunny.svg new file mode 100644 index 0000000..7e0fd50 --- /dev/null +++ b/public/schedule/duck+bunny.svg @@ -0,0 +1,44 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/public/schedule/duck+frog.svg b/public/schedule/duck+frog.svg new file mode 100644 index 0000000..1c21b20 --- /dev/null +++ b/public/schedule/duck+frog.svg @@ -0,0 +1,34 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/public/schedule/header_grass.svg b/public/schedule/header_grass.svg new file mode 100644 index 0000000..872fd44 --- /dev/null +++ b/public/schedule/header_grass.svg @@ -0,0 +1,15 @@ + + + + + + + + + + + + + + + diff --git a/public/schedule/location.svg b/public/schedule/location.svg new file mode 100644 index 0000000..e0d0ccc --- /dev/null +++ b/public/schedule/location.svg @@ -0,0 +1,3 @@ + + + diff --git a/public/schedule/plus.svg b/public/schedule/plus.svg new file mode 100644 index 0000000..c1c8b66 --- /dev/null +++ b/public/schedule/plus.svg @@ -0,0 +1,3 @@ + + + diff --git a/public/schedule/sleeping_cow.svg b/public/schedule/sleeping_cow.svg new file mode 100644 index 0000000..069da7b --- /dev/null +++ b/public/schedule/sleeping_cow.svg @@ -0,0 +1,37 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/public/schedule/vocal_angel_cow.svg b/public/schedule/vocal_angel_cow.svg new file mode 100644 index 0000000..4144e92 --- /dev/null +++ b/public/schedule/vocal_angel_cow.svg @@ -0,0 +1,99 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + From 887104e948f4614cb80edf9815c727bfac1c7e51 Mon Sep 17 00:00:00 2001 From: Afifah Hadi Date: Tue, 7 Apr 2026 17:51:07 -0700 Subject: [PATCH 2/8] added upcoming timeline component (changed title fromt upcoming events for better usability) --- .../UpcomingEvents/UpcomingEvents.tsx | 162 ++++++++++++++++++ app/(pages)/(index-page)/page.tsx | 2 + public/Images/upcoming/bunny.svg | 29 ++++ public/Images/upcoming/cow.svg | 41 +++++ public/Images/upcoming/ditto.svg | 15 ++ public/Images/upcoming/froggie.svg | 28 +++ public/Images/upcoming/green_flower.svg | 3 + public/Images/upcoming/mochinut.svg | 3 + public/Images/upcoming/scissors.svg | 12 ++ public/Images/upcoming/yellow_star.svg | 17 ++ 10 files changed, 312 insertions(+) create mode 100644 app/(pages)/(index-page)/_components/UpcomingEvents/UpcomingEvents.tsx create mode 100644 public/Images/upcoming/bunny.svg create mode 100644 public/Images/upcoming/cow.svg create mode 100644 public/Images/upcoming/ditto.svg create mode 100644 public/Images/upcoming/froggie.svg create mode 100644 public/Images/upcoming/green_flower.svg create mode 100644 public/Images/upcoming/mochinut.svg create mode 100644 public/Images/upcoming/scissors.svg create mode 100644 public/Images/upcoming/yellow_star.svg diff --git a/app/(pages)/(index-page)/_components/UpcomingEvents/UpcomingEvents.tsx b/app/(pages)/(index-page)/_components/UpcomingEvents/UpcomingEvents.tsx new file mode 100644 index 0000000..7c16e75 --- /dev/null +++ b/app/(pages)/(index-page)/_components/UpcomingEvents/UpcomingEvents.tsx @@ -0,0 +1,162 @@ +'use client'; + +import { useEffect, useMemo, useState } from 'react'; +import Image from 'next/image'; +import rawEvents from '@data/hub-2026-staging.events.json'; + +import bunny from '@public/Images/upcoming/bunny.svg'; +import cow from '@public/Images/upcoming/cow.svg'; +import froggie from '@public/Images/upcoming/froggie.svg'; +import yellowStar from '@public/Images/upcoming/yellow_star.svg'; +import scissors from '@public/Images/upcoming/scissors.svg'; +import mochinut from '@public/Images/upcoming/mochinut.svg'; +import ditto from '@public/Images/upcoming/ditto.svg'; +import greenFlower from '@public/Images/upcoming/green_flower.svg'; + +interface UpcomingEventsProps { + className?: string; +} + +interface RawUpcomingEvent { + name: string; + type: string; + start_time: { $date: string }; +} + +interface UpcomingEvent { + id: string; + name: string; + startTime: Date; +} + +const DISPLAY_LIMIT = 3; + +const formatEventTime = (date: Date) => + new Intl.DateTimeFormat('en-US', { + hour: 'numeric', + minute: '2-digit', + hour12: true, + }).format(date); + +const allEvents = (rawEvents as RawUpcomingEvent[]).map((event, index) => ({ + id: `${index}-${event.name}-${event.start_time.$date}`, + name: event.name, + type: (event.type || '').toUpperCase(), + startTime: new Date(event.start_time.$date), +})); + +export default function UpcomingEvents({ className }: UpcomingEventsProps) { + const [nowMs, setNowMs] = useState(() => Date.now()); + + useEffect(() => { + const intervalId = window.setInterval(() => { + setNowMs(Date.now()); + }, 60_000); + + return () => window.clearInterval(intervalId); + }, []); + + const upcomingGeneralEvents = useMemo( + () => + allEvents + .filter( + (event) => + event.type === 'GENERAL' && event.startTime.getTime() > nowMs + ) + .sort((a, b) => a.startTime.getTime() - b.startTime.getTime()) + .slice(0, DISPLAY_LIMIT), + [nowMs] + ); + + return ( +
+ + + + + +
+
+
+

+ Upcoming Timeline +

+ +
+ {upcomingGeneralEvents.length > 0 ? ( + upcomingGeneralEvents.map((event) => ( +
+

+ {formatEventTime(event.startTime)} +

+

+ {event.name} +

+
+ )) + ) : ( +
+

+ No upcoming general events yet +

+
+ )} +
+
+
+ +
+
+ Bunny tile artwork + Yellow star tile artwork +
+ +
+ Cow tile artwork + Frog tile artwork +
+
+
+
+ ); +} diff --git a/app/(pages)/(index-page)/page.tsx b/app/(pages)/(index-page)/page.tsx index 75eb9ef..1bcd3e7 100644 --- a/app/(pages)/(index-page)/page.tsx +++ b/app/(pages)/(index-page)/page.tsx @@ -5,6 +5,7 @@ import AccordionFAQ from './_components/FAQ/faq'; import Create from './_components/Create/create'; import DonorScroll from './_components/DonorScroll/DonorScroll'; import Sponsers from './_components/Sponsers/Sponsers'; +import UpcomingEvents from './_components/UpcomingEvents/UpcomingEvents'; import ScheduleSneakPeek from './_components/ScheduleSneakPeak/ScheduleSneakPeek'; export default function Home() { @@ -12,6 +13,7 @@ export default function Home() {
+ diff --git a/public/Images/upcoming/bunny.svg b/public/Images/upcoming/bunny.svg new file mode 100644 index 0000000..915791d --- /dev/null +++ b/public/Images/upcoming/bunny.svg @@ -0,0 +1,29 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/public/Images/upcoming/cow.svg b/public/Images/upcoming/cow.svg new file mode 100644 index 0000000..efcae78 --- /dev/null +++ b/public/Images/upcoming/cow.svg @@ -0,0 +1,41 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/public/Images/upcoming/ditto.svg b/public/Images/upcoming/ditto.svg new file mode 100644 index 0000000..4c35082 --- /dev/null +++ b/public/Images/upcoming/ditto.svg @@ -0,0 +1,15 @@ + + + + + + + + + + + + + + + diff --git a/public/Images/upcoming/froggie.svg b/public/Images/upcoming/froggie.svg new file mode 100644 index 0000000..d65e263 --- /dev/null +++ b/public/Images/upcoming/froggie.svg @@ -0,0 +1,28 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/public/Images/upcoming/green_flower.svg b/public/Images/upcoming/green_flower.svg new file mode 100644 index 0000000..e67d734 --- /dev/null +++ b/public/Images/upcoming/green_flower.svg @@ -0,0 +1,3 @@ + + + diff --git a/public/Images/upcoming/mochinut.svg b/public/Images/upcoming/mochinut.svg new file mode 100644 index 0000000..bd80b4c --- /dev/null +++ b/public/Images/upcoming/mochinut.svg @@ -0,0 +1,3 @@ + + + diff --git a/public/Images/upcoming/scissors.svg b/public/Images/upcoming/scissors.svg new file mode 100644 index 0000000..7ec828a --- /dev/null +++ b/public/Images/upcoming/scissors.svg @@ -0,0 +1,12 @@ + + + + + + + + + + + + diff --git a/public/Images/upcoming/yellow_star.svg b/public/Images/upcoming/yellow_star.svg new file mode 100644 index 0000000..325c425 --- /dev/null +++ b/public/Images/upcoming/yellow_star.svg @@ -0,0 +1,17 @@ + + + + + + + + + + + + + + + + + From 64909283880ab79469a76be8851aea0e2897af5e Mon Sep 17 00:00:00 2001 From: michelleyeoh Date: Wed, 8 Apr 2026 18:11:37 -0700 Subject: [PATCH 3/8] rename file and fix width --- .../ScheduleSneakPeak/ScheduleSneakPeek.tsx | 2 +- .../UpcomingTimeline.tsx} | 18 +++++++++--------- app/(pages)/(index-page)/page.tsx | 4 ++-- 3 files changed, 12 insertions(+), 12 deletions(-) rename app/(pages)/(index-page)/_components/{UpcomingEvents/UpcomingEvents.tsx => UpcomingTimeline/UpcomingTimeline.tsx} (89%) diff --git a/app/(pages)/(index-page)/_components/ScheduleSneakPeak/ScheduleSneakPeek.tsx b/app/(pages)/(index-page)/_components/ScheduleSneakPeak/ScheduleSneakPeek.tsx index 4e9c6d4..01576a6 100644 --- a/app/(pages)/(index-page)/_components/ScheduleSneakPeak/ScheduleSneakPeek.tsx +++ b/app/(pages)/(index-page)/_components/ScheduleSneakPeak/ScheduleSneakPeek.tsx @@ -177,7 +177,7 @@ export default function ScheduleSneakPeek({ className={`w-full bg-[#FAFAFA] py-14 md:py-16 ${className ?? ''}`} >
-
+

{liveLabel} diff --git a/app/(pages)/(index-page)/_components/UpcomingEvents/UpcomingEvents.tsx b/app/(pages)/(index-page)/_components/UpcomingTimeline/UpcomingTimeline.tsx similarity index 89% rename from app/(pages)/(index-page)/_components/UpcomingEvents/UpcomingEvents.tsx rename to app/(pages)/(index-page)/_components/UpcomingTimeline/UpcomingTimeline.tsx index 7c16e75..ecc4403 100644 --- a/app/(pages)/(index-page)/_components/UpcomingEvents/UpcomingEvents.tsx +++ b/app/(pages)/(index-page)/_components/UpcomingTimeline/UpcomingTimeline.tsx @@ -13,7 +13,7 @@ import mochinut from '@public/Images/upcoming/mochinut.svg'; import ditto from '@public/Images/upcoming/ditto.svg'; import greenFlower from '@public/Images/upcoming/green_flower.svg'; -interface UpcomingEventsProps { +interface UpcomingTimelineProps { className?: string; } @@ -45,7 +45,7 @@ const allEvents = (rawEvents as RawUpcomingEvent[]).map((event, index) => ({ startTime: new Date(event.start_time.$date), })); -export default function UpcomingEvents({ className }: UpcomingEventsProps) { +export default function UpcomingTimeline({ className }: UpcomingTimelineProps) { const [nowMs, setNowMs] = useState(() => Date.now()); useEffect(() => { @@ -78,7 +78,7 @@ export default function UpcomingEvents({ className }: UpcomingEventsProps) { -

-
-
+
+
+

Upcoming Timeline

@@ -108,7 +108,7 @@ export default function UpcomingEvents({ className }: UpcomingEventsProps) { upcomingGeneralEvents.map((event) => (

{formatEventTime(event.startTime)} @@ -119,7 +119,7 @@ export default function UpcomingEvents({ className }: UpcomingEventsProps) {

)) ) : ( -
+

No upcoming general events yet

@@ -143,7 +143,7 @@ export default function UpcomingEvents({ className }: UpcomingEventsProps) { />
-
+
Cow tile artwork - + From 6bbe736ba2e6e47ca5e30ef579e190a9f7846cec Mon Sep 17 00:00:00 2001 From: michelleyeoh Date: Wed, 8 Apr 2026 18:20:01 -0700 Subject: [PATCH 4/8] updated sneak peek col widths --- .../ScheduleSneakPeak/CalendarItem.tsx | 2 +- .../ScheduleSneakPeak/ScheduleSneakPeek.tsx | 108 +++++++++--------- 2 files changed, 57 insertions(+), 53 deletions(-) diff --git a/app/(pages)/(index-page)/_components/ScheduleSneakPeak/CalendarItem.tsx b/app/(pages)/(index-page)/_components/ScheduleSneakPeak/CalendarItem.tsx index 9e196c0..5140c25 100644 --- a/app/(pages)/(index-page)/_components/ScheduleSneakPeak/CalendarItem.tsx +++ b/app/(pages)/(index-page)/_components/ScheduleSneakPeak/CalendarItem.tsx @@ -53,7 +53,7 @@ export function CalendarItem({ event, attendeeCount }: CalendarItemProps) { }} >
-
+

{name} diff --git a/app/(pages)/(index-page)/_components/ScheduleSneakPeak/ScheduleSneakPeek.tsx b/app/(pages)/(index-page)/_components/ScheduleSneakPeak/ScheduleSneakPeek.tsx index 01576a6..62fe07a 100644 --- a/app/(pages)/(index-page)/_components/ScheduleSneakPeak/ScheduleSneakPeek.tsx +++ b/app/(pages)/(index-page)/_components/ScheduleSneakPeak/ScheduleSneakPeek.tsx @@ -176,59 +176,63 @@ export default function ScheduleSneakPeek({ id="schedule-sneak-peek" className={`w-full bg-[#FAFAFA] py-14 md:py-16 ${className ?? ''}`} > -
-
-
-

- {liveLabel} -

-

- Happening now -

-
-
- {liveEvents.length > 0 ? ( - liveEvents.map((event) => ( - - )) - ) : ( - - )} -
-
- -
-

- {upcomingLabel} -

-

- Upcoming Events -

-
-
- {upcomingEvents.length > 0 ? ( - upcomingEvents.map((event) => ( - +
+
+
+

+ {liveLabel} +

+

+ Happening now +

+
+
+ {liveEvents.length > 0 ? ( + liveEvents.map((event) => ( + + )) + ) : ( + - )) - ) : ( - - )} -
-
+ )} +
+
+
+ +
+
+

+ {upcomingLabel} +

+

+ Upcoming Events +

+
+
+ {upcomingEvents.length > 0 ? ( + upcomingEvents.map((event) => ( + + )) + ) : ( + + )} +
+
+

From 2aabe74cc097662c86a38647d4a865e3c3cf7942 Mon Sep 17 00:00:00 2001 From: michelleyeoh Date: Wed, 8 Apr 2026 18:30:22 -0700 Subject: [PATCH 5/8] fixed character size box --- .../UpcomingTimeline/UpcomingTimeline.tsx | 24 +++++++++---------- 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/app/(pages)/(index-page)/_components/UpcomingTimeline/UpcomingTimeline.tsx b/app/(pages)/(index-page)/_components/UpcomingTimeline/UpcomingTimeline.tsx index ecc4403..9b30395 100644 --- a/app/(pages)/(index-page)/_components/UpcomingTimeline/UpcomingTimeline.tsx +++ b/app/(pages)/(index-page)/_components/UpcomingTimeline/UpcomingTimeline.tsx @@ -143,18 +143,18 @@ export default function UpcomingTimeline({ className }: UpcomingTimelineProps) { />
-
- Cow tile artwork - Frog tile artwork -
+
+ Cow tile artwork + Frog tile artwork +
From 21c6b71a25e1851e4e5af6c9fb175f658790a5a3 Mon Sep 17 00:00:00 2001 From: michelleyeoh Date: Wed, 8 Apr 2026 18:32:09 -0700 Subject: [PATCH 6/8] updated framer npm --- package-lock.json | 26 +++++++++++++------------- package.json | 6 +++--- 2 files changed, 16 insertions(+), 16 deletions(-) diff --git a/package-lock.json b/package-lock.json index 710373f..d194a64 100644 --- a/package-lock.json +++ b/package-lock.json @@ -15,7 +15,7 @@ "@szhsin/react-accordion": "^1.4.1", "@vercel/analytics": "^1.6.1", "autoprefixer": "^10.4.20", - "framer-motion": "^12.34.0", + "framer-motion": "^12.38.0", "next": "14.2.4", "react": "^18", "react-dom": "^18", @@ -4208,13 +4208,13 @@ } }, "node_modules/framer-motion": { - "version": "12.34.0", - "resolved": "https://registry.npmjs.org/framer-motion/-/framer-motion-12.34.0.tgz", - "integrity": "sha512-+/H49owhzkzQyxtn7nZeF4kdH++I2FWrESQ184Zbcw5cEqNHYkE5yxWxcTLSj5lNx3NWdbIRy5FHqUvetD8FWg==", + "version": "12.38.0", + "resolved": "https://registry.npmjs.org/framer-motion/-/framer-motion-12.38.0.tgz", + "integrity": "sha512-rFYkY/pigbcswl1XQSb7q424kSTQ8q6eAC+YUsSKooHQYuLdzdHjrt6uxUC+PRAO++q5IS7+TamgIw1AphxR+g==", "license": "MIT", "dependencies": { - "motion-dom": "^12.34.0", - "motion-utils": "^12.29.2", + "motion-dom": "^12.38.0", + "motion-utils": "^12.36.0", "tslib": "^2.4.0" }, "peerDependencies": { @@ -5501,18 +5501,18 @@ } }, "node_modules/motion-dom": { - "version": "12.34.0", - "resolved": "https://registry.npmjs.org/motion-dom/-/motion-dom-12.34.0.tgz", - "integrity": "sha512-Lql3NuEcScRDxTAO6GgUsRHBZOWI/3fnMlkMcH5NftzcN37zJta+bpbMAV9px4Nj057TuvRooMK7QrzMCgtz6Q==", + "version": "12.38.0", + "resolved": "https://registry.npmjs.org/motion-dom/-/motion-dom-12.38.0.tgz", + "integrity": "sha512-pdkHLD8QYRp8VfiNLb8xIBJis1byQ9gPT3Jnh2jqfFtAsWUA3dEepDlsWe/xMpO8McV+VdpKVcp+E+TGJEtOoA==", "license": "MIT", "dependencies": { - "motion-utils": "^12.29.2" + "motion-utils": "^12.36.0" } }, "node_modules/motion-utils": { - "version": "12.29.2", - "resolved": "https://registry.npmjs.org/motion-utils/-/motion-utils-12.29.2.tgz", - "integrity": "sha512-G3kc34H2cX2gI63RqU+cZq+zWRRPSsNIOjpdl9TN4AQwC4sgwYPl/Q/Obf/d53nOm569T0fYK+tcoSV50BWx8A==", + "version": "12.36.0", + "resolved": "https://registry.npmjs.org/motion-utils/-/motion-utils-12.36.0.tgz", + "integrity": "sha512-eHWisygbiwVvf6PZ1vhaHCLamvkSbPIeAYxWUuL3a2PD/TROgE7FvfHWTIH4vMl798QLfMw15nRqIaRDXTlYRg==", "license": "MIT" }, "node_modules/ms": { diff --git a/package.json b/package.json index 5f2c60f..b116284 100644 --- a/package.json +++ b/package.json @@ -13,10 +13,10 @@ "@fortawesome/free-brands-svg-icons": "^7.1.0", "@fortawesome/free-solid-svg-icons": "^7.1.0", "@fortawesome/react-fontawesome": "^3.1.1", - "@vercel/analytics": "^1.6.1", "@szhsin/react-accordion": "^1.4.1", + "@vercel/analytics": "^1.6.1", "autoprefixer": "^10.4.20", - "framer-motion": "^12.34.0", + "framer-motion": "^12.38.0", "next": "14.2.4", "react": "^18", "react-dom": "^18", @@ -30,8 +30,8 @@ "@types/react": "^18", "@types/react-dom": "^18", "@types/react-transition-group": "^4.4.12", - "autoprefixer": "^10.4.24", "@typescript-eslint/eslint-plugin": "^6.16.0", + "autoprefixer": "^10.4.24", "eslint": "^8.57.1", "eslint-config-next": "14.2.4", "eslint-config-prettier": "^9.1.0", From e66cacc2d3d361b1c46c8635582f68079b21ad7f Mon Sep 17 00:00:00 2001 From: michelleyeoh Date: Wed, 8 Apr 2026 18:33:39 -0700 Subject: [PATCH 7/8] lint fix --- .../UpcomingTimeline/UpcomingTimeline.tsx | 22 +++++++++---------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/app/(pages)/(index-page)/_components/UpcomingTimeline/UpcomingTimeline.tsx b/app/(pages)/(index-page)/_components/UpcomingTimeline/UpcomingTimeline.tsx index 9b30395..10ca664 100644 --- a/app/(pages)/(index-page)/_components/UpcomingTimeline/UpcomingTimeline.tsx +++ b/app/(pages)/(index-page)/_components/UpcomingTimeline/UpcomingTimeline.tsx @@ -144,17 +144,17 @@ export default function UpcomingTimeline({ className }: UpcomingTimelineProps) {
- Cow tile artwork - Frog tile artwork -
+ Cow tile artwork + Frog tile artwork +
From 40d8c457ce293a5baea522899896edcc5c4b4dba Mon Sep 17 00:00:00 2001 From: michelleyeoh Date: Wed, 8 Apr 2026 18:40:19 -0700 Subject: [PATCH 8/8] address comments --- .../CalendarItem.tsx | 0 .../ScheduleSneakPeek.tsx | 3 ++- .../scheduleEventStyles.ts | 0 .../{ScheduleSneakPeak => ScheduleSneakPeek}/scheduleTime.ts | 5 ++++- app/(pages)/(index-page)/page.tsx | 2 +- 5 files changed, 7 insertions(+), 3 deletions(-) rename app/(pages)/(index-page)/_components/{ScheduleSneakPeak => ScheduleSneakPeek}/CalendarItem.tsx (100%) rename app/(pages)/(index-page)/_components/{ScheduleSneakPeak => ScheduleSneakPeek}/ScheduleSneakPeek.tsx (98%) rename app/(pages)/(index-page)/_components/{ScheduleSneakPeak => ScheduleSneakPeek}/scheduleEventStyles.ts (100%) rename app/(pages)/(index-page)/_components/{ScheduleSneakPeak => ScheduleSneakPeek}/scheduleTime.ts (90%) diff --git a/app/(pages)/(index-page)/_components/ScheduleSneakPeak/CalendarItem.tsx b/app/(pages)/(index-page)/_components/ScheduleSneakPeek/CalendarItem.tsx similarity index 100% rename from app/(pages)/(index-page)/_components/ScheduleSneakPeak/CalendarItem.tsx rename to app/(pages)/(index-page)/_components/ScheduleSneakPeek/CalendarItem.tsx diff --git a/app/(pages)/(index-page)/_components/ScheduleSneakPeak/ScheduleSneakPeek.tsx b/app/(pages)/(index-page)/_components/ScheduleSneakPeek/ScheduleSneakPeek.tsx similarity index 98% rename from app/(pages)/(index-page)/_components/ScheduleSneakPeak/ScheduleSneakPeek.tsx rename to app/(pages)/(index-page)/_components/ScheduleSneakPeek/ScheduleSneakPeek.tsx index 62fe07a..d765ad7 100644 --- a/app/(pages)/(index-page)/_components/ScheduleSneakPeak/ScheduleSneakPeek.tsx +++ b/app/(pages)/(index-page)/_components/ScheduleSneakPeek/ScheduleSneakPeek.tsx @@ -2,6 +2,7 @@ import { useEffect, useMemo, useState } from 'react'; import Image from 'next/image'; +import type { ComponentProps } from 'react'; import rawScheduleEvents from '@data/hub-2026-staging.events.json'; import Event, { EventTag, EventType } from '@data/event'; import CalendarItem from './CalendarItem'; @@ -102,7 +103,7 @@ function EmptyState({ }: { title: string; description: string; - imageSrc: React.ComponentProps['src']; + imageSrc: ComponentProps['src']; imageAlt: string; }) { return ( diff --git a/app/(pages)/(index-page)/_components/ScheduleSneakPeak/scheduleEventStyles.ts b/app/(pages)/(index-page)/_components/ScheduleSneakPeek/scheduleEventStyles.ts similarity index 100% rename from app/(pages)/(index-page)/_components/ScheduleSneakPeak/scheduleEventStyles.ts rename to app/(pages)/(index-page)/_components/ScheduleSneakPeek/scheduleEventStyles.ts diff --git a/app/(pages)/(index-page)/_components/ScheduleSneakPeak/scheduleTime.ts b/app/(pages)/(index-page)/_components/ScheduleSneakPeek/scheduleTime.ts similarity index 90% rename from app/(pages)/(index-page)/_components/ScheduleSneakPeak/scheduleTime.ts rename to app/(pages)/(index-page)/_components/ScheduleSneakPeek/scheduleTime.ts index 3fe35fb..49140ed 100644 --- a/app/(pages)/(index-page)/_components/ScheduleSneakPeak/scheduleTime.ts +++ b/app/(pages)/(index-page)/_components/ScheduleSneakPeek/scheduleTime.ts @@ -19,7 +19,10 @@ export const formatScheduleTimeRange = (start: Date, end?: Date): string => { const endAMPM = endTimeStr.slice(-2); if (startAMPM === endAMPM) { - return `${startTimeStr.slice(0, -2)} - ${endTimeStr}`; + const startWithoutDayPeriod = startTimeStr + .replace(/\s?(AM|PM)$/i, '') + .trimEnd(); + return `${startWithoutDayPeriod} - ${endTimeStr}`; } return `${startTimeStr} - ${endTimeStr}`; diff --git a/app/(pages)/(index-page)/page.tsx b/app/(pages)/(index-page)/page.tsx index ed7de3c..59547dd 100644 --- a/app/(pages)/(index-page)/page.tsx +++ b/app/(pages)/(index-page)/page.tsx @@ -6,7 +6,7 @@ import Create from './_components/Create/create'; import DonorScroll from './_components/DonorScroll/DonorScroll'; import Sponsers from './_components/Sponsers/Sponsers'; import UpcomingTimeline from './_components/UpcomingTimeline/UpcomingTimeline'; -import ScheduleSneakPeek from './_components/ScheduleSneakPeak/ScheduleSneakPeek'; +import ScheduleSneakPeek from './_components/ScheduleSneakPeek/ScheduleSneakPeek'; export default function Home() { return (