Skip to content

Commit f4d2aa2

Browse files
ChaoticallyAlysPranav-BatraYitong LiuCopilot
authored
672/event types (#705)
* feat(frontend): ✨ added different event types based on keywords/regex patterns * feat(chore): ✨ 🔧 altered event-type-badge to use classifyEvents() * feat(chore): ✨ 🔧 altered upcoming-event-card to use EventTypeBadge * feat(frontend): ✨ fixed bad imports and slightly updated event classif logic * feat: ✨ added new filtered event types buttons on event page Co-authored-by: Copilot <copilot@github.com> * feat: ✨ reworked upcoming-event-card to reflect new event badge * fix(chore): 🐛 🔧 corrected EventTypeBadge usage in event-dialog-content * fix(chore): 🐛 🔧 eventTypeBadge is hidden on mobile home screen * feat(chore): ✨ 🔧 added more ethinicities to cultural keywords --------- Co-authored-by: Pranav Batra <pranav.batra2006@gmail.com> Co-authored-by: Yitong Liu <yitonl21@uci.edu> Co-authored-by: Copilot <copilot@github.com>
1 parent 2876c8f commit f4d2aa2

7 files changed

Lines changed: 215 additions & 60 deletions

File tree

apps/next/src/app/events/page.tsx

Lines changed: 43 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -13,15 +13,19 @@ import CalendarView from "@/components/ui/calendar-view";
1313
import EventCard, { type EventInfo } from "@/components/ui/card/event-card";
1414
import EventCardSkeleton from "@/components/ui/skeleton/event-card-skeleton";
1515
import { useMediaQuery } from "@/hooks/useMediaQuery";
16-
import { getEventType } from "@/utils/funcs";
16+
import {
17+
classifyEvent,
18+
EVENT_CATEGORIES,
19+
type EventCategory,
20+
} from "@/utils/classifyEvent";
1721
import { HallEnum } from "@/utils/types";
1822

1923
const Events = () => {
2024
const [selectedDiningHall, setSelectedDiningHall] = useState<
2125
"both" | "anteatery" | "brandywine"
2226
>("both");
2327
const [selectedEventType, setSelectedEventType] = useState<
24-
"both" | "special" | "celebration"
28+
"both" | EventCategory
2529
>("both");
2630
const [viewMode, setViewMode] = useState<"grid" | "calendar">("grid");
2731
const [selectedEventData, setSelectedEventData] = useState<EventInfo | null>(
@@ -39,24 +43,28 @@ const Events = () => {
3943
before: endOfMonth(currentDate),
4044
});
4145

42-
const sortedEvents =
43-
(events?.length ?? 0) > 0
44-
? [...(events ?? [])].sort(
45-
(a: any, b: any) =>
46-
new Date(a.start).getTime() - new Date(b.start).getTime(),
47-
)
48-
: [];
46+
const sortedEvents = (events ?? []).sort(
47+
(a: any, b: any) =>
48+
new Date(a.start).getTime() - new Date(b.start).getTime(),
49+
);
50+
51+
const eventsWithType = sortedEvents.map((event: any) => ({
52+
...event,
53+
eventType: classifyEvent(
54+
event.title,
55+
`${event.shortDescription ?? ""} ${event.longDescription ?? ""}`,
56+
),
57+
}));
4958

50-
const filteredEvents = sortedEvents.filter((event: any) => {
59+
const filteredEvents = eventsWithType.filter((event: any) => {
5160
const matchesDiningHall =
5261
selectedDiningHall === "both" ||
5362
(selectedDiningHall === "anteatery" &&
5463
event.restaurantId === "anteatery") ||
5564
(selectedDiningHall === "brandywine" &&
5665
event.restaurantId === "brandywine");
5766
const matchesEventType =
58-
selectedEventType === "both" ||
59-
getEventType(event.title) === selectedEventType;
67+
selectedEventType === "both" || event.eventType === selectedEventType;
6068
return matchesDiningHall && matchesEventType;
6169
});
6270

@@ -85,6 +93,7 @@ const Events = () => {
8593
? HallEnum.ANTEATERY
8694
: HallEnum.BRANDYWINE,
8795
isOngoing: resource.start <= now && resource.end >= now,
96+
eventType: resource.eventType,
8897
});
8998
};
9099

@@ -156,7 +165,7 @@ const Events = () => {
156165
<span className="text-sm font-medium text-slate-900 dark:text-white">
157166
Event Type
158167
</span>
159-
<div className="flex gap-3">
168+
<div className="flex flex-wrap gap-3">
160169
<Button
161170
variant="outlined"
162171
size="small"
@@ -169,37 +178,32 @@ const Events = () => {
169178
>
170179
All Events
171180
</Button>
172-
<Button
173-
variant="outlined"
174-
size="small"
175-
onClick={() => setSelectedEventType("special")}
176-
className={`!px-4 !py-1 flex items-center justify-center !normal-case !text-sm !font-thin ${
177-
selectedEventType === "special"
178-
? "!bg-sky-700 !text-white !border-sky-700 hover:!bg-sky-800 dark:!bg-blue-300 dark:!text-gray-900 dark:!border-blue-300 dark:hover:!bg-blue-400"
179-
: "!bg-white !border-sky-700 !text-slate-900 hover:!bg-sky-50 dark:!bg-transparent dark:!border-blue-300 dark:!text-white dark:hover:!bg-zinc-700"
180-
}`}
181-
>
182-
Special Meals
183-
</Button>
184-
<Button
185-
variant="outlined"
186-
size="small"
187-
onClick={() => setSelectedEventType("celebration")}
188-
className={`!px-4 !py-1 flex items-center justify-center !normal-case !text-sm !font-thin ${
189-
selectedEventType === "celebration"
190-
? "!bg-sky-700 !text-white !border-sky-700 hover:!bg-sky-800 dark:!bg-blue-300 dark:!text-gray-900 dark:!border-blue-300 dark:hover:!bg-blue-400"
191-
: "!bg-white !border-sky-700 !text-slate-900 hover:!bg-sky-50 dark:!bg-transparent dark:!border-blue-300 dark:!text-white dark:hover:!bg-zinc-700"
192-
}`}
193-
>
194-
Celebration
195-
</Button>
181+
{EVENT_CATEGORIES.map((category) => {
182+
const isSelected = selectedEventType === category;
183+
184+
return (
185+
<Button
186+
key={category}
187+
variant="outlined"
188+
size="small"
189+
onClick={() => setSelectedEventType(category)}
190+
className={`!px-4 !py-1 flex items-center justify-center !normal-case !text-sm !font-thin ${
191+
isSelected
192+
? "!bg-sky-700 dark:!bg-sky-400 !text-white !border-sky-700 dark:!border-sky-400 hover:!bg-sky-800 dark:hover:!bg-sky-500"
193+
: "!bg-white dark:!bg-zinc-800 !border-sky-700 dark:!border-sky-400 !text-slate-900 dark:!text-zinc-100 hover:!bg-sky-50 dark:hover:!bg-zinc-700"
194+
}`}
195+
>
196+
{category}
197+
</Button>
198+
);
199+
})}
196200
</div>
197201
</div>
198202
<div className="flex flex-col gap-3">
199203
<span className="text-sm font-medium text-slate-900 dark:text-white">
200204
Location
201205
</span>
202-
<div className="flex gap-3">
206+
<div className="flex flex-wrap gap-3">
203207
<Button
204208
variant="outlined"
205209
size="small"
@@ -279,6 +283,7 @@ const Events = () => {
279283
shortDesc={event.shortDescription}
280284
longDesc={event.longDescription}
281285
isOngoing={event.start <= now && event.end >= now}
286+
eventType={event.eventType}
282287
/>
283288
))}
284289
</div>

apps/next/src/components/ui/card/event-card.tsx

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import Image from "next/image";
77
import React from "react";
88
import EventTypeBadge from "@/components/ui/event-type-badge";
99
import { useMediaQuery } from "@/hooks/useMediaQuery";
10+
import type { EventCategory } from "@/utils/classifyEvent";
1011
import { dateToString, timeToString, toTitleCase } from "@/utils/funcs";
1112
import { HallEnum } from "@/utils/types";
1213
import EventDialogContent from "../event-dialog-content";
@@ -35,6 +36,8 @@ export interface EventInfo {
3536
location: HallEnum;
3637
/** If true, indicates the event is currently ongoing and displays a badge. */
3738
isOngoing: boolean;
39+
/** The category of the event, determined by its description. */
40+
eventType: EventCategory;
3841
}
3942

4043
/**
@@ -77,7 +80,7 @@ const EventCardContent = React.forwardRef<
7780
height={300}
7881
className="w-full object-contain"
7982
/>
80-
<EventTypeBadge title={props.name} />
83+
<EventTypeBadge type={props.eventType} />
8184
</div>
8285
<CardContent className="flex flex-col gap-2 p-4">
8386
<div className="flex flex-row gap-2 items-center">

apps/next/src/components/ui/card/upcoming-event-card.tsx

Lines changed: 17 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,11 @@
11
import { AccessTime, CalendarMonth, LocationOn } from "@mui/icons-material";
22
import { Box, Card, Dialog, Typography } from "@mui/material";
33
import { useState } from "react";
4+
import { classifyEvent } from "@/utils/classifyEvent";
45
import { timeToString, toTitleCase } from "@/utils/funcs";
56
import { HallEnum, numToMonth } from "@/utils/types";
67
import EventDialogContent from "../event-dialog-content";
8+
import EventTypeBadge from "../event-type-badge";
79
import type { EventInfo } from "./event-card";
810

911
/** A compact card for an upcoming event in the horizontal scroll row */
@@ -25,7 +27,10 @@ export default function UpcomingEventCard({
2527
const [open, setOpen] = useState(false);
2628
const startDate = event.start ? new Date(event.start) : null;
2729
const endDate = event.end ? new Date(event.end) : null;
28-
30+
const eventType = classifyEvent(
31+
event.title,
32+
`${event.shortDescription ?? ""} ${event.longDescription ?? ""}`,
33+
);
2934
/*
3035
3136
Seems to be an error where HallEnum is not properly getting the info
@@ -49,6 +54,7 @@ export default function UpcomingEventCard({
4954
isOngoing: startDate
5055
? startDate <= new Date() && (endDate ? endDate >= new Date() : false)
5156
: false,
57+
eventType,
5258
};
5359

5460
// alternative sizing depending on mobile/desktop
@@ -60,22 +66,20 @@ export default function UpcomingEventCard({
6066
return (
6167
<>
6268
<Card
63-
className="w-full rounded-xl p-5 shadow-sm hover:shadow-md transition cursor-pointer text-left bg-transparent"
64-
sx={{ border: 1, borderColor: "divider" }}
69+
className="relative w-full rounded-xl border border-neutral-200 dark:border-neutral-700 p-5 shadow-sm hover:shadow-md transition cursor-pointer text-left bg-transparent"
6570
onClick={() => setOpen(true)}
6671
>
67-
<div className="mb-3 flex items-start gap-2 min-w-0">
68-
<Typography
69-
className={`${titleSize} font-bold leading-tight pr-2 line-clamp-2 min-w-0 flex-1 whitespace-normal break-normal`}
70-
color="primary"
72+
<div className="absolute top-2 right-0 h-14 w-48 scale-75 origin-top-right">
73+
<div className="hidden md:block [&>span]:!bg-sky-100 [&>span]:!text-sky-700 [&>span]:!shadow-sm">
74+
<EventTypeBadge type={eventType} />
75+
</div>
76+
</div>
77+
<div className="mb-3 flex items-start gap-2 min-w-0 pr-28">
78+
<h3
79+
className={`${titleSize} whitespace-normal break-normal min-w-0 flex-1 whitespace-normal break-normal font-bold leading-tight text-sky-700`}
7180
>
7281
{event.title}
73-
</Typography>
74-
<span
75-
className={`flex-shrink-0 ${tagSize} font-semibold tracking-wider bg-sky-100 text-sky-700 dark:bg-transparent dark:border dark:border-blue-300 dark:text-blue-300 px-2 py-0.5 rounded-full`}
76-
>
77-
Celebration
78-
</span>
82+
</h3>
7983
</div>
8084
<div className={spacing}>
8185
{startDate && (

apps/next/src/components/ui/event-dialog-content.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ export default function EventDialogContent(
3636
height={600}
3737
className="w-full object-contain"
3838
/>
39-
<EventTypeBadge title={props.name} />
39+
<EventTypeBadge type={props.eventType} />
4040
</div>
4141
<DialogContent
4242
sx={{ padding: "20px 24px 24px !important" }}

apps/next/src/components/ui/event-drawer-content.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ export default function EventDrawerContent(
3030
height={600}
3131
className="w-full object-contain"
3232
/>
33-
<EventTypeBadge title={props.name} />
33+
<EventTypeBadge title={props.name} desc={props.longDesc} />
3434
</div>
3535
<Box sx={{ padding: "20px 24px 24px" }} className="flex flex-col gap-2">
3636
<Typography
Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,9 @@
1-
import { getEventType } from "@/utils/funcs";
1+
import type { EventCategory } from "@/utils/classifyEvent";
22

3-
export default function EventTypeBadge({ title }: { title: string }) {
4-
const type = getEventType(title);
5-
if (type !== "celebration" && type !== "special") return null;
3+
export default function EventTypeBadge({ type }: { type: EventCategory }) {
64
return (
7-
<span className="absolute bottom-3 right-3 bg-white text-black dark:bg-[#303035] dark:text-white text-sm font-medium px-4 py-1.5 rounded-full shadow-md">
8-
{type === "celebration" ? "Celebration" : "Special Meal"}
5+
<span className="absolute bottom-3 right-3 bg-white/80 text-black text-sm font-medium px-4 py-1.5 rounded-full shadow-md">
6+
{type}
97
</span>
108
);
119
}

0 commit comments

Comments
 (0)