From 31487af928e477996c4a8edb9ac0ec9e352a5af7 Mon Sep 17 00:00:00 2001 From: Your El1an3 Date: Mon, 20 May 2024 20:45:49 +0200 Subject: [PATCH 01/33] dependencies update and import --- backend/server.js | 29 +++++++++++++++++++++++------ package.json | 11 +++++++++++ 2 files changed, 34 insertions(+), 6 deletions(-) diff --git a/backend/server.js b/backend/server.js index dfe86fb8e..6946a3f1b 100644 --- a/backend/server.js +++ b/backend/server.js @@ -1,27 +1,44 @@ import cors from "cors"; import express from "express"; import mongoose from "mongoose"; +import dotenv from "dotenv"; +import expressListEndpoints from "express-list-endpoints"; + +dotenv.config(); const mongoUrl = process.env.MONGO_URL || "mongodb://localhost/project-mongo"; mongoose.connect(mongoUrl); mongoose.Promise = Promise; -// 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 +//defines the port the app will run on const port = process.env.PORT || 8080; const app = express(); -// Add middlewares to enable cors and json body parsing +//add middlewares to enable cors and json body parsing app.use(cors()); app.use(express.json()); -// Start defining your routes here +//middleware to check if database is available +app.use((req, res, next) => { + if (mongoose.connection.readyState === 1) { + next(); + } else { + res.status(503).json({ error: "service unavailable" }); + } +}); + +//routes +app.get("/", (req, res) => { + const endpoints = expressListEndpoints(app); + res.json(endpoints); +}); + +//start defining your routes here app.get("/", (req, res) => { res.send("Hello Technigo!"); }); -// Start the server +//start the server app.listen(port, () => { console.log(`Server running on http://localhost:${port}`); }); diff --git a/package.json b/package.json index d774b8cc3..bc95add89 100644 --- a/package.json +++ b/package.json @@ -3,5 +3,16 @@ "version": "1.0.0", "scripts": { "postinstall": "npm install --prefix backend" + }, + "devDependencies": { + "@babel/cli": "^7.24.5", + "@babel/core": "^7.24.5", + "@babel/preset-env": "^7.24.5", + "nodemon": "^3.1.0" + }, + "dependencies": { + "dotenv": "^16.4.5", + "express-list-endpoints": "^7.1.0", + "mongoose": "^8.4.0" } } From f15207aca6cc53fd76940a618a599742f69807db Mon Sep 17 00:00:00 2001 From: Your El1an3 Date: Mon, 20 May 2024 21:59:12 +0200 Subject: [PATCH 02/33] added basic code from codealong --- backend/server.js | 60 +++++++++++++++++++++-- frontend/src/components/Dashboard.jsx | 0 frontend/src/components/Registration.jsx | 0 frontend/src/components/SignIn.jsx | 0 frontend/src/components/SignOutButton.jsx | 0 package.json | 1 + 6 files changed, 58 insertions(+), 3 deletions(-) create mode 100644 frontend/src/components/Dashboard.jsx create mode 100644 frontend/src/components/Registration.jsx create mode 100644 frontend/src/components/SignIn.jsx create mode 100644 frontend/src/components/SignOutButton.jsx diff --git a/backend/server.js b/backend/server.js index 6946a3f1b..6eaa97e57 100644 --- a/backend/server.js +++ b/backend/server.js @@ -3,13 +3,36 @@ import express from "express"; import mongoose from "mongoose"; import dotenv from "dotenv"; import expressListEndpoints from "express-list-endpoints"; +import bcrypt from "bcrypt"; dotenv.config(); -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; +//create a schema +const User = mongoose.model("User", { + name: { + type: String, + unique: true, + }, + // email: { + // type: String, + // unique: true, + // }, + password: { + type: String, + required: true, + }, + accessToken: { + type: String, + default: () => bcrypt.genSaltSync(), + }, +}); + +// console.log(bcrypt.genSaltSync()); + //defines the port the app will run on const port = process.env.PORT || 8080; const app = express(); @@ -27,6 +50,18 @@ app.use((req, res, next) => { } }); +//middleware to authenticate user +const authenticateUser = async (req, res, next) => { + const user = await User.findOne({ accessToken: req.header("Authorization") }); + if (user) { + req.user = user; + next(); + } else { + res.status(401), + json({ loggedOut: true, message: "you have to log in to get access" }); + } +}; + //routes app.get("/", (req, res) => { const endpoints = expressListEndpoints(app); @@ -34,8 +69,27 @@ app.get("/", (req, res) => { }); //start defining your routes here -app.get("/", (req, res) => { - res.send("Hello Technigo!"); +// app.get("/", (req, res) => { +// res.send("Hello Technigo!"); +// }); + +app.post("/dashboard", authenticateUser); +app.post("/dashboard", 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 }); + if (user && bcrypt.compareSync(req.body.password, user.password)) { + //success + res.json({ userId: user._id, accessToken: user.accessToken }); + } else { + //failure + // A) user doesn not exist + // B) encrypted password does not match + res.json({ notFound: true }); + } }); //start the server 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/Registration.jsx b/frontend/src/components/Registration.jsx new file mode 100644 index 000000000..e69de29bb diff --git a/frontend/src/components/SignIn.jsx b/frontend/src/components/SignIn.jsx new file mode 100644 index 000000000..e69de29bb diff --git a/frontend/src/components/SignOutButton.jsx b/frontend/src/components/SignOutButton.jsx new file mode 100644 index 000000000..e69de29bb diff --git a/package.json b/package.json index bc95add89..d157509d7 100644 --- a/package.json +++ b/package.json @@ -11,6 +11,7 @@ "nodemon": "^3.1.0" }, "dependencies": { + "bcrypt": "^5.1.1", "dotenv": "^16.4.5", "express-list-endpoints": "^7.1.0", "mongoose": "^8.4.0" From 01929c5c2e2f2c22130ac95e516a8f8625901c09 Mon Sep 17 00:00:00 2001 From: Your El1an3 Date: Wed, 22 May 2024 09:00:23 +0200 Subject: [PATCH 03/33] created endpoints and schema --- backend/server.js | 62 +++++++++++++++++++++++++++++++++-------------- 1 file changed, 44 insertions(+), 18 deletions(-) diff --git a/backend/server.js b/backend/server.js index 6eaa97e57..33bb82d5f 100644 --- a/backend/server.js +++ b/backend/server.js @@ -11,16 +11,13 @@ const mongoUrl = process.env.MONGO_URL || "mongodb://localhost/auth"; mongoose.connect(mongoUrl); mongoose.Promise = Promise; -//create a schema -const User = mongoose.model("User", { +//create schema +const userSchema = new mongoose.Schema({ name: { type: String, unique: true, + required: true, }, - // email: { - // type: String, - // unique: true, - // }, password: { type: String, required: true, @@ -31,6 +28,9 @@ const User = mongoose.model("User", { }, }); +//create model +const User = mongoose.model("User", userSchema); + // console.log(bcrypt.genSaltSync()); //defines the port the app will run on @@ -62,21 +62,41 @@ const authenticateUser = async (req, res, next) => { } }; -//routes -app.get("/", (req, res) => { - const endpoints = expressListEndpoints(app); - res.json(endpoints); +//registration endpoint +app.post("/register", async (req, res) => { + try { + const { name, password } = req.body; + const salt = bcrypt.genSaltSync(); + const hashedPassword = bcrypt.hashSync(password, salt); + + const newUser = new User({ + name, + password: hashedPassword, + accessToken: bcrypt.genSaltSync(), //generate a new token + }); + + await newUser.save(); + res.status(201).json({ id: newUser._id, accessToken: newUser.accessToken }); + } catch (error) { + res + .status(400) + .json({ message: "Could not create user", errors: error.errors }); + } }); -//start defining your routes here -// app.get("/", (req, res) => { -// res.send("Hello Technigo!"); -// }); +//sign-in endpoint +app.post("/sessions", async (req, res) => { + const user = await User.findOne({ name: req.body.name }); + if (user && bcrypt.compareSync(req.body.password, user.password)) { + res.json({ userId: user._id, accessToken: user.accessToken }); + } else { + res.status(401).json({ notFound: true }); + } +}); -app.post("/dashboard", authenticateUser); -app.post("/dashboard", 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 +//authenticated endpoint +app.get("/dashboard", authenticateUser, (req, res) => { + res.json({ message: "This is the secret dashboard!", user: req.user }); }); app.post("/sessions", async (req, res) => { @@ -92,6 +112,12 @@ app.post("/sessions", async (req, res) => { } }); +//route to list all endpoints +app.get("/", (req, res) => { + const endpoints = expressListEndpoints(app); + res.json(endpoints); +}); + //start the server app.listen(port, () => { console.log(`Server running on http://localhost:${port}`); From d6554416b7d89522a66d50ff6901877c5a836ae9 Mon Sep 17 00:00:00 2001 From: Your El1an3 Date: Wed, 22 May 2024 12:12:04 +0200 Subject: [PATCH 04/33] updated dependencies in backend --- backend/package.json | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/backend/package.json b/backend/package.json index 8de5c4ce0..17a4b9a1d 100644 --- a/backend/package.json +++ b/backend/package.json @@ -12,9 +12,13 @@ "@babel/core": "^7.17.9", "@babel/node": "^7.16.8", "@babel/preset-env": "^7.16.11", + "bcrypt": "^5.1.1", "cors": "^2.8.5", - "express": "^4.17.3", - "mongoose": "^8.0.0", + "dotenv": "^16.4.5", + "express": "^4.19.2", + "express-list-endpoints": "^7.1.0", + "mongodb": "^4.17.2", + "mongoose": "^8.4.0", "nodemon": "^3.0.1" } } From abcbc52c7f464840d755154d72faf123cdf99228 Mon Sep 17 00:00:00 2001 From: Your El1an3 Date: Wed, 22 May 2024 12:45:41 +0200 Subject: [PATCH 05/33] updated frontend dependencies & read me --- frontend/package.json | 6 ++++-- frontend/src/App.jsx | 8 +++++++- frontend/src/components/Dashboard.jsx | 3 +++ frontend/src/components/Registration.jsx | 3 +++ frontend/src/components/SignIn.jsx | 3 +++ frontend/src/components/SignOutButton.jsx | 3 +++ 6 files changed, 23 insertions(+), 3 deletions(-) diff --git a/frontend/package.json b/frontend/package.json index e9c95b79f..866abc046 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -10,8 +10,10 @@ "preview": "vite preview" }, "dependencies": { - "react": "^18.2.0", - "react-dom": "^18.2.0" + "react": "^18.3.1", + "react-dom": "^18.3.1", + "react-router-dom": "^6.23.1", + "styled-components": "^6.1.11" }, "devDependencies": { "@types/react": "^18.2.15", diff --git a/frontend/src/App.jsx b/frontend/src/App.jsx index 1091d4310..1b11e31d1 100644 --- a/frontend/src/App.jsx +++ b/frontend/src/App.jsx @@ -1,3 +1,9 @@ +import { SignIn } from "./components/SignIn"; + export const App = () => { - return
Find me in src/app.jsx!
; + return ( + <> + + + ); }; diff --git a/frontend/src/components/Dashboard.jsx b/frontend/src/components/Dashboard.jsx index e69de29bb..5cdac21f8 100644 --- a/frontend/src/components/Dashboard.jsx +++ b/frontend/src/components/Dashboard.jsx @@ -0,0 +1,3 @@ +export const Dashboard = () => { + return
Dashboard
; +}; diff --git a/frontend/src/components/Registration.jsx b/frontend/src/components/Registration.jsx index e69de29bb..d8d8bcfdd 100644 --- a/frontend/src/components/Registration.jsx +++ b/frontend/src/components/Registration.jsx @@ -0,0 +1,3 @@ +export const Registration = () => { + return
Registration
; +}; diff --git a/frontend/src/components/SignIn.jsx b/frontend/src/components/SignIn.jsx index e69de29bb..3c13e48ef 100644 --- a/frontend/src/components/SignIn.jsx +++ b/frontend/src/components/SignIn.jsx @@ -0,0 +1,3 @@ +export const SignIn = () => { + return
SignIn
; +}; diff --git a/frontend/src/components/SignOutButton.jsx b/frontend/src/components/SignOutButton.jsx index e69de29bb..0ac7616dd 100644 --- a/frontend/src/components/SignOutButton.jsx +++ b/frontend/src/components/SignOutButton.jsx @@ -0,0 +1,3 @@ +export const SignOutButton = () => { + return
SignOutButton
; +}; From e6e10c2fc3a769204f8e9438c8f5049b214d3970 Mon Sep 17 00:00:00 2001 From: Your El1an3 Date: Wed, 22 May 2024 12:54:12 +0200 Subject: [PATCH 06/33] created components and reusables --- frontend/src/components/SignIn.jsx | 18 +++++++++++++++++- frontend/src/components/SignOutButton.jsx | 3 --- frontend/src/reusables/Button.jsx | 3 +++ frontend/src/reusables/Form.jsx | 3 +++ frontend/src/reusables/Header.jsx | 3 +++ 5 files changed, 26 insertions(+), 4 deletions(-) delete mode 100644 frontend/src/components/SignOutButton.jsx create mode 100644 frontend/src/reusables/Button.jsx create mode 100644 frontend/src/reusables/Form.jsx create mode 100644 frontend/src/reusables/Header.jsx diff --git a/frontend/src/components/SignIn.jsx b/frontend/src/components/SignIn.jsx index 3c13e48ef..3661a574d 100644 --- a/frontend/src/components/SignIn.jsx +++ b/frontend/src/components/SignIn.jsx @@ -1,3 +1,19 @@ +//imports +import { Form } from "../reusables/Form"; +import { Header } from "../reusables/Header"; +import { Button } from "../reusables/Button"; + +//styling +//use styled components here + +//component + export const SignIn = () => { - return
SignIn
; + return ( + <> +
+
+ + + + ); }; diff --git a/frontend/src/reusables/Header.jsx b/frontend/src/reusables/Header.jsx index ed27af82a..5b494da7a 100644 --- a/frontend/src/reusables/Header.jsx +++ b/frontend/src/reusables/Header.jsx @@ -1,3 +1,72 @@ +//imports +import styled from "styled-components"; +import HeaderPicture from "../../public/header.jpg"; +import Globe from "../../public/globe.png"; + +//styles +const HeaderContainer = styled.section` + display: flex; + flex-direction: column; + align-items: center; + justify-content: flex-end; + background-image: url(${HeaderPicture}); + background-size: cover; + background-position: center; + width: 100%; + height: 400px; + + @media all and (min-width: 744px) { + height: 500px; + } + @media all and (min-width: 1024px) { + flex-direction: row; + width: 50%; + } +`; + +const HeaderGlobe = styled.img` + position: absolute; + left: -44px; + top: -44px; + width: 320px; + height: 320px; + + @media all and (min-width: 744px) { + width: 380px; + height: 380px; + } + /* @media all and (min-width: 1024px) { + + } */ +`; + +const HeaderSlogan = styled.h1` + font-family: Abril Fatface, serif; + font-weight: 400; + font-size: 2em; + color: var(--grey); + /* background: var(--darkgreen); */ + margin: 20px 0; + text-align: center; + text-shadow: 2px 2px 5px rgba(0, 0, 0, 1); + + @media all and (min-width: 744px) { + font-size: 2.5em; // Adjust font size for larger screens + } + @media all and (min-width: 1024px) { + font-size: 3em; // Adjust font size for larger screens + } +`; + +//component export const Header = () => { - return
Header
; + return ( + + + + STEP OUT, STEP UP
+ eGO GREEN +
+
+ ); }; From 22374ce80d6a16537c95554e5e41528383185fd2 Mon Sep 17 00:00:00 2001 From: Your El1an3 Date: Thu, 23 May 2024 20:26:05 +0200 Subject: [PATCH 12/33] styling and routes set up --- frontend/package.json | 1 + frontend/src/App.jsx | 14 ++++- frontend/src/components/Registration.jsx | 50 +++++++++++++-- frontend/src/components/SignIn.jsx | 56 +++++++++++++++-- frontend/src/index.css | 2 +- frontend/src/reusables/Button.jsx | 25 +++++++- frontend/src/reusables/Form.jsx | 77 +++++++++++++++--------- frontend/src/reusables/Header.jsx | 37 +++--------- frontend/vite.config.js | 16 +++-- 9 files changed, 203 insertions(+), 75 deletions(-) diff --git a/frontend/package.json b/frontend/package.json index 866abc046..955b69152 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -19,6 +19,7 @@ "@types/react": "^18.2.15", "@types/react-dom": "^18.2.7", "@vitejs/plugin-react": "^4.0.3", + "babel-plugin-styled-components": "^2.1.4", "eslint": "^8.45.0", "eslint-plugin-react": "^7.32.2", "eslint-plugin-react-hooks": "^4.6.0", diff --git a/frontend/src/App.jsx b/frontend/src/App.jsx index 1b11e31d1..64cd49e78 100644 --- a/frontend/src/App.jsx +++ b/frontend/src/App.jsx @@ -1,9 +1,17 @@ +import { BrowserRouter, Routes, Route } from "react-router-dom"; import { SignIn } from "./components/SignIn"; +import { Registration } from "./components/Registration"; +import { Dashboard } from "./components/Dashboard"; export const App = () => { return ( - <> - - + + + } /> + } /> + } /> + } /> + + ); }; diff --git a/frontend/src/components/Registration.jsx b/frontend/src/components/Registration.jsx index 95c756fa6..8ed2511a4 100644 --- a/frontend/src/components/Registration.jsx +++ b/frontend/src/components/Registration.jsx @@ -1,13 +1,51 @@ -//import -// import styled from "styled-components"; -import { Header } from "../reusables/Header"; +//imports +import styled from "styled-components"; import { Form } from "../reusables/Form"; +import { Header } from "../reusables/Header"; + +//styling +const RegistrationContainer = styled.section` + display: flex; + flex-direction: column; + align-items: center; + + @media all and (min-width: 1024px) { + flex-direction: row; + } +`; + +const FormWrapper = styled.div` + display: flex; + flex-direction: column; +`; + +const TextContainer = styled.div` + display: flex; + flex-direction: column; + align-items: center; + padding-top: 50px; +`; + +const StyledTitle = styled.h1` + color: var(--darkgreen); + font-family: "Abril Fatface", serif; + font-weight: 400; + font-size: 1.75em; + padding-top: 15px; +`; +//component export const Registration = () => { return ( - <> +
-
- + + + +

