//Calendar implementation for the HTWK Leipzig timetable. Evaluation and display of the individual dates in iCal format. //Copyright (C) 2024 HTWKalender support@htwkalender.de //This program is free software: you can redistribute it and/or modify //it under the terms of the GNU Affero General Public License as published by //the Free Software Foundation, either version 3 of the License, or //(at your option) any later version. //This program is distributed in the hope that it will be useful, //but WITHOUT ANY WARRANTY; without even the implied warranty of //MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the //GNU Affero General Public License for more details. //You should have received a copy of the GNU Affero General Public License //along with this program. If not, see . import ICAL from "ical.js"; import { CalendarComponent } from "ical"; /** * Interface for the color distinction event * @param title Event name * @param color Color code for the event */ export interface ColorDistinctionEvent { summary: string | undefined; color: string; } /** * Parses iCal data and returns an array of calendar components * @param icalData iCal data to parse * @returns Array of calendar components */ export function parseICalData( icalData: string | undefined, ): CalendarComponent[] { if (icalData === undefined || !icalData) { return []; } else { const jCalData = ICAL.parse(icalData); const comp = new ICAL.Component(jCalData); const vEvents = comp.getAllSubcomponents("vevent"); const events: CalendarComponent[] = vEvents.map((vevent: CalendarComponent) => { return new ICAL.Event(vevent); }); const colorDistinctionEvents: ColorDistinctionEvent[] = extractedColorizedEvents(events); return vEvents.map((vevent: CalendarComponent) => { const event = new ICAL.Event(vevent); return { title: event.summary, start: event.startDate.toJSDate(), end: event.endDate.toJSDate(), notes: event.description, allDay: event.startDate.isDate, color: colorDistinctionEvents.find( (e: ColorDistinctionEvent) => e.summary === event.summary, )?.color, id: event.uid, location: event.location, }; }); } } /** * Extracts the event names and assigns a color to each event * @param vEvents Array of calendar components * @returns Array of objects with event name and color */ function extractedColorizedEvents( vEvents: CalendarComponent[], ): ColorDistinctionEvent[] { return colorizeEvents(filterEventsDistinct(vEvents)); } /** * Filters out duplicate events * @param vEvents Array of calendar components * @returns Array of calendar components without duplicates */ function filterEventsDistinct( vEvents: CalendarComponent[], ): CalendarComponent[] { return vEvents.filter( (vevent: CalendarComponent, index: number, self: CalendarComponent[]) => { return ( self.findIndex((v) => { return v.summary === vevent.summary; }) === index ); }, ); } /** * Assigns a color to each event * @param vEvents Array of calendar components * @returns Array of objects with event name and color */ function colorizeEvents(vEvents: CalendarComponent[]): ColorDistinctionEvent[] { return vEvents.map((vevent: CalendarComponent) => { const colors: string[] = [ "var(--htwk-rot-200)", "var(--htwk-gruen-300)", "var(--htwk-magenta-400)", "var(--htwk-cyan-400)", "var(--htwk-silbergrau-600)", "var(--htwk-yellow-300)", "var(--htwk-blau-300)", "var(--htwk-dunkelblau-200)", "var(--htwk-rot-400)", "var(--htwk-gruen-400)", "var(--htwk-blau-200)", ]; const randomColor = colors[ vEvents.findIndex((e: CalendarComponent) => { return e.summary === vevent.summary; }) % colors.length ]; return { summary: vevent.summary, color: randomColor, }; }); } // Exported for testing export const exportedForTesting = { extractedColorizedEvents, filterEventsDistinct, colorizeEvents, };