diff --git a/backend/src/calendar.rs b/backend/src/calendar.rs index c157697..741b511 100644 --- a/backend/src/calendar.rs +++ b/backend/src/calendar.rs @@ -361,11 +361,12 @@ impl CalDAVClient { None }; - // Determine if it's an all-day event - let all_day = properties - .get("DTSTART") - .map(|s| !s.contains("T")) - .unwrap_or(false); + // Determine if it's an all-day event by checking for VALUE=DATE parameter + let empty_string = String::new(); + let dtstart_raw = properties.get("DTSTART").unwrap_or(&empty_string); + let all_day = dtstart_raw.contains("VALUE=DATE") || (!dtstart_raw.contains("T") && dtstart_raw.len() == 8); + + eprintln!("🔍 DTSTART parsing: '{}' -> all_day: {}", dtstart_raw, all_day); // Parse status let status = properties diff --git a/backend/src/handlers/events.rs b/backend/src/handlers/events.rs index 0010720..0290d6d 100644 --- a/backend/src/handlers/events.rs +++ b/backend/src/handlers/events.rs @@ -458,9 +458,15 @@ pub async fn create_event( parse_event_datetime(&request.start_date, &request.start_time, request.all_day) .map_err(|e| ApiError::BadRequest(format!("Invalid start date/time: {}", e)))?; - let end_datetime = parse_event_datetime(&request.end_date, &request.end_time, request.all_day) + let mut end_datetime = parse_event_datetime(&request.end_date, &request.end_time, request.all_day) .map_err(|e| ApiError::BadRequest(format!("Invalid end date/time: {}", e)))?; + // For all-day events, add one day to end date for RFC-5545 compliance + // RFC-5545 uses exclusive end dates for all-day events + if request.all_day { + end_datetime = end_datetime + chrono::Duration::days(1); + } + // Validate that end is after start (allow equal times for all-day events) if request.all_day { if end_datetime < start_datetime { @@ -756,9 +762,15 @@ pub async fn update_event( parse_event_datetime(&request.start_date, &request.start_time, request.all_day) .map_err(|e| ApiError::BadRequest(format!("Invalid start date/time: {}", e)))?; - let end_datetime = parse_event_datetime(&request.end_date, &request.end_time, request.all_day) + let mut end_datetime = parse_event_datetime(&request.end_date, &request.end_time, request.all_day) .map_err(|e| ApiError::BadRequest(format!("Invalid end date/time: {}", e)))?; + // For all-day events, add one day to end date for RFC-5545 compliance + // RFC-5545 uses exclusive end dates for all-day events + if request.all_day { + end_datetime = end_datetime + chrono::Duration::days(1); + } + // Validate that end is after start (allow equal times for all-day events) if request.all_day { if end_datetime < start_datetime { diff --git a/backend/src/handlers/series.rs b/backend/src/handlers/series.rs index 945881b..92082b5 100644 --- a/backend/src/handlers/series.rs +++ b/backend/src/handlers/series.rs @@ -175,6 +175,7 @@ pub async fn create_event_series( // Create the VEvent for the series let mut event = VEvent::new(uid.clone(), start_datetime); event.dtend = Some(end_datetime); + event.all_day = request.all_day; // Set the all_day flag properly event.summary = if request.title.trim().is_empty() { None } else { diff --git a/frontend/src/components/event_modal.rs b/frontend/src/components/event_modal.rs index 941c249..bc1723e 100644 --- a/frontend/src/components/event_modal.rs +++ b/frontend/src/components/event_modal.rs @@ -63,7 +63,7 @@ pub fn EventModal(props: &EventModalProps) -> Html { html! {