Implement complete recurring event drag modification system
- Add recurring edit modal with three modification options: • "Only this event" - Creates exception for single occurrence • "This and future events" - Splits series from occurrence forward • "All occurrences in this series" - Updates entire series time - Enhance backend update API to support series modifications: • Add update_action parameter for recurring event operations • Implement time-only updates that preserve original start dates • Convert timestamped occurrence UIDs to base UIDs for series updates • Preserve recurrence rules during series modifications - Fix recurring event drag operations: • Show modal for recurring events instead of direct updates • Handle EXDATE creation for single occurrence modifications • Support series splitting with UNTIL clause modifications • Maintain proper UID management for different modification types - Clean up debug logging and restore page refresh for data consistency 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
		
							
								
								
									
										93
									
								
								src/components/recurring_edit_modal.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										93
									
								
								src/components/recurring_edit_modal.rs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,93 @@ | ||||
| use yew::prelude::*; | ||||
| use chrono::NaiveDateTime; | ||||
| use crate::services::calendar_service::CalendarEvent; | ||||
|  | ||||
| #[derive(Clone, PartialEq)] | ||||
| pub enum RecurringEditAction { | ||||
|     ThisEvent, | ||||
|     FutureEvents, | ||||
|     AllEvents, | ||||
| } | ||||
|  | ||||
| #[derive(Properties, PartialEq)] | ||||
| pub struct RecurringEditModalProps { | ||||
|     pub show: bool, | ||||
|     pub event: CalendarEvent, | ||||
|     pub new_start: NaiveDateTime, | ||||
|     pub new_end: NaiveDateTime, | ||||
|     pub on_choice: Callback<RecurringEditAction>, | ||||
|     pub on_cancel: Callback<()>, | ||||
| } | ||||
|  | ||||
| #[function_component(RecurringEditModal)] | ||||
| pub fn recurring_edit_modal(props: &RecurringEditModalProps) -> Html { | ||||
|     if !props.show { | ||||
|         return html! {}; | ||||
|     } | ||||
|  | ||||
|     let event_title = props.event.summary.as_ref().map(|s| s.as_str()).unwrap_or("Untitled Event"); | ||||
|      | ||||
|     let on_this_event = { | ||||
|         let on_choice = props.on_choice.clone(); | ||||
|         Callback::from(move |_| { | ||||
|             on_choice.emit(RecurringEditAction::ThisEvent); | ||||
|         }) | ||||
|     }; | ||||
|      | ||||
|     let on_future_events = { | ||||
|         let on_choice = props.on_choice.clone(); | ||||
|         Callback::from(move |_| { | ||||
|             on_choice.emit(RecurringEditAction::FutureEvents); | ||||
|         }) | ||||
|     }; | ||||
|      | ||||
|     let on_all_events = { | ||||
|         let on_choice = props.on_choice.clone(); | ||||
|         Callback::from(move |_| { | ||||
|             on_choice.emit(RecurringEditAction::AllEvents); | ||||
|         }) | ||||
|     }; | ||||
|      | ||||
|     let on_cancel = { | ||||
|         let on_cancel = props.on_cancel.clone(); | ||||
|         Callback::from(move |_| { | ||||
|             on_cancel.emit(()); | ||||
|         }) | ||||
|     }; | ||||
|  | ||||
|     html! { | ||||
|         <div class="modal-backdrop"> | ||||
|             <div class="modal-content recurring-edit-modal"> | ||||
|                 <div class="modal-header"> | ||||
|                     <h3>{"Edit Recurring Event"}</h3> | ||||
|                 </div> | ||||
|                 <div class="modal-body"> | ||||
|                     <p>{format!("You're modifying \"{}\" which is part of a recurring series.", event_title)}</p> | ||||
|                     <p>{"How would you like to apply this change?"}</p> | ||||
|                      | ||||
|                     <div class="recurring-edit-options"> | ||||
|                         <button class="btn btn-primary recurring-option" onclick={on_this_event}> | ||||
|                             <div class="option-title">{"This event only"}</div> | ||||
|                             <div class="option-description">{"Change only this occurrence"}</div> | ||||
|                         </button> | ||||
|                          | ||||
|                         <button class="btn btn-primary recurring-option" onclick={on_future_events}> | ||||
|                             <div class="option-title">{"This and future events"}</div> | ||||
|                             <div class="option-description">{"Change this occurrence and all future occurrences"}</div> | ||||
|                         </button> | ||||
|                          | ||||
|                         <button class="btn btn-primary recurring-option" onclick={on_all_events}> | ||||
|                             <div class="option-title">{"All events in series"}</div> | ||||
|                             <div class="option-description">{"Change all occurrences in the series"}</div> | ||||
|                         </button> | ||||
|                     </div> | ||||
|                 </div> | ||||
|                 <div class="modal-footer"> | ||||
|                     <button class="btn btn-secondary" onclick={on_cancel}> | ||||
|                         {"Cancel"} | ||||
|                     </button> | ||||
|                 </div> | ||||
|             </div> | ||||
|         </div> | ||||
|     } | ||||
| } | ||||
		Reference in New Issue
	
	Block a user
	 Connor Johnstone
					Connor Johnstone