use yew::prelude::*; use web_sys::HtmlInputElement; use gloo_storage::{LocalStorage, Storage}; #[derive(Properties, PartialEq)] pub struct LoginProps { pub on_login: Callback, // Callback with JWT token } #[function_component] pub fn Login(props: &LoginProps) -> Html { let username = use_state(String::new); let password = use_state(String::new); let error_message = use_state(|| Option::::None); let is_loading = use_state(|| false); let username_ref = use_node_ref(); let password_ref = use_node_ref(); 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_submit = { 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 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 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 { match perform_login(username, password).await { Ok(token) => { // Store token 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; } is_loading.set(false); on_login.emit(token); } Err(err) => { error_message.set(Some(err)); is_loading.set(false); } } }); }) }; html! { {"Sign In"} {"Username"} {"Password"} { if let Some(error) = (*error_message).clone() { html! { {error} } } else { html! {} } } { if *is_loading { "Signing in..." } else { "Sign In" } } {"Don't have an account? "}{"Sign up here"} } } /// Perform login using the auth service async fn perform_login(username: String, password: String) -> Result { use crate::auth::{AuthService, LoginRequest}; let auth_service = AuthService::new(); let request = LoginRequest { username, password }; match auth_service.login(request).await { Ok(response) => Ok(response.token), Err(err) => Err(err), } }
{"Don't have an account? "}{"Sign up here"}