From 0a214ca388190792018a257e293f5aebfd1a2516 Mon Sep 17 00:00:00 2001 From: Dennis Brentjes Date: Sun, 1 May 2022 17:41:14 +0200 Subject: [PATCH] Fixes the infinite loop and refactores some statechanges into useEffect hooks --- backend/src/api.rs | 29 ++++++++++++------ backend/src/schema.rs | 21 +++++-------- frontend/src/App.js | 38 ++++++++++++++---------- frontend/src/components/AddGameNight.jsx | 23 ++++++++++---- frontend/src/components/Gamenights.jsx | 4 --- frontend/src/components/MenuBar.jsx | 2 +- 6 files changed, 68 insertions(+), 49 deletions(-) diff --git a/backend/src/api.rs b/backend/src/api.rs index 1ca76bb..de90066 100644 --- a/backend/src/api.rs +++ b/backend/src/api.rs @@ -24,13 +24,20 @@ pub enum ApiResponseVariant { // Flash(Flash) } +#[derive(Debug, Serialize, Deserialize)] +pub struct UserWithToken { + #[serde(flatten)] + pub user: schema::User, + pub jwt: String, +} + #[derive(Serialize, Deserialize, Debug)] struct ApiResponse { result: Cow<'static, str>, #[serde(skip_serializing_if = "Option::is_none")] message: Option>, #[serde(skip_serializing_if = "Option::is_none")] - jwt: Option>, + user: Option, #[serde(skip_serializing_if = "Option::is_none")] gamenights: Option>, } @@ -42,7 +49,7 @@ impl ApiResponse { const SUCCES: Self = Self { result: Self::SUCCES_RESULT, message: None, - jwt: None, + user: None, gamenights: None, }; @@ -50,16 +57,19 @@ impl ApiResponse { Self { result: Self::FAILURE_RESULT, message: Some(Cow::Owned(message)), - jwt: None, + user: None, gamenights: None, } } - fn login_response(jwt: String) -> Self { + fn login_response(user: schema::User, jwt: String) -> Self { Self { result: Self::SUCCES_RESULT, message: None, - jwt: Some(Cow::Owned(jwt)), + user: Some(UserWithToken { + user: user, + jwt: jwt + }), gamenights: None, } } @@ -68,7 +78,7 @@ impl ApiResponse { Self { result: Self::SUCCES_RESULT, message: None, - jwt: None, + user: None, gamenights: Some(gamenights), } } @@ -190,10 +200,11 @@ pub async fn login_post_json( )))); } + let user = login_result.user.unwrap(); let my_claims = Claims { exp: Utc::now().timestamp() + chrono::Duration::days(7).num_seconds(), - uid: login_result.id.unwrap(), - role: login_result.role.unwrap(), + uid: user.id, + role: user.role, }; let secret = &config.inner().jwt_secret; @@ -202,7 +213,7 @@ pub async fn login_post_json( &my_claims, &EncodingKey::from_secret(secret.as_bytes()), ) { - Ok(token) => ApiResponseVariant::Value(json!(ApiResponse::login_response(token))), + Ok(token) => ApiResponseVariant::Value(json!(ApiResponse::login_response(user, token))), Err(error) => { ApiResponseVariant::Value(json!(ApiResponse::error(error.to_string()))) } diff --git a/backend/src/schema.rs b/backend/src/schema.rs index 8cad685..80bf4e4 100644 --- a/backend/src/schema.rs +++ b/backend/src/schema.rs @@ -175,25 +175,19 @@ pub async fn login(conn: DbConn, login: Login) -> Result role, - Err(error) => return Err(DatabaseError::Query(error.to_string())), + let user: User = match user::table.find(id).first(c) { + Ok(user) => user, + Err(error) => return Err(DatabaseError::Query(error.to_string())) }; Ok(LoginResult { result: true, - id: Some(id), - role: Some(role), + user : Some(user) }) } else { Ok(LoginResult { result: false, - id: None, - role: None, + user: None }) } }) @@ -251,7 +245,7 @@ pub async fn run_migrations(rocket: Rocket) -> Rocket { rocket } -#[derive(Debug, Serialize, Deserialize, DbEnum, Clone)] +#[derive(Debug, Serialize, Deserialize, DbEnum, Clone, Copy)] pub enum Role { Admin, User, @@ -318,6 +312,5 @@ pub struct Login { #[derive(Serialize, Deserialize, Debug)] pub struct LoginResult { pub result: bool, - pub id: Option, - pub role: Option, + pub user: Option, } diff --git a/frontend/src/App.js b/frontend/src/App.js index a50ba33..67c3013 100644 --- a/frontend/src/App.js +++ b/frontend/src/App.js @@ -1,4 +1,3 @@ -import logo from './logo.svg'; import './App.css'; import React, { useState, useEffect } from 'react'; import MenuBar from './components/MenuBar'; @@ -6,10 +5,11 @@ import Login from './components/Login'; import Gamenights from './components/Gamenights' import AddGameNight from './components/AddGameNight' +const localStorageUserKey = 'user'; + function App() { const [user, setUser] = useState(null); - const [token, setToken] = useState(null); const [gamenights, setGamenights] = useState([]); const [flashData, setFlashData] = useState({}); @@ -23,7 +23,8 @@ function App() { .then(response => response.json()) .then(data => { if(data.result === "Ok") { - setToken(data.jwt); + setUser(data.user); + localStorage.setItem(localStorageUserKey, JSON.stringify(data.user)); } else { setFlashData({ type: "Error", @@ -34,17 +35,17 @@ function App() { }; const handleAddGameNight = (input) => { - if (token !== null) { + if (user !== null) { const requestOptions = { method: 'POST', headers: { 'Content-Type': 'application/json', - 'Authorization': `Bearer ${token}` + 'Authorization': `Bearer ${user.jwt}` }, body: JSON.stringify(input) }; - fetch('api/gamenight', requestOptions) + return fetch('api/gamenight', requestOptions) .then(response => response.json()) .then(data => { if(data.result !== "Ok") { @@ -52,24 +53,25 @@ function App() { type: "Error", message: data.message }); + return false; } else { - setToken(token); + setUser({ ...user }); + return true; } - }); + }) } - - } + }; const onLogout = () => { setUser(null); - setToken(null); - } + localStorage.removeItem(localStorageUserKey); + }; useEffect(() => { - if (token !== null) { + if (user !== null) { const requestOptions = { method: 'GET', - headers: { 'Authorization': `Bearer ${token}` }, + headers: { 'Authorization': `Bearer ${user.jwt}` }, }; fetch('api/gamenights', requestOptions) .then(response => response.json()) @@ -84,9 +86,13 @@ function App() { } }); } - }); + }, [user]) - if(token === null) { + useEffect(() => { + setUser(JSON.parse(localStorage.getItem(localStorageUserKey))); + }, []); + + if(user === null) { return (
diff --git a/frontend/src/components/AddGameNight.jsx b/frontend/src/components/AddGameNight.jsx index 718cb06..4b883fc 100644 --- a/frontend/src/components/AddGameNight.jsx +++ b/frontend/src/components/AddGameNight.jsx @@ -1,4 +1,4 @@ -import React, { useState } from 'react'; +import React, { useEffect, useState } from 'react'; function AddGameNight(props) { const [expanded, setExpanded] = useState(false); @@ -9,6 +9,12 @@ function AddGameNight(props) { props.onChange({ game: gameName, datetime: date + }).then((result) => { + if(result) { + setExpanded(false); + setGameName(""); + setDate(null); + } }); event.preventDefault(); }; @@ -21,6 +27,13 @@ function AddGameNight(props) { setDate(event.target.value); }; + useEffect(() => { + if(!expanded) { + setGameName(""); + setDate(null); + } + }, [expanded]); + if(expanded) { return (
@@ -32,20 +45,20 @@ function AddGameNight(props) { - - date: + - +
); } else { return ( - + ); } } diff --git a/frontend/src/components/Gamenights.jsx b/frontend/src/components/Gamenights.jsx index fecf5f4..252b02a 100644 --- a/frontend/src/components/Gamenights.jsx +++ b/frontend/src/components/Gamenights.jsx @@ -2,14 +2,10 @@ import React from 'react'; function Gamenights(props) { - console.log(props.gamenights); - let gamenights = props.gamenights.map(g => (
  • {g.game}
  • ) ); - console.log(gamenights); - return (
      {gamenights} diff --git a/frontend/src/components/MenuBar.jsx b/frontend/src/components/MenuBar.jsx index 0d06e7f..06adf25 100644 --- a/frontend/src/components/MenuBar.jsx +++ b/frontend/src/components/MenuBar.jsx @@ -7,7 +7,7 @@ function MenuBar(props) { Gamenight
    • - User: {props.user} + User: {props.user.username}