Add calendar selection dropdown and fix multi-calendar event display
- Add calendar selection dropdown to event creation modal - Update EventCreationData to include selected_calendar field - Pass available calendars from user info to modal component - Initialize dropdown with first available calendar as default - Fix backend to fetch events from ALL calendars, not just the first - Update refresh_event to search across all calendars - Events created in any calendar now properly display in UI 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -39,11 +39,24 @@ pub async fn get_calendar_events(
|
||||
return Ok(Json(vec![])); // No calendars found
|
||||
}
|
||||
|
||||
// Fetch events from the first calendar
|
||||
let calendar_path = &calendar_paths[0];
|
||||
let events = client.fetch_events(calendar_path)
|
||||
.await
|
||||
.map_err(|e| ApiError::Internal(format!("Failed to fetch events: {}", e)))?;
|
||||
// Fetch events from all calendars
|
||||
let mut all_events = Vec::new();
|
||||
for calendar_path in &calendar_paths {
|
||||
match client.fetch_events(calendar_path).await {
|
||||
Ok(mut events) => {
|
||||
// Set calendar_path for each event to identify which calendar it belongs to
|
||||
for event in &mut events {
|
||||
event.calendar_path = Some(calendar_path.clone());
|
||||
}
|
||||
all_events.extend(events);
|
||||
},
|
||||
Err(e) => {
|
||||
// Log the error but continue with other calendars
|
||||
eprintln!("Failed to fetch events from calendar {}: {}", calendar_path, e);
|
||||
}
|
||||
}
|
||||
}
|
||||
let events = all_events;
|
||||
|
||||
// Filter events by month if specified
|
||||
let filtered_events = if let (Some(year), Some(month)) = (params.year, params.month) {
|
||||
@@ -80,11 +93,23 @@ pub async fn refresh_event(
|
||||
return Ok(Json(None)); // No calendars found
|
||||
}
|
||||
|
||||
// Fetch the specific event by UID from the first calendar
|
||||
let calendar_path = &calendar_paths[0];
|
||||
let event = client.fetch_event_by_uid(calendar_path, &uid)
|
||||
.await
|
||||
.map_err(|e| ApiError::Internal(format!("Failed to fetch event: {}", e)))?;
|
||||
// Search for the specific event by UID across all calendars
|
||||
let mut found_event = None;
|
||||
for calendar_path in &calendar_paths {
|
||||
match client.fetch_event_by_uid(calendar_path, &uid).await {
|
||||
Ok(Some(mut event)) => {
|
||||
event.calendar_path = Some(calendar_path.clone());
|
||||
found_event = Some(event);
|
||||
break;
|
||||
},
|
||||
Ok(None) => continue, // Event not found in this calendar
|
||||
Err(e) => {
|
||||
eprintln!("Failed to fetch event from calendar {}: {}", calendar_path, e);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
let event = found_event;
|
||||
|
||||
Ok(Json(event))
|
||||
}
|
||||
|
||||
@@ -273,11 +273,12 @@ pub fn App() -> Html {
|
||||
reminder_str,
|
||||
recurrence_str,
|
||||
event_data.recurrence_days,
|
||||
None // Let backend use first available calendar
|
||||
event_data.selected_calendar
|
||||
).await {
|
||||
Ok(_) => {
|
||||
web_sys::console::log_1(&"Event created successfully".into());
|
||||
// Refresh the page to show the new event
|
||||
// Trigger a page reload to refresh events from all calendars
|
||||
// TODO: This could be improved to do a more targeted refresh
|
||||
web_sys::window().unwrap().location().reload().unwrap();
|
||||
}
|
||||
Err(err) => {
|
||||
@@ -542,6 +543,7 @@ pub fn App() -> Html {
|
||||
move |_| create_event_modal_open.set(false)
|
||||
})}
|
||||
on_create={on_event_create}
|
||||
available_calendars={user_info.as_ref().map(|ui| ui.calendars.clone()).unwrap_or_default()}
|
||||
/>
|
||||
</div>
|
||||
</BrowserRouter>
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
use yew::prelude::*;
|
||||
use web_sys::{HtmlInputElement, HtmlTextAreaElement, HtmlSelectElement};
|
||||
use chrono::{NaiveDate, NaiveTime};
|
||||
use crate::services::calendar_service::CalendarInfo;
|
||||
|
||||
#[derive(Properties, PartialEq)]
|
||||
pub struct CreateEventModalProps {
|
||||
@@ -8,6 +9,7 @@ pub struct CreateEventModalProps {
|
||||
pub selected_date: Option<NaiveDate>,
|
||||
pub on_close: Callback<()>,
|
||||
pub on_create: Callback<EventCreationData>,
|
||||
pub available_calendars: Vec<CalendarInfo>,
|
||||
}
|
||||
|
||||
#[derive(Clone, PartialEq, Debug)]
|
||||
@@ -88,6 +90,7 @@ pub struct EventCreationData {
|
||||
pub reminder: ReminderType,
|
||||
pub recurrence: RecurrenceType,
|
||||
pub recurrence_days: Vec<bool>, // [Sun, Mon, Tue, Wed, Thu, Fri, Sat] for weekly recurrence
|
||||
pub selected_calendar: Option<String>, // Calendar path
|
||||
}
|
||||
|
||||
impl Default for EventCreationData {
|
||||
@@ -114,6 +117,7 @@ impl Default for EventCreationData {
|
||||
reminder: ReminderType::default(),
|
||||
recurrence: RecurrenceType::default(),
|
||||
recurrence_days: vec![false; 7], // [Sun, Mon, Tue, Wed, Thu, Fri, Sat] - all false by default
|
||||
selected_calendar: None,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -123,18 +127,25 @@ pub fn create_event_modal(props: &CreateEventModalProps) -> Html {
|
||||
let event_data = use_state(|| EventCreationData::default());
|
||||
|
||||
// Initialize with selected date if provided
|
||||
use_effect_with((props.selected_date, props.is_open), {
|
||||
use_effect_with((props.selected_date, props.is_open, props.available_calendars.clone()), {
|
||||
let event_data = event_data.clone();
|
||||
move |(selected_date, is_open)| {
|
||||
move |(selected_date, is_open, available_calendars)| {
|
||||
if *is_open {
|
||||
if let Some(date) = selected_date {
|
||||
let mut data = if let Some(date) = selected_date {
|
||||
let mut data = (*event_data).clone();
|
||||
data.start_date = *date;
|
||||
data.end_date = *date;
|
||||
event_data.set(data);
|
||||
data
|
||||
} else {
|
||||
event_data.set(EventCreationData::default());
|
||||
EventCreationData::default()
|
||||
};
|
||||
|
||||
// Set default calendar to the first available one
|
||||
if data.selected_calendar.is_none() && !available_calendars.is_empty() {
|
||||
data.selected_calendar = Some(available_calendars[0].path.clone());
|
||||
}
|
||||
|
||||
event_data.set(data);
|
||||
}
|
||||
|| ()
|
||||
}
|
||||
@@ -164,6 +175,18 @@ pub fn create_event_modal(props: &CreateEventModalProps) -> Html {
|
||||
})
|
||||
};
|
||||
|
||||
let on_calendar_change = {
|
||||
let event_data = event_data.clone();
|
||||
Callback::from(move |e: Event| {
|
||||
if let Some(select) = e.target_dyn_into::<HtmlSelectElement>() {
|
||||
let mut data = (*event_data).clone();
|
||||
let value = select.value();
|
||||
data.selected_calendar = if value.is_empty() { None } else { Some(value) };
|
||||
event_data.set(data);
|
||||
}
|
||||
})
|
||||
};
|
||||
|
||||
let on_description_input = {
|
||||
let event_data = event_data.clone();
|
||||
Callback::from(move |e: InputEvent| {
|
||||
@@ -420,6 +443,31 @@ pub fn create_event_modal(props: &CreateEventModalProps) -> Html {
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="event-calendar">{"Calendar"}</label>
|
||||
<select
|
||||
id="event-calendar"
|
||||
class="form-input"
|
||||
onchange={on_calendar_change}
|
||||
>
|
||||
<option value="" selected={data.selected_calendar.is_none()}>{"Select calendar..."}</option>
|
||||
{
|
||||
props.available_calendars.iter().map(|calendar| {
|
||||
let is_selected = data.selected_calendar.as_ref() == Some(&calendar.path);
|
||||
html! {
|
||||
<option
|
||||
key={calendar.path.clone()}
|
||||
value={calendar.path.clone()}
|
||||
selected={is_selected}
|
||||
>
|
||||
{&calendar.display_name}
|
||||
</option>
|
||||
}
|
||||
}).collect::<Html>()
|
||||
}
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="event-description">{"Description"}</label>
|
||||
<textarea
|
||||
|
||||
Reference in New Issue
Block a user