If you already have an account, sign in on the

+ Startpage +
+
+ ); }; diff --git a/frontend/src/components/SignIn.jsx b/frontend/src/components/SignIn.jsx index 2a1da49c0..9d11dd024 100644 --- a/frontend/src/components/SignIn.jsx +++ b/frontend/src/components/SignIn.jsx @@ -2,26 +2,74 @@ import styled from "styled-components"; import { Form } from "../reusables/Form"; import { Header } from "../reusables/Header"; -import { Button } from "../reusables/Button"; +import { useState } from "react"; //styling const SignInContainer = styled.section` display: flex; flex-direction: column; + align-items: center; @media all and (min-width: 1024px) { flex-direction: row; } `; -//component +const FormWrapper = styled.div` + display: flex; + flex-direction: column; +`; + +const TextContainer = styled.div` + display: flex; + flex-direction: column; + align-items: center; + padding-top: 50px; +`; + +const StyledTitle = styled.h1` + color: var(--darkgreen); + font-family: "Abril Fatface", serif; + font-weight: 400; + font-size: 1.75em; + padding-top: 15px; +`; +//component export const SignIn = () => { + const [message, setMessage] = useState(""); + const apiEnv = import.meta.env.VITE_API_KEY; + + const handleSignIn = async (name, password) => { + const response = await fetch(`${apiEnv}/login`, { + method: "POST", + headers: { + "Content-Type": "application/json", + }, + body: JSON.stringify({ name, password }), + }); + + const data = await response.json(); + if (response.status === 200) { + setMessage("Sign-in successful!"); + localStorage.setItem("accessToken", data.accessToken); + localStorage.setItem("userId", data.userId); + } else { + setMessage("Sign-in failed: Invalid name or password"); + } + }; + return (
- - - +

{title}

+ + setName(e.target.value)} + placeholder="Username" + required + /> + setPassword(e.target.value)} + placeholder="Password" + required + /> + + ); }; diff --git a/frontend/src/reusables/Header.jsx b/frontend/src/reusables/Header.jsx index 5b494da7a..f12efae5a 100644 --- a/frontend/src/reusables/Header.jsx +++ b/frontend/src/reusables/Header.jsx @@ -13,10 +13,10 @@ const HeaderContainer = styled.section` background-size: cover; background-position: center; width: 100%; - height: 400px; + height: 300px; @media all and (min-width: 744px) { - height: 500px; + height: 400px; } @media all and (min-width: 1024px) { flex-direction: row; @@ -26,12 +26,14 @@ const HeaderContainer = styled.section` const HeaderGlobe = styled.img` position: absolute; - left: -44px; - top: -44px; - width: 320px; - height: 320px; + left: -34px; + top: -34px; + width: 280px; + height: 280px; @media all and (min-width: 744px) { + left: -44px; + top: -44px; width: 380px; height: 380px; } @@ -39,34 +41,11 @@ const HeaderGlobe = styled.img` } */ `; - -const HeaderSlogan = styled.h1` - font-family: Abril Fatface, serif; - font-weight: 400; - font-size: 2em; - color: var(--grey); - /* background: var(--darkgreen); */ - margin: 20px 0; - text-align: center; - text-shadow: 2px 2px 5px rgba(0, 0, 0, 1); - - @media all and (min-width: 744px) { - font-size: 2.5em; // Adjust font size for larger screens - } - @media all and (min-width: 1024px) { - font-size: 3em; // Adjust font size for larger screens - } -`; - //component export const Header = () => { return ( - - STEP OUT, STEP UP
- eGO GREEN -
); }; diff --git a/frontend/vite.config.js b/frontend/vite.config.js index 5a33944a9..e645d69a0 100644 --- a/frontend/vite.config.js +++ b/frontend/vite.config.js @@ -1,7 +1,15 @@ -import { defineConfig } from 'vite' -import react from '@vitejs/plugin-react' +import { defineConfig } from "vite"; +import react from "@vitejs/plugin-react"; // https://vitejs.dev/config/ export default defineConfig({ - plugins: [react()], -}) + plugins: [ + react({ + babel: { + plugins: ["styled-components"], + babelrc: false, + configFile: false, + }, + }), + ], +}); From f9bf5f80f34d35f711eca16b2637539eaf11f967 Mon Sep 17 00:00:00 2001 From: Your El1an3 Date: Thu, 23 May 2024 20:35:41 +0200 Subject: [PATCH 13/33] update routes --- frontend/src/components/Registration.jsx | 5 ++++- frontend/src/components/SignIn.jsx | 5 ++++- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/frontend/src/components/Registration.jsx b/frontend/src/components/Registration.jsx index 8ed2511a4..345d677d7 100644 --- a/frontend/src/components/Registration.jsx +++ b/frontend/src/components/Registration.jsx @@ -1,5 +1,6 @@ //imports import styled from "styled-components"; +import { Link } from "react-router-dom"; import { Form } from "../reusables/Form"; import { Header } from "../reusables/Header"; @@ -43,7 +44,9 @@ export const Registration = () => {

If you already have an account, sign in on the

- Startpage + + Startpage +
diff --git a/frontend/src/components/SignIn.jsx b/frontend/src/components/SignIn.jsx index 9d11dd024..376e7f4ba 100644 --- a/frontend/src/components/SignIn.jsx +++ b/frontend/src/components/SignIn.jsx @@ -1,5 +1,6 @@ //imports import styled from "styled-components"; +import { Link } from "react-router-dom"; import { Form } from "../reusables/Form"; import { Header } from "../reusables/Header"; import { useState } from "react"; @@ -67,7 +68,9 @@ export const SignIn = () => { {message &&

{message}

}

Don't have an account yet?

- Register here + + Register here +
From e38285019161dc05ee60b36baf99f14c6ccdca9f Mon Sep 17 00:00:00 2001 From: Your El1an3 Date: Thu, 23 May 2024 21:01:36 +0200 Subject: [PATCH 14/33] fixed styling on deskopt --- frontend/src/components/Registration.jsx | 1 + frontend/src/components/SignIn.jsx | 1 + frontend/src/index.css | 5 +++++ frontend/src/reusables/Header.jsx | 12 +++++++++--- 4 files changed, 16 insertions(+), 3 deletions(-) diff --git a/frontend/src/components/Registration.jsx b/frontend/src/components/Registration.jsx index 345d677d7..f0394f79e 100644 --- a/frontend/src/components/Registration.jsx +++ b/frontend/src/components/Registration.jsx @@ -9,6 +9,7 @@ const RegistrationContainer = styled.section` display: flex; flex-direction: column; align-items: center; + min-height: 100vh; @media all and (min-width: 1024px) { flex-direction: row; diff --git a/frontend/src/components/SignIn.jsx b/frontend/src/components/SignIn.jsx index 376e7f4ba..f6cd5cba9 100644 --- a/frontend/src/components/SignIn.jsx +++ b/frontend/src/components/SignIn.jsx @@ -10,6 +10,7 @@ const SignInContainer = styled.section` display: flex; flex-direction: column; align-items: center; + min-height: 100vh; @media all and (min-width: 1024px) { flex-direction: row; diff --git a/frontend/src/index.css b/frontend/src/index.css index cb5413481..4d2b89052 100644 --- a/frontend/src/index.css +++ b/frontend/src/index.css @@ -14,6 +14,7 @@ } /* basics */ + * { padding: 0; margin: 0; @@ -22,3 +23,7 @@ font-weight: 300; color: var(--primary-blk); } + +body { + height: 100vh; +} diff --git a/frontend/src/reusables/Header.jsx b/frontend/src/reusables/Header.jsx index f12efae5a..7c0cf14f5 100644 --- a/frontend/src/reusables/Header.jsx +++ b/frontend/src/reusables/Header.jsx @@ -21,6 +21,7 @@ const HeaderContainer = styled.section` @media all and (min-width: 1024px) { flex-direction: row; width: 50%; + height: 100vh; } `; @@ -37,9 +38,14 @@ const HeaderGlobe = styled.img` width: 380px; height: 380px; } - /* @media all and (min-width: 1024px) { - - } */ + @media all and (min-width: 1024px) { + left: -60px; + top: -60px; + width: 58%; + height: auto; + max-width: 590px; + max-height: 590px; + } `; //component export const Header = () => { From c990fdbf8882040cc7023c9b3057f7412d964195 Mon Sep 17 00:00:00 2001 From: Your El1an3 Date: Thu, 23 May 2024 21:27:55 +0200 Subject: [PATCH 15/33] fixed styling --- backend/server.js | 59 +++++++++++++++++------------- frontend/src/components/SignIn.jsx | 3 ++ frontend/src/reusables/Button.jsx | 4 +- frontend/src/reusables/Form.jsx | 4 +- 4 files changed, 41 insertions(+), 29 deletions(-) diff --git a/backend/server.js b/backend/server.js index 1337554cd..f806e5949 100644 --- a/backend/server.js +++ b/backend/server.js @@ -4,6 +4,7 @@ import mongoose from "mongoose"; import dotenv from "dotenv"; import expressListEndpoints from "express-list-endpoints"; import bcrypt from "bcrypt"; +import crypto from "crypto"; dotenv.config(); @@ -11,12 +12,18 @@ const mongoUrl = process.env.MONGO_URL || "mongodb://localhost/auth"; mongoose.connect(mongoUrl); mongoose.Promise = Promise; -//create schema -const userSchema = new mongoose.Schema({ +//create schema and model + +const { Schema, model } = mongoose; + +const userSchema = new Schema({ name: { type: String, unique: true, - required: true, + }, + email: { + type: String, + unique: true, }, password: { type: String, @@ -24,14 +31,11 @@ const userSchema = new mongoose.Schema({ }, accessToken: { type: String, - default: () => bcrypt.genSaltSync(), + default: () => crypto.randomBytes(128).toString("hex"), }, }); -//create model -const User = mongoose.model("User", userSchema); - -// console.log(bcrypt.genSaltSync()); +const User = model("User", userSchema); //defines the port the app will run on const port = process.env.PORT || 8080; @@ -63,24 +67,28 @@ const authenticateUser = async (req, res, next) => { }; //registration endpoint -app.post("/register", async (req, res) => { +app.post("/register", (req, res) => { try { - const { name, password } = req.body; + const { name, email, password } = req.body; const salt = bcrypt.genSaltSync(); - const hashedPassword = bcrypt.hashSync(password, salt); - - const newUser = new User({ + const user = new User({ name, - password: hashedPassword, - accessToken: bcrypt.genSaltSync(), //generate a new token + email, + password: bcrypt.hashSync(password, salt), + }); + user.save(); + res.status(201).json({ + success: true, + message: "User created", + id: user._id, + accessToken: user.accessToken, }); - - await newUser.save(); - res.status(201).json({ id: newUser._id, accessToken: newUser.accessToken }); } catch (error) { - res - .status(400) - .json({ message: "Could not create user", errors: error.errors }); + res.status(400).json({ + success: false, + message: "Could not create user", + errors: error, + }); } }); @@ -97,8 +105,11 @@ app.post("/login", async (req, res) => { }); //authenticated endpoint -app.get("/dashboard", authenticateUser, (req, res) => { - res.json({ message: "This is the secret dashboard!", user: req.user }); +app.get("/dashboard", authenticateUser); +app.get("/dashboard", (req, res) => { + res.json({ + secret: "This is the secret dashboard!", + }); }); app.post("/login", async (req, res) => { @@ -108,8 +119,6 @@ app.post("/login", async (req, res) => { res.json({ userId: user._id, accessToken: user.accessToken }); } else { //failure - // A) user doesn not exist - // B) encrypted password does not match res.json({ notFound: true }); } }); diff --git a/frontend/src/components/SignIn.jsx b/frontend/src/components/SignIn.jsx index f6cd5cba9..d868b9a54 100644 --- a/frontend/src/components/SignIn.jsx +++ b/frontend/src/components/SignIn.jsx @@ -20,6 +20,9 @@ const SignInContainer = styled.section` const FormWrapper = styled.div` display: flex; flex-direction: column; + @media all and (min-width: 1024px) { + width: 50%; + } `; const TextContainer = styled.div` diff --git a/frontend/src/reusables/Button.jsx b/frontend/src/reusables/Button.jsx index 7d7aa42af..a48d31367 100644 --- a/frontend/src/reusables/Button.jsx +++ b/frontend/src/reusables/Button.jsx @@ -3,7 +3,7 @@ import styled from "styled-components"; //styling const StyledButton = styled.button` - width: 300px; + width: 280px; background: var(--darkgreen); border: none; border-radius: 30px; @@ -16,7 +16,7 @@ const StyledButton = styled.button` font-size: 1.25em; @media all and (min-width: 744px) { - width: 500px; + width: 450px; } `; diff --git a/frontend/src/reusables/Form.jsx b/frontend/src/reusables/Form.jsx index ab79076cc..cbf67d19e 100644 --- a/frontend/src/reusables/Form.jsx +++ b/frontend/src/reusables/Form.jsx @@ -28,7 +28,7 @@ const StyledForm = styled.form` `; const StyledInput = styled.input` - width: 300px; + width: 280px; background: var(--grey); border: none; border-radius: 30px; @@ -38,7 +38,7 @@ const StyledInput = styled.input` font-size: 1.1em; @media all and (min-width: 744px) { - width: 500px; + width: 450px; } `; From 60d26477d3957a97b9f04f85a0ac9dccb078fc1d Mon Sep 17 00:00:00 2001 From: Your El1an3 Date: Thu, 23 May 2024 21:43:56 +0200 Subject: [PATCH 16/33] minor styling fix --- frontend/src/components/Registration.jsx | 3 +++ 1 file changed, 3 insertions(+) diff --git a/frontend/src/components/Registration.jsx b/frontend/src/components/Registration.jsx index f0394f79e..320e3af9e 100644 --- a/frontend/src/components/Registration.jsx +++ b/frontend/src/components/Registration.jsx @@ -19,6 +19,9 @@ const RegistrationContainer = styled.section` const FormWrapper = styled.div` display: flex; flex-direction: column; + @media all and (min-width: 1024px) { + width: 50%; + } `; const TextContainer = styled.div` From d6597247da1291032c5d31c173fe1f3677c0ac85 Mon Sep 17 00:00:00 2001 From: Your El1an3 Date: Fri, 24 May 2024 12:40:26 +0200 Subject: [PATCH 17/33] added homepage, changed routing --- backend/server.js | 41 +++++++++------------ frontend/src/App.jsx | 6 ++-- frontend/src/components/Homepage.jsx | 18 ++++++++++ frontend/src/components/Registration.jsx | 5 +++ frontend/src/components/SignIn.jsx | 46 ++++++++++++++++++------ frontend/src/reusables/Button.jsx | 9 +++-- frontend/src/reusables/Form.jsx | 8 ++--- 7 files changed, 90 insertions(+), 43 deletions(-) create mode 100644 frontend/src/components/Homepage.jsx diff --git a/backend/server.js b/backend/server.js index f806e5949..b47efcd1d 100644 --- a/backend/server.js +++ b/backend/server.js @@ -13,9 +13,7 @@ mongoose.connect(mongoUrl); mongoose.Promise = Promise; //create schema and model - const { Schema, model } = mongoose; - const userSchema = new Schema({ name: { type: String, @@ -34,7 +32,6 @@ const userSchema = new Schema({ default: () => crypto.randomBytes(128).toString("hex"), }, }); - const User = model("User", userSchema); //defines the port the app will run on @@ -61,13 +58,15 @@ const authenticateUser = async (req, res, next) => { req.user = user; next(); } else { - res.status(401), - json({ loggedOut: true, message: "you have to log in to get access" }); + res.status(401).json({ + loggedOut: true, + message: "You have to log in to get access", + }); } }; //registration endpoint -app.post("/register", (req, res) => { +app.post("/register", async (req, res) => { try { const { name, email, password } = req.body; const salt = bcrypt.genSaltSync(); @@ -76,7 +75,7 @@ app.post("/register", (req, res) => { email, password: bcrypt.hashSync(password, salt), }); - user.save(); + await user.save(); res.status(201).json({ success: true, message: "User created", @@ -92,34 +91,26 @@ app.post("/register", (req, res) => { } }); -//login endpoint -app.post("/login", async (req, res) => { - //find user by name - const user = await User.findOne({ name: req.body.name }); - //check if password is correct - if (user && bcrypt.compareSync(req.body.password, user.password)) { - res.json({ userId: user._id, accessToken: user.accessToken }); - } else { - res.status(401).json({ message: "user name or password invalid" }); - } -}); - -//authenticated endpoint -app.get("/dashboard", authenticateUser); -app.get("/dashboard", (req, res) => { +//authenticated endpoint *super secret endpoint* +app.get("/dashboard", authenticateUser, (req, res) => { res.json({ - secret: "This is the secret dashboard!", + secret: "This is the secret dashboard, only visible to logged-in users!", }); }); +//login endpoint app.post("/login", async (req, res) => { + //find user by name const user = await User.findOne({ name: req.body.name }); + //check if password is correct if (user && bcrypt.compareSync(req.body.password, user.password)) { //success - res.json({ userId: user._id, accessToken: user.accessToken }); + res.status(200).json({ userId: user._id, accessToken: user.accessToken }); } else { //failure - res.json({ notFound: true }); + res + .status(401) + .json({ notFound: true, message: "Invalid name or password" }); } }); diff --git a/frontend/src/App.jsx b/frontend/src/App.jsx index 64cd49e78..eaf25f77a 100644 --- a/frontend/src/App.jsx +++ b/frontend/src/App.jsx @@ -2,15 +2,17 @@ import { BrowserRouter, Routes, Route } from "react-router-dom"; import { SignIn } from "./components/SignIn"; import { Registration } from "./components/Registration"; import { Dashboard } from "./components/Dashboard"; +import { Homepage } from "./components/Homepage"; export const App = () => { return ( - } /> + } /> + } /> } /> } /> - } /> + } /> ); diff --git a/frontend/src/components/Homepage.jsx b/frontend/src/components/Homepage.jsx new file mode 100644 index 000000000..4393b1912 --- /dev/null +++ b/frontend/src/components/Homepage.jsx @@ -0,0 +1,18 @@ +//import +import { Link } from "react-router-dom"; +//styling + +//component +export const Homepage = () => { + return ( +
+ Homepage + +

