Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
4faebc0
put may 9 and may 10 events on same page but different sections, chan…
hadiafifah Mar 4, 2026
05d8e46
Add my code for home page schedule fetching
ReehalS Feb 26, 2026
3f079d9
The first comment
ReehalS Feb 26, 2026
3e534aa
fixed second sub issue
hadiafifah Mar 4, 2026
e0b7940
refactored page.tsx and split into reusable components
hadiafifah Mar 4, 2026
48bb990
added day nav button animation
hadiafifah Mar 5, 2026
335b9ea
moved hooks
michelleyeoh Mar 6, 2026
1d87401
merge branch of main
michelleyeoh Mar 6, 2026
cbe82ea
comment out images temp
michelleyeoh Mar 11, 2026
b536d03
Merge branch 'main' of https://github.com/HackDavis/hackdavis-hub int…
michelleyeoh Mar 11, 2026
bbe08b9
Merge branch 'main' of https://github.com/HackDavis/hackdavis-hub int…
michelleyeoh Mar 23, 2026
d98b173
moved type file
michelleyeoh Mar 23, 2026
f558cde
update ui to figma reqests
michelleyeoh Mar 23, 2026
e82bce0
address fixes
michelleyeoh Mar 23, 2026
42707f7
typo and remove border
michelleyeoh Mar 23, 2026
3a946f6
add shared now hook and fix fixes
michelleyeoh Mar 23, 2026
0c66556
update now time caculation to pst
michelleyeoh Mar 23, 2026
a20dfac
ts fix
michelleyeoh Mar 23, 2026
a5aa451
margin fix
michelleyeoh Mar 23, 2026
3f63544
remove dedundant hook call
michelleyeoh Mar 23, 2026
2a1c7ea
added more margin
michelleyeoh Mar 23, 2026
728c81e
save event seconds and populate events
michelleyeoh Mar 23, 2026
f2ba101
revert loading condition
michelleyeoh Mar 24, 2026
fc1754a
update pst weekend and hard coded 9
michelleyeoh Mar 24, 2026
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
435 changes: 38 additions & 397 deletions app/(pages)/(hackers)/(hub)/schedule/page.tsx

Large diffs are not rendered by default.

120 changes: 81 additions & 39 deletions app/(pages)/(hackers)/_components/HomeHacking/ScheduleSneakPeek.tsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
'use client';

import { useMemo } from 'react';
import Link from 'next/link';
import Image from 'next/image';
import CalendarItem from '@pages/(hackers)/_components/Schedule/CalendarItem';
import {
EventEntry,
useScheduleSneakPeekData,
} from '../../../_hooks/useScheduleSneakPeekData';
import { useSharedNow } from '@pages/_hooks/useScheduleSharedNow';

import sleeping_cow from '@public/hackers/hero/sleeping_cow.svg';
import duckbunny from '@public/hackers/scheduleSneakPeek/duck+bunny.svg';
Expand Down Expand Up @@ -37,6 +39,26 @@ function SectionLabel({ label }: { label: string }) {
);
}

function CountdownLabel({ targetTime }: { targetTime: number }) {
const now = useSharedNow();

const timeLeft = useMemo(() => {
const diff = targetTime - now;
if (diff <= 0) return { h: 0, m: 0, s: 0 };
return {
h: Math.floor(diff / 3600000),
m: Math.floor((diff / 60000) % 60),
s: Math.floor((diff / 1000) % 60),
};
}, [targetTime, now]);

const label = `IN ${timeLeft.h.toString().padStart(2, '0')}:${timeLeft.m
.toString()
.padStart(2, '0')}:${timeLeft.s.toString().padStart(2, '0')}`;

return <SectionLabel label={label} />;
}

