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:
16
CLAUDE.md
16
CLAUDE.md
@@ -334,7 +334,7 @@ src/
|
||||
├── index.ts
|
||||
├── dateHelpers.ts # getDay() - get date for specific weekday relative to today
|
||||
├── formatters.ts # formatDate(), formatTime(), formatDateTime(), formatDateWithWeekday() - German locale
|
||||
└── rruleHelpers.ts # parseRRule() - parse RRULE strings to extract freq, until, count, interval, byDay
|
||||
└── rruleHelpers.ts # parseRRule(), buildRRule(), formatRecurrenceRule() - RRULE parsing, building, and German formatting
|
||||
```
|
||||
|
||||
**Key Types:**
|
||||
@@ -408,6 +408,10 @@ CalDAV sync with external calendar servers (e.g., Radicale) using `tsdav` and `i
|
||||
- **Calendar timer** (`calendar.tsx`): Every 10s while Calendar tab is focused, via `setInterval` in `useFocusEffect`
|
||||
- **Sync button** (`settings.tsx`): Manual trigger in CaldavSettings
|
||||
|
||||
**Lazy sync (server-side in ChatService):**
|
||||
- AI data access callbacks (`fetchEventsInRange`, `searchEvents`, `fetchEventById`) trigger `syncOnce()` before the first DB query
|
||||
- Uses `CaldavService.sync()` which checks config internally (silent no-op without config)
|
||||
|
||||
**Single-event sync (server-side in controllers):**
|
||||
- `EventController`: `pushToCaldav()` after create/update, `deleteFromCaldav()` after delete
|
||||
- `ChatController`: `pushAll()` after confirming an event proposal
|
||||
@@ -419,7 +423,7 @@ CalDAV sync with external calendar servers (e.g., Radicale) using `tsdav` and `i
|
||||
|
||||
**Architecture:**
|
||||
- `CaldavService` depends on `CaldavRepository` (config storage) and `EventService` (event CRUD)
|
||||
- `ChatService` depends only on `EventService` (not EventRepository) for all event operations
|
||||
- `ChatService` depends on `EventService` and `CaldavService` (lazy CalDAV sync on AI data access)
|
||||
- `EventController` and `ChatController` both receive `CaldavService` for CalDAV push on mutations
|
||||
|
||||
### Database Abstraction
|
||||
@@ -568,12 +572,12 @@ NODE_ENV=development # development = pretty logs, production = JSON
|
||||
- `utils/recurrenceExpander`: Handles RRULE parsing, strips `RRULE:` prefix if present (AI may include it), filters out exceptionDates
|
||||
- `logging/`: Structured logging with pino, pino-http middleware, @Logged decorator
|
||||
- All repositories and GPTAdapter decorated with @Logged for automatic method logging
|
||||
- `CaldavService`: Full CalDAV sync (connect, pullEvents, pushEvent, pushAll, deleteEvent, getConfig, saveConfig, deleteConfig)
|
||||
- `CaldavService`: Full CalDAV sync (connect, pullEvents, pushEvent, pushAll, deleteEvent, sync, getConfig, saveConfig, deleteConfig). `sync()` checks config internally and is a silent no-op without config.
|
||||
- `CaldavController`: REST endpoints for config CRUD, pull, push
|
||||
- `MongoCaldavRepository`: Config persistence with createOrUpdate, findByUserId, deleteByUserId
|
||||
- `EventController`: CalDAV push on create/update, CalDAV delete on delete (via pushToCaldav/deleteFromCaldav helpers)
|
||||
- `ChatController`: CalDAV pushAll after confirmEvent (ensures chat-created events sync)
|
||||
- `ChatService`: Refactored to use only EventService (no direct EventRepository dependency)
|
||||
- `ChatService`: Uses EventService + CaldavService (lazy sync on AI data access via syncOnce pattern)
|
||||
- `EventService`: Extended with searchByTitle(), findByCaldavUUID()
|
||||
- `utils/eventFormatters`: Refactored to use EventService instead of EventRepository
|
||||
- CORS configured to allow X-User-Id header
|
||||
@@ -584,7 +588,7 @@ NODE_ENV=development # development = pretty logs, production = JSON
|
||||
|
||||
**Shared:**
|
||||
- Types, DTOs, constants (Day, Month with German translations), ExpandedEvent type, CaldavConfig, CaldavSyncStatus defined and exported
|
||||
- `rruleHelpers.ts`: `parseRRule()` parses RRULE strings using rrule library, returns `ParsedRRule` with freq, until, count, interval, byDay
|
||||
- `rruleHelpers.ts`: `parseRRule()` parses RRULE strings using rrule library, returns `ParsedRRule` with freq, until, count, interval, byDay. `buildRRule()` builds RRULE from RepeatType + interval. `formatRecurrenceRule()` formats RRULE into German description (e.g., "Jede Woche", "Alle 2 Monate"). Exports `REPEAT_TYPE_LABELS` and `RepeatType`.
|
||||
- `formatters.ts`: German date/time formatters (`formatDate`, `formatTime`, `formatDateTime`, `formatDateWithWeekday`, `formatDateKey`) used by both client and server
|
||||
- rrule library added as dependency for RRULE parsing
|
||||
|
||||
@@ -634,7 +638,7 @@ NODE_ENV=development # development = pretty logs, production = JSON
|
||||
- `CustomTextInput`: Themed text input component with focus border highlight, supports controlled value via `text` prop
|
||||
- `CardBase`: Reusable card component with header (title/subtitle), content area, and optional footer button - configurable padding, border, text size via props, ScrollView uses `nestedScrollEnabled` for Android
|
||||
- `ModalBase`: Reusable modal wrapper with backdrop (absolute-positioned behind card), uses CardBase internally - provides click-outside-to-close, Android back button support, and proper scrolling on Android
|
||||
- `EventCardBase`: Event card with date/time/recurring icons - uses CardBase for structure
|
||||
- `EventCardBase`: Event card with date/time/recurring icons - uses CardBase for structure. Accepts `recurrenceRule` string (not boolean) and displays German-formatted recurrence via `formatRecurrenceRule()`
|
||||
- `EventCard`: Uses EventCardBase + edit/delete buttons (TouchableOpacity with delayPressIn for scroll-friendly touch handling)
|
||||
- `ProposedEventCard`: Uses EventCardBase + confirm/reject/edit buttons for chat proposals, displays green highlighted text for new changes ("Neue Ausnahme: [date]" for single delete, "Neues Ende: [date]" for UNTIL updates), shows yellow conflict warnings when proposed time overlaps with existing events. Edit button allows modifying proposals before confirming.
|
||||
- `DeleteEventModal`: Delete confirmation modal using ModalBase - shows three options for recurring events (single/future/all), simple confirm for non-recurring
|
||||
|
||||
Reference in New Issue
Block a user