Login here

+ + +

Register here

+ +
+ ); +}; diff --git a/frontend/src/components/Registration.jsx b/frontend/src/components/Registration.jsx index 320e3af9e..1cefa60d1 100644 --- a/frontend/src/components/Registration.jsx +++ b/frontend/src/components/Registration.jsx @@ -3,6 +3,7 @@ import styled from "styled-components"; import { Link } from "react-router-dom"; import { Form } from "../reusables/Form"; import { Header } from "../reusables/Header"; +import { Button } from "../reusables/Button"; //styling const RegistrationContainer = styled.section` @@ -46,8 +47,12 @@ export const Registration = () => {
+

If you already have an account, sign in on the

+ + Login here + Startpage diff --git a/frontend/src/components/SignIn.jsx b/frontend/src/components/SignIn.jsx index d868b9a54..ffb3c323a 100644 --- a/frontend/src/components/SignIn.jsx +++ b/frontend/src/components/SignIn.jsx @@ -3,6 +3,7 @@ import styled from "styled-components"; import { Link } from "react-router-dom"; import { Form } from "../reusables/Form"; import { Header } from "../reusables/Header"; +import { Button } from "../reusables/Button"; import { useState } from "react"; //styling @@ -29,30 +30,46 @@ const TextContainer = styled.div` display: flex; flex-direction: column; align-items: center; + padding-top: 20px; +`; + +const StyledTitle = styled.h2` + color: var(--black); + font-size: 1.25em; + padding-top: 15px; +`; + +const TitleWrapper = styled.div` + display: flex; + flex-direction: column; + justify-content: center; padding-top: 50px; `; -const StyledTitle = styled.h1` +const SignInTitle = styled.h1` color: var(--darkgreen); font-family: "Abril Fatface", serif; font-weight: 400; font-size: 1.75em; - padding-top: 15px; + align-self: center; `; //component export const SignIn = () => { const [message, setMessage] = useState(""); - const apiEnv = import.meta.env.VITE_API_KEY; + // const apiEnv = import.meta.env.VITE_API_KEY; const handleSignIn = async (name, password) => { - const response = await fetch(`${apiEnv}/login`, { - method: "POST", - headers: { - "Content-Type": "application/json", - }, - body: JSON.stringify({ name, password }), - }); + const response = await fetch( + `https://project-auth-ziup.onrender.com/login`, + { + method: "POST", + headers: { + "Content-Type": "application/json", + }, + body: JSON.stringify({ name, password }), + } + ); const data = await response.json(); if (response.status === 200) { @@ -68,13 +85,22 @@ export const SignIn = () => {
+ + Returning user? + Login here. + + + {/* shows error message */} {message &&

{message}

}

Don't have an account yet?

Register here + + Startpage +
diff --git a/frontend/src/reusables/Button.jsx b/frontend/src/reusables/Button.jsx index a48d31367..9828f9be4 100644 --- a/frontend/src/reusables/Button.jsx +++ b/frontend/src/reusables/Button.jsx @@ -1,3 +1,4 @@ +/* eslint-disable react/prop-types */ //import import styled from "styled-components"; @@ -15,12 +16,16 @@ const StyledButton = styled.button` font-weight: 400; font-size: 1.25em; + &:hover { + cursor: pointer; + } + @media all and (min-width: 744px) { width: 450px; } `; //component -export const Button = () => { - return Sign In; +export const Button = ({ children, ...props }) => { + return {children}; }; diff --git a/frontend/src/reusables/Form.jsx b/frontend/src/reusables/Form.jsx index cbf67d19e..2a073803f 100644 --- a/frontend/src/reusables/Form.jsx +++ b/frontend/src/reusables/Form.jsx @@ -1,7 +1,6 @@ /* eslint-disable react/prop-types */ //imports import styled from "styled-components"; -import { Button } from "./Button"; import { useState } from "react"; //styling @@ -19,7 +18,7 @@ const StyledForm = styled.form` flex-direction: column; align-items: center; justify-content: center; - padding-top: 50px; + padding-top: 20px; @media all and (min-width: 744px) { } @@ -32,7 +31,7 @@ const StyledInput = styled.input` background: var(--grey); border: none; border-radius: 30px; - padding: 10px 50px; + padding: 20px; height: 50px; margin: 20px; font-size: 1.1em; @@ -58,6 +57,7 @@ export const Form = ({ title, handleSubmit }) => { setName(e.target.value)} placeholder="Username" @@ -65,12 +65,12 @@ export const Form = ({ title, handleSubmit }) => { /> setPassword(e.target.value)} placeholder="Password" required /> - ); From 5af67bcb49bbdd30f565c2fbb73d4a194e52ed32 Mon Sep 17 00:00:00 2001 From: Your El1an3 Date: Fri, 24 May 2024 17:11:48 +0200 Subject: [PATCH 18/33] styled homepage --- frontend/src/components/Homepage.jsx | 73 ++++++++++++++++++++++++++-- frontend/src/reusables/Button.jsx | 3 +- 2 files changed, 70 insertions(+), 6 deletions(-) diff --git a/frontend/src/components/Homepage.jsx b/frontend/src/components/Homepage.jsx index 4393b1912..e64d8432e 100644 --- a/frontend/src/components/Homepage.jsx +++ b/frontend/src/components/Homepage.jsx @@ -1,18 +1,81 @@ //import import { Link } from "react-router-dom"; +import styled from "styled-components"; +import HeaderPicture from "../../public/header.jpg"; +import Globe from "../../public/globe.png"; +import { Button } from "../reusables/Button"; + //styling +const StyledSection = styled.section` + display: flex; + flex-direction: column; + align-items: center; + background-image: url(${HeaderPicture}); + background-size: cover; + background-position: center; + height: 100vh; + padding: 20px 0; +`; + +const HeaderGlobeContainer = styled.div` + display: flex; + justify-content: center; + align-items: center; + margin: 20px 0; +`; + +const HeaderGlobe = styled.img` + width: 280px; + height: 280px; + + @media all and (min-width: 744px) { + width: 400px; + height: 400px; + } +`; + +const BottomForm = styled.div` + background: var(--yellow); + position: fixed; + z-index: 0; + bottom: 0; + width: 744px; + height: 372px; + border-radius: 372px 372px 0 0; + + display: flex; + justify-content: center; + align-items: center; + text-align: center; + + @media all and (min-width: 744px) { + width: 520px; + height: 260px; + border-radius: 260px 260px 0 0; + } +`; + +const ActionButton = styled(Button)` + position: relative; + z-index: 1; +`; //component export const Homepage = () => { return ( -
- Homepage + -

Login here

+ + + + -

Register here

+ Take action -
+ +

Our Slogan goes here

+
+ ); }; diff --git a/frontend/src/reusables/Button.jsx b/frontend/src/reusables/Button.jsx index 9828f9be4..bec35a208 100644 --- a/frontend/src/reusables/Button.jsx +++ b/frontend/src/reusables/Button.jsx @@ -15,13 +15,14 @@ const StyledButton = styled.button` font-family: "Abril Fatface", serif; font-weight: 400; font-size: 1.25em; + z-index: 1; &:hover { cursor: pointer; } @media all and (min-width: 744px) { - width: 450px; + width: 400px; } `; From b8331f1ebcd569188049dd55b7dd95f499170fbb Mon Sep 17 00:00:00 2001 From: Your El1an3 Date: Fri, 24 May 2024 18:11:02 +0200 Subject: [PATCH 19/33] registration form --- frontend/src/components/Registration.jsx | 219 +++++++++++++++++++---- frontend/src/index.css | 15 ++ 2 files changed, 196 insertions(+), 38 deletions(-) diff --git a/frontend/src/components/Registration.jsx b/frontend/src/components/Registration.jsx index 1cefa60d1..940b1ec75 100644 --- a/frontend/src/components/Registration.jsx +++ b/frontend/src/components/Registration.jsx @@ -1,63 +1,206 @@ +// //imports +// import styled from "styled-components"; +// import { Link } from "react-router-dom"; +// import { Form } from "../reusables/Form"; +// import { Header } from "../reusables/Header"; +// import { Button } from "../reusables/Button"; + +// //styling +// const RegistrationContainer = styled.section` +// display: flex; +// flex-direction: column; +// align-items: center; +// min-height: 100vh; + +// @media all and (min-width: 1024px) { +// flex-direction: row; +// } +// `; + +// const FormWrapper = styled.div` +// display: flex; +// flex-direction: column; +// @media all and (min-width: 1024px) { +// width: 50%; +// } +// `; + +// const TextContainer = styled.div` +// display: flex; +// flex-direction: column; +// align-items: center; +// padding-top: 50px; +// `; + +// const StyledTitle = styled.h1` +// color: var(--darkgreen); +// font-family: "Abril Fatface", serif; +// font-weight: 400; +// font-size: 1.75em; +// padding-top: 15px; +// `; + +// //component +// export const Registration = () => { +// return ( +// +//
+// +// +// +// +//

