- Created calendar-models/ shared library with RFC 5545-compliant VEvent structures - Migrated backend to use shared VEvent with proper field mappings (dtstart/dtend, rrule, exdate, etc.) - Converted CalDAV client to parse into VEvent structures with structured types - Updated all CRUD handlers to use VEvent with CalendarUser, Attendee, VAlarm types - Restructured project as Cargo workspace with frontend/, backend/, calendar-models/ - Updated Trunk configuration for new directory structure - Fixed all compilation errors and field references throughout codebase - Updated documentation and build instructions for workspace structure 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
93 lines
3.2 KiB
Rust
93 lines
3.2 KiB
Rust
use yew::prelude::*;
|
|
use chrono::NaiveDateTime;
|
|
use crate::models::ical::VEvent;
|
|
|
|
#[derive(Clone, PartialEq)]
|
|
pub enum RecurringEditAction {
|
|
ThisEvent,
|
|
FutureEvents,
|
|
AllEvents,
|
|
}
|
|
|
|
#[derive(Properties, PartialEq)]
|
|
pub struct RecurringEditModalProps {
|
|
pub show: bool,
|
|
pub event: VEvent,
|
|
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>
|
|
}
|
|
} |