import dayjs from "dayjs" export const EVENT_REPEAT_INTERVALS = [ "Keine Wiederholung", "Täglich", "Wöchentlich", "2-wöchentlich", "Monatlich", "Jährlich" ] as const const DEFAULT_REPEAT_INTERVAL = "Keine Wiederholung" const MAX_OCCURRENCES = 500 const addInterval = (date: dayjs.Dayjs, repeatInterval: string) => { switch (repeatInterval) { case "Täglich": return date.add(1, "day") case "Wöchentlich": return date.add(1, "week") case "2-wöchentlich": return date.add(2, "week") case "Monatlich": return date.add(1, "month") case "Jährlich": return date.add(1, "year") default: return null } } export const normalizeRepeatInterval = (value?: string | null) => EVENT_REPEAT_INTERVALS.includes(value as typeof EVENT_REPEAT_INTERVALS[number]) ? value as typeof EVENT_REPEAT_INTERVALS[number] : DEFAULT_REPEAT_INTERVAL export const expandRecurringEvent = ( event: { startDate: string | Date endDate?: string | Date | null repeatInterval?: string | null }, rangeStart: string | Date, rangeEnd: string | Date, buildOccurrence: (occurrenceStart: dayjs.Dayjs, occurrenceEnd: dayjs.Dayjs | null, occurrenceIndex: number) => T ) => { const repeatInterval = normalizeRepeatInterval(event.repeatInterval) const baseStart = dayjs(event.startDate) const baseEnd = event.endDate ? dayjs(event.endDate) : null const visibleStart = dayjs(rangeStart) const visibleEnd = dayjs(rangeEnd) const durationMs = baseEnd ? Math.max(baseEnd.diff(baseStart), 0) : 0 if (repeatInterval === DEFAULT_REPEAT_INTERVAL) { const occurrenceEnd = baseEnd ? baseStart.add(durationMs, "millisecond") : null if (baseStart.isAfter(visibleEnd) || (occurrenceEnd && occurrenceEnd.isBefore(visibleStart))) return [] return [buildOccurrence(baseStart, occurrenceEnd, 0)] } const occurrences: T[] = [] let occurrenceStart = baseStart let occurrenceIndex = 0 while (occurrenceIndex < MAX_OCCURRENCES && occurrenceStart.isBefore(visibleEnd.add(1, "day"))) { const occurrenceEnd = baseEnd ? occurrenceStart.add(durationMs, "millisecond") : null if (!occurrenceStart.isAfter(visibleEnd) && !(occurrenceEnd && occurrenceEnd.isBefore(visibleStart))) { occurrences.push(buildOccurrence(occurrenceStart, occurrenceEnd, occurrenceIndex)) } const nextStart = addInterval(occurrenceStart, repeatInterval) if (!nextStart || nextStart.isSame(occurrenceStart)) break occurrenceStart = nextStart occurrenceIndex += 1 } return occurrences }