If you already have an account, sign in on the

+// +// Login here +// +// +// Startpage +// +//
+//
+// +// ); +// }; + //imports import styled from "styled-components"; +import { useState } from "react"; import { Link } from "react-router-dom"; -import { Form } from "../reusables/Form"; +import { useNavigate } from "react-router-dom"; import { Header } from "../reusables/Header"; import { Button } from "../reusables/Button"; -//styling -const RegistrationContainer = styled.section` - display: flex; - flex-direction: column; - align-items: center; - min-height: 100vh; +const API_KEY = "https://project-auth-ziup.onrender.com"; - @media all and (min-width: 1024px) { - flex-direction: row; +//styling +const RegistrationSection = styled.section` + /* display: flex; + justify-content: center; + @media all and (min-width: 744px) { } + @media all and (min-width: 1024px) { + } */ `; -const FormWrapper = styled.div` +const StyledForm = styled.form` display: flex; flex-direction: column; + align-items: center; + justify-content: center; + padding-top: 20px; + + @media all and (min-width: 744px) { + } @media all and (min-width: 1024px) { - width: 50%; } `; -const TextContainer = styled.div` - display: flex; - flex-direction: column; - align-items: center; - padding-top: 50px; -`; +const StyledInput = styled.input` + width: 280px; + background: var(--grey); + border: none; + border-radius: 30px; + padding: 20px; + height: 50px; + margin: 20px; + font-size: 1.1em; -const StyledTitle = styled.h1` - color: var(--darkgreen); - font-family: "Abril Fatface", serif; - font-weight: 400; - font-size: 1.75em; - padding-top: 15px; + @media all and (min-width: 744px) { + width: 450px; + } `; //component export const Registration = () => { + const [error, setError] = useState(null); + const navigate = useNavigate(); + const [formData, setFormData] = useState({ + name: "", + email: "", + password: "", + }); + + const handleChange = (e) => { + const { name, value } = e.target; + setFormData({ + ...formData, + [name]: value, + }); + }; + + const handleSubmit = async (e) => { + e.preventDefault(); + try { + const response = await fetch(`${API_KEY}/register`, { + method: "POST", + headers: { + "Content-Type": "application/json", + }, + body: JSON.stringify(formData), + }); + if (response.ok) { + const data = await response.json(); + const accessToken = data.accessToken; + localStorage.setItem("accessToken", accessToken); + + navigate("/dashboard"); + } else { + const errorData = await response.json(); + setError(errorData.error); + } + } catch (error) { + console.error("Error registering:", error); + setError("Something went wrong"); + } + }; + return ( - +
- - - - -

If you already have an account, sign in on the

- - Login here - - - Startpage - -
-
- +

User Registration

+ + + + + + + + + {/* shows error message */} + {error &&

Please try again!

} +
+ +

If you already have an account

+ +

Login here

+ + +

Home

+ + ); }; diff --git a/frontend/src/index.css b/frontend/src/index.css index 4d2b89052..a8a436ac6 100644 --- a/frontend/src/index.css +++ b/frontend/src/index.css @@ -27,3 +27,18 @@ body { height: 100vh; } + +h1 { + color: var(--darkgreen); + font-family: "Abril Fatface", serif; + font-weight: 400; + font-size: 1.75em; + align-self: center; +} + +h2 { + color: var(--black); + font-size: 1.25em; + padding-top: 15px; + align-self: center; +} From ad7aaa7eddaa6f4c4e9f33686cfa736c4e725508 Mon Sep 17 00:00:00 2001 From: Your El1an3 Date: Fri, 24 May 2024 19:42:47 +0200 Subject: [PATCH 20/33] created Login and deleted Sign in --- frontend/src/App.jsx | 4 +- frontend/src/components/Login.jsx | 127 +++++++++++++++++++++++ frontend/src/components/Registration.jsx | 93 +++-------------- frontend/src/components/SignIn.jsx | 108 ------------------- frontend/src/reusables/Button.jsx | 3 +- frontend/src/reusables/Header.jsx | 18 ++-- 6 files changed, 153 insertions(+), 200 deletions(-) create mode 100644 frontend/src/components/Login.jsx delete mode 100644 frontend/src/components/SignIn.jsx diff --git a/frontend/src/App.jsx b/frontend/src/App.jsx index eaf25f77a..e17adb8d6 100644 --- a/frontend/src/App.jsx +++ b/frontend/src/App.jsx @@ -1,5 +1,5 @@ import { BrowserRouter, Routes, Route } from "react-router-dom"; -import { SignIn } from "./components/SignIn"; +import { Login } from "./components/Login"; import { Registration } from "./components/Registration"; import { Dashboard } from "./components/Dashboard"; import { Homepage } from "./components/Homepage"; @@ -9,7 +9,7 @@ export const App = () => { } /> - } /> + } /> } /> } /> } /> diff --git a/frontend/src/components/Login.jsx b/frontend/src/components/Login.jsx new file mode 100644 index 000000000..dceeb2771 --- /dev/null +++ b/frontend/src/components/Login.jsx @@ -0,0 +1,127 @@ +//imports +import styled from "styled-components"; +import { useState } from "react"; +import { Link, useNavigate } from "react-router-dom"; +import { Header } from "../reusables/Header"; +import { Button } from "../reusables/Button"; + +// const API_KEY = "https://project-auth-ziup.onrender.com"; +const API_KEY = "http://localhost:8080"; + +//styling +const LoginSection = styled.section` + display: flex; + flex-direction: column; + align-items: center; +`; + +const StyledForm = styled.form` + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + padding-top: 20px; + + @media all and (min-width: 744px) { + } + @media all and (min-width: 1024px) { + } +`; + +const StyledInput = styled.input` + width: 280px; + background: var(--grey); + border: none; + border-radius: 30px; + padding: 20px; + height: 50px; + margin: 10px; + font-size: 1.1em; + + @media all and (min-width: 744px) { + width: 450px; + } +`; + +//component +export const Login = () => { + const navigate = useNavigate(); + const [message, setMessage] = useState(""); + + const [formData, setFormData] = useState({ + name: "", + password: "", + }); + + const handleChange = (e) => { + const { name, value } = e.target; + setFormData({ + ...formData, + [name]: value, + }); + }; + + const handleSubmit = async (e) => { + e.preventDefault(); + try { + const response = await fetch(`${API_KEY}/login`, { + method: "POST", + headers: { + "Content-Type": "application/json", + Authorization: `Bearer ${localStorage.getItem("accessToken")}`, + }, + body: JSON.stringify(formData), + }); + if (response.status === 200) { + const data = await response.json(); + const accessToken = data.accessToken; + setMessage("Sign-in successful!"); + localStorage.setItem("accessToken", accessToken); + navigate("/dashboard"); + } else { + setMessage("Sign-in failed: Invalid name or password"); + } + } catch (error) { + console.error("Login failed:", error); + } + }; + + return ( + +
+ + + + + {/* shows error message */} + {message &&

{message}

} +
+ +

If you already have an account

+ +

Register

+ + +

Home

+ + + ); +}; diff --git a/frontend/src/components/Registration.jsx b/frontend/src/components/Registration.jsx index 940b1ec75..32d397756 100644 --- a/frontend/src/components/Registration.jsx +++ b/frontend/src/components/Registration.jsx @@ -1,85 +1,18 @@ -// //imports -// import styled from "styled-components"; -// import { Link } from "react-router-dom"; -// import { Form } from "../reusables/Form"; -// import { Header } from "../reusables/Header"; -// import { Button } from "../reusables/Button"; - -// //styling -// const RegistrationContainer = styled.section` -// display: flex; -// flex-direction: column; -// align-items: center; -// min-height: 100vh; - -// @media all and (min-width: 1024px) { -// flex-direction: row; -// } -// `; - -// const FormWrapper = styled.div` -// display: flex; -// flex-direction: column; -// @media all and (min-width: 1024px) { -// width: 50%; -// } -// `; - -// const TextContainer = styled.div` -// display: flex; -// flex-direction: column; -// align-items: center; -// padding-top: 50px; -// `; - -// const StyledTitle = styled.h1` -// color: var(--darkgreen); -// font-family: "Abril Fatface", serif; -// font-weight: 400; -// font-size: 1.75em; -// padding-top: 15px; -// `; - -// //component -// export const Registration = () => { -// return ( -// -//
-// -// -// -// -//

If you already have an account, sign in on the

-// -// Login here -// -// -// Startpage -// -//
-//
-// -// ); -// }; - //imports import styled from "styled-components"; import { useState } from "react"; -import { Link } from "react-router-dom"; -import { useNavigate } from "react-router-dom"; +import { Link, useNavigate } from "react-router-dom"; import { Header } from "../reusables/Header"; import { Button } from "../reusables/Button"; -const API_KEY = "https://project-auth-ziup.onrender.com"; +// const API_KEY = "https://project-auth-ziup.onrender.com"; +const API_KEY = "http://localhost:8080"; //styling const RegistrationSection = styled.section` - /* display: flex; - justify-content: center; - @media all and (min-width: 744px) { - } - @media all and (min-width: 1024px) { - } */ + display: flex; + flex-direction: column; + align-items: center; `; const StyledForm = styled.form` @@ -102,7 +35,7 @@ const StyledInput = styled.input` border-radius: 30px; padding: 20px; height: 50px; - margin: 20px; + margin: 10px; font-size: 1.1em; @media all and (min-width: 744px) { @@ -157,10 +90,7 @@ export const Registration = () => { return (
-

User Registration

