setup.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 SetupView(
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("setup-name");
20 let pass = input_value("setup-pass");
21 let confirm = input_value("setup-confirm");
22 let name = name.trim();
23
24 if name.is_empty() || name.len() > 64 {
25 set_error.set("Please choose a name (1–64 characters).".into());
26 return;
27 }
28 if pass.len() < 8 {
29 set_error.set("Password must be at least 8 characters.".into());
30 return;
31 }
32 if pass != confirm {
33 set_error.set("Passwords don't match.".into());
34 return;
35 }
36
37 set_error.set(String::new());
38 set_busy.set(true);
39 let (name, pass) = (name.to_string(), pass);
40 spawn_local(async move {
41 match api::setup(name, pass).await {
42 Ok(_) => match api::me().await {
43 Ok(m) => {
44 navigate(&Location::root());
45 set_me.set(Some(m));
46 set_phase.set(AuthPhase::Authed);
47 }
48 Err(e) => {
49 set_error.set(e.to_string());
50 set_busy.set(false);
51 }
52 },
53 Err(e) => {
54 set_error.set(e.to_string());
55 set_busy.set(false);
56 }
57 }
58 });
59 };
60
61 view! {
62 <div class="center-screen">
63 <div class="card auth-card">
64 <Logo class="auth-logo".to_string()/>
65 <h1>"filebrowser-ng"</h1>
66 <p class="muted">
67 "First boot: create the admin account. This user can manage
68 other users and server settings."
69 </p>
70 <form on:submit=on_submit>
71 <label class="field">
72 <span>"Name"</span>
73 <input
74 id="setup-name"
75 type="text"
76 autofocus=true
77 autocomplete="username"
78 />
79 </label>
80 <label class="field">
81 <span>"Password"</span>
82 <input
83 id="setup-pass"
84 type="password"
85 autocomplete="new-password"
86 />
87 </label>
88 <label class="field">
89 <span>"Repeat password"</span>
90 <input
91 id="setup-confirm"
92 type="password"
93 autocomplete="new-password"
94 />
95 </label>
96 <p class="error">{move || error.get()}</p>
97 <button class="btn-primary" type="submit" disabled=move || busy.get()>
98 "Create admin account"
99 </button>
100 </form>
101 </div>
102 </div>
103 }
104}
105