use leptos::prelude::*; use leptos_router::hooks::use_navigate; use crate::api; use crate::i18n::*; #[component] pub fn AccountPage() -> impl IntoView { let i18n = use_i18n(); let auth_username = use_context::>>().expect("auth_username context not found"); let auth_email_verified = use_context::>().expect("auth_email_verified context not found"); let navigate = use_navigate(); // Only redirect to profile when the email is actually verified. Effect::new(move |_| { if let Some(u) = auth_username.get() { if auth_email_verified.get() { navigate(&format!("/profile/{u}"), Default::default()); } } }); let tab = RwSignal::new("login"); view! {

{t!(i18n, account_title)}

{move || { let username = auth_username.get(); let verified = auth_email_verified.get(); if username.is_some() && !verified { view! { }.into_any() } else if username.is_none() { view! {
{move || if tab.get() == "login" { view! { }.into_any() } else { view! { }.into_any() }}
}.into_any() } else { view! { }.into_any() } }}
} } #[component] fn VerificationBanner() -> impl IntoView { let i18n = use_i18n(); let pending = RwSignal::new(false); let sent = RwSignal::new(false); let error = RwSignal::new(String::new()); let resend = move |_| { if pending.get() { return; } pending.set(true); sent.set(false); error.set(String::new()); wasm_bindgen_futures::spawn_local(async move { match api::post_resend_verification().await { Ok(()) => { sent.set(true); } Err(e) => { error.set(e); } } pending.set(false); }); }; view! {

{t!(i18n, email_not_verified_banner)}

{move || if sent.get() { view! {

{ t_string!(i18n, verification_email_resent).to_string() }

}.into_any() } else if !error.get().is_empty() { view! {

{ error.get() }

}.into_any() } else { view! { }.into_any() }}
} } #[component] fn LoginForm() -> impl IntoView { let i18n = use_i18n(); let auth_username = use_context::>>().expect("auth_username context not found"); let auth_email_verified = use_context::>().expect("auth_email_verified context not found"); let navigate = use_navigate(); let login = RwSignal::new(String::new()); let password = RwSignal::new(String::new()); let error = RwSignal::new(String::new()); let pending = RwSignal::new(false); let submit = move |ev: leptos::ev::SubmitEvent| { ev.prevent_default(); if pending.get() { return; } pending.set(true); error.set(String::new()); let u = login.get(); let p = password.get(); let navigate = navigate.clone(); wasm_bindgen_futures::spawn_local(async move { match api::post_login(&u, &p).await { Ok(me) => { auth_username.set(Some(me.username.clone())); auth_email_verified.set(me.email_verified); if me.email_verified { navigate(&format!("/profile/{}", me.username), Default::default()); } // If not verified, the AccountPage Effect will show the banner. } Err(e) => { let msg = if e.is_empty() { t_string!(i18n, login_failed).to_string() } else { e }; error.set(msg); pending.set(false); } } }); }; view! {
{move || if !error.get().is_empty() { view! {

{ error.get() }

}.into_any() } else { view! { }.into_any() }} } } #[component] fn RegisterForm() -> impl IntoView { let i18n = use_i18n(); let auth_username = use_context::>>().expect("auth_username context not found"); let auth_email_verified = use_context::>().expect("auth_email_verified context not found"); let username = RwSignal::new(String::new()); let email = RwSignal::new(String::new()); let password = RwSignal::new(String::new()); let confirm_password = RwSignal::new(String::new()); let error = RwSignal::new(String::new()); let pending = RwSignal::new(false); let submit = move |ev: leptos::ev::SubmitEvent| { ev.prevent_default(); if pending.get() { return; } if password.get() != confirm_password.get() { error.set(t_string!(i18n, passwords_do_not_match).to_string()); return; } pending.set(true); error.set(String::new()); let u = username.get(); let e = email.get(); let p = password.get(); wasm_bindgen_futures::spawn_local(async move { match api::post_register(&u, &e, &p).await { Ok(me) => { auth_username.set(Some(me.username)); auth_email_verified.set(me.email_verified); // AccountPage shows verification banner when email_verified = false. } Err(err) => { error.set(err); pending.set(false); } } }); }; view! {
{move || if !error.get().is_empty() { view! {

{ error.get() }

}.into_any() } else { view! { }.into_any() }} } }