- - { value={formData.name} onChange={handleChange} placeholder="Username" + aria-label="Name" required /> - + { value={formData.email} onChange={handleChange} placeholder="Email" + aria-label="email" required /> - + { value={formData.password} onChange={handleChange} placeholder="Password" + aria-label="password" required /> {/* shows error message */} @@ -199,7 +132,7 @@ export const Registration = () => {

Login here

-

Home

+

Home

); diff --git a/frontend/src/components/SignIn.jsx b/frontend/src/components/SignIn.jsx deleted file mode 100644 index ffb3c323a..000000000 --- a/frontend/src/components/SignIn.jsx +++ /dev/null @@ -1,108 +0,0 @@ -//imports -import styled from "styled-components"; -import { Link } from "react-router-dom"; -import { Form } from "../reusables/Form"; -import { Header } from "../reusables/Header"; -import { Button } from "../reusables/Button"; -import { useState } from "react"; - -//styling -const SignInContainer = styled.section` - display: flex; - flex-direction: column; - align-items: center; - min-height: 100vh; - - @media all and (min-width: 1024px) { - flex-direction: row; - } -`; - -const FormWrapper = styled.div` - display: flex; - flex-direction: column; - @media all and (min-width: 1024px) { - width: 50%; - } -`; - -const TextContainer = styled.div` - display: flex; - flex-direction: column; - align-items: center; - padding-top: 20px; -`; - -const StyledTitle = styled.h2` - color: var(--black); - font-size: 1.25em; - padding-top: 15px; -`; - -const TitleWrapper = styled.div` - display: flex; - flex-direction: column; - justify-content: center; - padding-top: 50px; -`; - -const SignInTitle = styled.h1` - color: var(--darkgreen); - font-family: "Abril Fatface", serif; - font-weight: 400; - font-size: 1.75em; - align-self: center; -`; - -//component -export const SignIn = () => { - const [message, setMessage] = useState(""); - // const apiEnv = import.meta.env.VITE_API_KEY; - - const handleSignIn = async (name, password) => { - const response = await fetch( - `https://project-auth-ziup.onrender.com/login`, - { - method: "POST", - headers: { - "Content-Type": "application/json", - }, - body: JSON.stringify({ name, password }), - } - ); - - const data = await response.json(); - if (response.status === 200) { - setMessage("Sign-in successful!"); - localStorage.setItem("accessToken", data.accessToken); - localStorage.setItem("userId", data.userId); - } else { - setMessage("Sign-in failed: Invalid name or password"); - } - }; - - return ( - -
- - - Returning user? - Login here. - - - - {/* shows error message */} - {message &&

{message}

} - -

Don't have an account yet?

- - Register here - - - Startpage - -
-
- - ); -}; diff --git a/frontend/src/reusables/Button.jsx b/frontend/src/reusables/Button.jsx index bec35a208..daa91ff4b 100644 --- a/frontend/src/reusables/Button.jsx +++ b/frontend/src/reusables/Button.jsx @@ -15,10 +15,11 @@ const StyledButton = styled.button` font-family: "Abril Fatface", serif; font-weight: 400; font-size: 1.25em; - z-index: 1; + box-shadow: 2px 2px 4px rgba(0, 0, 0, 0.3); &:hover { cursor: pointer; + background: var(--lightgreen); } @media all and (min-width: 744px) { diff --git a/frontend/src/reusables/Header.jsx b/frontend/src/reusables/Header.jsx index 7c0cf14f5..132a79577 100644 --- a/frontend/src/reusables/Header.jsx +++ b/frontend/src/reusables/Header.jsx @@ -13,7 +13,7 @@ const HeaderContainer = styled.section` background-size: cover; background-position: center; width: 100%; - height: 300px; + height: 400px; @media all and (min-width: 744px) { height: 400px; @@ -27,16 +27,16 @@ const HeaderContainer = styled.section` const HeaderGlobe = styled.img` position: absolute; - left: -34px; - top: -34px; - width: 280px; - height: 280px; + left: -44px; + top: -44px; + width: 350px; + height: 350px; @media all and (min-width: 744px) { - left: -44px; - top: -44px; - width: 380px; - height: 380px; + left: -50px; + top: -50px; + width: 400px; + height: 400px; } @media all and (min-width: 1024px) { left: -60px; From c39c24babaf92acfbf3ccee5efaf18c5dacc80e1 Mon Sep 17 00:00:00 2001 From: Your El1an3 Date: Fri, 24 May 2024 21:55:58 +0200 Subject: [PATCH 21/33] finished frontend styling --- frontend/src/components/Dashboard.jsx | 87 ++++++++++++++++++- frontend/src/components/Login.jsx | 89 +++++++++++-------- frontend/src/components/Registration.jsx | 104 +++++++++++++---------- frontend/src/reusables/Form.jsx | 77 ----------------- 4 files changed, 201 insertions(+), 156 deletions(-) delete mode 100644 frontend/src/reusables/Form.jsx diff --git a/frontend/src/components/Dashboard.jsx b/frontend/src/components/Dashboard.jsx index 5cdac21f8..ebf2f5a98 100644 --- a/frontend/src/components/Dashboard.jsx +++ b/frontend/src/components/Dashboard.jsx @@ -1,3 +1,88 @@ +//imports +import styled from "styled-components"; +import { Button } from "../reusables/Button"; +import Globe from "../../public/globe.png"; +import HeaderPicture from "../../public/header.jpg"; +import { useNavigate } from "react-router-dom"; + +//styling +const DashboardSection = styled.section` + display: flex; + flex-direction: column; + + @media all and (min-width: 1024px) { + flex-direction: row; + } +`; + +const DashboardHeader = styled.div` + display: flex; + background-image: url(${HeaderPicture}); + background-size: cover; + background-position: center; + justify-content: space-between; + align-items: center; + + @media all and (min-width: 1024px) { + flex-direction: column-reverse; + justify-content: flex-end; + width: 30%; + height: 100vh; + } +`; + +const DashboardGlobe = styled.img` + height: 70px; + width: 70px; + margin: 20px; + @media all and (min-width: 1024px) { + height: 250px; + width: 250px; + } +`; + +const ContentWrapper = styled.div` + background: var(--grey); + border-radius: 20px; + box-shadow: 2px 2px 4px rgba(0, 0, 0, 0.3); + margin: 50px; + padding: 20px; + @media all and (min-width: 1024px) { + } +`; + +const StyledButton = styled(Button)` + width: 250px; +`; + +//component export const Dashboard = () => { - return
Dashboard
; + const navigate = useNavigate(); + + const handleLogout = () => { + localStorage.removeItem("accessToken"); + localStorage.removeItem("username"); + //navigate to homepage + navigate("/"); + }; + + return ( + + + + Log out + + +

Welcome

+

๐Ÿคซ This is only shown to logged in users ๐Ÿคซ

+

๐Ÿ‘‡

+

๐Ÿ‘‡

+

๐Ÿ‘‡

+

+ Here we will show the dashboard with all your travel data, points and + distances. +

+
+
+ ); }; diff --git a/frontend/src/components/Login.jsx b/frontend/src/components/Login.jsx index dceeb2771..728aa13b3 100644 --- a/frontend/src/components/Login.jsx +++ b/frontend/src/components/Login.jsx @@ -13,18 +13,33 @@ const LoginSection = styled.section` display: flex; flex-direction: column; align-items: center; + /* min-height: 100vh; */ + + @media all and (min-width: 1024px) { + flex-direction: row; + } `; -const StyledForm = styled.form` +const FormWrapper = styled.div` display: flex; flex-direction: column; align-items: center; justify-content: center; + @media all and (min-width: 1024px) { + width: 50%; + } +`; + +const StyledForm = styled.form` + display: flex; + flex-direction: column; + padding-top: 20px; @media all and (min-width: 744px) { } @media all and (min-width: 1024px) { + /* width: 50%; */ } `; @@ -37,9 +52,10 @@ const StyledInput = styled.input` height: 50px; margin: 10px; font-size: 1.1em; + box-shadow: 2px 2px 4px rgba(0, 0, 0, 0.3); @media all and (min-width: 744px) { - width: 450px; + width: 400px; } `; @@ -77,7 +93,8 @@ export const Login = () => { const accessToken = data.accessToken; setMessage("Sign-in successful!"); localStorage.setItem("accessToken", accessToken); - navigate("/dashboard"); + navigate("/dashboard", { state: { username: formData.name } }); + // console.log(formData.name); } else { setMessage("Sign-in failed: Invalid name or password"); } @@ -89,39 +106,41 @@ export const Login = () => { return (
- - + + + - - {/* shows error message */} - {message &&

{message}

} -
- -

If you already have an account

- -

Register

- - -

Home

- + + {/* show error message */} + {message &&

{message}

} +
+ +

If you don’t have an account yet, create yours below.๐Ÿ‘‡

+ +

Register

+ + +

Home

+ + ); }; diff --git a/frontend/src/components/Registration.jsx b/frontend/src/components/Registration.jsx index 32d397756..230a8c3a3 100644 --- a/frontend/src/components/Registration.jsx +++ b/frontend/src/components/Registration.jsx @@ -13,6 +13,21 @@ const RegistrationSection = styled.section` display: flex; flex-direction: column; align-items: center; + /* min-height: 100vh; */ + + @media all and (min-width: 1024px) { + flex-direction: row; + } +`; + +const FormWrapper = styled.div` + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + @media all and (min-width: 1024px) { + width: 50%; + } `; const StyledForm = styled.form` @@ -37,9 +52,10 @@ const StyledInput = styled.input` height: 50px; margin: 10px; font-size: 1.1em; + box-shadow: 2px 2px 4px rgba(0, 0, 0, 0.3); @media all and (min-width: 744px) { - width: 450px; + width: 400px; } `; @@ -90,50 +106,52 @@ export const Registration = () => { return (
- - + + + - + - - {/* shows error message */} - {error &&

Please try again!

} -
- -

If you already have an account

- -

Login here

- - -

Home

- + + {/* shows error message */} + {error &&

Please try again!

} +
+ +

If you already have an account

+ +

Login here

+ + +

Home

+ + ); }; diff --git a/frontend/src/reusables/Form.jsx b/frontend/src/reusables/Form.jsx deleted file mode 100644 index 2a073803f..000000000 --- a/frontend/src/reusables/Form.jsx +++ /dev/null @@ -1,77 +0,0 @@ -/* eslint-disable react/prop-types */ -//imports -import styled from "styled-components"; -import { useState } from "react"; - -//styling -const FormSection = styled.section` - display: flex; - justify-content: center; - @media all and (min-width: 744px) { - } - @media all and (min-width: 1024px) { - } -`; - -const StyledForm = styled.form` - display: flex; - flex-direction: column; - align-items: center; - justify-content: center; - padding-top: 20px; - - @media all and (min-width: 744px) { - } - @media all and (min-width: 1024px) { - } -`; - -const StyledInput = styled.input` - width: 280px; - background: var(--grey); - border: none; - border-radius: 30px; - padding: 20px; - height: 50px; - margin: 20px; - font-size: 1.1em; - - @media all and (min-width: 744px) { - width: 450px; - } -`; - -//component -export const Form = ({ title, handleSubmit }) => { - const [name, setName] = useState(""); - const [password, setPassword] = useState(""); - - const onSubmit = (event) => { - event.preventDefault(); - handleSubmit(name, password); - }; - - return ( - -

{title}

- - setName(e.target.value)} - placeholder="Username" - required - /> - setPassword(e.target.value)} - placeholder="Password" - required - /> - -
- ); -}; From 96431a04da03113b27d0f8057d9d0283922350f0 Mon Sep 17 00:00:00 2001 From: Your El1an3 Date: Fri, 24 May 2024 22:17:06 +0200 Subject: [PATCH 22/33] styling fix dashboard on desktop --- frontend/src/components/Dashboard.jsx | 2 ++ 1 file changed, 2 insertions(+) diff --git a/frontend/src/components/Dashboard.jsx b/frontend/src/components/Dashboard.jsx index ebf2f5a98..33c73904d 100644 --- a/frontend/src/components/Dashboard.jsx +++ b/frontend/src/components/Dashboard.jsx @@ -47,7 +47,9 @@ const ContentWrapper = styled.div` box-shadow: 2px 2px 4px rgba(0, 0, 0, 0.3); margin: 50px; padding: 20px; + @media all and (min-width: 1024px) { + width: 70%; } `; From ca710ed599de4647ee53f3c11d49a4f0a1aba252 Mon Sep 17 00:00:00 2001 From: Your El1an3 Date: Sat, 25 May 2024 10:15:53 +0200 Subject: [PATCH 23/33] styling changes, completing read me --- README.md | 9 +++++---- frontend/src/components/Homepage.jsx | 7 +++++-- frontend/src/components/Login.jsx | 16 ++++++++++++---- frontend/src/components/Registration.jsx | 20 +++++++++++--------- frontend/src/reusables/Header.jsx | 10 +++++----- 5 files changed, 38 insertions(+), 24 deletions(-) diff --git a/README.md b/README.md index 2818f7406..af126468b 100644 --- a/README.md +++ b/README.md @@ -1,12 +1,13 @@ # Project Auth API -Replace this readme with your own information about your project. - -Start by briefly describing the assignment in a sentence or two. Keep it short and to the point. +This fullstack project requires developing a backend to support user registration, login and an authenticated endpoint accessible only to loggen-in users. +The frontend features a startpage, a registration and login form and a page displaying authenticated content. Also sign-out button that removes the access token from local storage and brings the user back to the startpage. ## The problem -Describe how you approached to problem, and what tools and techniques you used to solve it. How did you plan? What technologies did you use? If you had more time, what would be next? +I started by using the code from the codealong in the backend, trying to figure out how to do an authentication process and use bycript properly. +Being frustrated with backend I started creating the frontend and for a bit my project was all over the place. +In the end I went back to finish and test backend and then finish a frontend that could also be used for our final project. ## View it live diff --git a/frontend/src/components/Homepage.jsx b/frontend/src/components/Homepage.jsx index e64d8432e..2c4f840ef 100644 --- a/frontend/src/components/Homepage.jsx +++ b/frontend/src/components/Homepage.jsx @@ -39,9 +39,12 @@ const BottomForm = styled.div` position: fixed; z-index: 0; bottom: 0; - width: 744px; + /* width: 744px; height: 372px; - border-radius: 372px 372px 0 0; + border-radius: 372px 372px 0 0; */ + width: 520px; + height: 260px; + border-radius: 260px 260px 0 0; display: flex; justify-content: center; diff --git a/frontend/src/components/Login.jsx b/frontend/src/components/Login.jsx index 728aa13b3..cb0f0dc7d 100644 --- a/frontend/src/components/Login.jsx +++ b/frontend/src/components/Login.jsx @@ -5,15 +5,16 @@ import { Link, useNavigate } from "react-router-dom"; import { Header } from "../reusables/Header"; import { Button } from "../reusables/Button"; -// const API_KEY = "https://project-auth-ziup.onrender.com"; -const API_KEY = "http://localhost:8080"; +const API_KEY = "https://project-auth-ziup.onrender.com"; +// const API_KEY = "http://localhost:8080"; //styling const LoginSection = styled.section` display: flex; flex-direction: column; align-items: center; - /* min-height: 100vh; */ + height: 100vh; + overflow: hidden; @media all and (min-width: 1024px) { flex-direction: row; @@ -59,6 +60,11 @@ const StyledInput = styled.input` } `; +const FormText = styled.p` + text-align: center; + padding: 0 20px; +`; + //component export const Login = () => { const navigate = useNavigate(); @@ -133,7 +139,9 @@ export const Login = () => { {message &&

