Web API, Web UI #86
|
@ -3578,6 +3578,7 @@ dependencies = [
|
|||
"graphql_client_web",
|
||||
"js-sys",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"tenebrous-api",
|
||||
"thiserror",
|
||||
"wasm-bindgen",
|
||||
|
|
|
@ -30,6 +30,7 @@ js-sys = "0.3"
|
|||
graphql_client = { git = "https://github.com/graphql-rust/graphql-client", branch = "master" }
|
||||
graphql_client_web = { git = "https://github.com/graphql-rust/graphql-client", branch = "master" }
|
||||
serde = { version = "1.0.67", features = ["derive"] }
|
||||
serde_json = {version = "1.0" }
|
||||
thiserror = "1.0"
|
||||
|
||||
[dependencies.web-sys]
|
||||
|
|
|
@ -17,21 +17,25 @@ async fn make_request(request: Request) -> Result<JsValue, UiError> {
|
|||
let resp: Response = resp_value.dyn_into().unwrap();
|
||||
|
||||
let json = JsFuture::from(resp.json()?).await?;
|
||||
console::log_1(&json);
|
||||
Ok(json)
|
||||
}
|
||||
|
||||
pub async fn fetch_jwt() -> Result<String, UiError> {
|
||||
pub async fn login(username: &str, password: &str) -> Result<String, UiError> {
|
||||
let mut opts = RequestInit::new();
|
||||
opts.method("POST");
|
||||
opts.mode(RequestMode::Cors);
|
||||
opts.credentials(RequestCredentials::Include);
|
||||
|
||||
opts.body(Some(&JsValue::from_str(
|
||||
r#"
|
||||
{ "username": "@projectmoon:agnos.is", "password": "lolol" }
|
||||
"#,
|
||||
)));
|
||||
let body = JsValue::from_str(
|
||||
&serde_json::json!({
|
||||
"username": username,
|
||||
"password": password
|
||||
})
|
||||
.to_string(),
|
||||
);
|
||||
|
||||
opts.body(Some(&body));
|
||||
let url = format!("http://localhost:10000/login");
|
||||
|
||||
let request = Request::new_with_str_and_init(&url, &opts)?;
|
||||
|
@ -59,7 +63,6 @@ pub async fn refresh_jwt() -> Result<String, UiError> {
|
|||
|
||||
//TODO don't unwrap the response. OR... change it so we have a standard response.
|
||||
let response = make_request(request).await?;
|
||||
console::log_1(&response);
|
||||
let response: LoginResponse = response.into_serde().unwrap();
|
||||
|
||||
Ok(response.jwt_token)
|
||||
|
|
|
@ -0,0 +1,137 @@
|
|||
use crate::error::UiError;
|
||||
use crate::state::{Action, Room, WebUiDispatcher};
|
||||
use crate::{api, state::WebUiState};
|
||||
use std::sync::Arc;
|
||||
use wasm_bindgen_futures::spawn_local;
|
||||
use web_sys::console;
|
||||
use web_sys::FocusEvent;
|
||||
use yew::prelude::*;
|
||||
use yewdux::dispatch::Dispatcher;
|
||||
use yewdux::prelude::*;
|
||||
use yewtil::NeqAssign;
|
||||
|
||||
#[doc(hidden)]
|
||||
pub(crate) struct YewduxLogin {
|
||||
dispatch: Arc<WebUiDispatcher>,
|
||||
link: ComponentLink<YewduxLogin>,
|
||||
username: String,
|
||||
password: String,
|
||||
}
|
||||
|
||||
pub enum LoginAction {
|
||||
UpdateUsername(String),
|
||||
UpdatePassword(String),
|
||||
Login,
|
||||
Noop,
|
||||
}
|
||||
|
||||
pub(crate) type Login = WithDispatch<YewduxLogin>;
|
||||
async fn do_login(
|
||||
dispatch: &WebUiDispatcher,
|
||||
username: &str,
|
||||
password: &str,
|
||||
) -> Result<(), UiError> {
|
||||
let jwt = api::auth::login(username, password).await?;
|
||||
//state.jwt_token = Some(jwt);
|
||||
dispatch.send(Action::UpdateJwt(jwt));
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn do_refresh_jwt(dispatch: &WebUiDispatcher) -> Result<(), UiError> {
|
||||
let jwt = api::auth::refresh_jwt().await?;
|
||||
dispatch.send(Action::UpdateJwt(jwt));
|
||||
Ok(())
|
||||
}
|
||||
|
||||
impl Component for YewduxLogin {
|
||||
type Message = LoginAction;
|
||||
type Properties = WebUiDispatcher;
|
||||
|
||||
fn create(dispatch: Self::Properties, link: ComponentLink<Self>) -> Self {
|
||||
Self {
|
||||
dispatch: Arc::new(dispatch),
|
||||
link,
|
||||
username: "".to_string(),
|
||||
password: "".to_string(),
|
||||
}
|
||||
}
|
||||
|
||||
fn update(&mut self, action: Self::Message) -> ShouldRender {
|
||||
match action {
|
||||
LoginAction::UpdateUsername(username) => self.username = username,
|
||||
LoginAction::UpdatePassword(password) => self.password = password,
|
||||
LoginAction::Login => {
|
||||
let dispatch = self.dispatch.clone();
|
||||
let username = self.username.clone();
|
||||
let password = self.password.clone();
|
||||
|
||||
spawn_local(async move {
|
||||
do_login(&*dispatch, &username, &password).await;
|
||||
});
|
||||
}
|
||||
_ => (),
|
||||
};
|
||||
|
||||
false
|
||||
}
|
||||
|
||||
fn change(&mut self, dispatch: Self::Properties) -> ShouldRender {
|
||||
self.dispatch.neq_assign(Arc::new(dispatch))
|
||||
}
|
||||
|
||||
fn rendered(&mut self, first_render: bool) {
|
||||
if first_render {
|
||||
//
|
||||
}
|
||||
}
|
||||
|
||||
fn view(&self) -> Html {
|
||||
let dispatch = Arc::new(self.dispatch.clone());
|
||||
let dispatch2 = dispatch.clone();
|
||||
|
||||
// let do_the_login = self.dispatch.reduce_callback(|state| {
|
||||
// spawn_local(async move {
|
||||
// do_login(state, "user", "pw").await;
|
||||
// });
|
||||
// });
|
||||
|
||||
let do_the_login = self.link.callback(move |e: FocusEvent| {
|
||||
e.prevent_default();
|
||||
LoginAction::Login
|
||||
});
|
||||
|
||||
// let refresh_jwt = self.link.callback(move |_| {
|
||||
// let dispatch = dispatch2.clone();
|
||||
// spawn_local(async move {
|
||||
// do_refresh_jwt(&*dispatch).await;
|
||||
// });
|
||||
// });
|
||||
|
||||
let update_username = self
|
||||
.link
|
||||
.callback(|e: InputData| LoginAction::UpdateUsername(e.value));
|
||||
|
||||
let update_password = self
|
||||
.link
|
||||
.callback(|e: InputData| LoginAction::UpdatePassword(e.value));
|
||||
|
||||
html! {
|
||||
<div>
|
||||
<form onsubmit=do_the_login>
|
||||
<label for="username">{"Username:"}</label>
|
||||
<input oninput=update_username id="username" name="username" type="text" placeholder="Username" />
|
||||
<label for="password">{"Password:"}</label>
|
||||
<input oninput=update_password id="password" name="password" type="password" placeholder="Password" />
|
||||
<input type="submit" value="Log In" />
|
||||
</form>
|
||||
//<button onclick=refresh_jwt>{ "Refresh JWT" }</button>
|
||||
<div>
|
||||
{ "Current JWT: " }
|
||||
{ self.dispatch.state().jwt_token.as_ref().unwrap_or(&"[not set]".to_string()) }
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
}
|
||||
|
||||
fn destroy(&mut self) {}
|
||||
}
|
|
@ -0,0 +1 @@
|
|||
pub mod login;
|
|
@ -15,6 +15,9 @@ pub enum UiError {
|
|||
|
||||
#[error("error: {0}")]
|
||||
JsError(String),
|
||||
|
||||
#[error("(de)serialization error: {0}")]
|
||||
SerdeError(#[from] serde_json::Error),
|
||||
}
|
||||
|
||||
impl From<wasm_bindgen::JsValue> for UiError {
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
use crate::components::login::Login;
|
||||
use rooms::RoomList;
|
||||
use rooms::YewduxRoomList;
|
||||
use wasm_bindgen::prelude::*;
|
||||
|
@ -6,6 +7,7 @@ use yew_router::prelude::*;
|
|||
use yewdux::prelude::*;
|
||||
|
||||
pub mod api;
|
||||
pub mod components;
|
||||
pub mod error;
|
||||
pub mod grpc;
|
||||
pub mod rooms;
|
||||
|
@ -38,7 +40,10 @@ fn render_route(routes: &AppRoute) -> Html {
|
|||
}
|
||||
AppRoute::Index => {
|
||||
html! {
|
||||
<div>
|
||||
<Login />
|
||||
<RoomList />
|
||||
</div>
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -44,12 +44,6 @@ async fn load_rooms(dispatch: &WebUiDispatcher) -> Result<(), UiError> {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
async fn do_jwt_stuff(dispatch: &WebUiDispatcher) -> Result<(), UiError> {
|
||||
let jwt = api::auth::fetch_jwt().await?;
|
||||
dispatch.send(Action::UpdateJwt(jwt));
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn do_refresh_jwt(dispatch: &WebUiDispatcher) -> Result<(), UiError> {
|
||||
let jwt = api::auth::refresh_jwt().await?;
|
||||
dispatch.send(Action::UpdateJwt(jwt));
|
||||
|
@ -105,13 +99,6 @@ impl Component for YewduxRoomList {
|
|||
});
|
||||
});
|
||||
|
||||
let jwt_update = self.link.callback(move |_| {
|
||||
let dispatch = dispatch2.clone();
|
||||
spawn_local(async move {
|
||||
do_jwt_stuff(&*dispatch).await;
|
||||
});
|
||||
});
|
||||
|
||||
let refresh_jwt = self.link.callback(move |_| {
|
||||
let dispatch = dispatch3.clone();
|
||||
spawn_local(async move {
|
||||
|
@ -121,10 +108,8 @@ impl Component for YewduxRoomList {
|
|||
|
||||
html! {
|
||||
<div>
|
||||
<button onclick=the_future>{ "Add Room" }</button>
|
||||
<button onclick=jwt_update>{ "Fetch JWT" }</button>
|
||||
<button onclick=the_future>{ "Fetch Rooms" }</button>
|
||||
<button onclick=refresh_jwt>{ "Refresh JWT" }</button>
|
||||
<div> { "Current JWT: " } { self.dispatch.state().jwt_token.as_ref().unwrap_or(&"[not set]".to_string()) }</div>
|
||||
<ul>
|
||||
{
|
||||
for self.dispatch.state().rooms.iter().map(|room| {
|
||||
|
|
Loading…
Reference in New Issue