Fix timezone handling for drag-and-drop and recurring event updates
- Fix double timezone conversion in drag-and-drop that caused 4-hour time shifts - Frontend now sends local times instead of UTC to backend for proper conversion - Add missing timezone parameter to update_series method to fix recurring event updates - Update both event modal and drag-and-drop paths to include timezone information - Maintain RFC 5545 compliance with proper timezone conversion in backend 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
		| @@ -759,6 +759,7 @@ pub fn App() -> Html { | ||||
|                                     params.17, // calendar_path | ||||
|                                     scope, | ||||
|                                     event_data_for_update.occurrence_date.map(|d| d.format("%Y-%m-%d").to_string()), // occurrence_date | ||||
|                                     params.20, // timezone | ||||
|                                 ) | ||||
|                                 .await | ||||
|                         } else { | ||||
| @@ -789,6 +790,7 @@ pub fn App() -> Html { | ||||
|                                     vec![], // exception_dates - empty for simple updates | ||||
|                                     None,   // update_action - None for regular updates | ||||
|                                     None,   // until_date - None for regular updates | ||||
|                                     params.20, // timezone | ||||
|                                 ) | ||||
|                                 .await | ||||
|                         }; | ||||
| @@ -875,6 +877,7 @@ pub fn App() -> Html { | ||||
|                             params.18, // recurrence_count | ||||
|                             params.19, // recurrence_until | ||||
|                             params.17, // calendar_path | ||||
|                             params.20, // timezone | ||||
|                         ) | ||||
|                         .await; | ||||
|                     match create_result { | ||||
| @@ -915,7 +918,7 @@ pub fn App() -> Html { | ||||
|                 chrono::NaiveDateTime, | ||||
|                 chrono::NaiveDateTime, | ||||
|                 bool, | ||||
|                 Option<chrono::DateTime<chrono::Utc>>, | ||||
|                 Option<chrono::NaiveDateTime>, | ||||
|                 Option<String>, | ||||
|                 Option<String>, | ||||
|             )| { | ||||
| @@ -954,30 +957,13 @@ pub fn App() -> Html { | ||||
|                             String::new() | ||||
|                         }; | ||||
|  | ||||
|                         // Convert local naive datetime to UTC before sending to backend | ||||
|                         use chrono::TimeZone; | ||||
|                         let local_tz = chrono::Local; | ||||
|                          | ||||
|                         let start_utc = local_tz.from_local_datetime(&new_start) | ||||
|                             .single() | ||||
|                             .unwrap_or_else(|| { | ||||
|                                 // Fallback for ambiguous times (DST transitions) | ||||
|                                 local_tz.from_local_datetime(&new_start).earliest().unwrap() | ||||
|                             }) | ||||
|                             .with_timezone(&chrono::Utc); | ||||
|                              | ||||
|                         let end_utc = local_tz.from_local_datetime(&new_end) | ||||
|                             .single() | ||||
|                             .unwrap_or_else(|| { | ||||
|                                 // Fallback for ambiguous times (DST transitions) | ||||
|                                 local_tz.from_local_datetime(&new_end).earliest().unwrap() | ||||
|                             }) | ||||
|                             .with_timezone(&chrono::Utc); | ||||
|  | ||||
|                         let start_date = start_utc.format("%Y-%m-%d").to_string(); | ||||
|                         let start_time = start_utc.format("%H:%M").to_string(); | ||||
|                         let end_date = end_utc.format("%Y-%m-%d").to_string(); | ||||
|                         let end_time = end_utc.format("%H:%M").to_string(); | ||||
|                         // Send local times to backend, which will handle timezone conversion | ||||
|                         let start_date = new_start.format("%Y-%m-%d").to_string(); | ||||
|                         let start_time = new_start.format("%H:%M").to_string(); | ||||
|                         let end_date = new_end.format("%Y-%m-%d").to_string(); | ||||
|                         let end_time = new_end.format("%H:%M").to_string(); | ||||
|  | ||||
|                         // Convert existing event data to string formats for the API | ||||
|                         let status_str = match original_event.status { | ||||
| @@ -1062,6 +1048,14 @@ pub fn App() -> Html { | ||||
|                                             original_event.calendar_path.clone(), | ||||
|                                             scope.clone(), | ||||
|                                             occurrence_date, | ||||
|                                             { | ||||
|                                                 // Get timezone offset | ||||
|                                                 let date = js_sys::Date::new_0(); | ||||
|                                                 let timezone_offset = date.get_timezone_offset(); // Minutes from UTC | ||||
|                                                 let hours = -(timezone_offset as i32) / 60; // Convert to hours, negate for proper sign | ||||
|                                                 let minutes = (timezone_offset as i32).abs() % 60; | ||||
|                                                 format!("{:+03}:{:02}", hours, minutes) // Format as +05:00 or -04:00 | ||||
|                                             }, | ||||
|                                         ) | ||||
|                                         .await, | ||||
|                                 ) | ||||
| @@ -1113,6 +1107,14 @@ pub fn App() -> Html { | ||||
|                                         Some("this_and_future".to_string()) | ||||
|                                     }, | ||||
|                                     until_date, | ||||
|                                     { | ||||
|                                         // Get timezone offset | ||||
|                                         let date = js_sys::Date::new_0(); | ||||
|                                         let timezone_offset = date.get_timezone_offset(); // Minutes from UTC | ||||
|                                         let hours = -(timezone_offset as i32) / 60; // Convert to hours, negate for proper sign | ||||
|                                         let minutes = (timezone_offset as i32).abs() % 60; | ||||
|                                         format!("{:+03}:{:02}", hours, minutes) // Format as +05:00 or -04:00 | ||||
|                                     }, | ||||
|                                 ) | ||||
|                                 .await | ||||
|                         }; | ||||
| @@ -1597,7 +1599,7 @@ pub fn App() -> Html { | ||||
|                                         }; | ||||
|  | ||||
|                                         // Get the occurrence date from the clicked event | ||||
|                                         let occurrence_date = Some(event.dtstart.date_naive().format("%Y-%m-%d").to_string()); | ||||
|                                         let occurrence_date = Some(event.dtstart.date().format("%Y-%m-%d").to_string()); | ||||
|  | ||||
|                                         web_sys::console::log_1(&format!("🔄 Delete action: {}", action_str).into()); | ||||
|                                         web_sys::console::log_1(&format!("🔄 Event UID: {}", event.uid).into()); | ||||
|   | ||||
| @@ -151,54 +151,41 @@ impl EventCreationData { | ||||
|         Option<String>, // calendar_path | ||||
|         Option<u32>, // recurrence_count | ||||
|         Option<String>, // recurrence_until | ||||
|         String, // timezone | ||||
|     ) { | ||||
|         use chrono::{Local, TimeZone}; | ||||
|          | ||||
|         // Convert local date/time to UTC for backend | ||||
|         let (utc_start_date, utc_start_time, utc_end_date, utc_end_time) = if self.all_day { | ||||
|             // For all-day events, just use the dates as-is (no time conversion needed) | ||||
|             ( | ||||
|                 self.start_date.format("%Y-%m-%d").to_string(), | ||||
|                 self.start_time.format("%H:%M").to_string(), | ||||
|                 self.end_date.format("%Y-%m-%d").to_string(), | ||||
|                 self.end_time.format("%H:%M").to_string(), | ||||
|             ) | ||||
|         // Use local date/times and timezone - no UTC conversion | ||||
|         let effective_end_date = if self.end_time == NaiveTime::from_hms_opt(0, 0, 0).unwrap() { | ||||
|             // If end time is midnight (00:00), treat it as beginning of next day | ||||
|             self.end_date + chrono::Duration::days(1) | ||||
|         } else { | ||||
|             // Convert local date/time to UTC, but preserve original local dates | ||||
|             let start_local = Local.from_local_datetime(&self.start_date.and_time(self.start_time)).single(); | ||||
|             let end_local = Local.from_local_datetime(&self.end_date.and_time(self.end_time)).single(); | ||||
|              | ||||
|             if let (Some(start_dt), Some(end_dt)) = (start_local, end_local) { | ||||
|                 let start_utc = start_dt.with_timezone(&chrono::Utc); | ||||
|                 let end_utc = end_dt.with_timezone(&chrono::Utc); | ||||
|                  | ||||
|                 // IMPORTANT: Use original local dates, not UTC dates! | ||||
|                 // This ensures events display on the correct day regardless of timezone conversion | ||||
|                 ( | ||||
|                     self.start_date.format("%Y-%m-%d").to_string(), | ||||
|                     start_utc.format("%H:%M").to_string(), | ||||
|                     self.end_date.format("%Y-%m-%d").to_string(), | ||||
|                     end_utc.format("%H:%M").to_string(), | ||||
|                 ) | ||||
|             } else { | ||||
|                 // Fallback if timezone conversion fails - use local time as-is | ||||
|                 web_sys::console::warn_1(&"⚠️ Failed to convert local time to UTC, using local time".into()); | ||||
|                 ( | ||||
|                     self.start_date.format("%Y-%m-%d").to_string(), | ||||
|                     self.start_time.format("%H:%M").to_string(), | ||||
|                     self.end_date.format("%Y-%m-%d").to_string(), | ||||
|                     self.end_time.format("%H:%M").to_string(), | ||||
|                 ) | ||||
|             } | ||||
|             self.end_date | ||||
|         }; | ||||
|          | ||||
|         // Get the local timezone | ||||
|         let timezone = { | ||||
|             use js_sys::Date; | ||||
|             let date = Date::new_0(); | ||||
|             let timezone_offset = date.get_timezone_offset(); // Minutes from UTC | ||||
|             let hours = -(timezone_offset as i32) / 60; // Convert to hours, negate for proper sign | ||||
|             let minutes = (timezone_offset as i32).abs() % 60; | ||||
|             format!("{:+03}:{:02}", hours, minutes) // Format as +05:00 or -04:00 | ||||
|         }; | ||||
|          | ||||
|         let (start_date, start_time, end_date, end_time) = ( | ||||
|             self.start_date.format("%Y-%m-%d").to_string(), | ||||
|             self.start_time.format("%H:%M").to_string(), | ||||
|             effective_end_date.format("%Y-%m-%d").to_string(), | ||||
|             self.end_time.format("%H:%M").to_string(), | ||||
|         ); | ||||
|          | ||||
|         ( | ||||
|             self.title.clone(), | ||||
|             self.description.clone(), | ||||
|             utc_start_date, | ||||
|             utc_start_time, | ||||
|             utc_end_date, | ||||
|             utc_end_time, | ||||
|             start_date, | ||||
|             start_time, | ||||
|             end_date, | ||||
|             end_time, | ||||
|             self.location.clone(), | ||||
|             self.all_day, | ||||
|             format!("{:?}", self.status).to_uppercase(), | ||||
| @@ -213,6 +200,7 @@ impl EventCreationData { | ||||
|             self.selected_calendar.clone(), | ||||
|             self.recurrence_count, | ||||
|             self.recurrence_until.map(|d| d.format("%Y-%m-%d").to_string()), | ||||
|             timezone, | ||||
|         ) | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -1,4 +1,4 @@ | ||||
| use chrono::{DateTime, Datelike, Duration, NaiveDate, TimeZone, Utc, Weekday}; | ||||
| use chrono::{DateTime, Datelike, Duration, NaiveDate, Utc, Weekday}; | ||||
| use gloo_storage::{LocalStorage, Storage}; | ||||
| use serde::{Deserialize, Serialize}; | ||||
| use std::collections::HashMap; | ||||
| @@ -275,14 +275,60 @@ impl CalendarService { | ||||
|         grouped | ||||
|     } | ||||
|  | ||||
|     /// Convert UTC events to local timezone for display | ||||
|     fn convert_utc_to_local(mut event: VEvent) -> VEvent { | ||||
|         // Check if event times are in UTC (legacy events from before timezone migration) | ||||
|         let is_utc_event = event.dtstart_tzid.as_ref().map_or(true, |tz| tz == "UTC"); | ||||
|          | ||||
|         if is_utc_event { | ||||
|             web_sys::console::log_1(&format!( | ||||
|                 "🕐 Converting UTC event '{}' to local time",  | ||||
|                 event.summary.as_deref().unwrap_or("Untitled") | ||||
|             ).into()); | ||||
|              | ||||
|             // Get current timezone offset (convert from UTC to local) | ||||
|             let date = js_sys::Date::new_0(); | ||||
|             let timezone_offset_minutes = date.get_timezone_offset() as i32; | ||||
|              | ||||
|             // Convert start time from UTC to local | ||||
|             // getTimezoneOffset() returns minutes UTC is ahead of local time | ||||
|             // To convert UTC to local, we subtract the offset (add negative offset) | ||||
|             let local_start = event.dtstart + chrono::Duration::minutes(-timezone_offset_minutes as i64); | ||||
|             event.dtstart = local_start; | ||||
|             event.dtstart_tzid = None; // Clear UTC timezone indicator | ||||
|              | ||||
|             // Convert end time if present | ||||
|             if let Some(end_utc) = event.dtend { | ||||
|                 let local_end = end_utc + chrono::Duration::minutes(-timezone_offset_minutes as i64); | ||||
|                 event.dtend = Some(local_end); | ||||
|                 event.dtend_tzid = None; // Clear UTC timezone indicator | ||||
|             } | ||||
|              | ||||
|             // Convert created/modified times if present | ||||
|             if let Some(created_utc) = event.created { | ||||
|                 event.created = Some(created_utc + chrono::Duration::minutes(-timezone_offset_minutes as i64)); | ||||
|                 event.created_tzid = None; | ||||
|             } | ||||
|              | ||||
|             if let Some(modified_utc) = event.last_modified { | ||||
|                 event.last_modified = Some(modified_utc + chrono::Duration::minutes(-timezone_offset_minutes as i64)); | ||||
|                 event.last_modified_tzid = None; | ||||
|             } | ||||
|         } | ||||
|          | ||||
|         event | ||||
|     } | ||||
|  | ||||
|     /// Expand recurring events using VEvent (RFC 5545 compliant) | ||||
|     pub fn expand_recurring_events(events: Vec<VEvent>) -> Vec<VEvent> { | ||||
|         let mut expanded_events = Vec::new(); | ||||
|         let today = chrono::Utc::now().date_naive(); | ||||
|         let today = chrono::Local::now().date_naive(); | ||||
|         let start_range = today - Duration::days(36500); // Show past 100 years (to catch any historical yearly events) | ||||
|         let end_range = today + Duration::days(36500); // Show next 100 years | ||||
|  | ||||
|         for event in events { | ||||
|             // Convert UTC events to local time for proper display | ||||
|             let event = Self::convert_utc_to_local(event); | ||||
|             if let Some(ref rrule) = event.rrule { | ||||
|                 web_sys::console::log_1( | ||||
|                     &format!( | ||||
| @@ -372,17 +418,18 @@ impl CalendarService { | ||||
|  | ||||
|         // Get UNTIL date if specified | ||||
|         let until_date = components.get("UNTIL").and_then(|until_str| { | ||||
|             // Parse UNTIL date in YYYYMMDDTHHMMSSZ format | ||||
|             // Parse UNTIL date in YYYYMMDDTHHMMSSZ format (treat as local time) | ||||
|             if let Ok(dt) = chrono::NaiveDateTime::parse_from_str( | ||||
|                 until_str.trim_end_matches('Z'), | ||||
|                 "%Y%m%dT%H%M%S", | ||||
|             ) { | ||||
|                 Some(chrono::Utc.from_utc_datetime(&dt)) | ||||
|                 Some(dt) | ||||
|             } else if let Ok(dt) = chrono::DateTime::parse_from_str(until_str, "%Y%m%dT%H%M%SZ") { | ||||
|                 Some(dt.with_timezone(&chrono::Utc)) | ||||
|                 // Convert UTC to local (naive) time for consistency | ||||
|                 Some(dt.naive_utc()) | ||||
|             } else if let Ok(date) = chrono::NaiveDate::parse_from_str(until_str, "%Y%m%d") { | ||||
|                 // Handle date-only UNTIL | ||||
|                 Some(chrono::Utc.from_utc_datetime(&date.and_hms_opt(23, 59, 59).unwrap())) | ||||
|                 Some(date.and_hms_opt(23, 59, 59).unwrap()) | ||||
|             } else { | ||||
|                 web_sys::console::log_1( | ||||
|                     &format!("⚠️ Failed to parse UNTIL date: {}", until_str).into(), | ||||
| @@ -395,7 +442,7 @@ impl CalendarService { | ||||
|             web_sys::console::log_1(&format!("📅 RRULE has UNTIL: {}", until).into()); | ||||
|         } | ||||
|  | ||||
|         let start_date = base_event.dtstart.date_naive(); | ||||
|         let start_date = base_event.dtstart.date(); | ||||
|         let mut current_date = start_date; | ||||
|         let mut occurrence_count = 0; | ||||
|  | ||||
| @@ -422,8 +469,8 @@ impl CalendarService { | ||||
|                 // Check if this occurrence is in the exception dates (EXDATE) | ||||
|                 let is_exception = base_event.exdate.iter().any(|exception_date| { | ||||
|                     // Compare dates ignoring sub-second precision | ||||
|                     let exception_naive = exception_date.naive_utc(); | ||||
|                     let occurrence_naive = occurrence_datetime.naive_utc(); | ||||
|                     let exception_naive = exception_date.and_utc(); | ||||
|                     let occurrence_naive = occurrence_datetime.and_utc(); | ||||
|  | ||||
|                     // Check if dates match (within a minute to handle minor time differences) | ||||
|                     let diff = occurrence_naive - exception_naive; | ||||
| @@ -555,7 +602,7 @@ impl CalendarService { | ||||
|         interval: i32, | ||||
|         start_range: NaiveDate, | ||||
|         end_range: NaiveDate, | ||||
|         until_date: Option<chrono::DateTime<chrono::Utc>>, | ||||
|         until_date: Option<chrono::NaiveDateTime>, | ||||
|         count: usize, | ||||
|     ) -> Vec<VEvent> { | ||||
|         let mut occurrences = Vec::new(); | ||||
| @@ -565,7 +612,7 @@ impl CalendarService { | ||||
|             return occurrences; | ||||
|         } | ||||
|  | ||||
|         let start_date = base_event.dtstart.date_naive(); | ||||
|         let start_date = base_event.dtstart.date(); | ||||
|  | ||||
|         // Find the Monday of the week containing the start_date (reference week) | ||||
|         let reference_week_start = | ||||
| @@ -623,8 +670,8 @@ impl CalendarService { | ||||
|  | ||||
|                 // Check if this occurrence is in the exception dates (EXDATE) | ||||
|                 let is_exception = base_event.exdate.iter().any(|exception_date| { | ||||
|                     let exception_naive = exception_date.naive_utc(); | ||||
|                     let occurrence_naive = occurrence_datetime.naive_utc(); | ||||
|                     let exception_naive = exception_date.and_utc(); | ||||
|                     let occurrence_naive = occurrence_datetime.and_utc(); | ||||
|                     let diff = occurrence_naive - exception_naive; | ||||
|                     let matches = diff.num_seconds().abs() < 60; | ||||
|  | ||||
| @@ -675,7 +722,7 @@ impl CalendarService { | ||||
|         interval: i32, | ||||
|         start_range: NaiveDate, | ||||
|         end_range: NaiveDate, | ||||
|         until_date: Option<chrono::DateTime<chrono::Utc>>, | ||||
|         until_date: Option<chrono::NaiveDateTime>, | ||||
|         count: usize, | ||||
|     ) -> Vec<VEvent> { | ||||
|         let mut occurrences = Vec::new(); | ||||
| @@ -691,7 +738,7 @@ impl CalendarService { | ||||
|             return occurrences; | ||||
|         } | ||||
|  | ||||
|         let start_date = base_event.dtstart.date_naive(); | ||||
|         let start_date = base_event.dtstart.date(); | ||||
|         let mut current_month_start = | ||||
|             NaiveDate::from_ymd_opt(start_date.year(), start_date.month(), 1).unwrap(); | ||||
|         let mut total_occurrences = 0; | ||||
| @@ -749,9 +796,7 @@ impl CalendarService { | ||||
|  | ||||
|                     // Check if this occurrence is in the exception dates (EXDATE) | ||||
|                     let is_exception = base_event.exdate.iter().any(|exception_date| { | ||||
|                         let exception_naive = exception_date.naive_utc(); | ||||
|                         let occurrence_naive = occurrence_datetime.naive_utc(); | ||||
|                         let diff = occurrence_naive - exception_naive; | ||||
|                         let diff = occurrence_datetime - *exception_date; | ||||
|                         diff.num_seconds().abs() < 60 | ||||
|                     }); | ||||
|  | ||||
| @@ -792,14 +837,14 @@ impl CalendarService { | ||||
|         interval: i32, | ||||
|         start_range: NaiveDate, | ||||
|         end_range: NaiveDate, | ||||
|         until_date: Option<chrono::DateTime<chrono::Utc>>, | ||||
|         until_date: Option<chrono::NaiveDateTime>, | ||||
|         count: usize, | ||||
|     ) -> Vec<VEvent> { | ||||
|         let mut occurrences = Vec::new(); | ||||
|  | ||||
|         // Parse BYDAY for monthly (e.g., "1MO" = first Monday, "-1FR" = last Friday) | ||||
|         if let Some((position, weekday)) = Self::parse_monthly_byday(byday) { | ||||
|             let start_date = base_event.dtstart.date_naive(); | ||||
|             let start_date = base_event.dtstart.date(); | ||||
|             let mut current_month_start = | ||||
|                 NaiveDate::from_ymd_opt(start_date.year(), start_date.month(), 1).unwrap(); | ||||
|             let mut total_occurrences = 0; | ||||
| @@ -830,9 +875,7 @@ impl CalendarService { | ||||
|  | ||||
|                         // Check EXDATE | ||||
|                         let is_exception = base_event.exdate.iter().any(|exception_date| { | ||||
|                             let exception_naive = exception_date.naive_utc(); | ||||
|                             let occurrence_naive = occurrence_datetime.naive_utc(); | ||||
|                             let diff = occurrence_naive - exception_naive; | ||||
|                             let diff = occurrence_datetime - *exception_date; | ||||
|                             diff.num_seconds().abs() < 60 | ||||
|                         }); | ||||
|  | ||||
| @@ -871,7 +914,7 @@ impl CalendarService { | ||||
|         interval: i32, | ||||
|         start_range: NaiveDate, | ||||
|         end_range: NaiveDate, | ||||
|         until_date: Option<chrono::DateTime<chrono::Utc>>, | ||||
|         until_date: Option<chrono::NaiveDateTime>, | ||||
|         count: usize, | ||||
|     ) -> Vec<VEvent> { | ||||
|         let mut occurrences = Vec::new(); | ||||
| @@ -887,7 +930,7 @@ impl CalendarService { | ||||
|             return occurrences; | ||||
|         } | ||||
|  | ||||
|         let start_date = base_event.dtstart.date_naive(); | ||||
|         let start_date = base_event.dtstart.date(); | ||||
|         let mut current_year = start_date.year(); | ||||
|         let mut total_occurrences = 0; | ||||
|  | ||||
| @@ -930,9 +973,7 @@ impl CalendarService { | ||||
|  | ||||
|                     // Check EXDATE | ||||
|                     let is_exception = base_event.exdate.iter().any(|exception_date| { | ||||
|                         let exception_naive = exception_date.naive_utc(); | ||||
|                         let occurrence_naive = occurrence_datetime.naive_utc(); | ||||
|                         let diff = occurrence_naive - exception_naive; | ||||
|                         let diff = occurrence_datetime - *exception_date; | ||||
|                         diff.num_seconds().abs() < 60 | ||||
|                     }); | ||||
|  | ||||
| @@ -1260,6 +1301,7 @@ impl CalendarService { | ||||
|         recurrence_count: Option<u32>, | ||||
|         recurrence_until: Option<String>, | ||||
|         calendar_path: Option<String>, | ||||
|         timezone: String, | ||||
|     ) -> Result<(), String> { | ||||
|         let window = web_sys::window().ok_or("No global window exists")?; | ||||
|  | ||||
| @@ -1293,7 +1335,8 @@ impl CalendarService { | ||||
|                 "recurrence_interval": 1_u32, // Default interval | ||||
|                 "recurrence_end_date": recurrence_until, | ||||
|                 "recurrence_count": recurrence_count, | ||||
|                 "calendar_path": calendar_path | ||||
|                 "calendar_path": calendar_path, | ||||
|                 "timezone": timezone | ||||
|             }); | ||||
|             let url = format!("{}/calendar/events/series/create", self.base_url); | ||||
|             (body, url) | ||||
| @@ -1317,7 +1360,8 @@ impl CalendarService { | ||||
|                 "reminder": reminder, | ||||
|                 "recurrence": recurrence, | ||||
|                 "recurrence_days": recurrence_days, | ||||
|                 "calendar_path": calendar_path | ||||
|                 "calendar_path": calendar_path, | ||||
|                 "timezone": timezone | ||||
|             }); | ||||
|             let url = format!("{}/calendar/events/create", self.base_url); | ||||
|             (body, url) | ||||
| @@ -1395,9 +1439,10 @@ impl CalendarService { | ||||
|         recurrence: String, | ||||
|         recurrence_days: Vec<bool>, | ||||
|         calendar_path: Option<String>, | ||||
|         exception_dates: Vec<DateTime<Utc>>, | ||||
|         exception_dates: Vec<chrono::NaiveDateTime>, | ||||
|         update_action: Option<String>, | ||||
|         until_date: Option<DateTime<Utc>>, | ||||
|         until_date: Option<chrono::NaiveDateTime>, | ||||
|         timezone: String, | ||||
|     ) -> Result<(), String> { | ||||
|         // Forward to update_event_with_scope with default scope | ||||
|         self.update_event_with_scope( | ||||
| @@ -1425,6 +1470,7 @@ impl CalendarService { | ||||
|             exception_dates, | ||||
|             update_action, | ||||
|             until_date, | ||||
|             timezone, | ||||
|         ) | ||||
|         .await | ||||
|     } | ||||
| @@ -1452,9 +1498,10 @@ impl CalendarService { | ||||
|         recurrence: String, | ||||
|         recurrence_days: Vec<bool>, | ||||
|         calendar_path: Option<String>, | ||||
|         exception_dates: Vec<DateTime<Utc>>, | ||||
|         exception_dates: Vec<chrono::NaiveDateTime>, | ||||
|         update_action: Option<String>, | ||||
|         until_date: Option<DateTime<Utc>>, | ||||
|         until_date: Option<chrono::NaiveDateTime>, | ||||
|         timezone: String, | ||||
|     ) -> Result<(), String> { | ||||
|         let window = web_sys::window().ok_or("No global window exists")?; | ||||
|  | ||||
| @@ -1485,8 +1532,9 @@ impl CalendarService { | ||||
|             "calendar_path": calendar_path, | ||||
|             "update_action": update_action, | ||||
|             "occurrence_date": null, | ||||
|             "exception_dates": exception_dates.iter().map(|dt| dt.to_rfc3339()).collect::<Vec<String>>(), | ||||
|             "until_date": until_date.as_ref().map(|dt| dt.to_rfc3339()) | ||||
|             "exception_dates": exception_dates.iter().map(|dt| dt.format("%Y-%m-%dT%H:%M:%S").to_string()).collect::<Vec<String>>(), | ||||
|             "until_date": until_date.as_ref().map(|dt| dt.format("%Y-%m-%dT%H:%M:%S").to_string()), | ||||
|             "timezone": timezone | ||||
|         }); | ||||
|         let url = format!("{}/calendar/events/update", self.base_url); | ||||
|  | ||||
| @@ -1692,6 +1740,7 @@ impl CalendarService { | ||||
|         calendar_path: Option<String>, | ||||
|         update_scope: String, | ||||
|         occurrence_date: Option<String>, | ||||
|         timezone: String, | ||||
|     ) -> Result<(), String> { | ||||
|         let window = web_sys::window().ok_or("No global window exists")?; | ||||
|  | ||||
| @@ -1723,7 +1772,8 @@ impl CalendarService { | ||||
|             "recurrence_count": recurrence_count, | ||||
|             "calendar_path": calendar_path, | ||||
|             "update_scope": update_scope, | ||||
|             "occurrence_date": occurrence_date | ||||
|             "occurrence_date": occurrence_date, | ||||
|             "timezone": timezone | ||||
|         }); | ||||
|  | ||||
|         let url = format!("{}/calendar/events/series/update", self.base_url); | ||||
|   | ||||
		Reference in New Issue
	
	Block a user
	 Connor Johnstone
					Connor Johnstone