use leptos::*; use crate::prelude::*; pub trait AuthToken { fn present(&self) -> bool; fn token(&self) -> String; fn username(&self) -> String; fn outbox(&self) -> String; } #[derive(Debug, Clone, Copy)] pub struct Auth { pub token: Signal>, pub user: Signal>, } #[component] pub fn LoginBox( token_tx: WriteSignal>, username_tx: WriteSignal>, home_tl: Timeline, server_tl: Timeline, ) -> impl IntoView { let auth = use_context::().expect("missing auth context"); let username_ref: NodeRef = create_node_ref(); let password_ref: NodeRef = create_node_ref(); view! { "hi "{move || auth.username() } () .await else { if let Some(rf) = password_ref.get() { rf.set_value("") }; return }; logging::log!("logged in until {}", auth_response.expires); // update our username and token cookies let username = auth_response.user.split('/').last().unwrap_or_default().to_string(); username_tx.set(Some(username.clone())); token_tx.set(Some(auth_response.token)); // reset home feed and point it to our user's inbox home_tl.reset(format!("{URL_BASE}/users/{}/inbox/page", username)); spawn_local(async move { if let Err(e) = home_tl.more(auth).await { tracing::error!("failed refreshing home timeline: {e}"); } }); // reset server feed: there may be more content now that we're authed server_tl.reset(format!("{URL_BASE}/inbox/page")); spawn_local(async move { if let Err(e) = server_tl.more(auth).await { tracing::error!("failed refreshing server timeline: {e}"); } }); }); } > } } #[derive(Debug, serde::Serialize)] struct LoginForm { email: String, password: String, } #[derive(Debug, Clone, serde::Deserialize)] struct AuthResponse { token: String, user: String, expires: chrono::DateTime, } impl AuthToken for Auth { fn token(&self) -> String { self.token.get().unwrap_or_default() } fn username(&self) -> String { self.user.get().unwrap_or_default() } fn present(&self) -> bool { self.token.get().map_or(false, |x| !x.is_empty()) } fn outbox(&self) -> String { format!("{URL_BASE}/users/{}/outbox", self.user.get().unwrap_or_default()) } }