178 lines
5.0 KiB
Rust
178 lines
5.0 KiB
Rust
use std::rc::Rc;
|
|
|
|
use gloo_console::log;
|
|
use visions_types::{AuthResponse, SessionId, UserOverview};
|
|
use wasm_bindgen::JsCast;
|
|
use web_sys::HtmlInputElement;
|
|
use yew::prelude::*;
|
|
|
|
mod client;
|
|
use client::*;
|
|
|
|
struct AuthInfo {
|
|
session_id: Option<SessionId>,
|
|
}
|
|
|
|
impl Default for AuthInfo {
|
|
fn default() -> Self {
|
|
Self { session_id: None }
|
|
}
|
|
}
|
|
|
|
enum AuthAction {
|
|
Auth(String),
|
|
Unauth,
|
|
}
|
|
|
|
impl Reducible for AuthInfo {
|
|
type Action = AuthAction;
|
|
|
|
fn reduce(self: Rc<Self>, action: Self::Action) -> Rc<Self> {
|
|
// log!("reduce", action);
|
|
match action {
|
|
AuthAction::Auth(session_id) => Self {
|
|
session_id: Some(session_id.into()),
|
|
}
|
|
.into(),
|
|
AuthAction::Unauth => Self { session_id: None }.into(),
|
|
}
|
|
}
|
|
}
|
|
|
|
#[derive(Properties, PartialEq)]
|
|
struct LoginProps {
|
|
on_login: Callback<(String, String)>,
|
|
}
|
|
|
|
#[function_component]
|
|
fn Login(LoginProps { on_login }: &LoginProps) -> Html {
|
|
let username = use_state(|| "".to_owned());
|
|
let password = use_state(|| "".to_owned());
|
|
|
|
let on_click = {
|
|
let on_login = on_login.clone();
|
|
let username = username.clone();
|
|
let password = password.clone();
|
|
Callback::from(move |_| on_login.emit((username.to_string(), password.to_string())))
|
|
};
|
|
|
|
let on_username_changed = {
|
|
let username = username.clone();
|
|
Callback::from(move |event: Event| {
|
|
let input = event
|
|
.target()
|
|
.and_then(|t| t.dyn_into::<HtmlInputElement>().ok());
|
|
if let Some(input) = input {
|
|
username.set(input.value());
|
|
}
|
|
})
|
|
};
|
|
|
|
let on_password_changed = {
|
|
let password = password.clone();
|
|
Callback::from(move |event: Event| {
|
|
let input = event
|
|
.target()
|
|
.and_then(|t| t.dyn_into::<HtmlInputElement>().ok());
|
|
if let Some(input) = input {
|
|
password.set(input.value());
|
|
}
|
|
})
|
|
};
|
|
|
|
html! {
|
|
<div class="login-form">
|
|
<div class="card">
|
|
<h1>{"Welcome to Visions VTT"}</h1>
|
|
<input type="text" name="username" placeholder="username" onchange={on_username_changed} />
|
|
<input type="password" name="password" placeholder="password" onchange={on_password_changed} />
|
|
<button onclick={on_click}>{"Login"}</button>
|
|
</div>
|
|
</div>
|
|
}
|
|
}
|
|
|
|
#[derive(Properties, PartialEq)]
|
|
struct LandingProps {
|
|
session_id: SessionId,
|
|
}
|
|
|
|
#[function_component]
|
|
fn Landing(LandingProps { session_id }: &LandingProps) -> Html {
|
|
let user_ref = use_state(|| vec![]);
|
|
|
|
{
|
|
let user_ref = user_ref.clone();
|
|
let session_id = session_id.clone();
|
|
use_effect(move || {
|
|
wasm_bindgen_futures::spawn_local(async move {
|
|
let client = Connection::new();
|
|
match client.list_users(&session_id).await {
|
|
Ok(users) => user_ref.set(users),
|
|
Err(ClientError::Unauthorized) => todo!(),
|
|
Err(ClientError::Err(status)) => {
|
|
log!("error: {:?}", status);
|
|
todo!()
|
|
}
|
|
}
|
|
})
|
|
});
|
|
}
|
|
|
|
html! {
|
|
<div>
|
|
{"Landing Page"}
|
|
{user_ref.iter().map(|overview| {
|
|
let overview = overview.clone();
|
|
html! { <UserOverviewComponent overview={overview} /> }}).collect::<Vec<Html>>()
|
|
}
|
|
</div>
|
|
}
|
|
}
|
|
|
|
#[derive(Properties, PartialEq)]
|
|
struct UserOverviewProps {
|
|
overview: UserOverview,
|
|
}
|
|
|
|
#[function_component]
|
|
fn UserOverviewComponent(UserOverviewProps { overview }: &UserOverviewProps) -> Html {
|
|
html! {
|
|
<div> { overview.name.clone() } </div>
|
|
}
|
|
}
|
|
|
|
#[function_component]
|
|
fn App() -> Html {
|
|
let auth_info = use_reducer(AuthInfo::default);
|
|
|
|
let on_login = {
|
|
let auth_info = auth_info.clone();
|
|
Callback::from(move |(username, password)| {
|
|
let auth_info = auth_info.clone();
|
|
wasm_bindgen_futures::spawn_local(async move {
|
|
let client = Connection::new();
|
|
match client.auth(username, password).await {
|
|
Ok(AuthResponse::Success(session_id)) => {
|
|
auth_info.dispatch(AuthAction::Auth(session_id.as_str().to_owned()))
|
|
}
|
|
Ok(AuthResponse::PasswordReset(session_id)) => {
|
|
auth_info.dispatch(AuthAction::Auth(session_id.as_str().to_owned()))
|
|
}
|
|
Err(ClientError::Unauthorized) => todo!(),
|
|
Err(ClientError::Err(status)) => todo!(),
|
|
};
|
|
})
|
|
})
|
|
};
|
|
|
|
match auth_info.session_id {
|
|
Some(ref session_id) => html! { <Landing session_id={session_id.clone()} /> },
|
|
None => html! { <Login on_login={on_login.clone()} /> },
|
|
}
|
|
}
|
|
|
|
fn main() {
|
|
yew::Renderer::<App>::new().render();
|
|
}
|