Fix single event deletion functionality with proper recurring vs non-recurring handling

This commit resolves multiple issues with event deletion:

Backend fixes:
- Fix CalDAV URL construction for DELETE requests (missing slash separator)
- Improve event lookup by href with exact matching and fallback to UID extraction
- Add support for both RFC3339 and simple YYYY-MM-DD date formats in occurrence parsing
- Implement proper logic to distinguish recurring vs non-recurring events in delete_this action
- For non-recurring events: delete entire event from CalDAV server
- For recurring events: add EXDATE to exclude specific occurrences
- Add comprehensive debug logging for troubleshooting deletion issues

Frontend fixes:
- Update callback signatures to support series endpoint parameters (7-parameter tuples)
- Add update_series method to CalendarService for series-specific operations
- Route single occurrence modifications through series endpoint with proper scoping
- Fix all component prop definitions to use new callback signature
- Update all emit calls to pass correct number of parameters

The deletion process now works correctly:
- Single events are completely removed from the calendar
- Recurring event occurrences are properly excluded via EXDATE
- Debug logging helps identify and resolve CalDAV communication issues

🤖 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 18:40:48 -04:00
parent a6aac42c78
commit ee1c6ee299
7 changed files with 267 additions and 93 deletions

View File

@@ -25,7 +25,7 @@ pub struct CalendarProps {
#[prop_or_default]
pub on_create_event_request: Option<Callback<EventCreationData>>,
#[prop_or_default]
pub on_event_update_request: Option<Callback<(VEvent, chrono::NaiveDateTime, chrono::NaiveDateTime, bool, Option<chrono::DateTime<chrono::Utc>>)>>,
pub on_event_update_request: Option<Callback<(VEvent, chrono::NaiveDateTime, chrono::NaiveDateTime, bool, Option<chrono::DateTime<chrono::Utc>>, Option<String>, Option<String>)>>,
#[prop_or_default]
pub context_menus_open: bool,
}
@@ -195,9 +195,9 @@ pub fn Calendar(props: &CalendarProps) -> Html {
// Handle drag-to-move event
let on_event_update = {
let on_event_update_request = props.on_event_update_request.clone();
Callback::from(move |(event, new_start, new_end, preserve_rrule, until_date): (VEvent, chrono::NaiveDateTime, chrono::NaiveDateTime, bool, Option<chrono::DateTime<chrono::Utc>>)| {
Callback::from(move |(event, new_start, new_end, preserve_rrule, until_date, update_scope, occurrence_date): (VEvent, chrono::NaiveDateTime, chrono::NaiveDateTime, bool, Option<chrono::DateTime<chrono::Utc>>, Option<String>, Option<String>)| {
if let Some(callback) = &on_event_update_request {
callback.emit((event, new_start, new_end, preserve_rrule, until_date));
callback.emit((event, new_start, new_end, preserve_rrule, until_date, update_scope, occurrence_date));
}
})
};

View File

@@ -28,7 +28,7 @@ pub struct RouteHandlerProps {
#[prop_or_default]
pub on_create_event_request: Option<Callback<crate::components::EventCreationData>>,
#[prop_or_default]
pub on_event_update_request: Option<Callback<(VEvent, chrono::NaiveDateTime, chrono::NaiveDateTime, bool, Option<chrono::DateTime<chrono::Utc>>)>>,
pub on_event_update_request: Option<Callback<(VEvent, chrono::NaiveDateTime, chrono::NaiveDateTime, bool, Option<chrono::DateTime<chrono::Utc>>, Option<String>, Option<String>)>>,
#[prop_or_default]
pub context_menus_open: bool,
}
@@ -106,7 +106,7 @@ pub struct CalendarViewProps {
#[prop_or_default]
pub on_create_event_request: Option<Callback<crate::components::EventCreationData>>,
#[prop_or_default]
pub on_event_update_request: Option<Callback<(VEvent, chrono::NaiveDateTime, chrono::NaiveDateTime, bool, Option<chrono::DateTime<chrono::Utc>>)>>,
pub on_event_update_request: Option<Callback<(VEvent, chrono::NaiveDateTime, chrono::NaiveDateTime, bool, Option<chrono::DateTime<chrono::Utc>>, Option<String>, Option<String>)>>,
#[prop_or_default]
pub context_menus_open: bool,
}

View File

@@ -25,7 +25,7 @@ pub struct WeekViewProps {
#[prop_or_default]
pub on_create_event_request: Option<Callback<EventCreationData>>,
#[prop_or_default]
pub on_event_update: Option<Callback<(VEvent, NaiveDateTime, NaiveDateTime, bool, Option<chrono::DateTime<chrono::Utc>>)>>,
pub on_event_update: Option<Callback<(VEvent, NaiveDateTime, NaiveDateTime, bool, Option<chrono::DateTime<chrono::Utc>>, Option<String>, Option<String>)>>,
#[prop_or_default]
pub context_menus_open: bool,
#[prop_or_default]
@@ -221,7 +221,7 @@ pub fn week_view(props: &WeekViewProps) -> Html {
let original_end = original_series.dtend.unwrap_or(original_series.dtstart).with_timezone(&chrono::Local).naive_local();
// Send until_date to backend instead of modifying RRULE on frontend
update_callback.emit((original_series, original_start, original_end, true, Some(until_utc))); // preserve_rrule = true, backend will add UNTIL
update_callback.emit((original_series, original_start, original_end, true, Some(until_utc), Some("this_and_future".to_string()), None)); // preserve_rrule = true, backend will add UNTIL
}
// 2. Create new series starting from this occurrence with modified times
@@ -465,7 +465,7 @@ pub fn week_view(props: &WeekViewProps) -> Html {
} else {
// Regular event - proceed with update
if let Some(callback) = &on_event_update {
callback.emit((event.clone(), new_start_datetime, new_end_datetime, true, None)); // Regular drag operation - preserve RRULE, no until_date
callback.emit((event.clone(), new_start_datetime, new_end_datetime, true, None, None, None)); // Regular drag operation - preserve RRULE, no until_date
}
}
},
@@ -501,7 +501,7 @@ pub fn week_view(props: &WeekViewProps) -> Html {
} else {
// Regular event - proceed with update
if let Some(callback) = &on_event_update {
callback.emit((event.clone(), new_start_datetime, new_end_datetime, true, None)); // Regular drag operation - preserve RRULE, no until_date
callback.emit((event.clone(), new_start_datetime, new_end_datetime, true, None, None, None)); // Regular drag operation - preserve RRULE, no until_date
}
}
},
@@ -532,7 +532,7 @@ pub fn week_view(props: &WeekViewProps) -> Html {
} else {
// Regular event - proceed with update
if let Some(callback) = &on_event_update {
callback.emit((event.clone(), new_start_datetime, new_end_datetime, true, None)); // Regular drag operation - preserve RRULE, no until_date
callback.emit((event.clone(), new_start_datetime, new_end_datetime, true, None, None, None)); // Regular drag operation - preserve RRULE, no until_date
}
}
}