diff --git a/common/src/lib.rs b/common/src/lib.rs index 39239fe..8edadfa 100644 --- a/common/src/lib.rs +++ b/common/src/lib.rs @@ -11,3 +11,12 @@ pub struct ChatMessage { pub struct LoggedInResponse { pub logged_in: bool, } + +#[derive(Serialize, Deserialize, Clone, Debug)] +pub struct LoginRequest { + pub username: String, + pub password: String, +} + +#[derive(Serialize, Deserialize, Clone, Debug)] +pub struct LoginResponse(pub Result<(), String>); diff --git a/frontend/src/pages/login.rs b/frontend/src/pages/login.rs index 84e3a01..6108564 100644 --- a/frontend/src/pages/login.rs +++ b/frontend/src/pages/login.rs @@ -1,10 +1,12 @@ use crate::components::Nav; -use common::LoggedInResponse; +use common::{LoggedInResponse, LoginRequest, LoginResponse}; use gloo::{ + console::{error, log}, history::{BrowserHistory, History}, net::http::Request, }; use serde::{Deserialize, Serialize}; +use web_sys::HtmlInputElement; use yew::{platform::spawn_local, prelude::*}; use yew_hooks::use_mount; @@ -24,7 +26,10 @@ impl Default for LoginQuery { #[function_component] #[allow(non_snake_case)] // Component names should be in PascalCase pub fn Login() -> Html { + let username_ref = use_node_ref(); + let password_ref = use_node_ref(); let disable_input = use_state(|| false); + let login_error = use_state(|| None); let query_params = BrowserHistory::new() .location() .query::() @@ -33,9 +38,16 @@ pub fn Login() -> Html { let login_submitted = { let disable_input = disable_input.clone(); let redirect = redirect.clone(); + let username_ref = username_ref.clone(); + let password_ref = password_ref.clone(); + let login_error = login_error.clone(); move || { disable_input.set(true); + let disable_input = disable_input.clone(); let redirect = redirect.clone(); + let username_ref = username_ref.clone(); + let password_ref = password_ref.clone(); + let login_error = login_error.clone(); spawn_local(async move { let location = web_sys::window().unwrap().location(); let login_url = format!( @@ -43,13 +55,40 @@ pub fn Login() -> Html { location.protocol().unwrap(), location.host().unwrap() ); - Request::post(&login_url) - .body("") + let username = username_ref.cast::().unwrap().value(); + let password = password_ref.cast::().unwrap().value(); + let req_body = LoginRequest { username, password }; + let resp = match Request::post(&login_url) + .json(&req_body) .unwrap() .send() .await - .unwrap(); - BrowserHistory::new().push(&redirect); + { + Ok(val) => val, + Err(err) => { + error!(format!("Could not send login request to server: {err}")); + login_error.set(Some("Error logging in".to_string())); + disable_input.set(false); + return; + } + }; + let LoginResponse(resp) = match resp.json().await { + Ok(val) => val, + Err(err) => { + error!(format!("Could not parse login response: {err}")); + login_error.set(Some("Error logging in".to_string())); + disable_input.set(false); + return; + } + }; + match resp { + Ok(_) => BrowserHistory::new().push(&redirect), + Err(err) => { + login_error.set(Some(err)); + password_ref.cast::().unwrap().set_value(""); + disable_input.set(false); + } + }; }); } }; @@ -92,20 +131,25 @@ pub fn Login() -> Html { style="max-width: 570px" >

{ "Login" }

+ if login_error.is_some() { + + } if !*disable_input { Response { .unwrap() } -async fn login(mut auth_session: AuthSession) -> Response { +async fn login( + mut auth_session: AuthSession, + Json(req): Json, +) -> Response { + if req.username != "pjht" || req.password != "123456" { + return Json(LoginResponse(Err( + "Invalid username or password".to_string() + ))) + .into_response(); + } if auth_session.login(&DummyAuthUser).await.is_err() { return StatusCode::INTERNAL_SERVER_ERROR.into_response(); } - StatusCode::OK.into_response() + Json(LoginResponse(Ok(()))).into_response() } async fn logout(mut auth_session: AuthSession) -> Response {