use gloo_storage::{LocalStorage, Storage}; use web_sys::HtmlInputElement; use yew::prelude::*; #[derive(Properties, PartialEq)] pub struct LoginProps { pub on_login: Callback, // Callback with JWT token } #[function_component] pub fn Login(props: &LoginProps) -> Html { // Load remembered values from LocalStorage on mount let server_url = use_state(|| { LocalStorage::get::("remembered_server_url").unwrap_or_default() }); let username = use_state(|| { LocalStorage::get::("remembered_username").unwrap_or_default() }); let password = use_state(String::new); let error_message = use_state(|| Option::::None); let is_loading = use_state(|| false); // Remember checkboxes state - default to checked let remember_server = use_state(|| true); let remember_username = use_state(|| true); let server_url_ref = use_node_ref(); let username_ref = use_node_ref(); let password_ref = use_node_ref(); let on_server_url_change = { let server_url = server_url.clone(); Callback::from(move |e: Event| { let target = e.target_unchecked_into::(); server_url.set(target.value()); }) }; let on_username_change = { let username = username.clone(); Callback::from(move |e: Event| { let target = e.target_unchecked_into::(); username.set(target.value()); }) }; let on_password_change = { let password = password.clone(); Callback::from(move |e: Event| { let target = e.target_unchecked_into::(); password.set(target.value()); }) }; let on_remember_server_change = { let remember_server = remember_server.clone(); let server_url = server_url.clone(); Callback::from(move |e: Event| { let target = e.target_unchecked_into::(); let checked = target.checked(); remember_server.set(checked); if checked { let _ = LocalStorage::set("remembered_server_url", (*server_url).clone()); } else { let _ = LocalStorage::delete("remembered_server_url"); } }) }; let on_remember_username_change = { let remember_username = remember_username.clone(); let username = username.clone(); Callback::from(move |e: Event| { let target = e.target_unchecked_into::(); let checked = target.checked(); remember_username.set(checked); if checked { let _ = LocalStorage::set("remembered_username", (*username).clone()); } else { let _ = LocalStorage::delete("remembered_username"); } }) }; let on_submit = { let server_url = server_url.clone(); let username = username.clone(); let password = password.clone(); let error_message = error_message.clone(); let is_loading = is_loading.clone(); let on_login = props.on_login.clone(); Callback::from(move |e: SubmitEvent| { e.prevent_default(); let server_url = (*server_url).clone(); let username = (*username).clone(); let password = (*password).clone(); let error_message = error_message.clone(); let is_loading = is_loading.clone(); let on_login = on_login.clone(); // Basic client-side validation if server_url.trim().is_empty() || username.trim().is_empty() || password.is_empty() { error_message.set(Some("Please fill in all fields".to_string())); return; } is_loading.set(true); error_message.set(None); wasm_bindgen_futures::spawn_local(async move { web_sys::console::log_1(&"🚀 Starting login process...".into()); match perform_login(server_url.clone(), username.clone(), password.clone()).await { Ok((token, session_token, credentials, preferences)) => { web_sys::console::log_1(&"✅ Login successful!".into()); // Store token and credentials in local storage if let Err(_) = LocalStorage::set("auth_token", &token) { error_message .set(Some("Failed to store authentication token".to_string())); is_loading.set(false); return; } if let Err(_) = LocalStorage::set("session_token", &session_token) { error_message .set(Some("Failed to store session token".to_string())); is_loading.set(false); return; } if let Err(_) = LocalStorage::set("caldav_credentials", &credentials) { error_message.set(Some("Failed to store credentials".to_string())); is_loading.set(false); return; } // Store preferences from database if let Ok(prefs_json) = serde_json::to_string(&preferences) { let _ = LocalStorage::set("user_preferences", &prefs_json); } is_loading.set(false); on_login.emit(token); } Err(err) => { web_sys::console::log_1(&format!("❌ Login failed: {}", err).into()); // Clear any existing invalid tokens let _ = LocalStorage::delete("auth_token"); let _ = LocalStorage::delete("session_token"); let _ = LocalStorage::delete("caldav_credentials"); error_message.set(Some(err)); is_loading.set(false); } } }); }) }; html! { } } /// Perform login using the CalDAV auth service async fn perform_login( server_url: String, username: String, password: String, ) -> Result<(String, String, String, serde_json::Value), String> { use crate::auth::{AuthService, CalDAVLoginRequest}; use serde_json; web_sys::console::log_1(&format!("📡 Creating auth service and request...").into()); let auth_service = AuthService::new(); let request = CalDAVLoginRequest { server_url: server_url.clone(), username: username.clone(), password: password.clone(), }; web_sys::console::log_1(&format!("🚀 Sending login request to backend...").into()); match auth_service.login(request).await { Ok(response) => { web_sys::console::log_1(&format!("✅ Backend responded successfully").into()); // Create credentials object to store let credentials = serde_json::json!({ "server_url": server_url, "username": username, "password": password }); // Extract preferences as JSON let preferences = serde_json::json!({ "calendar_selected_date": response.preferences.calendar_selected_date, "calendar_time_increment": response.preferences.calendar_time_increment, "calendar_view_mode": response.preferences.calendar_view_mode, "calendar_theme": response.preferences.calendar_theme, "calendar_colors": response.preferences.calendar_colors, }); Ok((response.token, response.session_token, credentials.to_string(), preferences)) } Err(err) => { web_sys::console::log_1(&format!("❌ Backend error: {}", err).into()); Err(err) } } }