Skip to content

fix(agenda): fix cache, event visibility, and recurring event handling#214

Open
stvsu wants to merge 2 commits into
vicinaehq:mainfrom
stvsu:feat/agenda-event-visibility-and-ux
Open

fix(agenda): fix cache, event visibility, and recurring event handling#214
stvsu wants to merge 2 commits into
vicinaehq:mainfrom
stvsu:feat/agenda-event-visibility-and-ux

Conversation

@stvsu
Copy link
Copy Markdown

@stvsu stvsu commented Mar 24, 2026

Summary

Fixes several bugs in the agenda extension discovered through real-world use with iCal feeds containing recurring events, multi-day all-day events, and non-UTC timezones.

Cache reliability

  • eventCalendars was a useRef — changes didn't trigger re-renders, so calendar name tags on events were stale after a refresh. Changed to useState.
  • Cache never showed last refresh timeloadFromCache wasn't returning the cache timestamp, so the smart refresh timer couldn't align to the last fetch. Fixed.
  • Cache strategy: replaced the hard 5-minute TTL with a background refresh model — the cache is shown immediately on open, then a network refresh runs on the user's configured interval. This avoids a blank screen on every open when the cache has expired.
  • Stale events shown from cache — on load, the cached event list is now filtered through isFutureEvent so events that ended since the cache was saved don't briefly appear before the network refresh completes.

Event visibility

  • isAllDayEvent only recognised 24-hour events — multi-day all-day events (e.g. a 3-day conference) were not identified as all-day. Fixed by checking midnight boundaries rather than exact 24h duration.
  • isFutureEvent used start time — in-progress events (meeting started 10 mins ago, ends in 50 mins) were filtered out. Now uses end time for timed events and end date for all-day events.
  • Multi-day all-day events only appeared on their start dategroupEventsByDate now expands them across every date they span.
  • Past date rows shown for ongoing multi-day events — a 4-day event starting Monday would show Monday/Tuesday rows on Wednesday. Fixed with a render-time filter on date keys.

Recurring events

  • RECURRENCE-ID overrides were ignored — when a single occurrence of a recurring event is rescheduled, the original time was shown instead of the new time. The rrule expansion loop now checks item.recurrences for each occurrence and uses the override if present.
  • In-progress recurring occurrences not shownrrule.between() was called with rangeStart = new Date(), so occurrences that started before the current moment were excluded even if the event was still running. Fixed by using midnight today as rangeStart with an isFutureEvent guard to filter out occurrences that have already ended.
  • Rescheduled occurrences with past original dates missing — if an occurrence's original date falls before rangeStart, rrule.between() never returns it, so the override was never processed. Added a secondary sweep of item.recurrences to catch these.

UX

  • All-day events show "All Day" subtitle instead of empty string
  • Navigation title shows last refresh time
  • Refresh action (using Keyboard.Shortcut.Common.Refresh) available in all list states

Test plan

  • Recurring events show correctly throughout the day, including in-progress occurrences
  • Rescheduled recurring occurrences show at the new time, not the original
  • Multi-day all-day events appear on each day they span
  • Only today-and-future date rows are shown (no stale past rows for ongoing multi-day events)
  • Opening the extension shows cached events immediately with no stale ended events
  • Refresh interval setting is respected; refresh timer aligns to last fetch, not extension open time
  • npm test passes (119 tests)

stvsu added 2 commits March 20, 2026 00:08
The cache was expiring every 5 minutes regardless of the user's configured refresh interval. Additionally, the last-refresh timestamp was not restored from cache, so the refresh timer always started from zero instead of being aligned to when data was last fetched.

Changes:

- Remove CACHE_DURATION time-based expiry; cache is now valid as long as the calendar configuration hasn't changed
- Restore lastRefresh from cached timestamp so the UI shows when data was last fetched even before a network refresh occurs
- Replace useRef with useState for eventCalendars so calendar names render correctly when loading from cache
- Replace fixed setInterval with setTimeout+setInterval so the first background refresh fires relative to cache age, not extension open time
- Split fetchCalendarData into refreshFromNetwork and loadCacheAndRefresh for clarity
Event visibility:
- isAllDayEvent now recognizes multi-day all-day events (not just 24h)
- isFutureEvent uses end time for timed events so in-progress events
  remain visible; uses end date for all-day events so multi-day events
  stay visible until their last day passes
- groupEventsByDate expands multi-day all-day events across all spanned
  dates so they appear under each day in the list
- Past-date section rows are filtered at render time so a multi-day
  event that started earlier in the week doesn't show stale rows

Recurring events:
- RECURRENCE-ID overrides are now applied: when an occurrence is
  rescheduled, the rescheduled time is used instead of the original
- rangeStart for rrule.between() is set to midnight today (wall-clock
  UTC) so in-progress occurrences are included in the expansion;
  isFutureEvent then filters out occurrences that have already ended
- A secondary sweep of item.recurrences catches overrides whose
  original occurrence falls before rangeStart (e.g. rescheduled from
  yesterday to later today)
- All RRULE processing extracted into processCalendarEvents() for
  testability

UX:
- All-day events show "All Day" as the accessory subtitle
- Navigation title shows last refresh time
- Cmd+R refresh action available on all list states

Tests:
- Integration tests for processCalendarEvents using synthetic iCal
  fixture strings covering future/past/in-progress events, in-progress
  recurring occurrences, RECURRENCE-ID overrides, and the sweep path
- Tests run with TZ=UTC for deterministic date arithmetic
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant