- 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>
93 lines
3.3 KiB
Rust
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>
|
|
}
|
|
} |