Implement complete recurring event deletion with EXDATE and RRULE UNTIL support
Frontend Changes: - Add DeleteAction enum with DeleteThis, DeleteFollowing, DeleteSeries options - Update EventContextMenu to show different delete options for recurring events - Add exception_dates field to CalendarEvent struct - Fix occurrence generation to respect EXDATE exclusions - Add comprehensive RRULE parsing with UNTIL date support - Fix UNTIL date parsing to handle backend format (YYYYMMDDTHHMMSSZ) - Enhanced debugging for RRULE processing and occurrence generation Backend Changes: - Add exception_dates field to CalendarEvent struct with EXDATE parsing/generation - Implement update_event method for CalDAV client - Add fetch_event_by_href helper function - Update DeleteEventRequest model with delete_action and occurrence_date fields - Implement proper delete_this logic with EXDATE addition - Implement delete_following logic with RRULE UNTIL modification - Add comprehensive logging for delete operations CalDAV Integration: - Proper EXDATE generation in iCal format for excluded occurrences - RRULE modification with UNTIL clause for partial series deletion - Event updating via CalDAV PUT operations - Full iCal RFC 5545 compliance for recurring event modifications 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
		| @@ -1,12 +1,21 @@ | ||||
| use yew::prelude::*; | ||||
| use web_sys::MouseEvent; | ||||
| use crate::services::calendar_service::CalendarEvent; | ||||
|  | ||||
| #[derive(Clone, PartialEq, Debug)] | ||||
| pub enum DeleteAction { | ||||
|     DeleteThis, | ||||
|     DeleteFollowing, | ||||
|     DeleteSeries, | ||||
| } | ||||
|  | ||||
| #[derive(Properties, PartialEq)] | ||||
| pub struct EventContextMenuProps { | ||||
|     pub is_open: bool, | ||||
|     pub x: i32, | ||||
|     pub y: i32, | ||||
|     pub on_delete: Callback<MouseEvent>, | ||||
|     pub event: Option<CalendarEvent>, | ||||
|     pub on_delete: Callback<DeleteAction>, | ||||
|     pub on_close: Callback<()>, | ||||
| } | ||||
|  | ||||
| @@ -23,11 +32,16 @@ pub fn event_context_menu(props: &EventContextMenuProps) -> Html { | ||||
|         props.x, props.y | ||||
|     ); | ||||
|  | ||||
|     let on_delete_click = { | ||||
|     // Check if the event is recurring | ||||
|     let is_recurring = props.event.as_ref() | ||||
|         .map(|event| event.recurrence_rule.is_some()) | ||||
|         .unwrap_or(false); | ||||
|  | ||||
|     let create_delete_callback = |action: DeleteAction| { | ||||
|         let on_delete = props.on_delete.clone(); | ||||
|         let on_close = props.on_close.clone(); | ||||
|         Callback::from(move |e: MouseEvent| { | ||||
|             on_delete.emit(e); | ||||
|         Callback::from(move |_: MouseEvent| { | ||||
|             on_delete.emit(action.clone()); | ||||
|             on_close.emit(()); | ||||
|         }) | ||||
|     }; | ||||
| @@ -38,10 +52,33 @@ pub fn event_context_menu(props: &EventContextMenuProps) -> Html { | ||||
|             class="context-menu"  | ||||
|             style={style} | ||||
|         > | ||||
|             <div class="context-menu-item context-menu-delete" onclick={on_delete_click}> | ||||
|                 <span class="context-menu-icon">{"🗑️"}</span> | ||||
|                 {"Delete Event"} | ||||
|             </div> | ||||
|             { | ||||
|                 if is_recurring { | ||||
|                     html! { | ||||
|                         <> | ||||
|                             <div class="context-menu-item context-menu-delete" onclick={create_delete_callback(DeleteAction::DeleteThis)}> | ||||
|                                 <span class="context-menu-icon">{"🗑️"}</span> | ||||
|                                 {"Delete This Event"} | ||||
|                             </div> | ||||
|                             <div class="context-menu-item context-menu-delete" onclick={create_delete_callback(DeleteAction::DeleteFollowing)}> | ||||
|                                 <span class="context-menu-icon">{"🗑️"}</span> | ||||
|                                 {"Delete Following Events"} | ||||
|                             </div> | ||||
|                             <div class="context-menu-item context-menu-delete" onclick={create_delete_callback(DeleteAction::DeleteSeries)}> | ||||
|                                 <span class="context-menu-icon">{"🗑️"}</span> | ||||
|                                 {"Delete Entire Series"} | ||||
|                             </div> | ||||
|                         </> | ||||
|                     } | ||||
|                 } else { | ||||
|                     html! { | ||||
|                         <div class="context-menu-item context-menu-delete" onclick={create_delete_callback(DeleteAction::DeleteThis)}> | ||||
|                             <span class="context-menu-icon">{"🗑️"}</span> | ||||
|                             {"Delete Event"} | ||||
|                         </div> | ||||
|                     } | ||||
|                 } | ||||
|             } | ||||
|         </div> | ||||
|     } | ||||
| } | ||||
		Reference in New Issue
	
	Block a user
	 Connor Johnstone
					Connor Johnstone