Implement shared RFC 5545 VEvent library with workspace restructuring
- 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>
This commit is contained in:
98
frontend/src/components/event_context_menu.rs
Normal file
98
frontend/src/components/event_context_menu.rs
Normal file
@@ -0,0 +1,98 @@
|
||||
use yew::prelude::*;
|
||||
use web_sys::MouseEvent;
|
||||
use crate::models::ical::VEvent;
|
||||
|
||||
#[derive(Clone, PartialEq, Debug)]
|
||||
pub enum DeleteAction {
|
||||
DeleteThis,
|
||||
DeleteFollowing,
|
||||
DeleteSeries,
|
||||
}
|
||||
|
||||
#[derive(Properties, PartialEq)]
|
||||
pub struct EventContextMenuProps {
|
||||
pub is_open: bool,
|
||||
pub x: i32,
|
||||
pub y: i32,
|
||||
pub event: Option<VEvent>,
|
||||
pub on_edit: Callback<()>,
|
||||
pub on_delete: Callback<DeleteAction>,
|
||||
pub on_close: Callback<()>,
|
||||
}
|
||||
|
||||
#[function_component(EventContextMenu)]
|
||||
pub fn event_context_menu(props: &EventContextMenuProps) -> Html {
|
||||
let menu_ref = use_node_ref();
|
||||
|
||||
if !props.is_open {
|
||||
return html! {};
|
||||
}
|
||||
|
||||
let style = format!(
|
||||
"position: fixed; left: {}px; top: {}px; z-index: 1001;",
|
||||
props.x, props.y
|
||||
);
|
||||
|
||||
// Check if the event is recurring
|
||||
let is_recurring = props.event.as_ref()
|
||||
.map(|event| event.rrule.is_some())
|
||||
.unwrap_or(false);
|
||||
|
||||
let on_edit_click = {
|
||||
let on_edit = props.on_edit.clone();
|
||||
let on_close = props.on_close.clone();
|
||||
Callback::from(move |_: MouseEvent| {
|
||||
on_edit.emit(());
|
||||
on_close.emit(());
|
||||
})
|
||||
};
|
||||
|
||||
let create_delete_callback = |action: DeleteAction| {
|
||||
let on_delete = props.on_delete.clone();
|
||||
let on_close = props.on_close.clone();
|
||||
Callback::from(move |_: MouseEvent| {
|
||||
on_delete.emit(action.clone());
|
||||
on_close.emit(());
|
||||
})
|
||||
};
|
||||
|
||||
html! {
|
||||
<div
|
||||
ref={menu_ref}
|
||||
class="context-menu"
|
||||
style={style}
|
||||
>
|
||||
<div class="context-menu-item" onclick={on_edit_click}>
|
||||
<span class="context-menu-icon">{"✏️"}</span>
|
||||
{"Edit Event"}
|
||||
</div>
|
||||
{
|
||||
if is_recurring {
|
||||
html! {
|
||||
<>
|
||||
<div class="context-menu-item context-menu-delete" onclick={create_delete_callback(DeleteAction::DeleteThis)}>
|
||||
<span class="context-menu-icon">{"🗑️"}</span>
|
||||
{"Delete This Event"}
|
||||
</div>
|
||||
<div class="context-menu-item context-menu-delete" onclick={create_delete_callback(DeleteAction::DeleteFollowing)}>
|
||||
<span class="context-menu-icon">{"🗑️"}</span>
|
||||
{"Delete Following Events"}
|
||||
</div>
|
||||
<div class="context-menu-item context-menu-delete" onclick={create_delete_callback(DeleteAction::DeleteSeries)}>
|
||||
<span class="context-menu-icon">{"🗑️"}</span>
|
||||
{"Delete Entire Series"}
|
||||
</div>
|
||||
</>
|
||||
}
|
||||
} else {
|
||||
html! {
|
||||
<div class="context-menu-item context-menu-delete" onclick={create_delete_callback(DeleteAction::DeleteThis)}>
|
||||
<span class="context-menu-icon">{"🗑️"}</span>
|
||||
{"Delete Event"}
|
||||
</div>
|
||||
}
|
||||
}
|
||||
}
|
||||
</div>
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user