fix: recurring event display and AI query improvements

- Use occurrenceStart instead of startTime in getEventsInRange so
  recurring events show their actual occurrence date to the AI
- Add lazy CalDAV sync in ChatService (syncOnce before first DB access)
- Add CaldavService.sync() with internal config check (silent no-op)
- Show German recurrence description (e.g. "Jede Woche") instead of
  generic "Wiederkehrend" in EventCardBase via formatRecurrenceRule()
- Move RepeatType and REPEAT_TYPE_LABELS from editEvent to shared
- Separate calendar overlay useFocusEffect from event loading
This commit is contained in:
2026-02-09 18:17:39 +01:00
parent 325246826a
commit 0a2aef2098
11 changed files with 105 additions and 29 deletions

View File

@@ -11,6 +11,24 @@ const REPEAT_TYPE_TO_FREQ: Record<RepeatType, string> = {
Jahr: "YEARLY",
};
const FREQ_TO_REPEAT_TYPE: Record<string, RepeatType> = Object.fromEntries(
Object.entries(REPEAT_TYPE_TO_FREQ).map(([k, v]) => [v, k as RepeatType]),
);
export const REPEAT_TYPE_LABELS: Record<RepeatType, string> = {
Tag: "Tage",
Woche: "Wochen",
Monat: "Monate",
Jahr: "Jahre",
};
const REPEAT_TYPE_SINGULAR: Record<RepeatType, string> = {
Tag: "Jeden Tag",
Woche: "Jede Woche",
Monat: "Jeden Monat",
Jahr: "Jedes Jahr",
};
/**
* Build an RRULE string from repeat count and type.
*
@@ -27,3 +45,30 @@ export function buildRRule(repeatType: RepeatType, interval: number = 1): string
return `FREQ=${freq};INTERVAL=${interval}`;
}
/**
* Format an RRULE string into a human-readable German description.
*
* @param rrule - RRULE string like "FREQ=WEEKLY;INTERVAL=2"
* @returns German description like "Alle 2 Wochen" or "Wöchentlich"
*/
export function formatRecurrenceRule(rrule: string): string {
const rule = rrule.replace(/^RRULE:/, "");
const parts = Object.fromEntries(
rule.split(";").map((p) => p.split("=") as [string, string]),
);
const freq = parts.FREQ;
const interval = parts.INTERVAL ? parseInt(parts.INTERVAL, 10) : 1;
const repeatType = FREQ_TO_REPEAT_TYPE[freq];
if (!repeatType) {
return "Wiederkehrend";
}
if (interval <= 1) {
return REPEAT_TYPE_SINGULAR[repeatType];
}
return `Alle ${interval} ${REPEAT_TYPE_LABELS[repeatType]}`;
}