From 2cfaf2b4cc94e76e82e756696ef653b285a3f711 Mon Sep 17 00:00:00 2001 From: Dennis Brentjes Date: Fri, 29 Apr 2022 22:40:10 +0200 Subject: [PATCH] Adds an add gamenight control and fixes the fetch gamenight Effect, Introduces an infinite fetch gamenights loop --- backend/src/api.rs | 31 +++++++++--- backend/src/main.rs | 1 + backend/src/schema.rs | 10 ++-- frontend/package-lock.json | 60 ++++++++++++++++++++++++ frontend/package.json | 1 + frontend/src/App.js | 37 +++++++++++++-- frontend/src/components/AddGameNight.jsx | 53 +++++++++++++++++++++ frontend/src/components/Gamenights.jsx | 6 ++- frontend/src/components/Login.jsx | 8 ++-- frontend/src/components/MenuBar.jsx | 2 +- 10 files changed, 189 insertions(+), 20 deletions(-) create mode 100644 frontend/src/components/AddGameNight.jsx diff --git a/backend/src/api.rs b/backend/src/api.rs index c04cb66..1ca76bb 100644 --- a/backend/src/api.rs +++ b/backend/src/api.rs @@ -31,6 +31,8 @@ struct ApiResponse { message: Option>, #[serde(skip_serializing_if = "Option::is_none")] jwt: Option>, + #[serde(skip_serializing_if = "Option::is_none")] + gamenights: Option>, } impl ApiResponse { @@ -41,6 +43,7 @@ impl ApiResponse { result: Self::SUCCES_RESULT, message: None, jwt: None, + gamenights: None, }; fn error(message: String) -> Self { @@ -48,6 +51,7 @@ impl ApiResponse { result: Self::FAILURE_RESULT, message: Some(Cow::Owned(message)), jwt: None, + gamenights: None, } } @@ -56,6 +60,16 @@ impl ApiResponse { result: Self::SUCCES_RESULT, message: None, jwt: Some(Cow::Owned(jwt)), + gamenights: None, + } + } + + fn gamenight_response(gamenights: Vec) -> Self { + Self { + result: Self::SUCCES_RESULT, + message: None, + jwt: None, + gamenights: Some(gamenights), } } } @@ -106,7 +120,7 @@ impl<'r> FromRequest<'r> for schema::User { #[get("/gamenights")] pub async fn gamenights(conn: DbConn, _user: schema::User) -> ApiResponseVariant { let gamenights = schema::get_all_gamenights(conn).await; - ApiResponseVariant::Value(json!(gamenights)) + ApiResponseVariant::Value(json!(ApiResponse::gamenight_response(gamenights))) } #[get("/gamenights", rank = 2)] @@ -117,17 +131,20 @@ pub async fn gamenights_unauthorized() -> ApiResponseVariant { #[post("/gamenight", format = "application/json", data = "")] pub async fn gamenight_post_json( conn: DbConn, - user: Option, + _user: schema::User, gamenight_json: Json, ) -> ApiResponseVariant { - if user.is_some() { - schema::insert_gamenight(conn, gamenight_json.into_inner()).await; - ApiResponseVariant::Value(json!(ApiResponse::SUCCES)) - } else { - ApiResponseVariant::Status(Status::Unauthorized) + match schema::insert_gamenight(conn, gamenight_json.into_inner()).await { + Ok(_) => ApiResponseVariant::Value(json!(ApiResponse::SUCCES)), + Err(err) => ApiResponseVariant::Value(json!(ApiResponse::error(err.to_string()))), } } +#[post("/gamenight", rank = 2)] +pub async fn gamenight_post_json_unauthorized() -> ApiResponseVariant { + ApiResponseVariant::Status(Status::Unauthorized) +} + #[post("/register", format = "application/json", data = "")] pub async fn register_post_json( conn: DbConn, diff --git a/backend/src/main.rs b/backend/src/main.rs index c916ffa..73dfd5c 100644 --- a/backend/src/main.rs +++ b/backend/src/main.rs @@ -59,6 +59,7 @@ fn rocket() -> _ { api::gamenights, api::gamenights_unauthorized, api::gamenight_post_json, + api::gamenight_post_json_unauthorized, api::register_post_json, api::login_post_json ], diff --git a/backend/src/schema.rs b/backend/src/schema.rs index 1cf0a77..8cad685 100644 --- a/backend/src/schema.rs +++ b/backend/src/schema.rs @@ -84,14 +84,18 @@ pub async fn get_all_gamenights(conn: DbConn) -> Vec { .await } -pub async fn insert_gamenight(conn: DbConn, new_gamenight: GameNightNoId) -> () { - conn.run(|c| { +pub async fn insert_gamenight(conn: DbConn, new_gamenight: GameNightNoId) -> Result<(), DatabaseError> { + let insert_result = conn.run(|c| { diesel::insert_into(gamenight::table) .values(new_gamenight) .execute(c) - .unwrap() }) .await; + + match insert_result { + Err(e) => Err(DatabaseError::Query(e.to_string())), + _ => Ok(()), + } } pub async fn insert_user(conn: DbConn, new_user: Register) -> Result<(), DatabaseError> { diff --git a/frontend/package-lock.json b/frontend/package-lock.json index 5dd9b40..e4ec604 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -17,6 +17,7 @@ "web-vitals": "^2.1.4" }, "devDependencies": { + "dotenv-cli": "^5.1.0", "npm-watch": "^0.11.0" } }, @@ -6441,6 +6442,39 @@ "node": ">=10" } }, + "node_modules/dotenv-cli": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/dotenv-cli/-/dotenv-cli-5.1.0.tgz", + "integrity": "sha512-NoEZAlKo9WVrG0b3i9mBxdD6INdDuGqdgR74t68t8084QcI077/1MnPerRW1odl+9uULhcdnQp2U0pYVppKHOA==", + "dev": true, + "dependencies": { + "cross-spawn": "^7.0.3", + "dotenv": "^16.0.0", + "dotenv-expand": "^8.0.1", + "minimist": "^1.2.5" + }, + "bin": { + "dotenv": "cli.js" + } + }, + "node_modules/dotenv-cli/node_modules/dotenv": { + "version": "16.0.0", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.0.0.tgz", + "integrity": "sha512-qD9WU0MPM4SWLPJy/r2Be+2WgQj8plChsyrCNQzW/0WjvcJQiKQJ9mH3ZgB3fxbUUxgc/11ZJ0Fi5KiimWGz2Q==", + "dev": true, + "engines": { + "node": ">=12" + } + }, + "node_modules/dotenv-cli/node_modules/dotenv-expand": { + "version": "8.0.3", + "resolved": "https://registry.npmjs.org/dotenv-expand/-/dotenv-expand-8.0.3.tgz", + "integrity": "sha512-SErOMvge0ZUyWd5B0NXMQlDkN+8r+HhVUsxgOO7IoPDOdDRD2JjExpN6y3KnFR66jsJMwSn1pqIivhU5rcJiNg==", + "dev": true, + "engines": { + "node": ">=12" + } + }, "node_modules/dotenv-expand": { "version": "5.1.0", "resolved": "https://registry.npmjs.org/dotenv-expand/-/dotenv-expand-5.1.0.tgz", @@ -21378,6 +21412,32 @@ "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-10.0.0.tgz", "integrity": "sha512-rlBi9d8jpv9Sf1klPjNfFAuWDjKLwTIJJ/VxtoTwIR6hnZxcEOQCZg2oIL3MWBYw5GpUDKOEnND7LXTbIpQ03Q==" }, + "dotenv-cli": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/dotenv-cli/-/dotenv-cli-5.1.0.tgz", + "integrity": "sha512-NoEZAlKo9WVrG0b3i9mBxdD6INdDuGqdgR74t68t8084QcI077/1MnPerRW1odl+9uULhcdnQp2U0pYVppKHOA==", + "dev": true, + "requires": { + "cross-spawn": "^7.0.3", + "dotenv": "^16.0.0", + "dotenv-expand": "^8.0.1", + "minimist": "^1.2.5" + }, + "dependencies": { + "dotenv": { + "version": "16.0.0", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.0.0.tgz", + "integrity": "sha512-qD9WU0MPM4SWLPJy/r2Be+2WgQj8plChsyrCNQzW/0WjvcJQiKQJ9mH3ZgB3fxbUUxgc/11ZJ0Fi5KiimWGz2Q==", + "dev": true + }, + "dotenv-expand": { + "version": "8.0.3", + "resolved": "https://registry.npmjs.org/dotenv-expand/-/dotenv-expand-8.0.3.tgz", + "integrity": "sha512-SErOMvge0ZUyWd5B0NXMQlDkN+8r+HhVUsxgOO7IoPDOdDRD2JjExpN6y3KnFR66jsJMwSn1pqIivhU5rcJiNg==", + "dev": true + } + } + }, "dotenv-expand": { "version": "5.1.0", "resolved": "https://registry.npmjs.org/dotenv-expand/-/dotenv-expand-5.1.0.tgz", diff --git a/frontend/package.json b/frontend/package.json index d94a219..bea5d74 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -40,6 +40,7 @@ ] }, "devDependencies": { + "dotenv-cli": "^5.1.0", "npm-watch": "^0.11.0" } } diff --git a/frontend/src/App.js b/frontend/src/App.js index bc17e46..a50ba33 100644 --- a/frontend/src/App.js +++ b/frontend/src/App.js @@ -3,7 +3,8 @@ import './App.css'; import React, { useState, useEffect } from 'react'; import MenuBar from './components/MenuBar'; import Login from './components/Login'; -import Gamenights from "./components/Gamenights" +import Gamenights from './components/Gamenights' +import AddGameNight from './components/AddGameNight' function App() { @@ -32,6 +33,33 @@ function App() { }); }; + const handleAddGameNight = (input) => { + if (token !== null) { + const requestOptions = { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + 'Authorization': `Bearer ${token}` + }, + body: JSON.stringify(input) + }; + + fetch('api/gamenight', requestOptions) + .then(response => response.json()) + .then(data => { + if(data.result !== "Ok") { + setFlashData({ + type: "Error", + message: data.message + }); + } else { + setToken(token); + } + }); + } + + } + const onLogout = () => { setUser(null); setToken(null); @@ -56,7 +84,7 @@ function App() { } }); } - }, [token]); + }); if(token === null) { return ( @@ -66,10 +94,11 @@ function App() { ); } else { return ( -
+ <> + -
+ ); } } diff --git a/frontend/src/components/AddGameNight.jsx b/frontend/src/components/AddGameNight.jsx new file mode 100644 index 0000000..718cb06 --- /dev/null +++ b/frontend/src/components/AddGameNight.jsx @@ -0,0 +1,53 @@ +import React, { useState } from 'react'; + +function AddGameNight(props) { + const [expanded, setExpanded] = useState(false); + const [gameName, setGameName] = useState(""); + const [date, setDate] = useState(null); + + const handleAddGamenight = (event) => { + props.onChange({ + game: gameName, + datetime: date + }); + event.preventDefault(); + }; + + const handleNameChange = (event) => { + setGameName(event.target.value); + }; + + const handleDateChange = (event) => { + setDate(event.target.value); + }; + + if(expanded) { + return ( +
+
+
+ Gamenight + + + + + + + +
+
+ +
+ ); + } else { + return ( + + ); + } +} + +export default AddGameNight \ No newline at end of file diff --git a/frontend/src/components/Gamenights.jsx b/frontend/src/components/Gamenights.jsx index 2e47119..fecf5f4 100644 --- a/frontend/src/components/Gamenights.jsx +++ b/frontend/src/components/Gamenights.jsx @@ -2,10 +2,14 @@ import React from 'react'; function Gamenights(props) { + console.log(props.gamenights); + let gamenights = props.gamenights.map(g => - (
  • {g.name}
  • ) + (
  • {g.game}
  • ) ); + console.log(gamenights); + return (
      {gamenights} diff --git a/frontend/src/components/Login.jsx b/frontend/src/components/Login.jsx index c492412..2a061ed 100644 --- a/frontend/src/components/Login.jsx +++ b/frontend/src/components/Login.jsx @@ -6,16 +6,16 @@ function Login(props) { const handleUsernameChange = (event) => { setUsername(event.target.value); - } + }; const handlePasswordChange = (event) => { setPassword(event.target.value); - } + }; const handleLogin = (event) => { - props.onChange({ username: this.state.username, password: this.state.password }); + props.onChange({ username: username, password: password }); event.preventDefault(); - } + }; return (
      diff --git a/frontend/src/components/MenuBar.jsx b/frontend/src/components/MenuBar.jsx index 996f6da..0d06e7f 100644 --- a/frontend/src/components/MenuBar.jsx +++ b/frontend/src/components/MenuBar.jsx @@ -7,7 +7,7 @@ function MenuBar(props) { Gamenight
    • - User + User: {props.user}