From 8fb20c3a94b420a0f7f36cd11a3b121257ea667c Mon Sep 17 00:00:00 2001 From: Pernilla Sterner Date: Wed, 22 May 2024 07:27:16 +0200 Subject: [PATCH 01/52] Create route for testing password --- backend/package.json | 7 ++++++- backend/server.js | 49 ++++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 53 insertions(+), 3 deletions(-) diff --git a/backend/package.json b/backend/package.json index 8de5c4ce0..588b5a6fe 100644 --- a/backend/package.json +++ b/backend/package.json @@ -12,9 +12,14 @@ "@babel/core": "^7.17.9", "@babel/node": "^7.16.8", "@babel/preset-env": "^7.16.11", + "bcrypt-nodejs": "^0.0.3", "cors": "^2.8.5", "express": "^4.17.3", - "mongoose": "^8.0.0", + "mongodb": "^6.6.2", + "mongoose": "^8.4.0", "nodemon": "^3.0.1" + }, + "devDependencies": { + "@types/bcrypt-nodejs": "^0.0.31" } } diff --git a/backend/server.js b/backend/server.js index dfe86fb8e..d4e4be798 100644 --- a/backend/server.js +++ b/backend/server.js @@ -1,15 +1,46 @@ import cors from "cors"; import express from "express"; import mongoose from "mongoose"; +import crypto from "crypto"; +import bcrypt from "bcrypt-nodejs"; -const mongoUrl = process.env.MONGO_URL || "mongodb://localhost/project-mongo"; +const mongoUrl = process.env.MONGO_URL || "mongodb://localhost/auth"; mongoose.connect(mongoUrl); mongoose.Promise = Promise; +const User = mongoose.model("User", { + name: { + type: String, + unique: true, + }, + password: { + type: String, + required: true, + }, + accessToken: { + type: String, + // Random string of bytes + default: () => crypto.randomBytes(128).toString("hex"), + }, +}); + +/* Example +// POST request +const request = { name: "Bob", password: "foobar" }; + +// DB Entry +const dbEntry = { name: "Bob", password: "45lkjt5elk52" }; + +bcrypt.compareSync(request.password, dbEntry.password); +*/ + +const user = new User({ name: "Bob", password: bcrypt.hashSync("foobar") }); +user.save(); + // Defines the port the app will run on. Defaults to 8080, but can be overridden // when starting the server. Example command to overwrite PORT env variable value: // PORT=9000 npm start -const port = process.env.PORT || 8080; +const port = process.env.PORT || 8000; const app = express(); // Add middlewares to enable cors and json body parsing @@ -21,6 +52,20 @@ app.get("/", (req, res) => { res.send("Hello Technigo!"); }); +app.post("/sessions", async (req, res) => { + const user = await User.findOne({ name: req.body.name }); + + if (user && bcrypt.compareSync(req.body.password, user.password)) { + // Success + res.json({ userId: user._id, accessToken: user.accessToken }); + } else { + // Failure + // a. User doesn't exist + // b. Encrypted password doesn't match + res.json({ notFound: true }); + } +}); + // Start the server app.listen(port, () => { console.log(`Server running on http://localhost:${port}`); From 047e5dea64ba51719b83420a36c05084ace4bfa6 Mon Sep 17 00:00:00 2001 From: Pernilla Sterner Date: Wed, 22 May 2024 10:11:54 +0200 Subject: [PATCH 02/52] Ignore note file --- .gitignore | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index 3d70248ba..f8e9ae98f 100644 --- a/.gitignore +++ b/.gitignore @@ -12,4 +12,6 @@ npm-debug.log* yarn-debug.log* yarn-error.log* -package-lock.json \ No newline at end of file +package-lock.json + +note.md \ No newline at end of file From 2f68fd195c951f9db07b19d03f328b31417ef557 Mon Sep 17 00:00:00 2001 From: Pernilla Sterner Date: Wed, 22 May 2024 10:12:21 +0200 Subject: [PATCH 03/52] Add registration form --- frontend/src/App.jsx | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/frontend/src/App.jsx b/frontend/src/App.jsx index 1091d4310..859d9a022 100644 --- a/frontend/src/App.jsx +++ b/frontend/src/App.jsx @@ -1,3 +1,9 @@ +import { RegistrationForm } from "./components/RegistrationForm"; + export const App = () => { - return
Find me in src/app.jsx!
; + return ( +
+ +
+ ); }; From 5ccdfdab67ac1173df598f64d9138d3ec56b326d Mon Sep 17 00:00:00 2001 From: Pernilla Sterner Date: Wed, 22 May 2024 10:13:02 +0200 Subject: [PATCH 04/52] Add components to register and log in --- frontend/src/components/Button.jsx | 0 frontend/src/components/Dashboard.jsx | 0 frontend/src/components/Login.jsx | 0 frontend/src/components/RegistrationForm.jsx | 7 +++++++ 4 files changed, 7 insertions(+) create mode 100644 frontend/src/components/Button.jsx create mode 100644 frontend/src/components/Dashboard.jsx create mode 100644 frontend/src/components/Login.jsx create mode 100644 frontend/src/components/RegistrationForm.jsx diff --git a/frontend/src/components/Button.jsx b/frontend/src/components/Button.jsx new file mode 100644 index 000000000..e69de29bb diff --git a/frontend/src/components/Dashboard.jsx b/frontend/src/components/Dashboard.jsx new file mode 100644 index 000000000..e69de29bb diff --git a/frontend/src/components/Login.jsx b/frontend/src/components/Login.jsx new file mode 100644 index 000000000..e69de29bb diff --git a/frontend/src/components/RegistrationForm.jsx b/frontend/src/components/RegistrationForm.jsx new file mode 100644 index 000000000..9c742630a --- /dev/null +++ b/frontend/src/components/RegistrationForm.jsx @@ -0,0 +1,7 @@ +export const RegistrationForm = () => { + return ( +
+
RegistrationForm
+
+ ); +}; From 4c4544245b8649c3c828f7028beae5ccfdfb0985 Mon Sep 17 00:00:00 2001 From: Pernilla Sterner Date: Wed, 22 May 2024 10:13:25 +0200 Subject: [PATCH 05/52] Creating endpoints for registration --- backend/server.js | 39 +++++++++++++++++++++++++++++---------- 1 file changed, 29 insertions(+), 10 deletions(-) diff --git a/backend/server.js b/backend/server.js index d4e4be798..a1f6087b6 100644 --- a/backend/server.js +++ b/backend/server.js @@ -8,8 +8,9 @@ const mongoUrl = process.env.MONGO_URL || "mongodb://localhost/auth"; mongoose.connect(mongoUrl); mongoose.Promise = Promise; +// Defining schema for a User const User = mongoose.model("User", { - name: { + username: { type: String, unique: true, }, @@ -27,33 +28,51 @@ const User = mongoose.model("User", { /* Example // POST request const request = { name: "Bob", password: "foobar" }; - // DB Entry const dbEntry = { name: "Bob", password: "45lkjt5elk52" }; - bcrypt.compareSync(request.password, dbEntry.password); */ -const user = new User({ name: "Bob", password: bcrypt.hashSync("foobar") }); +const user = new User({ username: "Bob", password: bcrypt.hashSync("foobar") }); user.save(); -// Defines the port the app will run on. Defaults to 8080, but can be overridden -// when starting the server. Example command to overwrite PORT env variable value: -// PORT=9000 npm start +// Defining port const port = process.env.PORT || 8000; const app = express(); -// Add middlewares to enable cors and json body parsing +const authenticateUser = async (req, res, next) => { + // Using authorization from header to find user + const user = await User.findOne({ accessToken: req.header("Authorization") }); + + // Checking if user is found + if (user) { + // Modifing request to add the user to the request + req.user = user; + // Allowing express to continue with the api request + next(); + } else { + // User is not authorized to continue with the request + req.status(401).json({ loggedOut: true }); + } +}; + +// Middlewares to enable cors and json body parsing app.use(cors()); app.use(express.json()); -// Start defining your routes here +// Defining routes app.get("/", (req, res) => { res.send("Hello Technigo!"); }); +app.post("/tweets", authenticateUser); +// app.post("/tweets", async (req, res) => { +// // This will only happen if the next() function is called from the middleware +// // now we can access the req.user object from the middleware +// }); + app.post("/sessions", async (req, res) => { - const user = await User.findOne({ name: req.body.name }); + const user = await User.findOne({ username: req.body.username }); if (user && bcrypt.compareSync(req.body.password, user.password)) { // Success From 1e3d2f68d47440eb3ceb0c3fb3285cb41b3a0b06 Mon Sep 17 00:00:00 2001 From: Pernilla Sterner Date: Wed, 22 May 2024 14:46:37 +0200 Subject: [PATCH 06/52] Feature team collaboration backend frontend (#3) * Install styled-components * Add route for user registration * Add btn component * Add components for login, register user and dashboard * Import header, login and registration components * Set basic styling and variables for colors * Create context for login and user * Big chunk of code including register user, login user and components for button, play and myprogress * Big chunk of code including register user, login user and components for button, play and myprogress * Big chunk of code including register user, login user and components for button, play and myprogress --- .gitignore | 2 - backend/server.js | 107 +++++++----- frontend/package.json | 4 +- frontend/src/App.jsx | 24 ++- frontend/src/components/Button.jsx | 24 +++ frontend/src/components/Dashboard.jsx | 0 frontend/src/components/Header.jsx | 71 ++++++++ frontend/src/components/Login.jsx | 72 +++++++++ frontend/src/components/MyProgress.jsx | 11 ++ frontend/src/components/Play.jsx | 10 ++ frontend/src/components/RegistrationForm.jsx | 162 ++++++++++++++++++- frontend/src/components/WelcomeText.jsx | 28 ++++ frontend/src/contexts/UserContext.jsx | 72 +++++++++ frontend/src/index.css | 31 +++- note.md | 49 ++++++ package.json | 4 + 16 files changed, 624 insertions(+), 47 deletions(-) delete mode 100644 frontend/src/components/Dashboard.jsx create mode 100644 frontend/src/components/Header.jsx create mode 100644 frontend/src/components/MyProgress.jsx create mode 100644 frontend/src/components/Play.jsx create mode 100644 frontend/src/components/WelcomeText.jsx create mode 100644 frontend/src/contexts/UserContext.jsx create mode 100644 note.md diff --git a/.gitignore b/.gitignore index f8e9ae98f..ba185cfbd 100644 --- a/.gitignore +++ b/.gitignore @@ -13,5 +13,3 @@ yarn-debug.log* yarn-error.log* package-lock.json - -note.md \ No newline at end of file diff --git a/backend/server.js b/backend/server.js index a1f6087b6..fba622b84 100644 --- a/backend/server.js +++ b/backend/server.js @@ -1,10 +1,13 @@ import cors from "cors"; import express from "express"; import mongoose from "mongoose"; -import crypto from "crypto"; import bcrypt from "bcrypt-nodejs"; +import crypto from "crypto"; -const mongoUrl = process.env.MONGO_URL || "mongodb://localhost/auth"; +// Defining port and connecting to mongoose +const port = process.env.PORT || 8000; +const app = express(); +const mongoUrl = process.env.MONGO_URL || "mongodb://localhost/auth-users"; mongoose.connect(mongoUrl); mongoose.Promise = Promise; @@ -13,45 +16,43 @@ const User = mongoose.model("User", { username: { type: String, unique: true, + required: true, }, password: { type: String, required: true, }, + firstName: { + type: String, + required: true, + }, + lastName: { + type: String, + required: true, + }, + age: { + type: String, + required: true, + }, + email: { + type: String, + unique: true, + required: true, + }, accessToken: { type: String, - // Random string of bytes default: () => crypto.randomBytes(128).toString("hex"), }, }); -/* Example -// POST request -const request = { name: "Bob", password: "foobar" }; -// DB Entry -const dbEntry = { name: "Bob", password: "45lkjt5elk52" }; -bcrypt.compareSync(request.password, dbEntry.password); -*/ - -const user = new User({ username: "Bob", password: bcrypt.hashSync("foobar") }); -user.save(); - -// Defining port -const port = process.env.PORT || 8000; -const app = express(); - +//Authenticate user as middleware const authenticateUser = async (req, res, next) => { - // Using authorization from header to find user const user = await User.findOne({ accessToken: req.header("Authorization") }); - - // Checking if user is found if (user) { - // Modifing request to add the user to the request + console.log("User is found", user); req.user = user; - // Allowing express to continue with the api request next(); } else { - // User is not authorized to continue with the request req.status(401).json({ loggedOut: true }); } }; @@ -62,29 +63,61 @@ app.use(express.json()); // Defining routes app.get("/", (req, res) => { - res.send("Hello Technigo!"); + res.send("Hello friend!"); }); -app.post("/tweets", authenticateUser); -// app.post("/tweets", async (req, res) => { -// // This will only happen if the next() function is called from the middleware -// // now we can access the req.user object from the middleware -// }); +//Create user with username and password +app.post("/users", async (req, res) => { + try { + const { username, firstName, lastName, age, email, password } = req.body; + const salt = bcrypt.genSaltSync(10); + const user = new User({ + username, + firstName, + lastName, + age, + email, + password: bcrypt.hashSync(password, salt), + }); + await user.save(); + res.status(201).json(user); + //res.status(201).json({ id: user._id, accessToken: user.accessToken }); + } catch (error) { + console.error("Error creating user:", error); + res + .status(400) + .json({ response: error, message: "Could not create user." }); + } +}); +//Endpoint for login app.post("/sessions", async (req, res) => { - const user = await User.findOne({ username: req.body.username }); + const userByUsername = await User.findOne({ username: req.body.username }); + const userByEmail = await User.findOne({ email: req.body.email }); - if (user && bcrypt.compareSync(req.body.password, user.password)) { - // Success - res.json({ userId: user._id, accessToken: user.accessToken }); + if ( + userByUsername && + bcrypt.compareSync(req.body.password, userByUsername.password) + ) { + res.json({ + userId: userByUsername._id, + accessToken: userByUsername.accessToken, + }); + } else if ( + userByEmail && + bcrypt.compareSync(req.body.password, userByEmail.password) + ) { + res.json({ userId: userByEmail._id, accessToken: userByEmail.accessToken }); } else { - // Failure - // a. User doesn't exist - // b. Encrypted password doesn't match res.json({ notFound: true }); } }); +app.post("/games", authenticateUser); +app.post("/games", async (req, res) => { + res.send("You are logged in"); +}); + // Start the server app.listen(port, () => { console.log(`Server running on http://localhost:${port}`); diff --git a/frontend/package.json b/frontend/package.json index e9c95b79f..9735cfbf6 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -11,7 +11,9 @@ }, "dependencies": { "react": "^18.2.0", - "react-dom": "^18.2.0" + "react-dom": "^18.2.0", + "react-router": "^6.23.1", + "react-router-dom": "^6.23.1" }, "devDependencies": { "@types/react": "^18.2.15", diff --git a/frontend/src/App.jsx b/frontend/src/App.jsx index 859d9a022..ea9055788 100644 --- a/frontend/src/App.jsx +++ b/frontend/src/App.jsx @@ -1,9 +1,27 @@ +import { BrowserRouter, Routes, Route } from "react-router-dom"; +import { Header } from "./components/Header"; import { RegistrationForm } from "./components/RegistrationForm"; +import { Login } from "./components/Login"; +// import { Play } from "./components/Play"; +// import { Progress } from "./components/MyProgress"; +import { WelcomeText } from "./components/WelcomeText"; +import { UserProvider } from "./contexts/UserContext"; export const App = () => { return ( -
- -
+ + +
+
+ + + } /> + } /> + {/* } /> */} + {/* } /> */} + +
+ + ); }; diff --git a/frontend/src/components/Button.jsx b/frontend/src/components/Button.jsx index e69de29bb..5176601f3 100644 --- a/frontend/src/components/Button.jsx +++ b/frontend/src/components/Button.jsx @@ -0,0 +1,24 @@ +import styled from "styled-components"; + +export const Button = styled.button` + background-color: var(--raspberry); + color: #fff; + border-radius: 30px; + border: none; + padding: 10px 20px; + font-size: 16px; + font-weight: 500; + transition: 0.2s ease; + text-decoration: none; + + &:hover { + background-color: var(--raspberryhover); + cursor: pointer; + } + + &:active { + background-color: var(--raspberryactive); + } +`; + +export default Button; diff --git a/frontend/src/components/Dashboard.jsx b/frontend/src/components/Dashboard.jsx deleted file mode 100644 index e69de29bb..000000000 diff --git a/frontend/src/components/Header.jsx b/frontend/src/components/Header.jsx new file mode 100644 index 000000000..4c3a71a00 --- /dev/null +++ b/frontend/src/components/Header.jsx @@ -0,0 +1,71 @@ +import styled from "styled-components"; + +export const Header = () => { + return ( + + Register here + Log in + Play + My progress + Sign out + + ); +}; + +const HeaderContainer = styled.div` + background-color: black; + width: 100%; + height: 30px; + opacity: 80%; + position: absolute; + margin: -8px; + display: flex; + flex-direction: row; + justify-content: space-evenly; + align-items: center; +`; + +const Register = styled.p` + color: white; + cursor: pointer; + + &:hover { + color: #fff9; + } +`; + +const Login = styled.p` + color: white; + cursor: pointer; + + &:hover { + color: #fff9; + } +`; + +const Play = styled.p` + color: white; + cursor: pointer; + + &:hover { + color: #fff9; + } +`; + +const MyProgress = styled.p` + color: white; + cursor: pointer; + + &:hover { + color: #fff9; + } +`; + +const SignOut = styled.p` + color: white; + cursor: pointer; + + &:hover { + color: #fff9; + } +`; diff --git a/frontend/src/components/Login.jsx b/frontend/src/components/Login.jsx index e69de29bb..af3784dec 100644 --- a/frontend/src/components/Login.jsx +++ b/frontend/src/components/Login.jsx @@ -0,0 +1,72 @@ +import styled from "styled-components"; +import { useState } from "react"; +import { useLogin } from "../contexts/UserContext"; +import { Button } from "./Button"; + +export const Login = () => { + const [username, setUsername] = useState(""); + const [password, setPassword] = useState(""); + const [error, setError] = useState(""); + const { login } = useLogin(); + + const handleSubmit = async (e) => { + e.preventDefault(); + try { + await login(username, password); + } catch (error) { + setError("Invalid username or password"); + } + }; + + return ( + +
+ Login + {error && {error}} + + + +
+
+ ); +}; + +const LoginContainer = styled.div` + background: #fff; + border-radius: 20px; + max-width: fit-content; + height: fit-content; + margin: 0 auto; +`; + +const Form = styled.form` + display: flex; + flex-direction: column; + padding: 2rem; +`; + +const Heading = styled.h3` + color: black; +`; + +const Error = styled.h3` + color: black; +`; diff --git a/frontend/src/components/MyProgress.jsx b/frontend/src/components/MyProgress.jsx new file mode 100644 index 000000000..dcdccbfbf --- /dev/null +++ b/frontend/src/components/MyProgress.jsx @@ -0,0 +1,11 @@ +import styled from "styled-components"; + +export const MyProgress = () => { + return My Progress; +}; +const ProgressTitle = styled.h2` + color: black; +`; +export const MyProgress = () => { + return
MyProgress
; +}; diff --git a/frontend/src/components/Play.jsx b/frontend/src/components/Play.jsx new file mode 100644 index 000000000..c7e546c22 --- /dev/null +++ b/frontend/src/components/Play.jsx @@ -0,0 +1,10 @@ +import styled from "styled-components"; + +export const Play = () => { + return ( + Welcome to Pluggin, Name. Ready to play some games? + ); +}; +const PlayTitle = styled.h2` + color: black; +`; diff --git a/frontend/src/components/RegistrationForm.jsx b/frontend/src/components/RegistrationForm.jsx index 9c742630a..4268d7a95 100644 --- a/frontend/src/components/RegistrationForm.jsx +++ b/frontend/src/components/RegistrationForm.jsx @@ -1,7 +1,163 @@ +import { useState } from "react"; +import { useLogin } from "../contexts/UserContext"; +import { Button } from "./Button"; + +import styled from "styled-components"; + export const RegistrationForm = () => { + // Set starting point for handling user data + const { registerUser } = useLogin(); + const [errorMessage, setErrorMessage] = useState(""); + const [registrationData, setRegistrationData] = useState({ + username: "", + firstName: "", + lastName: "", + age: "", + email: "", + password: "", + confirmPassword: "", + }); + + const handleChange = (e) => { + // Remove error message when start typing again + setErrorMessage(""); + const { name, value } = e.target; + + // Add incoming letters to formData + setRegistrationData({ + ...registrationData, + [name]: value, + }); + }; + + // Send the request to /users with the updated form data + const handleSubmit = async (e) => { + e.preventDefault(); + const { + username, + firstName, + lastName, + age, + email, + password, + confirmPassword, + } = registrationData; + // Check if password is correct + if (password !== confirmPassword) { + // Add error message and return; + setErrorMessage("The passwords are not identical"); + return; + } + + // Send code to backend -> do some stuff using try and catch + try { + await registerUser({ + username, + firstName, + lastName, + age, + email, + password, + }); + } catch (err) { + console.error("Error registration user", err); + } + }; + return ( -
-
RegistrationForm
-
+ +
+ Register + + + + + + + + {errorMessage} + {/* TODO: Skapa komponent av button */} + +
+
); }; + +const RegistrationContainer = styled.div` + background: #fff; + border-radius: 20px; + max-width: fit-content; + height: fit-content; + margin: 0 auto; +`; + +const Form = styled.form` + display: flex; + flex-direction: column; + padding: 2rem; +`; + +const ErrorMessage = styled.div` + color: red; + font-size: 13px; +`; + +const Heading = styled.h3` + color: black; +`; diff --git a/frontend/src/components/WelcomeText.jsx b/frontend/src/components/WelcomeText.jsx new file mode 100644 index 000000000..c00227a8a --- /dev/null +++ b/frontend/src/components/WelcomeText.jsx @@ -0,0 +1,28 @@ +import styled from "styled-components"; + +export const WelcomeText = () => { + return ( + + Welcome to PluggIn&apos + + The site were you can up your game in different school subjects. + + + ); +}; + +const WelcomeContainer = styled.div` + background: rgba(255, 255, 255, 0.5); + border-radius: 20px; + max-width: fit-content; + height: fit-content; + margin: 0 auto; +`; + +const Heading = styled.h1` + margin: 0; +`; + +const Text = styled.p` + margin: 0; +`; diff --git a/frontend/src/contexts/UserContext.jsx b/frontend/src/contexts/UserContext.jsx new file mode 100644 index 000000000..85c1d1f12 --- /dev/null +++ b/frontend/src/contexts/UserContext.jsx @@ -0,0 +1,72 @@ +import { createContext, useContext, useState } from "react"; + +const UserContext = createContext(); + +export const UserProvider = ({ children }) => { + const [user, setUser] = useState(null); + + const login = (username) => { + setUser({ username }); + }; + + const registerUser = async (userData) => { + console.log(userData); // I get correct data + try { + // Send data to backend /users + const response = await fetch("/users", { + method: "POST", + headers: { + "Content-Type": "application/json", + }, + body: JSON.stringify(userData), + }); + console.log(response); + if (!response.ok) { + throw new Error("Failed to register user"); + } + + const data = await response.json(); + console.log("Registration success", data); + } catch (err) { + console.error("Error registering new user:", err); + } + }; + + // //Create user with username and password + // app.post("/users", async (req, res) => { + // try { + // const { username, firstName, lastName, age, email, password } = req.body; + // const salt = bcrypt.genSaltSync(10); + // const user = new User({ + // username, + // firstName, + // lastName, + // age, + // email, + // password: bcrypt.hashSync(password, salt), + // }); + // await user.save(); + // res.status(201).json(user); + // //res.status(201).json({ id: user._id, accessToken: user.accessToken }); + // } catch (error) { + // console.error("Error creating user:", error); + // res + // .status(400) + // .json({ response: error, message: "Could not create user." }); + // } + // }); + + return ( + + {children} + + ); +}; +export const useLogin = () => useContext(UserContext); diff --git a/frontend/src/index.css b/frontend/src/index.css index 3e560a674..e0ad57899 100644 --- a/frontend/src/index.css +++ b/frontend/src/index.css @@ -5,9 +5,38 @@ sans-serif; -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; + --vanilla: #fef9ef; + --ocean: #227c9d; + --oceanhover: #4095b4; + --oceanactive: #1a5f79; + --teal: #17c3b2; + --tealhover: #2fd5c5; + --tealactive: #119285; + --sunset: #ffcb77; + --sunsethover: #ffd798; + --sunsetactive: #c59d5d; + --raspberry: #fe6d73; + --raspberryhover: #ff9296; + --raspberryactive: #c15457; } code { font-family: source-code-pro, Menlo, Monaco, Consolas, "Courier New", monospace; -} \ No newline at end of file +} + +body { + background-color: var(--sunset); +} + +main { + width: 100vw; + height: 100vh; + display: flex; + align-items: center; +} + +/* Remove this code. Should be global and in a separate component folder */ +input { + margin: 10px 0; +} diff --git a/note.md b/note.md new file mode 100644 index 000000000..27fe6c7c7 --- /dev/null +++ b/note.md @@ -0,0 +1,49 @@ +Backend + +- User model - add more data +- Passwords should be encrypted with bcrypt +- Registration endpoint for new users +- Sign-in endpoint +- Endpoint that will return some info for the logged in user /my-page (Should be displayed when logged in) +- Authenticated endpoint should return a 401 or 403 with an error message if you try to access it without a token or with an invalid token +- Validate the user input when creating a new user, and return error messages which could be shown by the frontend + +Frontend + +- Build a registration form that will POST to the API. Store the access token in the local storage. (Use token when making other requests) +- A sign-in form +- A page to show the authenticated content from the API +- A 'Sign out' button that removes the saved access token and redirects the user to the login form + +// Components (Frida) + +- Top menu header +- Registration form +- Login form +- Button (sign in and sign out) (Frida) +- Page with logged-in content + STYLED COMPONENTS + +// Endpoints + +- login +- logout + ✅ - registration (/users) +- my-page + +// Registration form (all required) (Pernilla) + +- username (unique) +- fname (parent) +- lname (parent) +- age +- email (unique) (parent) +- password +- password (double check the password) +- btn - register + +// Login form (all required) (Katarina) + +- email / username (unique) +- password +- btn - sign in diff --git a/package.json b/package.json index d774b8cc3..fc5db1894 100644 --- a/package.json +++ b/package.json @@ -3,5 +3,9 @@ "version": "1.0.0", "scripts": { "postinstall": "npm install --prefix backend" + }, + "dependencies": { + "react-router": "^6.23.1", + "styled-components": "^6.1.11" } } From c635550247c9f6ff67f8e5ffbc8a12041b9bc8b3 Mon Sep 17 00:00:00 2001 From: Pernilla Sterner Date: Wed, 22 May 2024 15:56:57 +0200 Subject: [PATCH 07/52] Feature routing (#4) * Fixing router for play and myprogress * Be able to register user data to mongodb * Send user to login page after register * Fix routes in the header. Make divs in the header --- backend/server.js | 2 +- frontend/src/App.jsx | 16 ++++++--- frontend/src/components/Games/English.jsx | 8 +++++ frontend/src/components/Games/Math.jsx | 8 +++++ frontend/src/components/Games/Swedish.jsx | 8 +++++ frontend/src/components/Header.jsx | 38 +++++++++++++++++--- frontend/src/components/Input.jsx | 3 ++ frontend/src/components/MyProgress.jsx | 7 ++-- frontend/src/components/Play.jsx | 1 + frontend/src/components/RegistrationForm.jsx | 8 ++++- frontend/src/components/WelcomeText.jsx | 2 +- frontend/src/contexts/UserContext.jsx | 28 ++------------- frontend/src/index.css | 4 +++ 13 files changed, 90 insertions(+), 43 deletions(-) create mode 100644 frontend/src/components/Games/English.jsx create mode 100644 frontend/src/components/Games/Math.jsx create mode 100644 frontend/src/components/Games/Swedish.jsx create mode 100644 frontend/src/components/Input.jsx diff --git a/backend/server.js b/backend/server.js index fba622b84..a875804de 100644 --- a/backend/server.js +++ b/backend/server.js @@ -7,7 +7,7 @@ import crypto from "crypto"; // Defining port and connecting to mongoose const port = process.env.PORT || 8000; const app = express(); -const mongoUrl = process.env.MONGO_URL || "mongodb://localhost/auth-users"; +const mongoUrl = process.env.MONGO_URL || "mongodb://localhost/auth"; mongoose.connect(mongoUrl); mongoose.Promise = Promise; diff --git a/frontend/src/App.jsx b/frontend/src/App.jsx index ea9055788..c4f4206e2 100644 --- a/frontend/src/App.jsx +++ b/frontend/src/App.jsx @@ -2,8 +2,11 @@ import { BrowserRouter, Routes, Route } from "react-router-dom"; import { Header } from "./components/Header"; import { RegistrationForm } from "./components/RegistrationForm"; import { Login } from "./components/Login"; -// import { Play } from "./components/Play"; -// import { Progress } from "./components/MyProgress"; +import { Play } from "./components/Play"; +import { Math } from "./components/Games/Math"; +import { Swedish } from "./components/Games/Swedish"; +import { English } from "./components/Games/English"; +import { Progress } from "./components/MyProgress"; import { WelcomeText } from "./components/WelcomeText"; import { UserProvider } from "./contexts/UserContext"; @@ -13,12 +16,15 @@ export const App = () => {
- + } /> } /> } /> - {/* } /> */} - {/* } /> */} + } /> + } /> + } /> + } /> + } />
diff --git a/frontend/src/components/Games/English.jsx b/frontend/src/components/Games/English.jsx new file mode 100644 index 000000000..dd97fb98f --- /dev/null +++ b/frontend/src/components/Games/English.jsx @@ -0,0 +1,8 @@ +import styled from "styled-components"; + +export const English = () => { + return Let's play an English game!; +}; +const EnglishTitle = styled.h2` + color: black; +`; diff --git a/frontend/src/components/Games/Math.jsx b/frontend/src/components/Games/Math.jsx new file mode 100644 index 000000000..c4f07a6e8 --- /dev/null +++ b/frontend/src/components/Games/Math.jsx @@ -0,0 +1,8 @@ +import styled from "styled-components"; + +export const Math = () => { + return Let's play a math game!; +}; +const MathTitle = styled.h2` + color: black; +`; diff --git a/frontend/src/components/Games/Swedish.jsx b/frontend/src/components/Games/Swedish.jsx new file mode 100644 index 000000000..c7c70f002 --- /dev/null +++ b/frontend/src/components/Games/Swedish.jsx @@ -0,0 +1,8 @@ +import styled from "styled-components"; + +export const Swedish = () => { + return Let's play a Swedish game!; +}; +const SwedishTitle = styled.h2` + color: black; +`; diff --git a/frontend/src/components/Header.jsx b/frontend/src/components/Header.jsx index 4c3a71a00..6b452a608 100644 --- a/frontend/src/components/Header.jsx +++ b/frontend/src/components/Header.jsx @@ -1,13 +1,26 @@ +import { Link } from "react-router-dom"; import styled from "styled-components"; export const Header = () => { return ( - Register here - Log in - Play - My progress - Sign out + + + Register here + + + Log in + + + + + Play + + + My progress + + Sign out + ); }; @@ -25,6 +38,13 @@ const HeaderContainer = styled.div` align-items: center; `; +const StartPage = styled.div` + display: flex; + flex-direction: row; + justify-content: space-evenly; + width: 100vh; +`; + const Register = styled.p` color: white; cursor: pointer; @@ -43,6 +63,14 @@ const Login = styled.p` } `; +const LoggedIn = styled.div` + display: flex; + flex-direction: row; + justify-content: space-between; + padding: 10px; + width: 100vh; +`; + const Play = styled.p` color: white; cursor: pointer; diff --git a/frontend/src/components/Input.jsx b/frontend/src/components/Input.jsx new file mode 100644 index 000000000..574a53c15 --- /dev/null +++ b/frontend/src/components/Input.jsx @@ -0,0 +1,3 @@ +export const Input = () => { + return
Input
; +}; diff --git a/frontend/src/components/MyProgress.jsx b/frontend/src/components/MyProgress.jsx index dcdccbfbf..f527ca033 100644 --- a/frontend/src/components/MyProgress.jsx +++ b/frontend/src/components/MyProgress.jsx @@ -1,11 +1,10 @@ import styled from "styled-components"; -export const MyProgress = () => { +export const Progress = () => { return My Progress; }; + const ProgressTitle = styled.h2` color: black; + margin: 0 auto; `; -export const MyProgress = () => { - return
MyProgress
; -}; diff --git a/frontend/src/components/Play.jsx b/frontend/src/components/Play.jsx index c7e546c22..fe4df45e9 100644 --- a/frontend/src/components/Play.jsx +++ b/frontend/src/components/Play.jsx @@ -7,4 +7,5 @@ export const Play = () => { }; const PlayTitle = styled.h2` color: black; + margin: 0 auto; `; diff --git a/frontend/src/components/RegistrationForm.jsx b/frontend/src/components/RegistrationForm.jsx index 4268d7a95..26ab79c68 100644 --- a/frontend/src/components/RegistrationForm.jsx +++ b/frontend/src/components/RegistrationForm.jsx @@ -1,6 +1,7 @@ import { useState } from "react"; import { useLogin } from "../contexts/UserContext"; import { Button } from "./Button"; +import { useNavigate } from "react-router-dom"; import styled from "styled-components"; @@ -18,6 +19,8 @@ export const RegistrationForm = () => { confirmPassword: "", }); + const navigate = useNavigate(); + const handleChange = (e) => { // Remove error message when start typing again setErrorMessage(""); @@ -59,6 +62,9 @@ export const RegistrationForm = () => { email, password, }); + + // Redirect to login page + navigate("/login"); } catch (err) { console.error("Error registration user", err); } @@ -68,6 +74,7 @@ export const RegistrationForm = () => {
Register + {errorMessage} - {/* TODO: Skapa komponent av button */}
diff --git a/frontend/src/components/WelcomeText.jsx b/frontend/src/components/WelcomeText.jsx index c00227a8a..4323896ea 100644 --- a/frontend/src/components/WelcomeText.jsx +++ b/frontend/src/components/WelcomeText.jsx @@ -3,7 +3,7 @@ import styled from "styled-components"; export const WelcomeText = () => { return ( - Welcome to PluggIn&apos + Welcome to PluggIn The site were you can up your game in different school subjects. diff --git a/frontend/src/contexts/UserContext.jsx b/frontend/src/contexts/UserContext.jsx index 85c1d1f12..2aa5a1524 100644 --- a/frontend/src/contexts/UserContext.jsx +++ b/frontend/src/contexts/UserContext.jsx @@ -12,8 +12,8 @@ export const UserProvider = ({ children }) => { const registerUser = async (userData) => { console.log(userData); // I get correct data try { - // Send data to backend /users - const response = await fetch("/users", { + // Ensure this points to the correct backend URL + const response = await fetch("http://localhost:8000/users", { method: "POST", headers: { "Content-Type": "application/json", @@ -32,30 +32,6 @@ export const UserProvider = ({ children }) => { } }; - // //Create user with username and password - // app.post("/users", async (req, res) => { - // try { - // const { username, firstName, lastName, age, email, password } = req.body; - // const salt = bcrypt.genSaltSync(10); - // const user = new User({ - // username, - // firstName, - // lastName, - // age, - // email, - // password: bcrypt.hashSync(password, salt), - // }); - // await user.save(); - // res.status(201).json(user); - // //res.status(201).json({ id: user._id, accessToken: user.accessToken }); - // } catch (error) { - // console.error("Error creating user:", error); - // res - // .status(400) - // .json({ response: error, message: "Could not create user." }); - // } - // }); - return ( Date: Thu, 23 May 2024 09:08:28 +0200 Subject: [PATCH 08/52] Styling (#5) Co-authored-by: fridaforser --- frontend/src/components/Button.jsx | 1 + frontend/src/components/Header.jsx | 19 ++++++----- frontend/src/components/Login.jsx | 19 ++++++++--- frontend/src/components/RegistrationForm.jsx | 34 ++++++++++++++------ frontend/src/index.css | 2 +- 5 files changed, 52 insertions(+), 23 deletions(-) diff --git a/frontend/src/components/Button.jsx b/frontend/src/components/Button.jsx index 5176601f3..43bbebe36 100644 --- a/frontend/src/components/Button.jsx +++ b/frontend/src/components/Button.jsx @@ -10,6 +10,7 @@ export const Button = styled.button` font-weight: 500; transition: 0.2s ease; text-decoration: none; + margin-top: 20px; &:hover { background-color: var(--raspberryhover); diff --git a/frontend/src/components/Header.jsx b/frontend/src/components/Header.jsx index 6b452a608..354346779 100644 --- a/frontend/src/components/Header.jsx +++ b/frontend/src/components/Header.jsx @@ -26,16 +26,17 @@ export const Header = () => { }; const HeaderContainer = styled.div` - background-color: black; + background-color: var( --sunset); width: 100%; height: 30px; - opacity: 80%; position: absolute; margin: -8px; display: flex; flex-direction: row; justify-content: space-evenly; align-items: center; + padding: 10px; + font-weight: 500; `; const StartPage = styled.div` @@ -46,7 +47,7 @@ const StartPage = styled.div` `; const Register = styled.p` - color: white; + color: var( --ocean); cursor: pointer; &:hover { @@ -55,7 +56,7 @@ const Register = styled.p` `; const Login = styled.p` - color: white; + color: var( --ocean); cursor: pointer; &:hover { @@ -69,10 +70,12 @@ const LoggedIn = styled.div` justify-content: space-between; padding: 10px; width: 100vh; + color: white; + `; const Play = styled.p` - color: white; + color: var( --ocean); cursor: pointer; &:hover { @@ -81,16 +84,16 @@ const Play = styled.p` `; const MyProgress = styled.p` - color: white; + color: var( --ocean); cursor: pointer; - + &:hover { color: #fff9; } `; const SignOut = styled.p` - color: white; + color: var( --ocean); cursor: pointer; &:hover { diff --git a/frontend/src/components/Login.jsx b/frontend/src/components/Login.jsx index af3784dec..98bce8bf0 100644 --- a/frontend/src/components/Login.jsx +++ b/frontend/src/components/Login.jsx @@ -24,7 +24,7 @@ export const Login = () => { Login {error && {error}}