Files
neuf-www/web/src/lib/event.ts

148 lines
3.3 KiB
TypeScript

import {
compareAsc,
getYear,
getMonth,
getWeek,
getDate,
endOfWeek,
startOfWeek,
eachDayOfInterval,
addWeeks,
} from "date-fns";
import { toLocalTime, formatDate } from "./date";
import { graphql } from "@/gql";
import { EventFragment, EventOccurrence } from "@/gql/graphql";
export type { EventFragment } from "@/gql/graphql";
export type SingularEvent = EventFragment & {
occurrence: EventOccurrence;
};
const EventFragmentDefinition = graphql(`
fragment Event on EventPage {
__typename
id
slug
title
body {
id
blockType
field
... on RichTextBlock {
rawValue
value
}
}
featuredImage {
url
width
height
}
facebookUrl
ticketUrl
priceRegular
priceMember
priceStudent
occurrences {
... on EventOccurrence {
__typename
id
start
end
venue {
__typename
id
slug
title
}
}
}
}
`);
export const allEventsQuery = graphql(`
query allEvents {
events: pages(contentType: "events.EventPage") {
... on EventPage {
...Event
}
}
}
`);
export function getSingularEvents(events: EventFragment[]) {
return events
.map((event) => {
return event.occurrences
?.filter((x): x is EventOccurrence => isDefined(x))
.map((occurrence) => {
const eventOccurrence = structuredClone(event);
eventOccurrence.occurrence = occurrence;
return eventOccurrence;
});
})
.flat()
.filter((x): x is SingularEvent => isDefined(x));
}
function isDefined<T>(val: T | undefined | null): val is T {
return val !== undefined && val !== null;
}
interface EventsByDate {
[yearMonth: string]: {
[week: number]: {
[day: number]: SingularEvent[];
};
};
}
export function organizeEventsByDate(events: SingularEvent[]): EventsByDate {
const sortedEvents = events.sort((a, b) =>
compareAsc(new Date(a.occurrence.start), new Date(b.occurrence.start))
);
const eventsByDate: EventsByDate = {};
const minDate = new Date(sortedEvents[0]?.occurrence.start);
const maxDate = new Date(
sortedEvents[sortedEvents.length - 1]?.occurrence.start
);
let currentDate = startOfWeek(minDate, { weekStartsOn: 1 });
while (currentDate <= maxDate) {
const yearMonth = formatDate(currentDate, "yyyy-MM");
const week = formatDate(currentDate, "w");
const daysOfWeek = eachDayOfInterval({
start: currentDate,
end: endOfWeek(currentDate, { weekStartsOn: 1 }),
});
if (!eventsByDate[yearMonth]) {
eventsByDate[yearMonth] = {};
}
if (!eventsByDate[yearMonth][week]) {
eventsByDate[yearMonth][week] = {};
}
daysOfWeek.forEach((day) => {
const formattedDay = formatDate(day, "yyyy-MM-dd");
if (!eventsByDate[yearMonth][week][formattedDay]) {
eventsByDate[yearMonth][week][formattedDay] = [];
}
});
currentDate = addWeeks(currentDate, 1);
}
sortedEvents.forEach((event) => {
const start = toLocalTime(event.occurrence.start);
const yearMonth = formatDate(start, "yyyy-MM");
const week = formatDate(start, "w");
const day = formatDate(start, "yyyy-MM-dd");
eventsByDate[yearMonth][week][day].push(event);
});
return eventsByDate;
}