diff --git a/CLAUDE.md b/CLAUDE.md index ef2724c..d172f1f 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -405,7 +405,7 @@ CalDAV sync with external calendar servers (e.g., Radicale) using `tsdav` and `i **Sync Triggers (client-side via `CaldavConfigService.sync()`):** - **Login** (`login.tsx`): After successful authentication - **Auto-login** (`AuthGuard.tsx`): After `loadStoredUser()` if authenticated -- **Calendar timer** (`calendar.tsx`): Every 10s while Calendar tab is focused, via `setInterval` in `useFocusEffect` +- **Calendar timer** (`calendar.tsx`): Events load instantly from DB on focus (`loadEvents`), CalDAV sync runs in background (`syncAndReload`) and reloads events after. Repeats every 10s via `setInterval` - **Sync button** (`settings.tsx`): Manual trigger in CaldavSettings **Lazy sync (server-side in ChatService):** @@ -618,7 +618,7 @@ NODE_ENV=development # development = pretty logs, production = JSON - Orange dot indicator for days with events - Tap-to-open modal overlay showing EventCards for selected day - Supports events from adjacent months visible in grid - - Uses `useFocusEffect` for automatic reload on tab focus with periodic CalDAV sync (10s interval while focused) + - Events load instantly from local DB on tab focus, CalDAV sync runs non-blocking in background (`syncAndReload`) with 10s interval - DeleteEventModal integration for recurring event deletion with three modes - EventOverlay hides when DeleteEventModal is open (fixes modal stacking on web) - Chat screen fully functional with FlashList, message sending, and event confirm/reject diff --git a/apps/client/src/app/(tabs)/calendar.tsx b/apps/client/src/app/(tabs)/calendar.tsx index 1f00961..07811bb 100644 --- a/apps/client/src/app/(tabs)/calendar.tsx +++ b/apps/client/src/app/(tabs)/calendar.tsx @@ -85,15 +85,9 @@ const Calendar = () => { const { events, setEvents, deleteEvent } = useEventsStore(); - // Sync CalDAV then load events for current view + // Load events from local DB (fast, no network sync) const loadEvents = useCallback(async () => { try { - try { - await CaldavConfigService.sync(); - } catch { - // No CalDAV config or sync failed — not critical - } - // Calculate first visible day (up to 6 days before month start) const firstOfMonth = new Date(currentYear, monthIndex, 1); const dayOfWeek = firstOfMonth.getDay(); @@ -119,16 +113,25 @@ const Calendar = () => { } }, [monthIndex, currentYear, setEvents]); - // Load events when tab gains focus or month/year changes - // NOTE: Wrapper needed because loadEvents is async (returns Promise) - // and useFocusEffect expects a sync function (optionally returning cleanup) + // Sync CalDAV in background, then reload events + const syncAndReload = useCallback(async () => { + try { + await CaldavConfigService.sync(); + await loadEvents(); + } catch { + // Sync failed — not critical + } + }, [loadEvents]); + + // Load events instantly on focus, then sync in background periodically useFocusEffect( useCallback(() => { loadEvents(); + syncAndReload(); - const interval = setInterval(loadEvents, 10_000); + const interval = setInterval(syncAndReload, 10_000); return () => clearInterval(interval); - }, [loadEvents]), + }, [loadEvents, syncAndReload]), ); // Re-open overlay after back navigation from editEvent