parent
e5a0c85e18
commit
0234a880cd
visions/ui
@ -12,7 +12,7 @@ serde_json = { workspace = true }
|
||||
visions-types = { path = "../types" }
|
||||
wasm-bindgen = { workspace = true }
|
||||
wasm-bindgen-futures = { workspace = true }
|
||||
web-sys = { workspace = true }
|
||||
web-sys = { workspace = true, features = ["Window"] }
|
||||
yew = { workspace = true }
|
||||
yew-router = { workspace = true }
|
||||
|
||||
|
@ -229,3 +229,22 @@ body {
|
||||
background-color: var(--button-background-dark);
|
||||
color: var(--text-inverse);
|
||||
}
|
||||
|
||||
.user-overview {
|
||||
display: flex;
|
||||
margin-top: var(--spacing-s);
|
||||
padding: var(--spacing-m);
|
||||
border-radius: var(--radius-m);
|
||||
}
|
||||
|
||||
.user-overview:nth-child(odd) {
|
||||
background-color: var(--highlight-background);
|
||||
}
|
||||
|
||||
.user-overview__name {
|
||||
width: 65%;
|
||||
}
|
||||
|
||||
.button-bar {
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
@ -2,7 +2,9 @@ use yew::{function_component, html, AttrValue, Callback, Html, MouseEvent, Prope
|
||||
|
||||
#[derive(Properties, PartialEq)]
|
||||
pub struct ButtonProps {
|
||||
#[prop_or(Callback::from(|_| ()))]
|
||||
pub on_click: Callback<MouseEvent>,
|
||||
|
||||
pub children: Html
|
||||
}
|
||||
|
||||
|
@ -1,14 +1,17 @@
|
||||
use yew::{function_component, html, Html, Properties};
|
||||
use yew::{function_component, html, AttrValue, Html, Properties};
|
||||
|
||||
#[derive(Properties, PartialEq)]
|
||||
pub struct RowProps {
|
||||
#[prop_or_default]
|
||||
pub class: Option<AttrValue>,
|
||||
pub children: Html
|
||||
}
|
||||
|
||||
#[function_component]
|
||||
pub fn Row(RowProps { children }: &RowProps) -> Html {
|
||||
pub fn Row(RowProps { ref class, children }: &RowProps) -> Html {
|
||||
let classes = format!("row {}", class.as_ref().map(|cn| cn.as_str().to_string()).unwrap_or("".to_string()));
|
||||
html! {
|
||||
<div class="row">
|
||||
<div class={classes}>
|
||||
{children.clone()}
|
||||
</div>
|
||||
}
|
||||
|
@ -1,7 +1,8 @@
|
||||
use std::rc::Rc;
|
||||
|
||||
use gloo_console::log;
|
||||
use visions_types::{AuthResponse, SessionId, UserOverview};
|
||||
use views::UserList;
|
||||
use visions_types::{AuthResponse, SessionId};
|
||||
use yew::prelude::*;
|
||||
use yew_router::prelude::*;
|
||||
|
||||
@ -42,7 +43,6 @@ 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()),
|
||||
@ -53,59 +53,21 @@ impl Reducible for AuthInfo {
|
||||
}
|
||||
}
|
||||
|
||||
#[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 auth_info = use_reducer(init_state);
|
||||
|
||||
/*
|
||||
use_effect(|| match web_sys::window() {
|
||||
Some(window) => match window.session_storage() {
|
||||
Ok(Some(storage)) => {
|
||||
auth_info.dispatch(AuthAction::Auth(session_id.as_str().to_owned()))
|
||||
}
|
||||
_ => (),
|
||||
},
|
||||
None => (),
|
||||
});
|
||||
*/
|
||||
|
||||
let on_login = {
|
||||
let auth_info = auth_info.clone();
|
||||
@ -115,6 +77,7 @@ fn App() -> Html {
|
||||
let client = Connection::new();
|
||||
match client.auth(username, password).await {
|
||||
Ok(AuthResponse::Success(session_id)) => {
|
||||
save_session_id(session_id.clone());
|
||||
auth_info.dispatch(AuthAction::Auth(session_id.as_str().to_owned()))
|
||||
}
|
||||
Ok(AuthResponse::PasswordReset(session_id)) => {
|
||||
@ -128,7 +91,7 @@ fn App() -> Html {
|
||||
};
|
||||
|
||||
match auth_info.session_id {
|
||||
Some(ref session_id) => html! { <Landing session_id={session_id.clone()} /> },
|
||||
Some(ref session_id) => html! { <UserList session_id={session_id.clone()} /> },
|
||||
None => html! { <Login on_login={on_login.clone()} /> },
|
||||
}
|
||||
}
|
||||
@ -140,6 +103,35 @@ fn switch(routes: Route) -> Html {
|
||||
}
|
||||
}
|
||||
|
||||
fn init_state() -> AuthInfo {
|
||||
match web_sys::window() {
|
||||
Some(window) => match window.session_storage() {
|
||||
Ok(Some(storage)) => {
|
||||
if let Ok(Some(session_id)) = storage.get_item("session_id") {
|
||||
AuthInfo {
|
||||
session_id: Some(session_id.into()),
|
||||
}
|
||||
} else {
|
||||
AuthInfo::default()
|
||||
}
|
||||
}
|
||||
_ => AuthInfo::default(),
|
||||
},
|
||||
None => AuthInfo::default(),
|
||||
}
|
||||
}
|
||||
|
||||
fn save_session_id(session_id: SessionId) {
|
||||
log!("save_session_id", web_sys::window());
|
||||
match web_sys::window() {
|
||||
Some(window) => match window.session_storage() {
|
||||
Ok(Some(storage)) => storage.set_item("session_id", session_id.as_str()).unwrap(),
|
||||
_ => (),
|
||||
},
|
||||
None => (),
|
||||
}
|
||||
}
|
||||
|
||||
#[function_component]
|
||||
fn AppWrapper() -> Html {
|
||||
html! {
|
||||
|
@ -1,7 +1,5 @@
|
||||
use gloo_console::log;
|
||||
use wasm_bindgen::JsCast;
|
||||
use web_sys::HtmlInputElement;
|
||||
use yew::{function_component, html, use_state, Callback, Event, Html, Properties};
|
||||
use yew::{function_component, html, use_state, Callback, Html, Properties};
|
||||
|
||||
use crate::components::{Button, TextEntry};
|
||||
|
||||
|
@ -4,3 +4,6 @@ pub use design::Design;
|
||||
mod login;
|
||||
pub use login::Login;
|
||||
|
||||
mod user_list;
|
||||
pub use user_list::UserList;
|
||||
|
||||
|
71
visions/ui/src/views/user_list.rs
Normal file
71
visions/ui/src/views/user_list.rs
Normal file
@ -0,0 +1,71 @@
|
||||
use gloo_console::log;
|
||||
use visions_types::{AccountStatus, SessionId, UserOverview};
|
||||
use yew::{function_component, html, use_effect, use_state, Html, Properties};
|
||||
|
||||
use crate::{client::{Client, ClientError, Connection}, components::*};
|
||||
|
||||
#[derive(Properties, PartialEq)]
|
||||
pub struct UserListProps {
|
||||
pub session_id: SessionId,
|
||||
}
|
||||
|
||||
#[function_component]
|
||||
pub fn UserList(UserListProps { session_id }: &UserListProps) -> 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>
|
||||
{user_ref.iter().map(|overview| {
|
||||
let overview = overview.clone();
|
||||
html! { <UserOverviewComponent overview={overview} /> }}).collect::<Vec<Html>>()
|
||||
}
|
||||
</div>
|
||||
|
||||
<Row class="button-bar">
|
||||
<Button>{"+ Add User"}</Button>
|
||||
<Button>{"Go to game"}</Button>
|
||||
</Row>
|
||||
</>
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Properties, PartialEq)]
|
||||
struct UserOverviewProps {
|
||||
overview: UserOverview,
|
||||
}
|
||||
|
||||
#[function_component]
|
||||
fn UserOverviewComponent(UserOverviewProps { overview }: &UserOverviewProps) -> Html {
|
||||
let account_status = match overview.status {
|
||||
AccountStatus::Ok => "",
|
||||
AccountStatus::PasswordReset(_) => "Password Reset",
|
||||
AccountStatus::Locked => "Locked",
|
||||
};
|
||||
html! {
|
||||
<div class="user-overview">
|
||||
<div class="user-overview__name">{overview.name.clone()}</div>
|
||||
<div class="user-overview__status">{account_status}</div>
|
||||
</div>
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user