2.8 KiB
2.8 KiB
Recurring Events
Recurring events follow the iCalendar RFC 5545 RRULE standard. No backend changes are needed — CalDAV (SabreDAV) handles recurrence natively.
Architecture
RecurrenceEditor (React)
-> IcsRecurrenceRule (ts-ics)
-> RRULE string (RFC 5545)
-> .ics file (CalDAV)
-> SabreDAV server
RecurrenceEditor Component
Located at
src/frontend/apps/calendars/src/features/calendar/components/RecurrenceEditor.tsx
import { RecurrenceEditor } from '@/features/calendar/components/RecurrenceEditor';
const [recurrence, setRecurrence] = useState<IcsRecurrenceRule>();
<RecurrenceEditor value={recurrence} onChange={setRecurrence} />
Include in the event object:
const event: IcsEvent = {
// ...other fields
recurrenceRule: recurrence,
};
Supported patterns
| Pattern | RRULE |
|---|---|
| Every day | FREQ=DAILY |
| Every 3 days | FREQ=DAILY;INTERVAL=3 |
| Every Monday | FREQ=WEEKLY;BYDAY=MO |
| Mon/Wed/Fri | FREQ=WEEKLY;BYDAY=MO,WE,FR |
| Every 2 weeks on Thu | FREQ=WEEKLY;INTERVAL=2;BYDAY=TH |
| 15th of each month | FREQ=MONTHLY;BYMONTHDAY=15 |
| March 15 yearly | FREQ=YEARLY;BYMONTH=3;BYMONTHDAY=15 |
| 10 occurrences | append ;COUNT=10 |
| Until a date | append ;UNTIL=20251231T235959Z |
Not yet supported
BYSETPOS(e.g. "1st Monday of month", "last Friday")- Edit single instance vs series (needs RECURRENCE-ID UI)
- Visual preview of recurrence pattern
Date validation
The component warns about edge cases:
- Feb 30/31 — "February has at most 29 days"
- Feb 29 — "Only exists in leap years"
- Day 31 on 30-day months — shown as warning
Translations
Supported: English, French, Dutch. Keys are in
src/frontend/apps/calendars/src/features/i18n/translations.json
under calendar.recurrence.*.
IcsRecurrenceRule interface (ts-ics)
interface IcsRecurrenceRule {
frequency: 'DAILY' | 'WEEKLY' | 'MONTHLY' | 'YEARLY';
interval?: number;
count?: number;
until?: IcsDateObject;
byDay?: { day: 'MO'|'TU'|'WE'|'TH'|'FR'|'SA'|'SU' }[];
byMonthDay?: number[];
byMonth?: number[];
}
How CalDAV handles it
- RRULE is stored as a property in the VEVENT inside the
.icsfile - SabreDAV expands recurring instances when clients query date ranges
- Individual instance modifications use RECURRENCE-ID (not yet in UI)
Example .ics:
BEGIN:VEVENT
UID:abc-123
SUMMARY:Weekly Team Meeting
DTSTART:20260125T140000Z
RRULE:FREQ=WEEKLY;BYDAY=MO;UNTIL=20261231T235959Z
END:VEVENT