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