Fix multi-day all-day events to display across all days they span

All-day events spanning multiple days were only showing on their start date.
For example, a "Vacation (Dec 20-25)" event would only appear on Dec 20th.

Root cause: Logic only checked events stored in each day's HashMap entry,
missing events that span into other days.

Solution:
- Modified all-day event collection to search all events across all days
- Added event_spans_date() helper function to check if event spans given date
- Properly handles iCalendar dtend convention (day after event ends)
- Added deduplication to prevent duplicate events from multiple day buckets
- Removed unused day_events variable

Result: Multi-day all-day events now correctly appear on every day they span,
while single-day events continue to work as before.

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
Connor Johnstone
2025-09-03 16:31:25 -04:00
parent 5ea33b7d0a
commit 53c4a99697

View File

@@ -316,10 +316,19 @@ pub fn week_view(props: &WeekViewProps) -> Html {
week_days.iter().map(|date| { week_days.iter().map(|date| {
let is_today = *date == props.today; let is_today = *date == props.today;
let weekday_name = get_weekday_name(date.weekday()); let weekday_name = get_weekday_name(date.weekday());
let day_events = props.events.get(date).cloned().unwrap_or_default();
// Filter for all-day events only // Collect all-day events that span this date (from any day in the week)
let all_day_events: Vec<_> = day_events.iter().filter(|event| event.all_day).collect(); let mut all_day_events: Vec<&VEvent> = Vec::new();
for events_list in props.events.values() {
for event in events_list {
if event.all_day && event_spans_date(event, *date) {
all_day_events.push(event);
}
}
}
// Remove duplicates (same event might appear in multiple day buckets)
all_day_events.sort_by_key(|e| &e.uid);
all_day_events.dedup_by_key(|e| &e.uid);
html! { html! {
<div class={classes!("week-day-header", if is_today { Some("today") } else { None })}> <div class={classes!("week-day-header", if is_today { Some("today") } else { None })}>
@@ -1308,3 +1317,19 @@ fn calculate_event_layout(events: &[VEvent], date: NaiveDate, time_increment: u3
event_columns event_columns
} }
// Check if an all-day event spans the given date
fn event_spans_date(event: &VEvent, date: NaiveDate) -> bool {
let start_date = event.dtstart.with_timezone(&Local).date_naive();
let end_date = if let Some(dtend) = event.dtend {
// For all-day events, dtend is often set to the day after the last day
// So we need to subtract a day to get the actual last day of the event
dtend.with_timezone(&Local).date_naive() - chrono::Duration::days(1)
} else {
// Single day event
start_date
};
// Check if the given date falls within the event's date range
date >= start_date && date <= end_date
}