diff --git a/app/(authenticated)/calendar/YSTVCalendar.tsx b/app/(authenticated)/calendar/YSTVCalendar.tsx index f449b023..5bc2f15d 100644 --- a/app/(authenticated)/calendar/YSTVCalendar.tsx +++ b/app/(authenticated)/calendar/YSTVCalendar.tsx @@ -32,6 +32,8 @@ import { z } from "zod"; import { keepPreviousData, useQuery } from "@tanstack/react-query"; import { fetchEvents } from "./actions"; import { calendarEventsQueryKey } from "./helpers"; +import { EventColours } from "@/features/calendar/types"; +import { EventType } from "@/features/calendar/types"; dayjs.extend(weekOfYear); @@ -86,6 +88,12 @@ const HistoryStateSchema = z.object({ filter: z.enum(["all", "mine", "vacant"]).optional(), }); +const getEventColor = (evt: Event): string => { + if (evt.is_cancelled) return "#B00020"; + if (evt.is_tentative) return "#8b8b8b"; + return EventColours[evt.event_type as EventType] || "#FFC0CB"; +}; + export default function YSTVCalendar() { const currentDate = new Date(); @@ -363,13 +371,13 @@ export default function YSTVCalendar() { end: evt.end_date, url: `/calendar/${evt.event_id}`, }; - if (evt.is_tentative) { - eventObject.color = "#8b8b8b"; - } + + eventObject.color = getEventColor(evt); + if (evt.is_cancelled) { - eventObject.color = "#B00020"; eventObject.className = "ystv-calendar-strike-through"; } + if (evt.end_date.valueOf() < currentDate.valueOf()) { eventObject.className += " opacity-50"; } @@ -381,8 +389,6 @@ export default function YSTVCalendar() { ); } -type EventType = "show" | "meeting" | "social" | "other"; - interface Event { event_id: number; event_type: EventType | string; diff --git a/app/(authenticated)/calendar/new/page.tsx b/app/(authenticated)/calendar/new/page.tsx index 88150223..d52d4b1d 100644 --- a/app/(authenticated)/calendar/new/page.tsx +++ b/app/(authenticated)/calendar/new/page.tsx @@ -52,7 +52,7 @@ export default async function NewEventPage() { ); if (permittedEventTypes.length === 0) { throw new Forbidden([ - "Calendar.Admin or Calendar.{Show,Meeting,Social}.{Creator,Admin}" as any, + "Calendar.Admin or Calendar.{Show,Meeting,Workshop,Social}.{Creator,Admin}" as any, ]); } const allMembers = await getAllUsers(); diff --git a/app/(authenticated)/calendar/page.tsx b/app/(authenticated)/calendar/page.tsx index 8a01f8f1..a546fd9c 100644 --- a/app/(authenticated)/calendar/page.tsx +++ b/app/(authenticated)/calendar/page.tsx @@ -13,6 +13,7 @@ import { } from "@tanstack/react-query"; import { fetchEvents } from "./actions"; import { calendarEventsQueryKey } from "./helpers"; +import EventColoursKey from "@/components/EventColoursKey"; export default async function CalendarPage() { await mustGetCurrentUser(); @@ -83,6 +84,7 @@ export default async function CalendarPage() {
+ ); } diff --git a/components/EventColoursKey.tsx b/components/EventColoursKey.tsx new file mode 100644 index 00000000..a6df65fb --- /dev/null +++ b/components/EventColoursKey.tsx @@ -0,0 +1,17 @@ +import { EventColours } from "@/features/calendar/types"; + +export default function EventColoursKey() { + return ( +
+ {Object.entries(EventColours).map(([type, colour]) => ( +
+
+ {type} +
+ ))} +
+ ); +} diff --git a/features/calendar/permissions.ts b/features/calendar/permissions.ts index aa7dda44..23b4353d 100644 --- a/features/calendar/permissions.ts +++ b/features/calendar/permissions.ts @@ -16,7 +16,14 @@ export function adminEventTypes(userPermissions: Permission[]): EventType[] { userPermissions.includes("Calendar.Admin") || userPermissions.includes("SuperUser") ) { - permittedEventTypes.push("show", "meeting", "social", "public", "other"); + permittedEventTypes.push( + "show", + "meeting", + "workshop", + "social", + "public", + "other", + ); } else { if (userPermissions.includes("Calendar.Show.Admin")) { permittedEventTypes.push("show"); @@ -24,6 +31,9 @@ export function adminEventTypes(userPermissions: Permission[]): EventType[] { if (userPermissions.includes("Calendar.Meeting.Admin")) { permittedEventTypes.push("meeting"); } + if (userPermissions.includes("Calendar.Workshop.Admin")) { + permittedEventTypes.push("workshop"); + } if (userPermissions.includes("Calendar.Social.Admin")) { permittedEventTypes.push("social"); } @@ -48,6 +58,9 @@ export function creatableEventTypes( if (userPermissions.includes("Calendar.Meeting.Creator")) { base.push("meeting"); } + if (userPermissions.includes("Calendar.Workshop.Creator")) { + base.push("workshop"); + } if (userPermissions.includes("Calendar.Social.Creator")) { base.push("social"); } diff --git a/features/calendar/types.ts b/features/calendar/types.ts index ed8a875f..1dbe073a 100644 --- a/features/calendar/types.ts +++ b/features/calendar/types.ts @@ -1,6 +1,7 @@ export const EventTypes = [ "show", "meeting", + "workshop", "social", "public", "other", @@ -10,3 +11,20 @@ export type EventType = (typeof EventTypes)[number]; export function hasRSVP(type: EventType): boolean { return type !== "show"; } + +enum Colours { + Blue = "#0074E0", + Green = "#218721", + Orange = "#DB6F0A", + Pink = "#D82C7F", + Purple = "#800080", +} + +export const EventColours: Record = { + show: Colours.Blue, // Blue + meeting: Colours.Green, + workshop: Colours.Orange, + social: Colours.Purple, + public: Colours.Blue, + other: Colours.Pink, +}; diff --git a/lib/auth/permissions.ts b/lib/auth/permissions.ts index a1720496..1222c089 100644 --- a/lib/auth/permissions.ts +++ b/lib/auth/permissions.ts @@ -17,6 +17,8 @@ export const PermissionEnum = z.enum([ "Calendar.Show.Creator", "Calendar.Meeting.Admin", "Calendar.Meeting.Creator", + "Calendar.Workshop.Admin", + "Calendar.Workshop.Creator", "Calendar.Social.Admin", "Calendar.Social.Creator", "Calendar.Public.Admin",