function Panel({
title,
liveEvents,
Expand Down Expand Up @@ -68,6 +90,25 @@ function Panel({
/>
));

const upcomingGroups = useMemo(() => {
const groupsMap = new Map<number, EventEntry[]>();
for (const entry of upcomingEvents) {
const startTime = new Date(entry.event.start_time).getTime();
const existing = groupsMap.get(startTime);
if (existing) {
existing.push(entry);
} else {
groupsMap.set(startTime, [entry]);
}
}
return Array.from(groupsMap.entries())
.map(([startTime, entries]) => ({
startTime,
entries,
}))
.sort((a, b) => a.startTime - b.startTime);
}, [upcomingEvents]);

return (
<div className="rounded-[16px] bg-[#FFFFFF] p-5 lg:p-6">
<h2 className="font-jakarta text-[clamp(1.1rem,3vw,2.25rem)] font-semibold leading-tight tracking-[0.64px] text-[#3F3F3F] mb-4">
Expand Down Expand Up @@ -102,7 +143,7 @@ function Panel({
href="/schedule"
className="hover:brightness-[97%] hover:saturate-[140%]"
>
{title == 'Your schedule' ? (
{title === 'Your schedule' ? (
<button className="bg-[#CCFFFE] text-[#003D3D] rounded-full p-[12px] font-semibold text-center px-[24px] text-[14px] tracking-[0.64px]">
Add to your schedule
</button>
Expand All @@ -111,44 +152,45 @@ function Panel({
</div>
)}
</div>

<SectionLabel label="IN 0:30:00" />
<div className="space-y-3">
{upcomingEvents.length > 0 ? (
renderEventItems(upcomingEvents, 'upcoming')
) : (
<div className="bg-[#F3F3FC] rounded-[12px] flex flex-col items-center p-[36px] gap-[12px]">
<Image
src={title === 'Happening now' ? sleeping_cow : duckfrog}
alt={
title === 'Happening now'
? 'Sleeping cow'
: 'Duck on top of frog'
}
/>
<p className="font-semibold text-center text-[#3F3F3F] text-[16px] tracking-[0.64px]">
{title === 'Your schedule'
? 'No upcoming events on your schedule'
: 'No upcoming events'}
</p>
<p className="text-center text-[#7C7C85] md:w-[70%] text-[14px] tracking-[0.64px]">
{title === 'Your schedule'
? 'This is where you’ll see upcoming events. Seems like there’s nothing coming up! Take a look to see if there’s anything you want to check out.'
: 'This is where you’ll see upcoming events. Seems like there’s nothing coming up!'}
</p>
<Link
href="/schedule"
className="hover:brightness-[97%] hover:saturate-[140%]"
>
{title == 'Your schedule' ? (
<button className="bg-[#CCFFFE] text-[#003D3D] rounded-full p-[12px] font-semibold text-center px-[24px] text-[14px] tracking-[0.64px]">
Explore events
</button>
) : null}
</Link>
{upcomingGroups.length > 0 ? (
upcomingGroups.map((group) => (
<div key={group.startTime}>
<CountdownLabel targetTime={group.startTime} />
<div className="space-y-3">
{renderEventItems(group.entries, `upcoming-${group.startTime}`)}
</div>
</div>
)}
</div>
))
) : (
<div className="bg-[#F3F3FC] rounded-[12px] flex flex-col items-center p-[36px] gap-[12px]">
<Image
src={title === 'Happening now' ? sleeping_cow : duckfrog}
alt={
title === 'Happening now' ? 'Sleeping cow' : 'Duck on top of frog'
}
/>
<p className="font-semibold text-center text-[#3F3F3F] text-[16px] tracking-[0.64px]">
{title === 'Your schedule'
? 'No upcoming events on your schedule'
: 'No upcoming events'}
</p>
<p className="text-center text-[#7C7C85] md:w-[70%] text-[14px] tracking-[0.64px]">
{title === 'Your schedule'
? 'This is where you’ll see upcoming events. Seems like there’s nothing coming up! Take a look to see if there’s anything you want to check out.'
: 'This is where you’ll see upcoming events. Seems like there’s nothing coming up!'}
</p>
<Link
href="/schedule"
className="hover:brightness-[97%] hover:saturate-[140%]"
>
{title === 'Your schedule' ? (
<button className="bg-[#CCFFFE] text-[#003D3D] rounded-full p-[12px] font-semibold text-center px-[24px] text-[14px] tracking-[0.64px]">
Explore events
</button>
) : null}
</Link>
</div>
)}
</div>
);
}
Expand Down Expand Up @@ -186,7 +228,7 @@ export default function ScheduleSneakPeek({
</span>
</div>

<div className="border-b border-[#E3E3E3] mt-4 mb-6" />
<div className="border-b border-[#E3E3E3] mt-4 mb-[2.5rem]" />

<div className="grid grid-cols-1 lg:grid-cols-2 gap-4 lg:gap-5">
<Panel
Expand Down
25 changes: 12 additions & 13 deletions app/(pages)/(hackers)/_components/Schedule/CalendarItem.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ export function CalendarItem({
}}
>
<div
className={`flex items-start justify-between sm:items-center gap-4 relative ${
className={`flex items-start justify-between sm:items-center gap-[40px] md:gap-[60px] relative ${
displayType === 'ACTIVITIES'
? 'w-full flex-col sm:flex-row'
: 'flex-col'
Expand All @@ -71,11 +71,11 @@ export function CalendarItem({
}`}
>
<div className="w-full sm:w-auto">
<h2 className="font-metropolis text-xl sm:text-2xl font-semibold tracking-[0.72px] sm:mb-2 text-balance">
<h2 className="font-metropolis text-[18px] md:text-[20px] font-semibold tracking-[0.72px] mb-1 text-balance">
{name}
</h2>
<div className="flex items-center flex-wrap gap-y-2">
<span className="font-plus-jakarta-sans text-xs xs:text-sm md:text-base lg:text-lg font-normal leading-[145%] tracking-[0.36px] mr-5">
<span className="font-plus-jakarta-sans text-[14px] font-normal leading-[145%] tracking-[0.36px] mr-5">
{timeDisplay}
{displayType === 'MEALS' && ' (Subject to change)'}
</span>
Expand All @@ -88,23 +88,22 @@ export function CalendarItem({
height={13.44}
className="mr-1"
/>
<span className="font-plus-jakarta-sans text-xs xs:text-sm md:text-base lg:text-lg font-normal leading-[145%] tracking-[0.36px]">
<span className="font-plus-jakarta-sans text-[14px] font-normal leading-[145%] tracking-[0.36px]">
{location}
</span>
</div>
)}
</div>
{tags && tags.length > 0 && (
<div className="flex gap-2 items-center sm:py-2 flex-wrap mt-2">
<div className="flex gap-2 items-center flex-wrap mt-[12px]">
{tags.map((tag) => (
<div
className="px-3 py-1.5 border rounded-md"
style={{ borderColor: eventStyle.textColor }}
className="px-[8px] py-[4px] bg-[rgba(209,247,110,0.60)]"
key={tag}
>
<span
key={tag}
className="font-plus-jakarta-sans text-sm font-normal leading-[145%] tracking-[0.36px]"
className="font-dm-mono text-sm font-normal leading-[145%] tracking-[0.36px]"
>
{tag.toUpperCase()}
</span>
Expand All @@ -116,8 +115,8 @@ export function CalendarItem({
{displayType !== 'GENERAL' && displayType !== 'MEALS' && (
<div className="flex flex-col gap-2 items-end text-right pt-1">
{host && (
<span className="font-plus-jakarta-sans text-xs xs:text-sm md:text-base lg:text-lg font-normal leading-[145%] tracking-[0.36px] text-balance">
{host}
<span className="font-plus-jakarta-sans text-[14px] font-normal leading-[145%] tracking-[0.36px] text-balance">
{host.toUpperCase()}
</span>
)}
</div>
Expand All @@ -140,13 +139,13 @@ export function CalendarItem({

`}
>
<div className="relative w-16 h-12">
<div className="relative w-[44.4px] h-[30px]">
<Image src={attendee_icon} alt="attendee icon" fill />
</div>
<span className="font-plus-jakarta-sans text-xs xs:text-sm md:text-base lg:text-lg font-normal leading-[145%] tracking-[0.36px] text-balance">
<span className="font-plus-jakarta-sans text-[14px] font-normal leading-[145%] tracking-[0.36px] text-balance">
{`${attendeeCount ?? ''} Hacker${
attendeeCount && attendeeCount < 2 ? ' is' : 's are'
} attending this event`}
} attending`}
</span>
</div>
)}
Expand Down
51 changes: 51 additions & 0 deletions app/(pages)/(hackers)/_components/Schedule/DayNavButtons.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
import { useState } from 'react';
import { DAY_KEYS, DAY_LABELS, DayKey } from './constants';

interface DayNavButtonsProps {
activeDay: DayKey;
onSelectDay: (day: DayKey) => void;
className?: string;
buttonClassName?: string;
}

export default function DayNavButtons({
activeDay,
onSelectDay,
className,
buttonClassName,
}: DayNavButtonsProps) {
const [hoveredDay, setHoveredDay] = useState<DayKey | null>(null);
const previewDay =
hoveredDay && hoveredDay !== activeDay ? hoveredDay : activeDay;

return (
<div className={className}>
{DAY_KEYS.map((dayKey) => (
<button
key={dayKey}
onClick={() => onSelectDay(dayKey)}
onMouseEnter={() => setHoveredDay(dayKey)}
onMouseLeave={() => setHoveredDay(null)}
onFocus={() => setHoveredDay(dayKey)}
onBlur={() => setHoveredDay(null)}
type="button"
className={`relative w-fit bg-transparent border-none p-0 text-left font-dm-mono text-base md:text-lg font-medium tracking-[0.36px] leading-[100%] inline-flex items-center ${
activeDay === dayKey ? 'text-[#3F3F3F]' : 'text-[#ACACB9]'
} ${buttonClassName ?? ''}`}
>
<span
className={`hidden md:block absolute left-0 top-1/2 -translate-y-1/2 origin-left transition-all duration-200 ease-out ${
previewDay === dayKey
? 'scale-x-100 opacity-100'
: 'scale-x-0 opacity-0'
}`}
aria-hidden
>
{'\u2022'}
</span>
<span className="font-dm-mono pl-5">{DAY_LABELS[dayKey]}</span>
</button>
))}
</div>
);
}
Loading
Loading