From 6f7d3e5922d1b4c77c754fb6b1da02abab1baf82 Mon Sep 17 00:00:00 2001 From: Josephineoderland <153084500+Josephineoderland@users.noreply.github.com> Date: Wed, 22 May 2024 13:20:58 +0200 Subject: [PATCH 01/13] backend --- backend/middleware/authenticateUser.js | 19 ++++++++++ backend/model/User.js | 23 ++++++++++++ backend/package.json | 6 +++- backend/routes/Auth.js | 43 ++++++++++++++++++++++ backend/server.js | 49 +++++++++++++++----------- backend/utils/generateSecretKey.js | 4 +++ 6 files changed, 123 insertions(+), 21 deletions(-) create mode 100644 backend/middleware/authenticateUser.js create mode 100644 backend/model/User.js create mode 100644 backend/routes/Auth.js create mode 100644 backend/utils/generateSecretKey.js diff --git a/backend/middleware/authenticateUser.js b/backend/middleware/authenticateUser.js new file mode 100644 index 000000000..d1e7b100b --- /dev/null +++ b/backend/middleware/authenticateUser.js @@ -0,0 +1,19 @@ +import jwt from "jsonwebtoken" +import User from "../model/User.js" + +const authenticateUser = async (req, res, next) => { + try { + const token = req.header("Authorization").replace("Bearer ", "") + const decoded = jwt.verify(token, process.env.JWT_SECRET) + const user = await User.findOne({ _id: decoded.userId }) + if (!user) { + throw new Error() + } + req.user = user + next() + } catch (error) { + res.status(401).json({ error: "Please authenticate" }) + } +} + +export default authenticateUser diff --git a/backend/model/User.js b/backend/model/User.js new file mode 100644 index 000000000..d2c760c85 --- /dev/null +++ b/backend/model/User.js @@ -0,0 +1,23 @@ +import mongoose from 'mongoose'; +import bcrypt from 'bcryptjs'; + +const userSchema = new mongoose.Schema({ + username: { type: String, required: true, unique: true }, + password: { type: String, required: true } +}); + +userSchema.pre('save', async function(next) { + const user = this; + if (!user.isModified('password')) return next(); + try { + const hash = await bcrypt.hash(user.password, 10); + user.password = hash; + next(); + } catch (error) { + return next(error); + } +}); + +const User = mongoose.model('User', userSchema); + +export default User; \ No newline at end of file diff --git a/backend/package.json b/backend/package.json index 8de5c4ce0..33bd494b3 100644 --- a/backend/package.json +++ b/backend/package.json @@ -1,9 +1,11 @@ { "name": "project-auth-backend", "version": "1.0.0", + "main": "server.js", + "type": "module", "description": "Starter project to get up and running with express quickly", "scripts": { - "start": "babel-node server.js", + "start": "node --env-file=.env server.js", "dev": "nodemon server.js --exec babel-node" }, "author": "", @@ -14,6 +16,8 @@ "@babel/preset-env": "^7.16.11", "cors": "^2.8.5", "express": "^4.17.3", + "express-list-endpoints": "^7.1.0", + "jsonwebtoken": "^9.0.2", "mongoose": "^8.0.0", "nodemon": "^3.0.1" } diff --git a/backend/routes/Auth.js b/backend/routes/Auth.js new file mode 100644 index 000000000..fe405c50a --- /dev/null +++ b/backend/routes/Auth.js @@ -0,0 +1,43 @@ +import express from "express" +import bcrypt from "bcryptjs" +import jwt from "jsonwebtoken" +import User from "../model/User.js" +import authenticateUser from "../middleware/authenticateUser.js" + +const authRouter = express.Router() + +authRouter.post("/signup", async (req, res) => { + try { + const { username, password } = req.body + const hashedPassword = await bcrypt.hash(password, 10) + const user = new User({ username, password: hashedPassword }) + await user.save() + res.status(201).json({ message: "User registered successfully" }) + } catch (error) { + res.status(500).json({ error: error.message }) + } +}) + +authRouter.post("/login", async (req, res) => { + try { + const { username, password } = req.body + const user = await User.findOne({ username }) + if (!user) { + return res.status(401).json({ error: "Invalid username or password" }) + } + const isPasswordValid = await bcrypt.compare(password, user.password) + if (!isPasswordValid) { + return res.status(401).json({ error: "Invalid username or password" }) + } + const token = jwt.sign({ userId: user._id }, process.env.JWT_SECRET) + res.status(200).json({ token }) + } catch (error) { + res.status(500).json({ error: error.message }) + } +}) + +authRouter.get("/thoughts", authenticateUser, (req, res) => { + res.send("Authenticated content") +}) + +export default authRouter diff --git a/backend/server.js b/backend/server.js index dfe86fb8e..c197993e8 100644 --- a/backend/server.js +++ b/backend/server.js @@ -1,27 +1,36 @@ -import cors from "cors"; -import express from "express"; -import mongoose from "mongoose"; +import express from "express" +import mongoose from "mongoose" +import cors from "cors" +import listEndpoints from "express-list-endpoints" +import authRouter from "./routes/auth.js" -const mongoUrl = process.env.MONGO_URL || "mongodb://localhost/project-mongo"; -mongoose.connect(mongoUrl); -mongoose.Promise = Promise; +const app = express() +const port = process.env.SERVER_PORT || 3001 -// 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 app = express(); +app.use(cors()) +app.use(express.json()) + + +mongoose.connect(`mongodb://${process.env.DB_HOST}:${process.env.DB_PORT}`, { + dbName: process.env.DB_NAME, + user: process.env.DB_USER, + pass: process.env.DB_PASS, +}) +const db = mongoose.connection +db.on("error", console.error.bind(console, "Anslutningsfel:")) +db.once("open", () => { + console.log("Ansluten till databasen") +}) -// Add middlewares to enable cors and json body parsing -app.use(cors()); -app.use(express.json()); -// Start defining your routes here app.get("/", (req, res) => { - res.send("Hello Technigo!"); -}); + const endpoints = listEndpoints(app) + res.json(endpoints) +}) + + +app.use(authRouter) -// Start the server app.listen(port, () => { - console.log(`Server running on http://localhost:${port}`); -}); + console.log(`Chattservern lyssnar på port ${port}`) +}) diff --git a/backend/utils/generateSecretKey.js b/backend/utils/generateSecretKey.js new file mode 100644 index 000000000..07e6bcd32 --- /dev/null +++ b/backend/utils/generateSecretKey.js @@ -0,0 +1,4 @@ +import crypto from "crypto" + +const jwtSecret = crypto.randomBytes(32).toString("hex") +console.log(jwtSecret) From 0a45fc6d9c73a21d02c855e04c704721fe75f6a1 Mon Sep 17 00:00:00 2001 From: Josephineoderland <153084500+Josephineoderland@users.noreply.github.com> Date: Wed, 22 May 2024 13:28:22 +0200 Subject: [PATCH 02/13] backend --- backend/package.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/backend/package.json b/backend/package.json index 33bd494b3..0cc685bf2 100644 --- a/backend/package.json +++ b/backend/package.json @@ -5,8 +5,8 @@ "type": "module", "description": "Starter project to get up and running with express quickly", "scripts": { - "start": "node --env-file=.env server.js", - "dev": "nodemon server.js --exec babel-node" + "start": "node server.js", + "dev": "nodemon --env-file=.env server.js --exec babel-node" }, "author": "", "license": "ISC", From 62aa656d77c7d0d43155934b2fca92ca9392f83f Mon Sep 17 00:00:00 2001 From: Josephineoderland <153084500+Josephineoderland@users.noreply.github.com> Date: Wed, 22 May 2024 13:37:14 +0200 Subject: [PATCH 03/13] backend --- backend/server.js | 3 --- 1 file changed, 3 deletions(-) diff --git a/backend/server.js b/backend/server.js index c197993e8..c947d2bd7 100644 --- a/backend/server.js +++ b/backend/server.js @@ -10,7 +10,6 @@ const port = process.env.SERVER_PORT || 3001 app.use(cors()) app.use(express.json()) - mongoose.connect(`mongodb://${process.env.DB_HOST}:${process.env.DB_PORT}`, { dbName: process.env.DB_NAME, user: process.env.DB_USER, @@ -22,13 +21,11 @@ db.once("open", () => { console.log("Ansluten till databasen") }) - app.get("/", (req, res) => { const endpoints = listEndpoints(app) res.json(endpoints) }) - app.use(authRouter) app.listen(port, () => { From 9e2f65665b5b10a5ebbbedfeceaa76f941108947 Mon Sep 17 00:00:00 2001 From: Josephineoderland <153084500+Josephineoderland@users.noreply.github.com> Date: Wed, 22 May 2024 13:53:42 +0200 Subject: [PATCH 04/13] backend --- backend/server.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/backend/server.js b/backend/server.js index c947d2bd7..2ed0136f1 100644 --- a/backend/server.js +++ b/backend/server.js @@ -26,7 +26,7 @@ app.get("/", (req, res) => { res.json(endpoints) }) -app.use(authRouter) +app.use("/", authRouter) app.listen(port, () => { console.log(`Chattservern lyssnar på port ${port}`) From 60b7040b92f79956b06b61c76c19776bef3ae883 Mon Sep 17 00:00:00 2001 From: Josephineoderland <153084500+Josephineoderland@users.noreply.github.com> Date: Wed, 22 May 2024 14:03:33 +0200 Subject: [PATCH 05/13] backend --- backend/server.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/backend/server.js b/backend/server.js index 2ed0136f1..1d55e999f 100644 --- a/backend/server.js +++ b/backend/server.js @@ -2,7 +2,7 @@ import express from "express" import mongoose from "mongoose" import cors from "cors" import listEndpoints from "express-list-endpoints" -import authRouter from "./routes/auth.js" +import authRouter from "./routes/Auth.js" const app = express() const port = process.env.SERVER_PORT || 3001 @@ -26,7 +26,7 @@ app.get("/", (req, res) => { res.json(endpoints) }) -app.use("/", authRouter) +app.use(authRouter) app.listen(port, () => { console.log(`Chattservern lyssnar på port ${port}`) From 699a711092d9092bbd779eeb7f5b5f1d7a548882 Mon Sep 17 00:00:00 2001 From: Josephineoderland <153084500+Josephineoderland@users.noreply.github.com> Date: Wed, 22 May 2024 14:07:03 +0200 Subject: [PATCH 06/13] backend --- backend/package.json | 1 + 1 file changed, 1 insertion(+) diff --git a/backend/package.json b/backend/package.json index 0cc685bf2..602d0fa65 100644 --- a/backend/package.json +++ b/backend/package.json @@ -14,6 +14,7 @@ "@babel/core": "^7.17.9", "@babel/node": "^7.16.8", "@babel/preset-env": "^7.16.11", + "bcryptjs": "^2.4.3", "cors": "^2.8.5", "express": "^4.17.3", "express-list-endpoints": "^7.1.0", From 9dc6f094726de7499b4c3e8f0b0840cf73880a02 Mon Sep 17 00:00:00 2001 From: Josephineoderland <153084500+Josephineoderland@users.noreply.github.com> Date: Wed, 22 May 2024 14:51:10 +0200 Subject: [PATCH 07/13] backend --- backend/routes/Auth.js | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/backend/routes/Auth.js b/backend/routes/Auth.js index fe405c50a..12e029f50 100644 --- a/backend/routes/Auth.js +++ b/backend/routes/Auth.js @@ -18,6 +18,15 @@ authRouter.post("/signup", async (req, res) => { } }) +authRouter.get("/signup", async (req, res) => { + try { + const users = await User.find() + res.status(200).json(users) + } catch (error) { + res.status(500).json({ error: error.message }) + } +}) + authRouter.post("/login", async (req, res) => { try { const { username, password } = req.body From 08e279ed272794f66e687d31d545d2e7920826b5 Mon Sep 17 00:00:00 2001 From: Josephineoderland <153084500+Josephineoderland@users.noreply.github.com> Date: Wed, 22 May 2024 15:27:34 +0200 Subject: [PATCH 08/13] backend --- backend/package.json | 1 + backend/routes/Auth.js | 4 ++++ 2 files changed, 5 insertions(+) diff --git a/backend/package.json b/backend/package.json index 602d0fa65..9acfeaf05 100644 --- a/backend/package.json +++ b/backend/package.json @@ -19,6 +19,7 @@ "express": "^4.17.3", "express-list-endpoints": "^7.1.0", "jsonwebtoken": "^9.0.2", + "jwt-decode": "^4.0.0", "mongoose": "^8.0.0", "nodemon": "^3.0.1" } diff --git a/backend/routes/Auth.js b/backend/routes/Auth.js index 12e029f50..1b87dec54 100644 --- a/backend/routes/Auth.js +++ b/backend/routes/Auth.js @@ -45,6 +45,10 @@ authRouter.post("/login", async (req, res) => { } }) +authRouter.get("/login", (req, res) => { + res.status(404).send("Not found") +}) + authRouter.get("/thoughts", authenticateUser, (req, res) => { res.send("Authenticated content") }) From 9186e2eea4cf5305502cecbb419c60ffbbc4b2b8 Mon Sep 17 00:00:00 2001 From: Josephineoderland <153084500+Josephineoderland@users.noreply.github.com> Date: Wed, 22 May 2024 15:47:51 +0200 Subject: [PATCH 09/13] backend --- backend/middleware/authenticateUser.js | 2 ++ backend/routes/Auth.js | 7 +++---- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/backend/middleware/authenticateUser.js b/backend/middleware/authenticateUser.js index d1e7b100b..33d5a91cd 100644 --- a/backend/middleware/authenticateUser.js +++ b/backend/middleware/authenticateUser.js @@ -5,6 +5,8 @@ const authenticateUser = async (req, res, next) => { try { const token = req.header("Authorization").replace("Bearer ", "") const decoded = jwt.verify(token, process.env.JWT_SECRET) + console.log('Token:', token); + console.log('Dekrypterad token:', decoded); const user = await User.findOne({ _id: decoded.userId }) if (!user) { throw new Error() diff --git a/backend/routes/Auth.js b/backend/routes/Auth.js index 1b87dec54..52a70f023 100644 --- a/backend/routes/Auth.js +++ b/backend/routes/Auth.js @@ -31,6 +31,8 @@ authRouter.post("/login", async (req, res) => { try { const { username, password } = req.body const user = await User.findOne({ username }) + console.log("Inkommande lösenord:", password) + console.log("Hashat lösenord i databasen:", user.password) if (!user) { return res.status(401).json({ error: "Invalid username or password" }) } @@ -39,16 +41,13 @@ authRouter.post("/login", async (req, res) => { return res.status(401).json({ error: "Invalid username or password" }) } const token = jwt.sign({ userId: user._id }, process.env.JWT_SECRET) + console.log("Genererat JWT-token:", token) res.status(200).json({ token }) } catch (error) { res.status(500).json({ error: error.message }) } }) -authRouter.get("/login", (req, res) => { - res.status(404).send("Not found") -}) - authRouter.get("/thoughts", authenticateUser, (req, res) => { res.send("Authenticated content") }) From 0d6fcfa1cbbaea26fb26361e4d93a666a48368aa Mon Sep 17 00:00:00 2001 From: Josephineoderland <153084500+Josephineoderland@users.noreply.github.com> Date: Wed, 22 May 2024 16:08:42 +0200 Subject: [PATCH 10/13] backend --- backend/routes/Auth.js | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/backend/routes/Auth.js b/backend/routes/Auth.js index 52a70f023..82a9a52e5 100644 --- a/backend/routes/Auth.js +++ b/backend/routes/Auth.js @@ -9,8 +9,7 @@ const authRouter = express.Router() authRouter.post("/signup", async (req, res) => { try { const { username, password } = req.body - const hashedPassword = await bcrypt.hash(password, 10) - const user = new User({ username, password: hashedPassword }) + const user = new User({ username, password: password }) await user.save() res.status(201).json({ message: "User registered successfully" }) } catch (error) { @@ -30,13 +29,17 @@ authRouter.get("/signup", async (req, res) => { authRouter.post("/login", async (req, res) => { try { const { username, password } = req.body + console.log(username) + console.log(password) const user = await User.findOne({ username }) + console.log(user) console.log("Inkommande lösenord:", password) console.log("Hashat lösenord i databasen:", user.password) if (!user) { return res.status(401).json({ error: "Invalid username or password" }) } const isPasswordValid = await bcrypt.compare(password, user.password) + console.log(isPasswordValid) if (!isPasswordValid) { return res.status(401).json({ error: "Invalid username or password" }) } From c880c3fc8bbaaf2232296ddd35f1c3b5f7bdf437 Mon Sep 17 00:00:00 2001 From: Josephineoderland <153084500+Josephineoderland@users.noreply.github.com> Date: Wed, 22 May 2024 16:42:03 +0200 Subject: [PATCH 11/13] backend --- backend/model/Thought.js | 10 ++++++++++ backend/routes/Auth.js | 24 ++++++++++++++++++++++-- 2 files changed, 32 insertions(+), 2 deletions(-) create mode 100644 backend/model/Thought.js diff --git a/backend/model/Thought.js b/backend/model/Thought.js new file mode 100644 index 000000000..924a482e7 --- /dev/null +++ b/backend/model/Thought.js @@ -0,0 +1,10 @@ +import mongoose from 'mongoose'; + +const thoughtSchema = new mongoose.Schema({ + text: { type: String, required: true }, + user: { type: mongoose.Schema.Types.ObjectId, ref: 'User', required: true } +}); + +const Thought = mongoose.model('Thought', thoughtSchema); + +export default Thought; diff --git a/backend/routes/Auth.js b/backend/routes/Auth.js index 82a9a52e5..580d6c2f5 100644 --- a/backend/routes/Auth.js +++ b/backend/routes/Auth.js @@ -3,6 +3,7 @@ import bcrypt from "bcryptjs" import jwt from "jsonwebtoken" import User from "../model/User.js" import authenticateUser from "../middleware/authenticateUser.js" +import Thought from "../model/Thought.js" const authRouter = express.Router() @@ -51,8 +52,27 @@ authRouter.post("/login", async (req, res) => { } }) -authRouter.get("/thoughts", authenticateUser, (req, res) => { - res.send("Authenticated content") +authRouter.get("/thoughts", authenticateUser, async (req, res) => { + try { + const userId = req.user._id + const userThoughts = await Thought.find({ user: userId }) + + res.status(200).json(userThoughts) + } catch (error) { + res.status(500).json({ error: error.message }) + } +}) + +authRouter.post("/thoughts", authenticateUser, async (req, res) => { + try { + const { thought } = req.body + const userId = req.user._id + const newThought = new Thought({ text: thought, user: userId }) + await newThought.save() + res.status(201).json({ message: "Thought saved successfully" }) + } catch (error) { + res.status(500).json({ error: error.message }) + } }) export default authRouter From f23da3aa05046d680855d535b1ffa4ea464974d8 Mon Sep 17 00:00:00 2001 From: Josephineoderland <153084500+Josephineoderland@users.noreply.github.com> Date: Wed, 22 May 2024 16:57:11 +0200 Subject: [PATCH 12/13] frontend --- frontend/package.json | 6 +- frontend/src/App.jsx | 26 ++++++++- frontend/src/components/Home.jsx | 20 +++++++ frontend/src/components/Login.jsx | 80 +++++++++++++++++++++++++++ frontend/src/components/Register.jsx | 44 +++++++++++++++ frontend/src/components/Thoughts.jsx | 82 ++++++++++++++++++++++++++++ frontend/src/context/AuthContext.jsx | 28 ++++++++++ frontend/src/context/authHelpers.jsx | 24 ++++++++ frontend/src/main.jsx | 2 +- 9 files changed, 307 insertions(+), 5 deletions(-) create mode 100644 frontend/src/components/Home.jsx create mode 100644 frontend/src/components/Login.jsx create mode 100644 frontend/src/components/Register.jsx create mode 100644 frontend/src/components/Thoughts.jsx create mode 100644 frontend/src/context/AuthContext.jsx create mode 100644 frontend/src/context/authHelpers.jsx diff --git a/frontend/package.json b/frontend/package.json index e9c95b79f..e971eb2e5 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -10,8 +10,12 @@ "preview": "vite preview" }, "dependencies": { + "axios": "^1.7.2", + "jwt-decode": "^4.0.0", + "prop-types": "^15.8.1", "react": "^18.2.0", - "react-dom": "^18.2.0" + "react-dom": "^18.2.0", + "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 1091d4310..b7976c6d7 100644 --- a/frontend/src/App.jsx +++ b/frontend/src/App.jsx @@ -1,3 +1,23 @@ -export const App = () => { - return
Find me in src/app.jsx!
; -}; +import { BrowserRouter as Router, Route, Routes } from "react-router-dom" +import Register from "./components/Register" +import Login from "./components/Login" +import Thoughts from "./components/Thoughts" +import Home from "./components/Home" +import { AuthProvider } from "./context/AuthContext" + +function App() { + return ( + + + + } /> + } /> + } /> + } /> + + + + ) +} + +export default App diff --git a/frontend/src/components/Home.jsx b/frontend/src/components/Home.jsx new file mode 100644 index 000000000..35a3a879f --- /dev/null +++ b/frontend/src/components/Home.jsx @@ -0,0 +1,20 @@ +import { Link } from "react-router-dom"; + +const Home = () => { + return ( +
+

Welcome to the Home Page

+

Please select an option:

+
+ + + + + + +
+
+ ); +}; + +export default Home; \ No newline at end of file diff --git a/frontend/src/components/Login.jsx b/frontend/src/components/Login.jsx new file mode 100644 index 000000000..ae8af7863 --- /dev/null +++ b/frontend/src/components/Login.jsx @@ -0,0 +1,80 @@ +import { useState, useContext, useEffect } from "react" +import axios from "axios" +import { useNavigate } from "react-router-dom" +import { AuthContext } from "../context/AuthContext" +import { getUserIdFromToken } from "../context/authHelpers" + +const Login = () => { + const [username, setUsername] = useState("") + const [password, setPassword] = useState("") + const { login } = useContext(AuthContext) + const navigate = useNavigate() + + useEffect(() => { + const token = localStorage.getItem("token") + if (token && getUserIdFromToken(token)) { + navigate("/thoughts") + } + }, [navigate]) + + const handleSubmit = async (e) => { + e.preventDefault() + try { + console.log("Starting login process...") + + const userResponse = await axios.get( + `https://project-auth-7ju7.onrender.com/signup?username=${username}` + ) + console.log("User response:", userResponse.data) + + if (!userResponse.data || !userResponse.data.length) { + alert("User does not exist. Please register first.") + return + } + + console.log("User exists. Proceeding with login...") + + const response = await axios.post( + "https://project-auth-7ju7.onrender.com/login", + { + username, + password, + } + ) + + console.log("Login response:", response.data) + + localStorage.setItem("token", response.data.token) + + + login(response.data.token) + + console.log("Login successful. Navigating to /thoughts...") + navigate("/thoughts") + } catch (error) { + console.error("Login failed:", error) + alert("Login failed") + } + } + + return ( +
+

Login

+ setUsername(e.target.value)} + /> + setPassword(e.target.value)} + /> + +
+ ) +} + +export default Login diff --git a/frontend/src/components/Register.jsx b/frontend/src/components/Register.jsx new file mode 100644 index 000000000..4345380c6 --- /dev/null +++ b/frontend/src/components/Register.jsx @@ -0,0 +1,44 @@ +import { useState } from "react" +import axios from "axios" +import { useNavigate } from "react-router-dom" + +const Register = () => { + const [username, setUsername] = useState("") + const [password, setPassword] = useState("") + const navigate = useNavigate() + + const handleSubmit = async (e) => { + e.preventDefault() + try { + await axios.post("https://project-auth-7ju7.onrender.com/signup", { + username, + password, + }) + navigate("/login") + } catch (error) { + console.error(error) + alert("Registration failed") + } + } + + return ( +
+

Register

+ setUsername(e.target.value)} + /> + setPassword(e.target.value)} + /> + +
+ ) +} + +export default Register diff --git a/frontend/src/components/Thoughts.jsx b/frontend/src/components/Thoughts.jsx new file mode 100644 index 000000000..5044f239f --- /dev/null +++ b/frontend/src/components/Thoughts.jsx @@ -0,0 +1,82 @@ +import { useState, useContext, useEffect, useCallback } from "react" +import axios from "axios" +import { AuthContext } from "../context/AuthContext" +import { useNavigate } from "react-router-dom" + +const Thoughts = () => { + const { token, logout } = useContext(AuthContext) + const [thought, setThought] = useState("") + const [error, setError] = useState(null) + const [thoughtsList, setThoughtsList] = useState([]) + const navigate = useNavigate() + + const fetchThoughts = useCallback(async () => { + try { + const response = await axios.get( + "https://project-auth-7ju7.onrender.com/thoughts", + { + headers: { + Authorization: `Bearer ${token}`, + }, + } + ) + setThoughtsList(response.data) + } catch (error) { + console.error("Failed to fetch thoughts:", error) + setError("Failed to fetch thoughts. Please try again.") + } + }, [token]) + + useEffect(() => { + fetchThoughts() + }, [fetchThoughts]) + + const handleSubmit = async (e) => { + e.preventDefault() + try { + const response = await axios.post( + "https://project-auth-7ju7.onrender.com/thoughts", + { thought }, + { + headers: { + Authorization: `Bearer ${token}`, + }, + } + ) + console.log("Thought submitted:", response.data) + setThought("") + fetchThoughts() + } catch (error) { + console.error("Failed to submit thought:", error) + setError("Failed to submit thought. Please try again.") + } + } + + const handleLogout = () => { + logout() + navigate("/") + } + + return ( +
+

Thoughts

+
+ + +
+ {error &&

{error}

} + + +
+ ) +} + +export default Thoughts diff --git a/frontend/src/context/AuthContext.jsx b/frontend/src/context/AuthContext.jsx new file mode 100644 index 000000000..95b76574a --- /dev/null +++ b/frontend/src/context/AuthContext.jsx @@ -0,0 +1,28 @@ +import { createContext, useState } from "react" +import PropTypes from "prop-types" + +export const AuthContext = createContext() + +export const AuthProvider = ({ children }) => { + const [token, setToken] = useState(localStorage.getItem("token") || null) + + const login = (token) => { + setToken(token) + localStorage.setItem("token", token) + } + + const logout = () => { + setToken(null) + localStorage.removeItem("token") + } + + return ( + + {children} + + ) +} + +AuthProvider.propTypes = { + children: PropTypes.node.isRequired, +} diff --git a/frontend/src/context/authHelpers.jsx b/frontend/src/context/authHelpers.jsx new file mode 100644 index 000000000..2ec7e17b9 --- /dev/null +++ b/frontend/src/context/authHelpers.jsx @@ -0,0 +1,24 @@ +import {jwtDecode} from "jwt-decode" + +export const getUserIdFromToken = (token) => { + if (!token) return null + try { + const decodedToken = jwtDecode(token) + return decodedToken.id + } catch (error) { + return null + } +} + +export const isLoggedIn = () => { + const token = localStorage.getItem("token") + if (!token) return false + + try { + const decodedToken = jwtDecode(token) + const currentTime = Date.now() / 1000 + return decodedToken.exp > currentTime + } catch (error) { + return false + } +} diff --git a/frontend/src/main.jsx b/frontend/src/main.jsx index 51294f399..5bb11ee1e 100644 --- a/frontend/src/main.jsx +++ b/frontend/src/main.jsx @@ -1,6 +1,6 @@ import React from "react"; import ReactDOM from "react-dom/client"; -import { App } from "./App.jsx"; +import App from "./App.jsx"; import "./index.css"; ReactDOM.createRoot(document.getElementById("root")).render( From c0a3ba4c320afb82fda69a562e9759bce7ca85d9 Mon Sep 17 00:00:00 2001 From: Josephineoderland <153084500+Josephineoderland@users.noreply.github.com> Date: Wed, 22 May 2024 17:24:52 +0200 Subject: [PATCH 13/13] frontend --- frontend/package.json | 1 + netlify.toml | 6 ------ package.json | 5 +++++ 3 files changed, 6 insertions(+), 6 deletions(-) delete mode 100644 netlify.toml diff --git a/frontend/package.json b/frontend/package.json index e971eb2e5..f616712d4 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -4,6 +4,7 @@ "version": "0.0.0", "type": "module", "scripts": { + "start": "vite", "dev": "vite", "build": "vite build", "lint": "eslint . --ext js,jsx --report-unused-disable-directives --max-warnings 0", diff --git a/netlify.toml b/netlify.toml deleted file mode 100644 index 95443a1f3..000000000 --- a/netlify.toml +++ /dev/null @@ -1,6 +0,0 @@ -# This file tells netlify where the code for this project is and -# how it should build the JavaScript assets to deploy from. -[build] - base = "frontend/" - publish = "build/" - command = "npm run build" diff --git a/package.json b/package.json index d774b8cc3..b3b389107 100644 --- a/package.json +++ b/package.json @@ -3,5 +3,10 @@ "version": "1.0.0", "scripts": { "postinstall": "npm install --prefix backend" + }, + "dependencies": { + "bcryptjs": "^2.4.3", + "express": "^4.19.2", + "mongoose": "^8.4.0" } }