{message}

} -

If you don’t have an account yet, create yours below.๐Ÿ‘‡

+ + If you don’t have an account yet, create yours below.๐Ÿ‘‡{" "} +

Register

diff --git a/frontend/src/components/Registration.jsx b/frontend/src/components/Registration.jsx index 230a8c3a3..088801521 100644 --- a/frontend/src/components/Registration.jsx +++ b/frontend/src/components/Registration.jsx @@ -5,15 +5,16 @@ import { Link, useNavigate } from "react-router-dom"; import { Header } from "../reusables/Header"; import { Button } from "../reusables/Button"; -// const API_KEY = "https://project-auth-ziup.onrender.com"; -const API_KEY = "http://localhost:8080"; +const API_KEY = "https://project-auth-ziup.onrender.com"; +// const API_KEY = "http://localhost:8080"; //styling const RegistrationSection = styled.section` display: flex; flex-direction: column; align-items: center; - /* min-height: 100vh; */ + height: 100vh; + overflow: hidden; @media all and (min-width: 1024px) { flex-direction: row; @@ -36,11 +37,6 @@ const StyledForm = styled.form` align-items: center; justify-content: center; padding-top: 20px; - - @media all and (min-width: 744px) { - } - @media all and (min-width: 1024px) { - } `; const StyledInput = styled.input` @@ -59,6 +55,11 @@ const StyledInput = styled.input` } `; +const FormText = styled.p` + text-align: center; + padding: 0 20px; +`; + //component export const Registration = () => { const [error, setError] = useState(null); @@ -144,7 +145,8 @@ export const Registration = () => { {error &&

Please try again!

} -

If you already have an account

+ If you already have an account๐Ÿ‘‡ +

Login here

diff --git a/frontend/src/reusables/Header.jsx b/frontend/src/reusables/Header.jsx index 132a79577..94ca3ea19 100644 --- a/frontend/src/reusables/Header.jsx +++ b/frontend/src/reusables/Header.jsx @@ -13,7 +13,7 @@ const HeaderContainer = styled.section` background-size: cover; background-position: center; width: 100%; - height: 400px; + height: 300px; @media all and (min-width: 744px) { height: 400px; @@ -27,10 +27,10 @@ const HeaderContainer = styled.section` const HeaderGlobe = styled.img` position: absolute; - left: -44px; - top: -44px; - width: 350px; - height: 350px; + left: -40px; + top: -40px; + width: 280px; + height: 280px; @media all and (min-width: 744px) { left: -50px; From e6c6dc9ce0c887273e74458d49f69d48963530c8 Mon Sep 17 00:00:00 2001 From: Your El1an3 Date: Sat, 25 May 2024 10:20:38 +0200 Subject: [PATCH 24/33] cleaning up code --- frontend/src/components/Homepage.jsx | 3 --- frontend/src/components/Login.jsx | 12 +++--------- 2 files changed, 3 insertions(+), 12 deletions(-) diff --git a/frontend/src/components/Homepage.jsx b/frontend/src/components/Homepage.jsx index 2c4f840ef..7d1473c6d 100644 --- a/frontend/src/components/Homepage.jsx +++ b/frontend/src/components/Homepage.jsx @@ -39,9 +39,6 @@ const BottomForm = styled.div` position: fixed; z-index: 0; bottom: 0; - /* width: 744px; - height: 372px; - border-radius: 372px 372px 0 0; */ width: 520px; height: 260px; border-radius: 260px 260px 0 0; diff --git a/frontend/src/components/Login.jsx b/frontend/src/components/Login.jsx index cb0f0dc7d..af0e51e17 100644 --- a/frontend/src/components/Login.jsx +++ b/frontend/src/components/Login.jsx @@ -34,14 +34,9 @@ const FormWrapper = styled.div` const StyledForm = styled.form` display: flex; flex-direction: column; - + align-items: center; + justify-content: center; padding-top: 20px; - - @media all and (min-width: 744px) { - } - @media all and (min-width: 1024px) { - /* width: 50%; */ - } `; const StyledInput = styled.input` @@ -99,8 +94,7 @@ export const Login = () => { const accessToken = data.accessToken; setMessage("Sign-in successful!"); localStorage.setItem("accessToken", accessToken); - navigate("/dashboard", { state: { username: formData.name } }); - // console.log(formData.name); + navigate("/dashboard"); } else { setMessage("Sign-in failed: Invalid name or password"); } From d55f1b9f5764146b348fcfc8a3b3e6ef95e4128a Mon Sep 17 00:00:00 2001 From: Your El1an3 Date: Sat, 25 May 2024 17:20:25 +0200 Subject: [PATCH 25/33] added more error handling, fixed styling homepage --- frontend/src/components/Homepage.jsx | 17 ++++----- frontend/src/components/Registration.jsx | 48 ++++++++++++++++++++++-- 2 files changed, 52 insertions(+), 13 deletions(-) diff --git a/frontend/src/components/Homepage.jsx b/frontend/src/components/Homepage.jsx index 7d1473c6d..b5b64f52d 100644 --- a/frontend/src/components/Homepage.jsx +++ b/frontend/src/components/Homepage.jsx @@ -39,19 +39,18 @@ const BottomForm = styled.div` position: fixed; z-index: 0; bottom: 0; - width: 520px; - height: 260px; - border-radius: 260px 260px 0 0; - + width: 280px; + height: 140px; + border-radius: 140px 140px 0 0; display: flex; justify-content: center; align-items: center; text-align: center; @media all and (min-width: 744px) { - width: 520px; - height: 260px; - border-radius: 260px 260px 0 0; + width: 400px; + height: 200px; + border-radius: 200px 200px 0 0; } `; @@ -73,9 +72,7 @@ export const Homepage = () => { Take action - -

Our Slogan goes here

-
+ ); }; diff --git a/frontend/src/components/Registration.jsx b/frontend/src/components/Registration.jsx index 088801521..8d6fad7c6 100644 --- a/frontend/src/components/Registration.jsx +++ b/frontend/src/components/Registration.jsx @@ -60,9 +60,15 @@ const FormText = styled.p` padding: 0 20px; `; +const ErrorText = styled.p` + color: var(--lightgreen); + font-size: 0.9em; + margin-top: -10px; +`; + //component export const Registration = () => { - const [error, setError] = useState(null); + const [error, setError] = useState({}); const navigate = useNavigate(); const [formData, setFormData] = useState({ name: "", @@ -76,10 +82,41 @@ export const Registration = () => { ...formData, [name]: value, }); + setError({ + ...error, + [name]: "", + general: "", + }); + }; + + const validateEmail = (email) => { + const emailPattern = /^[^\s@]+@[^\s@]+\.[^\s@]+$/; + return emailPattern.test(email); }; const handleSubmit = async (e) => { e.preventDefault(); + + const newErrors = {}; + if (!formData.name) { + newErrors.name = "Username is required"; + } + + if (!formData.email) { + newErrors.email = "Email is required"; + } else if (!validateEmail(formData.email)) { + newErrors.email = "Invalid email format"; + } + + if (!formData.password) { + newErrors.password = "Password is required"; + } + + if (Object.keys(newErrors).length > 0) { + setError(newErrors); + return; + } + try { const response = await fetch(`${API_KEY}/register`, { method: "POST", @@ -119,6 +156,8 @@ export const Registration = () => { aria-label="Name" required /> + {/* show error message */} + {error.name && {error.name}} { aria-label="email" required /> + {/* show error message */} + {error.email && {error.email}} { aria-label="password" required /> - {/* shows error message */} - {error &&

