feat(events): reliable holiday skipping for recurrences + UI badge; clean logs

Backend: generate EventException on create/update when skip_holidays or recurrence changes; emit RecurrenceException (EXDATE) with exact occurrence start time (UTC)
API: return master events with RecurrenceRule + RecurrenceException
Frontend: map RecurrenceException → recurrenceException; ensure SkipHolidays instances never render on holidays; place TentTree icon (black) next to main event icon via template
Docs: update README and Copilot instructions for recurrence/holiday behavior
Cleanup: remove dataSource and debug console logs
This commit is contained in:
RobbStarkAustria
2025-10-12 12:00:43 +00:00
parent 7ab4ea14c4
commit 773628c324
15 changed files with 698 additions and 122 deletions

View File

@@ -0,0 +1,31 @@
export interface EventException {
id?: number;
event_id: number;
exception_date: string; // YYYY-MM-DD
is_skipped: boolean;
override_title?: string;
override_description?: string;
override_start?: string;
override_end?: string;
}
export async function createEventException(exception: Omit<EventException, 'id'>) {
const res = await fetch('/api/event_exceptions', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(exception),
});
const data = await res.json();
if (!res.ok || data.error) throw new Error(data.error || 'Fehler beim Erstellen der Ausnahme');
return data;
}
export async function listEventExceptions(eventId?: number) {
const params = new URLSearchParams();
if (eventId) params.set('event_id', eventId.toString());
const res = await fetch(`/api/event_exceptions?${params.toString()}`);
const data = await res.json();
if (!res.ok || data.error) throw new Error(data.error || 'Fehler beim Laden der Ausnahmen');
return data as EventException[];
}