//! The page behind a guest link: `/#l=`. use api::{GuestAuth, GuestKey, GuestUnlock, GuestView}; use leptos::prelude::*; use leptos::task::spawn_local; use crate::{ThemeToggle, http, map}; #[derive(Clone, PartialEq)] enum State { Loading, Locked, Open(String), Gone, Failed(String), } fn storage() -> Option { window().session_storage().ok().flatten() } #[component] pub fn GuestPage(token: String) -> impl IntoView { let storage_key = format!("link {token}"); let key = RwSignal::new(storage().and_then(|s| s.get_item(&storage_key).ok().flatten())); let token = StoredValue::new(token); let auth = move || GuestAuth { token: token.get_value(), key: key.get_untracked(), }; let state = RwSignal::new(State::Loading); let check = move || { spawn_local(async move { state.set(match http::post::("/api/guest", &auth()).await { Ok(v) => State::Open(v.person.username), Err(e) if e.status == 401 => State::Locked, Err(e) if e.status == 404 => State::Gone, Err(e) => State::Failed(e.to_string()), }) }) }; check(); let password = RwSignal::new(String::new()); let error = RwSignal::new(None::); let unlock = move |ev: leptos::ev::SubmitEvent| { ev.prevent_default(); let body = GuestUnlock { token: token.get_value(), password: password.get_untracked(), }; let storage_key = storage_key.clone(); spawn_local(async move { match http::post::("/api/guest/unlock", &body).await { Ok(k) => { if let Some(s) = storage() { let _ = s.set_item(&storage_key, &k.key); } key.set(Some(k.key)); error.set(None); check(); } Err(e) => error.set(Some(match e.status { 401 => "Wrong password.".into(), 429 => "Too many failed attempts. Try again in 15 minutes.".into(), _ => e.to_string(), })), } }); }; let title = move || match state.get() { State::Open(name) => format!("Location of {name}"), _ => "Shared location".into(), }; view! {
opentracker {title}
{move || match state.get() { State::Loading => ().into_any(), State::Locked => { view! { } .into_any() } State::Open(_) => view! {
}.into_any(), State::Gone => { view! { } .into_any() } State::Failed(msg) => view! { }.into_any(), }} } }