From dc72ddb56222a56b948145db8c0afc3adad5d403 Mon Sep 17 00:00:00 2001 From: Mithun Titus Maria Ruban Raj Date: Mon, 6 Apr 2026 21:47:00 -0400 Subject: [PATCH 1/2] Added Events and My Schedule tab and their functionalities respectively --- src/app/(profile)/my-schedule/page.tsx | 96 ++++++++++++++++++++++ src/components/layout/Header/index.tsx | 31 +++++++ src/features/home/components/EventCard.tsx | 4 + src/lib/events.ts | 32 ++++++++ 4 files changed, 163 insertions(+) create mode 100644 src/app/(profile)/my-schedule/page.tsx diff --git a/src/app/(profile)/my-schedule/page.tsx b/src/app/(profile)/my-schedule/page.tsx new file mode 100644 index 0000000..bc6383a --- /dev/null +++ b/src/app/(profile)/my-schedule/page.tsx @@ -0,0 +1,96 @@ +import Box from "@mui/material/Box"; +import Typography from "@mui/material/Typography"; +import { eq } from "drizzle-orm"; + +import db from "@/db"; +import { eventAttendees } from "@/db/schema"; +import ListView from "@/features/toggles/ToggleViews/ListView"; +import { auth } from "@/lib/auth"; +import { getUpcomingEvents } from "@/lib/events"; + +export default async function MySchedulePage(): Promise { + const session = await auth(); + const userId = session?.user?.id; + + if (!userId) { + return ( + <> + {} + + + My Schedule + + + + {/* PAGE CONTENT */} + + Please Sign In. + + + ); + } + + const events = await getUpcomingEvents(); + + const registrations = await db + .select({ eventId: eventAttendees.eventId }) + .from(eventAttendees) + .where(eq(eventAttendees.userId, userId)); + + const registeredSet = new Set(registrations.map((r) => r.eventId)); + + const registeredEvents = events + .filter((e) => registeredSet.has(e.id)) + .map((e) => ({ + ...e, + isRegistered: true, + })); + + return ( + <> + {/* FULL-WIDTH HEADER (same as Update Profile) */} + + + My Schedule + + + + {/* PAGE CONTENT */} + + {registeredEvents.length === 0 ? ( + You are not registered for any events yet. + ) : ( + + )} + + + ); +} diff --git a/src/components/layout/Header/index.tsx b/src/components/layout/Header/index.tsx index 8637600..0a766a0 100644 --- a/src/components/layout/Header/index.tsx +++ b/src/components/layout/Header/index.tsx @@ -5,6 +5,7 @@ import Toolbar from "@mui/material/Toolbar"; import Typography from "@mui/material/Typography"; import Image from "next/image"; import Link from "next/link"; +import { usePathname } from "next/navigation"; import { useSession } from "next-auth/react"; import * as React from "react"; @@ -17,6 +18,9 @@ export default function Header(): React.ReactElement { const canCreate = role === "admin" || role === "manager"; const headerColor = { admin: "secondary.main", manager: "#276636" }; const fontColor = { admin: "#ffffff", manager: "#ffffff" }; + const pathname = usePathname(); + const isEvents = pathname === "/"; + const isMySchedule = pathname === "/my-schedule"; const appBarSx = role && role in headerColor ? { backgroundColor: headerColor[role as keyof typeof headerColor] } @@ -88,6 +92,33 @@ export default function Header(): React.ReactElement { + + + + Events + + + + + + My Schedule + + + {canCreate && ( diff --git a/src/features/home/components/EventCard.tsx b/src/features/home/components/EventCard.tsx index b9f963c..73849c0 100644 --- a/src/features/home/components/EventCard.tsx +++ b/src/features/home/components/EventCard.tsx @@ -4,6 +4,7 @@ import LocationPinIcon from "@mui/icons-material/LocationPin"; import PersonIcon from "@mui/icons-material/Person"; import QueryBuilderIcon from "@mui/icons-material/QueryBuilder"; import { Box, Card, CardContent, Typography } from "@mui/material"; +import { useRouter } from "next/navigation"; import { useSession } from "next-auth/react"; import * as React from "react"; @@ -31,6 +32,8 @@ export default function VolunteerEventCard( ): React.ReactElement { const { status } = useSession(); + const router = useRouter(); + const timeRange = getTimeRange( event.eventDate, event.startTime, @@ -79,6 +82,7 @@ export default function VolunteerEventCard( setIsRegistered(true); setRegisteredUsers((prev) => prev + 1); } + router.refresh(); } catch (error) { if (error instanceof Error) { if (error.message === "Event capacity reached") { diff --git a/src/lib/events.ts b/src/lib/events.ts index 1b913c9..82988de 100644 --- a/src/lib/events.ts +++ b/src/lib/events.ts @@ -28,3 +28,35 @@ export async function getUpcomingEvents(): Promise< ) .orderBy(asc(events.eventDate)); } + +export async function getUserRegisteredEvents( + userId: string, +): Promise<(typeof events.$inferSelect)[]> { + const today = new Date(); + const threeMonthsFromNow = new Date(today); + threeMonthsFromNow.setMonth(today.getMonth() + 3); + + const todayStr = today.toISOString().split("T")[0]; + const threeMonthsStr = threeMonthsFromNow.toISOString().split("T")[0]; + + const registrations = await db + .select({ eventId: eventAttendees.eventId }) + .from(eventAttendees) + .where(eq(eventAttendees.userId, userId)); + + if (registrations.length === 0) return []; + + const eventIds = registrations.map((r) => r.eventId); + + return db + .select() + .from(events) + .where( + and( + inArray(events.id, eventIds), + gte(events.eventDate, todayStr), + lte(events.eventDate, threeMonthsStr), + ), + ) + .orderBy(asc(events.eventDate)); +} From 966bca44353e9369b0862bf84ef6a1806b79f463 Mon Sep 17 00:00:00 2001 From: Mithun Titus Maria Ruban Raj Date: Mon, 6 Apr 2026 21:47:49 -0400 Subject: [PATCH 2/2] Added Events and My Schedule tab and their functionalities respectively --- src/app/(profile)/my-schedule/page.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/app/(profile)/my-schedule/page.tsx b/src/app/(profile)/my-schedule/page.tsx index bc6383a..5495350 100644 --- a/src/app/(profile)/my-schedule/page.tsx +++ b/src/app/(profile)/my-schedule/page.tsx @@ -38,7 +38,7 @@ export default async function MySchedulePage(): Promise { py: 5, }} > - Please Sign In. + Please Sign In );