Please try again!

} + {/* show error message */} + {error.password && {error.password}} + {error.general && {error.general}} If you already have an account๐Ÿ‘‡ From fbfaf00c17e47fe5a85483b4df6f66d2f8f9b699 Mon Sep 17 00:00:00 2001 From: Your El1an3 Date: Sun, 26 May 2024 13:37:48 +0200 Subject: [PATCH 26/33] update read me --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index af126468b..0f577362e 100644 --- a/README.md +++ b/README.md @@ -9,6 +9,8 @@ I started by using the code from the codealong in the backend, trying to figure Being frustrated with backend I started creating the frontend and for a bit my project was all over the place. In the end I went back to finish and test backend and then finish a frontend that could also be used for our final project. +If I had more time, I would add a loading animation page, because it takes forever on login and registration. + ## View it live Backend: https://project-auth-ziup.onrender.com From 5a6aeea4a165d04fdc84069ec55bc77dfe864dac Mon Sep 17 00:00:00 2001 From: Your El1an3 Date: Thu, 30 May 2024 10:43:51 +0200 Subject: [PATCH 27/33] fixed env file added netlify.toml --- frontend/netlify.toml | 7 +++++++ frontend/src/App.jsx | 2 +- frontend/src/components/Login.jsx | 5 +++-- frontend/src/components/Registration.jsx | 5 +++-- 4 files changed, 14 insertions(+), 5 deletions(-) create mode 100644 frontend/netlify.toml diff --git a/frontend/netlify.toml b/frontend/netlify.toml new file mode 100644 index 000000000..cd39fd085 --- /dev/null +++ b/frontend/netlify.toml @@ -0,0 +1,7 @@ +# 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 = "dist" + command = "npm run build" + diff --git a/frontend/src/App.jsx b/frontend/src/App.jsx index e17adb8d6..91bd54c08 100644 --- a/frontend/src/App.jsx +++ b/frontend/src/App.jsx @@ -12,7 +12,7 @@ export const App = () => { } /> } /> } /> - } /> + {/* } /> */} ); diff --git a/frontend/src/components/Login.jsx b/frontend/src/components/Login.jsx index af0e51e17..0a33c60f4 100644 --- a/frontend/src/components/Login.jsx +++ b/frontend/src/components/Login.jsx @@ -5,7 +5,6 @@ import { Link, useNavigate } from "react-router-dom"; import { Header } from "../reusables/Header"; import { Button } from "../reusables/Button"; -const API_KEY = "https://project-auth-ziup.onrender.com"; // const API_KEY = "http://localhost:8080"; //styling @@ -70,6 +69,8 @@ export const Login = () => { password: "", }); + const apiEnv = import.meta.env.VITE_API_KEY; + const handleChange = (e) => { const { name, value } = e.target; setFormData({ @@ -81,7 +82,7 @@ export const Login = () => { const handleSubmit = async (e) => { e.preventDefault(); try { - const response = await fetch(`${API_KEY}/login`, { + const response = await fetch(`${apiEnv}/login`, { method: "POST", headers: { "Content-Type": "application/json", diff --git a/frontend/src/components/Registration.jsx b/frontend/src/components/Registration.jsx index 8d6fad7c6..f12242838 100644 --- a/frontend/src/components/Registration.jsx +++ b/frontend/src/components/Registration.jsx @@ -5,7 +5,6 @@ import { Link, useNavigate } from "react-router-dom"; import { Header } from "../reusables/Header"; import { Button } from "../reusables/Button"; -const API_KEY = "https://project-auth-ziup.onrender.com"; // const API_KEY = "http://localhost:8080"; //styling @@ -76,6 +75,8 @@ export const Registration = () => { password: "", }); + const apiEnv = import.meta.env.VITE_API_KEY; + const handleChange = (e) => { const { name, value } = e.target; setFormData({ @@ -118,7 +119,7 @@ export const Registration = () => { } try { - const response = await fetch(`${API_KEY}/register`, { + const response = await fetch(`${apiEnv}/register`, { method: "POST", headers: { "Content-Type": "application/json", From 4447102a47c42a20cdc617bcbb16915debc7d4c3 Mon Sep 17 00:00:00 2001 From: Your El1an3 Date: Thu, 30 May 2024 10:49:39 +0200 Subject: [PATCH 28/33] fixes in post route --- frontend/src/components/Login.jsx | 2 +- frontend/src/components/Registration.jsx | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/frontend/src/components/Login.jsx b/frontend/src/components/Login.jsx index 0a33c60f4..790f5dba2 100644 --- a/frontend/src/components/Login.jsx +++ b/frontend/src/components/Login.jsx @@ -82,7 +82,7 @@ export const Login = () => { const handleSubmit = async (e) => { e.preventDefault(); try { - const response = await fetch(`${apiEnv}/login`, { + const response = await fetch(`${apiEnv}login`, { method: "POST", headers: { "Content-Type": "application/json", diff --git a/frontend/src/components/Registration.jsx b/frontend/src/components/Registration.jsx index f12242838..31494abf3 100644 --- a/frontend/src/components/Registration.jsx +++ b/frontend/src/components/Registration.jsx @@ -119,7 +119,7 @@ export const Registration = () => { } try { - const response = await fetch(`${apiEnv}/register`, { + const response = await fetch(`${apiEnv}register`, { method: "POST", headers: { "Content-Type": "application/json", From b2668a3b09415b80e047ece038bec4017b5a36c7 Mon Sep 17 00:00:00 2001 From: Your El1an3 Date: Thu, 30 May 2024 12:17:32 +0200 Subject: [PATCH 29/33] fixed error messages, added loading component --- frontend/netlify.toml | 5 +++++ frontend/src/components/Login.jsx | 14 +++++++++++--- frontend/src/components/Registration.jsx | 2 +- frontend/src/reusables/Loading.jsx | 19 +++++++++++++++++++ 4 files changed, 36 insertions(+), 4 deletions(-) create mode 100644 frontend/src/reusables/Loading.jsx diff --git a/frontend/netlify.toml b/frontend/netlify.toml index cd39fd085..558042533 100644 --- a/frontend/netlify.toml +++ b/frontend/netlify.toml @@ -5,3 +5,8 @@ publish = "dist" command = "npm run build" +[[redirects]] + from = "/*" + to = "/index.html" + status = 200 + diff --git a/frontend/src/components/Login.jsx b/frontend/src/components/Login.jsx index 790f5dba2..87e08150e 100644 --- a/frontend/src/components/Login.jsx +++ b/frontend/src/components/Login.jsx @@ -4,8 +4,9 @@ import { useState } from "react"; import { Link, useNavigate } from "react-router-dom"; import { Header } from "../reusables/Header"; import { Button } from "../reusables/Button"; +import { Loading } from "../reusables/Loading"; -// const API_KEY = "http://localhost:8080"; +// const apiEnv = "http://localhost:8080/"; //styling const LoginSection = styled.section` @@ -63,6 +64,7 @@ const FormText = styled.p` export const Login = () => { const navigate = useNavigate(); const [message, setMessage] = useState(""); + const [loading, setLoading] = useState(false); const [formData, setFormData] = useState({ name: "", @@ -81,6 +83,7 @@ export const Login = () => { const handleSubmit = async (e) => { e.preventDefault(); + setLoading(true); try { const response = await fetch(`${apiEnv}login`, { method: "POST", @@ -97,10 +100,14 @@ export const Login = () => { localStorage.setItem("accessToken", accessToken); navigate("/dashboard"); } else { - setMessage("Sign-in failed: Invalid name or password"); + const errorData = await response.json(); + setMessage(`Sign-in failed: ${errorData.message}`); } } catch (error) { console.error("Login failed:", error); + setMessage("An error occurred. Please try again later."); + } finally { + setLoading(false); } }; @@ -133,7 +140,8 @@ export const Login = () => { {/* show error message */} {message &&

{message}

} - + {/* Conditionally render loading spinner or login button */} + {loading ? : } If you don’t have an account yet, create yours below.๐Ÿ‘‡{" "} diff --git a/frontend/src/components/Registration.jsx b/frontend/src/components/Registration.jsx index 31494abf3..70d8e8f52 100644 --- a/frontend/src/components/Registration.jsx +++ b/frontend/src/components/Registration.jsx @@ -5,7 +5,7 @@ import { Link, useNavigate } from "react-router-dom"; import { Header } from "../reusables/Header"; import { Button } from "../reusables/Button"; -// const API_KEY = "http://localhost:8080"; +// const apiEnv = "http://localhost:8080/"; //styling const RegistrationSection = styled.section` diff --git a/frontend/src/reusables/Loading.jsx b/frontend/src/reusables/Loading.jsx new file mode 100644 index 000000000..9027d9616 --- /dev/null +++ b/frontend/src/reusables/Loading.jsx @@ -0,0 +1,19 @@ +import styled from "styled-components"; + +export const Loading = styled.div` + border: 4px solid rgba(0, 0, 0, 0.1); + width: 36px; + height: 36px; + border-radius: 50%; + border-left-color: #09f; + animation: spin 1s ease infinite; + + @keyframes spin { + 0% { + transform: rotate(0deg); + } + 100% { + transform: rotate(360deg); + } + } +`; From eccfdafade489ee4aea957a88fd197a5692473ae Mon Sep 17 00:00:00 2001 From: Your El1an3 Date: Thu, 30 May 2024 12:25:42 +0200 Subject: [PATCH 30/33] styling fix --- frontend/src/reusables/Loading.jsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/frontend/src/reusables/Loading.jsx b/frontend/src/reusables/Loading.jsx index 9027d9616..835b40cd7 100644 --- a/frontend/src/reusables/Loading.jsx +++ b/frontend/src/reusables/Loading.jsx @@ -1,11 +1,11 @@ import styled from "styled-components"; export const Loading = styled.div` - border: 4px solid rgba(0, 0, 0, 0.1); + border: 4px solid var(--darkgreen) (0, 0, 0, 0.1); width: 36px; height: 36px; border-radius: 50%; - border-left-color: #09f; + border-left-color: var(--lightgreen); animation: spin 1s ease infinite; @keyframes spin { From ecc6e872a355661d69001afd42dfa66525124688 Mon Sep 17 00:00:00 2001 From: Your El1an3 Date: Thu, 30 May 2024 12:34:03 +0200 Subject: [PATCH 31/33] another styling fix --- frontend/src/reusables/Loading.jsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frontend/src/reusables/Loading.jsx b/frontend/src/reusables/Loading.jsx index 835b40cd7..758ad3f01 100644 --- a/frontend/src/reusables/Loading.jsx +++ b/frontend/src/reusables/Loading.jsx @@ -1,7 +1,7 @@ import styled from "styled-components"; export const Loading = styled.div` - border: 4px solid var(--darkgreen) (0, 0, 0, 0.1); + border: 4px solid rgba(67, 105, 87, 0.1); width: 36px; height: 36px; border-radius: 50%; From 5b42e7e688882fa297744f1530ccdb4a670e54dd Mon Sep 17 00:00:00 2001 From: Your El1an3 Date: Thu, 30 May 2024 12:54:04 +0200 Subject: [PATCH 32/33] . --- frontend/src/App.jsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/frontend/src/App.jsx b/frontend/src/App.jsx index 91bd54c08..c0721be24 100644 --- a/frontend/src/App.jsx +++ b/frontend/src/App.jsx @@ -1,7 +1,7 @@ import { BrowserRouter, Routes, Route } from "react-router-dom"; import { Login } from "./components/Login"; import { Registration } from "./components/Registration"; -import { Dashboard } from "./components/Dashboard"; +// import { Dashboard } from "./components/Dashboard"; import { Homepage } from "./components/Homepage"; export const App = () => { @@ -11,7 +11,7 @@ export const App = () => { } /> } /> } /> - } /> + {/* } /> */} {/* } /> */} From 172b0f5b14a27a97ae009a0fb239ab428c74adee Mon Sep 17 00:00:00 2001 From: Your El1an3 Date: Thu, 30 May 2024 12:57:51 +0200 Subject: [PATCH 33/33] undo last commit --- frontend/src/App.jsx | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/frontend/src/App.jsx b/frontend/src/App.jsx index c0721be24..45af87ccc 100644 --- a/frontend/src/App.jsx +++ b/frontend/src/App.jsx @@ -1,7 +1,7 @@ import { BrowserRouter, Routes, Route } from "react-router-dom"; import { Login } from "./components/Login"; import { Registration } from "./components/Registration"; -// import { Dashboard } from "./components/Dashboard"; +import { Dashboard } from "./components/Dashboard"; import { Homepage } from "./components/Homepage"; export const App = () => { @@ -11,8 +11,7 @@ export const App = () => { } /> } /> } /> - {/* } /> */} - {/* } /> */} + } /> );