login.rs
⎇
Raw
1use leptos::prelude::*;
2use wasm_bindgen_futures::spawn_local;
3
4use crate::api::{self, Me, input_value};
5use crate::app::AuthPhase;
6use crate::router::{Location, navigate};
7
8#[component]
9pub fn LoginView(
10 set_me: WriteSignal<Option<Me>>,
11 set_phase: WriteSignal<AuthPhase>,
12) -> impl IntoView {
13 let (error, set_error) = signal(String::new());
14 let (busy, set_busy) = signal(false);
15
16 let on_submit = move |ev: web_sys::SubmitEvent| {
17 ev.prevent_default();
18 let name = input_value("login-name");
19 let pass = input_value("login-pass");
20 if name.trim().is_empty() || pass.is_empty() {
21 set_error.set("Please enter your name and password.".into());
22 return;
23 }
24 set_error.set(String::new());
25 set_busy.set(true);
26 let name = name.trim().to_string();
27 spawn_local(async move {
28 match api::login(name, pass).await {
29 Ok(_) => match api::me().await {
30 Ok(m) => {
31 navigate(&Location::root());
32 set_me.set(Some(m));
33 set_phase.set(AuthPhase::Authed);
34 }
35 Err(e) => {
36 set_error.set(e.to_string());
37 set_busy.set(false);
38 }
39 },
40 Err(e) => {
41 set_error.set(e.to_string());
42 set_busy.set(false);
43 }
44 }
45 });
46 };
47
48 view! {
49 <div class="center-screen">
50 <div class="card auth-card">
51 <h1>"filebrowser-ng"</h1>
52 <p class="muted">"Sign in to continue."</p>
53 <form on:submit=on_submit>
54 <label class="field">
55 <span>"Name"</span>
56 <input
57 id="login-name"
58 type="text"
59 autofocus=true
60 autocomplete="username"
61 />
62 </label>
63 <label class="field">
64 <span>"Password"</span>
65 <input
66 id="login-pass"
67 type="password"
68 autocomplete="current-password"
69 />
70 </label>
71 <p class="error">{move || error.get()}</p>
72 <button class="btn-primary" type="submit" disabled=move || busy.get()>
73 "Sign in"
74 </button>
75 </form>
76 </div>
77 </div>
78 }
79}
80