97 lines
2.8 KiB
Rust
97 lines
2.8 KiB
Rust
mod api;
|
|
mod components;
|
|
mod pages;
|
|
mod types;
|
|
|
|
use yew::prelude::*;
|
|
use yew_router::prelude::*;
|
|
|
|
use components::navbar::Navbar;
|
|
use pages::{switch, Route};
|
|
use types::UserInfo;
|
|
|
|
#[derive(Clone, PartialEq)]
|
|
enum AuthState {
|
|
Loading,
|
|
NeedsSetup,
|
|
NeedsLogin,
|
|
Authenticated(UserInfo),
|
|
}
|
|
|
|
#[function_component(App)]
|
|
fn app() -> Html {
|
|
let auth = use_state(|| AuthState::Loading);
|
|
|
|
// Check auth state on mount
|
|
{
|
|
let auth = auth.clone();
|
|
use_effect_with((), move |_| {
|
|
wasm_bindgen_futures::spawn_local(async move {
|
|
match api::get_me().await {
|
|
Ok(user) => auth.set(AuthState::Authenticated(user)),
|
|
Err(_) => {
|
|
// Not logged in — check if setup is needed
|
|
match api::check_setup_required().await {
|
|
Ok(sr) if sr.required => auth.set(AuthState::NeedsSetup),
|
|
_ => auth.set(AuthState::NeedsLogin),
|
|
}
|
|
}
|
|
}
|
|
});
|
|
});
|
|
}
|
|
|
|
let on_auth_success = {
|
|
let auth = auth.clone();
|
|
Callback::from(move |_: ()| {
|
|
let auth = auth.clone();
|
|
wasm_bindgen_futures::spawn_local(async move {
|
|
if let Ok(user) = api::get_me().await {
|
|
auth.set(AuthState::Authenticated(user));
|
|
}
|
|
});
|
|
})
|
|
};
|
|
|
|
match &*auth {
|
|
AuthState::Loading => html! {
|
|
<div class="auth-page">
|
|
<p class="loading">{ "Loading..." }</p>
|
|
</div>
|
|
},
|
|
AuthState::NeedsSetup => html! {
|
|
<pages::setup::SetupPage on_setup={on_auth_success.clone()} />
|
|
},
|
|
AuthState::NeedsLogin => html! {
|
|
<pages::login::LoginPage on_login={on_auth_success.clone()} />
|
|
},
|
|
AuthState::Authenticated(user) => {
|
|
let user = user.clone();
|
|
let on_logout = {
|
|
let auth = auth.clone();
|
|
Callback::from(move |_: ()| {
|
|
let auth = auth.clone();
|
|
wasm_bindgen_futures::spawn_local(async move {
|
|
let _ = api::logout().await;
|
|
auth.set(AuthState::NeedsLogin);
|
|
});
|
|
})
|
|
};
|
|
html! {
|
|
<BrowserRouter>
|
|
<div class="app">
|
|
<Navbar username={user.username.clone()} role={user.role.clone()} on_logout={on_logout} />
|
|
<div class="main-content">
|
|
<Switch<Route> render={switch} />
|
|
</div>
|
|
</div>
|
|
</BrowserRouter>
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
fn main() {
|
|
yew::Renderer::<App>::new().render();
|
|
}
|