use yew::prelude::*; use web_sys::HtmlInputElement; use gloo_storage::{LocalStorage, Storage}; #[derive(Properties, PartialEq)] pub struct RegisterProps { pub on_register: Callback, // Callback with JWT token } #[function_component] pub fn Register(props: &RegisterProps) -> Html { let username = use_state(String::new); let email = use_state(String::new); let password = use_state(String::new); let confirm_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 email_ref = use_node_ref(); let password_ref = use_node_ref(); let confirm_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_email_change = { let email = email.clone(); Callback::from(move |e: Event| { let target = e.target_unchecked_into::(); email.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_confirm_password_change = { let confirm_password = confirm_password.clone(); Callback::from(move |e: Event| { let target = e.target_unchecked_into::(); confirm_password.set(target.value()); }) }; let on_submit = { let username = username.clone(); let email = email.clone(); let password = password.clone(); let confirm_password = confirm_password.clone(); let error_message = error_message.clone(); let is_loading = is_loading.clone(); let on_register = props.on_register.clone(); Callback::from(move |e: SubmitEvent| { e.prevent_default(); let username = (*username).clone(); let email = (*email).clone(); let password = (*password).clone(); let confirm_password = (*confirm_password).clone(); let error_message = error_message.clone(); let is_loading = is_loading.clone(); let on_register = on_register.clone(); // Client-side validation if let Err(validation_error) = validate_registration(&username, &email, &password, &confirm_password) { error_message.set(Some(validation_error)); return; } is_loading.set(true); error_message.set(None); wasm_bindgen_futures::spawn_local(async move { match perform_registration(username, email, 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_register.emit(token); } Err(err) => { error_message.set(Some(err)); is_loading.set(false); } } }); }) }; html! {

{"Create Account"}

{ if let Some(error) = (*error_message).clone() { html! {
{error}
} } else { html! {} } }
} } /// Validate registration form data fn validate_registration(username: &str, email: &str, password: &str, confirm_password: &str) -> Result<(), String> { if username.trim().is_empty() { return Err("Username is required".to_string()); } if username.len() < 3 { return Err("Username must be at least 3 characters long".to_string()); } if email.trim().is_empty() { return Err("Email is required".to_string()); } if !email.contains('@') { return Err("Please enter a valid email address".to_string()); } if password.is_empty() { return Err("Password is required".to_string()); } if password.len() < 6 { return Err("Password must be at least 6 characters long".to_string()); } if password != confirm_password { return Err("Passwords do not match".to_string()); } Ok(()) } /// Perform registration using the auth service async fn perform_registration(username: String, email: String, password: String) -> Result { use crate::auth::{AuthService, RegisterRequest}; let auth_service = AuthService::new(); let request = RegisterRequest { username, email, password }; match auth_service.register(request).await { Ok(response) => Ok(response.token), Err(err) => Err(err), } }