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