Files
calendar/src/components/recurring_edit_modal.rs
Connor Johnstone 81805289e4 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>
2025-08-29 15:22:34 -04:00

93 lines
3.3 KiB
Rust

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>
}
}