use yew::prelude::*; use yew_router::prelude::*; use gloo_storage::{LocalStorage, Storage}; use crate::components::{Login, Calendar}; use crate::services::{CalendarService, CalendarEvent}; use std::collections::HashMap; use chrono::{Local, NaiveDate, Datelike}; #[derive(Clone, Routable, PartialEq)] enum Route { #[at("/")] Home, #[at("/login")] Login, #[at("/calendar")] Calendar, } #[function_component] pub fn App() -> Html { let auth_token = use_state(|| -> Option { LocalStorage::get("auth_token").ok() }); let on_login = { let auth_token = auth_token.clone(); Callback::from(move |token: String| { auth_token.set(Some(token)); }) }; let on_logout = { let auth_token = auth_token.clone(); Callback::from(move |_| { let _ = LocalStorage::delete("auth_token"); auth_token.set(None); }) }; html! {
{ if auth_token.is_some() { html! { <>
render={move |route| { let auth_token = (*auth_token).clone(); let on_login = on_login.clone(); match route { Route::Home => { if auth_token.is_some() { html! { to={Route::Calendar}/> } } else { html! { to={Route::Login}/> } } } Route::Login => { if auth_token.is_some() { html! { to={Route::Calendar}/> } } else { html! { } } } Route::Calendar => { if auth_token.is_some() { html! { } } else { html! { to={Route::Login}/> } } } } }} />
} } else { html! { } } }
} } #[function_component] fn CalendarView() -> Html { let events = use_state(|| HashMap::>::new()); let loading = use_state(|| true); let error = use_state(|| None::); let refreshing_event = use_state(|| None::); // Get current auth token let auth_token: Option = LocalStorage::get("auth_token").ok(); let today = Local::now().date_naive(); let current_year = today.year(); let current_month = today.month(); // Event refresh callback let on_event_click = { let events = events.clone(); let refreshing_event = refreshing_event.clone(); let auth_token = auth_token.clone(); Callback::from(move |event: CalendarEvent| { if let Some(token) = auth_token.clone() { let events = events.clone(); let refreshing_event = refreshing_event.clone(); let uid = event.uid.clone(); refreshing_event.set(Some(uid.clone())); wasm_bindgen_futures::spawn_local(async move { let calendar_service = CalendarService::new(); // Get password from stored credentials let password = if let Ok(credentials_str) = LocalStorage::get::("caldav_credentials") { if let Ok(credentials) = serde_json::from_str::(&credentials_str) { credentials["password"].as_str().unwrap_or("").to_string() } else { String::new() } } else { String::new() }; match calendar_service.refresh_event(&token, &password, &uid).await { Ok(Some(refreshed_event)) => { // If this is a recurring event, we need to regenerate all occurrences let mut updated_events = (*events).clone(); // First, remove all existing occurrences of this event for (_, day_events) in updated_events.iter_mut() { day_events.retain(|e| e.uid != uid); } // Then, if it's a recurring event, generate new occurrences if refreshed_event.recurrence_rule.is_some() { let new_occurrences = CalendarService::expand_recurring_events(vec![refreshed_event.clone()]); // Add all new occurrences to the appropriate dates for occurrence in new_occurrences { let date = occurrence.get_date(); updated_events.entry(date) .or_insert_with(Vec::new) .push(occurrence); } } else { // Non-recurring event, just add it to the appropriate date let date = refreshed_event.get_date(); updated_events.entry(date) .or_insert_with(Vec::new) .push(refreshed_event); } events.set(updated_events); } Ok(None) => { // Event was deleted, remove it from the map let mut updated_events = (*events).clone(); for (_, day_events) in updated_events.iter_mut() { day_events.retain(|e| e.uid != uid); } events.set(updated_events); } Err(_err) => { // Log error but don't show it to user - keep using cached event // Silently fall back to cached event data } } refreshing_event.set(None); }); } }) }; // Fetch events when component mounts { let events = events.clone(); let loading = loading.clone(); let error = error.clone(); let auth_token = auth_token.clone(); use_effect_with((), move |_| { if let Some(token) = auth_token { let events = events.clone(); let loading = loading.clone(); let error = error.clone(); wasm_bindgen_futures::spawn_local(async move { let calendar_service = CalendarService::new(); // Get password from stored credentials let password = if let Ok(credentials_str) = LocalStorage::get::("caldav_credentials") { if let Ok(credentials) = serde_json::from_str::(&credentials_str) { credentials["password"].as_str().unwrap_or("").to_string() } else { String::new() } } else { String::new() }; match calendar_service.fetch_events_for_month(&token, &password, current_year, current_month).await { Ok(calendar_events) => { let grouped_events = CalendarService::group_events_by_date(calendar_events); events.set(grouped_events); loading.set(false); } Err(err) => { error.set(Some(format!("Failed to load events: {}", err))); loading.set(false); } } }); } else { loading.set(false); error.set(Some("No authentication token found".to_string())); } || () }); } html! {
{ if *loading { html! {

{"Loading calendar events..."}

} } else if let Some(err) = (*error).clone() { let dummy_callback = Callback::from(|_: CalendarEvent| {}); html! {

{format!("Error: {}", err)}

} } else { html! { } } }
} }