app.rs
⎇
Raw
1use leptos::prelude::*;
2use wasm_bindgen_futures::spawn_local;
3
4use crate::api::{self, Me};
5use crate::router::{Location, parse_location};
6
7#[derive(Clone, Copy, PartialEq, Debug)]
8pub enum AuthPhase {
9 Loading,
10 Setup,
11 Login,
12 Authed,
13}
14
15#[component]
16pub fn App() -> impl IntoView {
17 let (phase, set_phase) = signal(AuthPhase::Loading);
18 let (me, set_me) = signal(Option::<Me>::None);
19 let (loc, set_loc) = signal(Location::root());
20
21 // The URL hash is the source of truth for the location.
22 {
23 set_loc.set(parse_location());
24 crate::util::owned_window_listener(leptos::ev::hashchange, move |_| {
25 set_loc.set(parse_location());
26 });
27 }
28
29 // Initial /me probe: first boot, signed in, or needs login.
30 spawn_local(async move {
31 match api::me().await {
32 Ok(m) => {
33 let first_boot = m.first_boot;
34 set_me.set(Some(m));
35 set_phase.set(if first_boot {
36 AuthPhase::Setup
37 } else {
38 AuthPhase::Authed
39 });
40 }
41 Err(_) => set_phase.set(AuthPhase::Login),
42 }
43 });
44
45 view! {
46 {move || {
47 // Public share links (`#/s/{token}/...`) bypass the auth flow.
48 let loc_now = loc.get();
49 if let Some(token) = loc_now.share_token.clone() {
50 return view! {
51 <crate::views::share_page::ShareView token=token loc=loc/>
52 }
53 .into_view()
54 .into_any();
55 }
56 match phase.get() {
57 AuthPhase::Loading => view! {
58 <div class="center-screen">
59 <p class="muted">"Loading…"</p>
60 </div>
61 }
62 .into_view()
63 .into_any(),
64 AuthPhase::Setup => view! {
65 <crate::views::setup::SetupView set_me=set_me set_phase=set_phase/>
66 }
67 .into_view()
68 .into_any(),
69 AuthPhase::Login => view! {
70 <crate::views::login::LoginView set_me=set_me set_phase=set_phase/>
71 }
72 .into_view()
73 .into_any(),
74 AuthPhase::Authed => view! {
75 <crate::views::shell::ShellView
76 me=me
77 set_me=set_me
78 set_phase=set_phase
79 loc=loc
80 />
81 }
82 .into_view()
83 .into_any(),
84 }
85 }}
86 }
87}
88