119 lines
3.3 KiB
TypeScript
119 lines
3.3 KiB
TypeScript
"use client";
|
|
|
|
import { useQueryState, parseAsStringLiteral, parseAsString } from "nuqs";
|
|
import { EventItem } from "./EventItem";
|
|
import { EventFilter } from "./EventFilter";
|
|
import {
|
|
EventFragment,
|
|
EventCategory,
|
|
SingularEvent,
|
|
getSingularEvents,
|
|
organizeEventsByDate,
|
|
} from "@/lib/event";
|
|
import { isTodayOrFuture } from "@/lib/date";
|
|
import styles from "./eventContainer.module.scss";
|
|
import { formatDate, formatYearMonth } from "@/lib/date";
|
|
import { parse } from "date-fns";
|
|
|
|
/*
|
|
TODO: canonical / alternate URLs https://github.com/47ng/nuqs?tab=readme-ov-file#seo
|
|
*/
|
|
|
|
export const EventContainer = ({
|
|
events,
|
|
eventCategories,
|
|
}: {
|
|
events: EventFragment[];
|
|
eventCategories: EventCategory[];
|
|
}) => {
|
|
const [mode, setMode] = useQueryState(
|
|
"mode",
|
|
parseAsStringLiteral(["list", "calendar"]).withDefault("list")
|
|
);
|
|
|
|
const filterableCategories = eventCategories.filter((x) => x.showInFilters);
|
|
const [category, setCategory] = useQueryState("category", parseAsString);
|
|
|
|
const filteredEvents = events.filter(
|
|
(x) =>
|
|
!category ||
|
|
x.categories.map((eventCategory) => eventCategory.slug).includes(category)
|
|
);
|
|
|
|
return (
|
|
<div className={styles.events}>
|
|
<EventFilter
|
|
eventCategories={filterableCategories}
|
|
setCategory={setCategory}
|
|
activeCategory={category}
|
|
/>
|
|
<div className={styles.eventWrapper}>
|
|
<div className={styles.displayOptions}>
|
|
<button onClick={() => setMode(null)}>Vis liste</button>
|
|
<button onClick={() => setMode("calendar")}>Vis kalender</button>
|
|
</div>
|
|
{mode === "list" && <EventList events={filteredEvents} />}
|
|
{mode === "calendar" && <EventCalendar events={filteredEvents} />}
|
|
</div>
|
|
</div>
|
|
);
|
|
};
|
|
|
|
const EventList = ({ events }: { events: EventFragment[] }) => {
|
|
return (
|
|
<ul className={styles.eventList}>
|
|
{events.map((event) => (
|
|
<EventItem key={event.id} event={event} mode="list" />
|
|
))}
|
|
</ul>
|
|
);
|
|
};
|
|
|
|
const CalendarDay = ({
|
|
day,
|
|
events,
|
|
}: {
|
|
day: string;
|
|
events: SingularEvent[];
|
|
}) => (
|
|
<div
|
|
className={`${styles.calendarDay} ${events.length === 0 && styles.empty}`}
|
|
>
|
|
<h3>{formatDate(parse(day, "yyyy-MM-dd", new Date()), "eeee dd.MM.")}</h3>
|
|
<ul>
|
|
{events.map((event) => (
|
|
<EventItem key={event.id} event={event} mode="calendar" size="small" />
|
|
))}
|
|
</ul>
|
|
</div>
|
|
);
|
|
|
|
const EventCalendar = ({ events }: { events: EventFragment[] }) => {
|
|
const futureSingularEvents = getSingularEvents(events).filter(
|
|
(x) => x.occurrence?.start && isTodayOrFuture(x.occurrence.start)
|
|
);
|
|
|
|
const eventsByDate = organizeEventsByDate(futureSingularEvents);
|
|
|
|
return (
|
|
<div className={styles.eventCalendar}>
|
|
{Object.keys(eventsByDate).map((yearMonth) => (
|
|
<div key={yearMonth} className={styles.calendarYearMonth}>
|
|
<h2>{formatYearMonth(yearMonth)}</h2>
|
|
{Object.keys(eventsByDate[yearMonth]).map((week) => (
|
|
<div key={week} className={styles.calendarWeek}>
|
|
{Object.keys(eventsByDate[yearMonth][week]).map((day) => (
|
|
<CalendarDay
|
|
key={day}
|
|
day={day}
|
|
events={eventsByDate[yearMonth][week][day]}
|
|
/>
|
|
))}
|
|
</div>
|
|
))}
|
|
</div>
|
|
))}
|
|
</div>
|
|
);
|
|
};
|