Fix frontend to use series endpoint for single occurrence modifications

- Extended update callback signature to include update_scope and occurrence_date parameters
- Modified app.rs to detect when series endpoint should be used vs regular endpoint
- Updated calendar_service to automatically set occurrence_date for "this_only" updates
- Modified all callback emit calls throughout frontend to include new parameters
- Week_view now properly calls series endpoint with "this_only" scope for single occurrence edits

This ensures that single occurrence modifications (RecurringEditAction::ThisEvent)
now go through the proper series endpoint which will:
- Add EXDATE to the original recurring series
- Create exception event with RECURRENCE-ID
- Show proper debug logging in backend

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
Connor Johnstone
2025-08-30 14:01:30 -04:00
parent 071fc3099f
commit a6aac42c78
3 changed files with 96 additions and 39 deletions

View File

@@ -112,27 +112,26 @@ pub fn week_view(props: &WeekViewProps) -> Html {
if let Some(edit) = (*pending_recurring_edit).clone() {
match action {
RecurringEditAction::ThisEvent => {
// Create exception for this occurrence only
// Use the series endpoint with "this_only" scope for RFC 5545 compliant single occurrence modification
// 1. First, add EXDATE to the original series to exclude this occurrence
web_sys::console::log_1(&format!("🎯 Single occurrence modification: calling series update with this_only scope for event '{}'",
edit.event.summary.as_deref().unwrap_or("Untitled")
).into());
// TODO: Need to call calendar service directly with update_scope "this_only" and occurrence_date
// For now, fall back to the old method but with better logging
if let Some(update_callback) = &on_event_update {
let mut updated_series = edit.event.clone();
updated_series.exdate.push(edit.event.dtstart);
// This currently goes to regular update endpoint, but we need it to go to series endpoint
// with update_scope: "this_only" and occurrence_date: edit.event.dtstart.format("%Y-%m-%d")
let updated_event = edit.event.clone();
// Keep the original series times unchanged - we're only adding EXDATE
let original_start = edit.event.dtstart.with_timezone(&chrono::Local).naive_local();
let original_end = edit.event.dtend.unwrap_or(edit.event.dtstart).with_timezone(&chrono::Local).naive_local();
web_sys::console::log_1(&format!("⚠️ Using regular update callback - this should be changed to use series endpoint with this_only scope").into());
web_sys::console::log_1(&format!("📅 Adding EXDATE {} to series '{}'",
edit.event.dtstart.format("%Y-%m-%d %H:%M:%S UTC"),
edit.event.summary.as_deref().unwrap_or("Untitled")
).into());
// Update the original series with the exception (times unchanged)
update_callback.emit((updated_series, original_start, original_end, true, None)); // preserve_rrule = true for EXDATE, no until_date
update_callback.emit((updated_event, edit.new_start, edit.new_end, true, None, Some("this_only".to_string()), Some(edit.event.dtstart.format("%Y-%m-%d").to_string()))); // preserve_rrule = true, update_scope = this_only
}
// 2. Then create the new single event using the create callback
// Note: The proper fix requires calling calendar_service.update_event_with_scope() directly
// with update_scope: "this_only" and occurrence_date
if let Some(create_callback) = &on_create_event_request {
// Convert to EventCreationData for single event
let event_data = EventCreationData {
@@ -272,7 +271,7 @@ pub fn week_view(props: &WeekViewProps) -> Html {
let series_event = edit.event.clone();
if let Some(callback) = &on_event_update {
callback.emit((series_event, edit.new_start, edit.new_end, true, None)); // Regular drag operation - preserve RRULE, no until_date
callback.emit((series_event, edit.new_start, edit.new_end, true, None, Some("all_in_series".to_string()), None)); // Regular drag operation - preserve RRULE, update_scope = all_in_series
}
},
}

View File

@@ -929,8 +929,13 @@ impl CalendarService {
"recurrence_end_date": until_date.as_ref().map(|dt| dt.format("%Y-%m-%d").to_string()),
"recurrence_count": None as Option<u32>, // No count limit by default
"calendar_path": calendar_path,
"update_scope": update_scope,
"occurrence_date": None as Option<String> // For specific occurrence updates
"update_scope": update_scope.clone(),
"occurrence_date": if update_scope == "this_only" {
// For single occurrence updates, use the original event's start date as occurrence_date
Some(start_date.clone())
} else {
None
}
});
let url = format!("{}/calendar/events/series/update", self.base_url);
(body, url)