diff --git a/backend/.gitignore b/backend/.gitignore index 25c8fdbab..8f5e467c8 100644 --- a/backend/.gitignore +++ b/backend/.gitignore @@ -1,2 +1,3 @@ node_modules -package-lock.json \ No newline at end of file +package-lock.json +.env \ No newline at end of file diff --git a/backend/authenticateUser.js b/backend/authenticateUser.js new file mode 100644 index 000000000..753250ea4 --- /dev/null +++ b/backend/authenticateUser.js @@ -0,0 +1,21 @@ +import UserModel from "./models/userModel.js"; + +export const authenticateUser = async (req, res, next) => { + const accessToken = req.header("Authorization"); + + if ( + req.headers.authorization && + req.headers.authorization.startsWith("Bearer") + ) + try { + const user = await UserModel.findOne({ accessToken: accessToken }); + if (user) { + req.user = user; + next(); + } else { + res.status(401).json({ success: false, response: "please log in" }); + } + } catch (e) { + res.status(500).json({ success: false, response: e.message }); + } +}; diff --git a/backend/models/userModel.js b/backend/models/userModel.js new file mode 100644 index 000000000..02b66ea09 --- /dev/null +++ b/backend/models/userModel.js @@ -0,0 +1,37 @@ +import mongoose from "mongoose"; +import crypto from "crypto"; + +const { Schema } = mongoose; + +const userSchema = new Schema( + { + username: { + type: String, + required: true, + unique: true, + minlength: 2, // corrected typo: minlenght -> minlength + }, + password: { + type: String, + required: true, + minlength: 6, + }, + email: { + type: String, + required: true, + unique: true, + }, + accessToken: { + type: String, + default: () => crypto.randomBytes(128).toString("hex"), + required: false, + }, + }, + { + timestamps: true, + } +); + +const UserModel = mongoose.model("User", userSchema); + +export default UserModel; diff --git a/backend/package.json b/backend/package.json index 8de5c4ce0..a42b3c455 100644 --- a/backend/package.json +++ b/backend/package.json @@ -4,17 +4,25 @@ "description": "Starter project to get up and running with express quickly", "scripts": { "start": "babel-node server.js", - "dev": "nodemon server.js --exec babel-node" + "dev": "nodemon server.js --exec babel-node", + "build": "babel src -d dist" }, "author": "", "license": "ISC", + "type": "module", "dependencies": { "@babel/core": "^7.17.9", "@babel/node": "^7.16.8", "@babel/preset-env": "^7.16.11", + "bcrypt": "^5.0.0", "cors": "^2.8.5", + "dotenv": "^16.4.5", "express": "^4.17.3", - "mongoose": "^8.0.0", + "express-async-handler": "^1.2.0", + "express-list-endpoints": "^7.1.0", + "jsonwebtoken": "^9.0.2", + "mongodb": "^6.5.0", + "mongoose": "^8.3.2", "nodemon": "^3.0.1" } } diff --git a/backend/routes/userRoutes.js b/backend/routes/userRoutes.js new file mode 100644 index 000000000..89ab9943a --- /dev/null +++ b/backend/routes/userRoutes.js @@ -0,0 +1,244 @@ +import express from "express"; +import bcrypt from "bcrypt"; +import jwt from "jsonwebtoken"; + +import UserModel from "../models/userModel.js"; // Make sure to import your user model here + +import asyncHandler from "express-async-handler"; +import dotenv from "dotenv"; +import { authenticateUser } from "../authenticateUser.js"; // If you have an authentication middleware, import it here + +dotenv.config(); + +const router = express.Router(); + +const generateToken = (user) => { + // Function to generate JWT token + return jwt.sign({ id: user._id }, process.env.JWT_SECRET, { + expiresIn: "24h", + }); +}; + +// Route for user registration +router.post( + "/register", + asyncHandler(async (req, res) => { + const { username, password, email } = req.body; + try { + // Check if all required fields are provided + if (!username || !password || !email) { + res.status(400); + throw new Error("Please provide all fields"); + } + // Check if user with the same username or email already exists + const existingUser = await UserModel.findOne({ + $or: [{ username }, { email }], + }); + if (existingUser) { + res.status(400); + throw new Error( + `User with ${ + existingUser.username === username ? "username" : "email" + } already exists` + ); + } + // Hash the password + const salt = bcrypt.genSaltSync(10); + const hashedPassword = bcrypt.hashSync(password, salt); + // Create a new user + const newUser = new UserModel({ + username, + email, + password: hashedPassword, + }); + await newUser.save(); + // Respond with success message and token + res.status(201).json({ + success: true, + response: { + username: newUser.username, + email: newUser.email, + id: newUser._id, + accessToken: generateToken(newUser), + }, + }); + } catch (e) { + // Handle any errors + res.status(500).json({ success: false, response: e.message }); + } + }) +); + +// Route for user login +router.post( + "/login", + asyncHandler(async (req, res) => { + const { username, password } = req.body; + try { + // Find user by username + const user = await UserModel.findOne({ username }); + if (!user) { + return res + .status(401) + .json({ success: false, response: "User not found" }); + } + // Compare passwords + const isMatch = await bcrypt.compare(password, user.password); + if (!isMatch) { + return res + .status(401) + .json({ success: false, response: "Incorrect password" }); + } + // Respond with success message and token + res.status(200).json({ + success: true, + response: { + username: user.username, + email: user.email, + id: user._id, + accessToken: generateToken(user), + }, + }); + } catch (error) { + // Handle any errors + res.status(500).json({ + success: false, + response: { + message: error.message, + }, + }); + } + }) +); + +// Sample route accessible only to logged-in users +router.get( + "/logged-in", + authenticateUser, // Authentication middleware to verify JWT token + asyncHandler(async (req, res) => { + res.status(200).json({ + success: true, + response: { + message: "User is logged in", + }, + }); + }) +); + +export default router; + +/*import express from "express"; +import bcrypt from "bcrypt"; +import jwt from "jsonwebtoken"; + +import UserModel from "../models/userModel.js"; + +import asyncHandler from "express-async-handler"; +import dotenv from "dotenv"; +import { authenticateUser } from "../authenticateUser.js"; + +dotenv.config(); + +const router = express.Router(); + +const generateToken = (user) => { + return jwt.sign({ id: user._id }, process.env.JWT_SECRET, { + expiresIn: "24h", + }); +}; + +router.post( + "/register", + asyncHandler(async (req, res) => { + const { username, password, email } = req.body; + try { + if (!username || !password || !email) { + res.status(400); + throw new Error("please add all fields"); + } + const existingUser = await UserModel.findOne({ + $or: [{ username }, { email }], + }); + if (existingUser) { + res.status(400); + throw new Error( + `user with ${ + existingUser.username === username ? "username" : "email" + } already exists` + ); + } + const salt = bcrypt.genSaltSync(10); + const hashedPassword = bcrypt.hashSync(password, salt); + const newUser = new UserModel({ + username, + email, + password: hashedPassword, + }); + await newUser.save(); + res.status(201).json({ + success: true, + response: { + username: newUser.username, + email: newUser.email, + id: newUser._id, + accessToken: geneerateToken(newUser), + }, + }); + } catch (e) { + res.status(500).json({ success: false, response: e.message }); + } + }) +); + +router.post( + "/login", + asyncHandler(async (req, res) => { + const { username, password } = req.body; + try { + const user = await UserModel.findOne({ username }); + if (!user) { + return res + .status(401) + .json({ success: false, response: "user not found" }); + } + const isMatch = await bcrypt.compare(password, user.password); + if (!isMatch) { + return res + .status(401) + .json({ success: false, response: "incorrect password" }); + } + res.status(200).json({ + success: true, + response: { + username: user.username, + email: user.email, + id: user._id, + accessToken: geneerateToken(user), + }, + }); + } catch (error) { + res.status(500).json({ + success: false, + response: { + message: error.message, + }, + }); + } + }) +); + +router.get( + "/logged-in", + authenticateUser, + asyncHandler(async (req, res) => { + res.status(200).json({ + success: true, + response: { + message: "user is logged in", + }, + }); + }) +); + +export default router; +*/ diff --git a/backend/server.js b/backend/server.js index 2d7ae8aa1..35049bfca 100644 --- a/backend/server.js +++ b/backend/server.js @@ -1,27 +1,44 @@ import express from "express"; +import expressListEndpoints from "express-list-endpoints"; import cors from "cors"; import mongoose from "mongoose"; +import dotenv from "dotenv"; +import userRoutes from "./routes/userRoutes.js"; -const mongoUrl = process.env.MONGO_URL || "mongodb://localhost/project-mongo"; -mongoose.connect(mongoUrl, { useNewUrlParser: true, useUnifiedTopology: true }); -mongoose.Promise = Promise; +dotenv.config(); -// 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(); +const port = process.env.PORT || 9090; -// Add middlewares to enable cors and json body parsing +// Middleware app.use(cors()); app.use(express.json()); +app.use(express.urlencoded({ extended: true })); +app.use(userRoutes); -// Start defining your routes here +// Routes app.get("/", (req, res) => { - res.send("Hello Technigo!"); + const endpoints = expressListEndpoints(app); + res.json(endpoints); + console.log("List of Endpoints:"); + console.log(endpoints); }); -// Start the server -app.listen(port, () => { - console.log(`Server running on http://localhost:${port}`); -}); +// Database connection + +mongoose + .connect(process.env.MONGODB_URI, { + //useNewUrlParser: true, + //useUnifiedTopology: true, + }) + .then(() => { + console.log("Connected to MongoDB Atlas"); + // Start the server after successfully connecting to the database + app.listen(port, () => { + console.log(`Server running on http://localhost:${port}`); + }); + }) + .catch((error) => { + console.error("Error connecting to MongoDB Atlas:", error); + process.exit(1); + }); diff --git a/bash.exe.stackdump b/bash.exe.stackdump new file mode 100644 index 000000000..15faa3ea6 --- /dev/null +++ b/bash.exe.stackdump @@ -0,0 +1,41 @@ +Stack trace: +Frame Function Args +0007FFFFCD30 00021006118E (0002102A6010, 000210272B51, 00000000005C, 0007FFFFB6E0) msys-2.0.dll+0x2118E +0007FFFFCD30 0002100469BA (0007FFFFC790, 000200000000, 000700000000, 000700000001) msys-2.0.dll+0x69BA +0007FFFFCD30 0002100469F2 (000000000000, 000000000000, 00000000005C, 000700000003) msys-2.0.dll+0x69F2 +0007FFFFCD30 000210101C61 (000210177A63, 000800007568, 000000000000, 0002102752E0) msys-2.0.dll+0xC1C61 +0007FFFFCD30 000210101C79 (0002101778B0, 0007FFFFC8F8, 000000000004, 0007FFFFC910) msys-2.0.dll+0xC1C79 +0007FFFFCD30 000210104644 (0007FFFFCD30, 000000000000, 0007FFFFC910, 0002102752E0) msys-2.0.dll+0xC4644 +0007FFFFCD30 000210059095 (000000000004, 000000000004, 0007FFFFCA68, 0000FFFFFFFF) msys-2.0.dll+0x19095 +0007FFFFCD30 000210059865 (000800000000, 000800006F28, 000000000000, 000000030201) msys-2.0.dll+0x19865 +0007FFFFCD30 000210059D77 (00021017DA35, 000000000000, 000000000000, 000000000000) msys-2.0.dll+0x19D77 +0007FFFFCD30 00021005A0B6 (000000000000, 0007FFFFCD30, FFFFFFFFFFFFFFC6, 000700000000) msys-2.0.dll+0x1A0B6 +0007FFFFCD30 000210047151 (000000000000, 000000000000, 000000000000, 000000000000) msys-2.0.dll+0x7151 +0007FFFFFFF0 000210045C86 (000000000000, 000000000000, 000000000000, 000000000000) msys-2.0.dll+0x5C86 +0007FFFFFFF0 000210045D34 (000000000000, 000000000000, 000000000000, 000000000000) msys-2.0.dll+0x5D34 +End of stack trace +Loaded modules: +000100400000 bash.exe +7FF997AF0000 ntdll.dll +7FF9967C0000 KERNEL32.DLL +7FF9950C0000 KERNELBASE.dll +7FF991C30000 apphelp.dll +7FF996B40000 USER32.dll +7FF9954A0000 win32u.dll +7FF995AA0000 GDI32.dll +7FF9956B0000 gdi32full.dll +7FF994EB0000 msvcp_win.dll +7FF995590000 ucrtbase.dll +000210040000 msys-2.0.dll +7FF996890000 advapi32.dll +7FF9959F0000 msvcrt.dll +7FF995940000 sechost.dll +7FF995470000 bcrypt.dll +7FF995E10000 RPCRT4.dll +7FF994560000 CRYPTBASE.DLL +7FF994E30000 bcryptPrimitives.dll +7FF995F30000 IMM32.DLL +7FF980520000 netapi32.dll +7FF980500000 SAMCLI.DLL +7FF9888E0000 SAMLIB.dll +7FF9938E0000 NETUTILS.DLL diff --git a/frontend/.gitignore b/frontend/.gitignore index 265f50c92..6254213ab 100644 --- a/frontend/.gitignore +++ b/frontend/.gitignore @@ -23,4 +23,5 @@ dist-ssr *.sln *.sw? -package-lock.json \ No newline at end of file +package-lock.json +.env \ No newline at end of file diff --git a/frontend/index.html b/frontend/index.html index 0c589eccd..79c470191 100644 --- a/frontend/index.html +++ b/frontend/index.html @@ -1,4 +1,4 @@ - + diff --git a/frontend/package.json b/frontend/package.json index e9c95b79f..ea51431de 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -10,13 +10,19 @@ "preview": "vite preview" }, "dependencies": { + "axios": "^1.6.8", + "lottie-react": "^2.4.0", "react": "^18.2.0", - "react-dom": "^18.2.0" + "react-dom": "^18.2.0", + "react-router-dom": "^6.23.0", + "styled-components": "^6.1.8", + "zustand": "^4.5.2" }, "devDependencies": { - "@types/react": "^18.2.15", + "@types/react": "^18.2.79", "@types/react-dom": "^18.2.7", "@vitejs/plugin-react": "^4.0.3", + "@vitejs/plugin-react-refresh": "^1.3.6", "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 1091d4310..2cd115875 100644 --- a/frontend/src/App.jsx +++ b/frontend/src/App.jsx @@ -1,3 +1,17 @@ +// eslint-disable-next-line no-unused-vars +import React from "react"; +import { BrowserRouter, Routes } from "react-router-dom"; +import { routes } from "./routes/RoutesComp"; +import "./index.css"; + export const App = () => { - return
Find me in src/app.jsx!
; + return ( +
+ +
+ {routes} +
+
+
+ ); }; diff --git a/frontend/src/axiosConfig.js b/frontend/src/axiosConfig.js new file mode 100644 index 000000000..25af1f751 --- /dev/null +++ b/frontend/src/axiosConfig.js @@ -0,0 +1,8 @@ +// api.js +import axios from "axios"; + +const api = axios.create({ + baseURL: "https://project-auth-3.onrender.com/", // Update with your backend server URL +}); + +export default api; diff --git a/frontend/src/components/LogIn.jsx b/frontend/src/components/LogIn.jsx new file mode 100644 index 000000000..6f75e4aa5 --- /dev/null +++ b/frontend/src/components/LogIn.jsx @@ -0,0 +1,84 @@ +// eslint-disable-next-line no-unused-vars +import React from "react"; +import { useEffect } from "react"; +import { useNavigate } from "react-router-dom"; +import { userStore } from "./UserStore"; + +//const apiEnv = import.meta.env.VITE_BACKEND_API; + +export const Login = () => { + const { + username, + setUsername, + password, + setPassword, + user, + setUser, + setAccessToken, + } = userStore(); + const navigate = useNavigate(); + + const handleLogin = async () => { + if (!username || !password) { + alert("Please enter both username and password"); + return; + } + + try { + const apiEnv = "https://project-auth-3.onrender.com"; // Backend API URL + //const url = `${apiEnv}/login`; // Construct the complete URL + //console.log("URL:", url); // Log the constructed URL + + const response = await fetch(`${apiEnv}/login`, { + method: "POST", + headers: { + "Content-Type": "application/json", + }, + body: JSON.stringify({ username, password }), + }); + console.log(response); + + if (response.ok) { + const data = await response.json(); + + setAccessToken(data.accessToken); + + setUser(data); + + localStorage.setItem("accessToken", data.accessToken); + setUsername(""); + setPassword(""); + + alert("Login successful!"); + navigate("/logged-in"); + } else { + const errorData = await response.json(); + alert(`Login failed: ${errorData.error}`); + } + } catch (error) { + alert("Error during login:", error.message); + } + }; + + useEffect(() => { + console.log("User:", user); + }, [user]); + + return ( +
+ setUsername(e.target.value)} + /> + setPassword(e.target.value)} + /> + +
+ ); +}; diff --git a/frontend/src/components/LogOut.jsx b/frontend/src/components/LogOut.jsx new file mode 100644 index 000000000..cb5b91538 --- /dev/null +++ b/frontend/src/components/LogOut.jsx @@ -0,0 +1,23 @@ +// eslint-disable-next-line no-unused-vars +import React from "react"; +//import { useNavigate } from "react-router-dom"; +import { userStore } from "./UserStore"; + +export const Logout = () => { + //const navigate = useNavigate(); + const { setAccessToken, setIsLoggedIn, setUser } = userStore(); + + const handleLogOut = () => { + { + // Clear local user data (if needed) + setUser(null); + setAccessToken(null); + setIsLoggedIn(true); + + // Redirect to the login page + //navigate(""); + } + }; + + return ; +}; diff --git a/frontend/src/components/LogedInComponet.jsx b/frontend/src/components/LogedInComponet.jsx new file mode 100644 index 000000000..e5ed43b2f --- /dev/null +++ b/frontend/src/components/LogedInComponet.jsx @@ -0,0 +1,101 @@ +// eslint-disable-next-line no-unused-vars +import React from "react"; +import axios from "axios"; +import { useNavigate } from "react-router-dom"; +import { useEffect } from "react"; +import { userStore } from "./UserStore"; + +const apiEnv = import.meta.env.VITE_BACKEND_API; + +export const LogedInComp = () => { + const { accessToken, isLoggedIn, setIsLoggedIn } = userStore(); + const navigate = useNavigate(); + + useEffect(() => { + const fetchLoggedInData = async () => { + try { + const response = await axios.get(`${apiEnv}/logged-in`, { + headers: { + "Content-Type": "application/json", + Authorization: `${accessToken}`, + }, + }); + + if (response.status === 200) { + const data = response.data; + console.log(data); + setIsLoggedIn(true); + } else { + console.error("Failed to fetch authenticated content"); + navigate("/"); + } + } catch (error) { + console.error("Error fetching authenticated content:", error); + navigate("/"); + } + }; + + fetchLoggedInData(); + }, [accessToken, isLoggedIn, setIsLoggedIn, navigate]); + + return ( + isLoggedIn && ( +
+

YAY! You are logged in!

+
+ ) + ); +}; + +/* +import { useNavigate } from "react-router-dom"; +import { useEffect } from "react"; +import { userStore } from "./UserStore"; + +const apiEnv = import.meta.env.VITE_BACKEND_API; + +export const LogedInComp = () => { + const { accessToken, isLoggedIn, setIsLoggedIn } = userStore(); + + const navigate = useNavigate(); + + useEffect(() => { + const fetchLoggedInData = async () => { + try { + const response = await fetch(`${apiEnv}/logged-in`, { + headers: { + "Content-Type": "application/json", + Authorization: `${accessToken}`, + }, + }); + + if (response.ok) { + const data = await response.json(); + console.log(data); + + setIsLoggedIn(true); + } else { + console.error("Failed to fetch authenticated content"); + navigate("/"); + } + } catch (error) { + console.error("Error fetching authenticated content:", error); + } + }; + + fetchLoggedInData(); + }); + + return ( + isLoggedIn && ( +
+ AI Generated Image +

Congratulations! You are logged in. Here is a cute puppy for you!

+
+ ) + ); +}; +*/ diff --git a/frontend/src/components/SignUp.jsx b/frontend/src/components/SignUp.jsx new file mode 100644 index 000000000..87f247f5e --- /dev/null +++ b/frontend/src/components/SignUp.jsx @@ -0,0 +1,137 @@ +// eslint-disable-next-line no-unused-vars +import React from "react"; +import { useState } from "react"; + +export const SignUp = () => { + const [email, setEmail] = useState(""); + const [username, setUsername] = useState(""); + const [password, setPassword] = useState(""); + + const handleSignup = async () => { + try { + const apiEnv = "https://project-auth-3.onrender.com"; // Backend API URL + const url = `${apiEnv}/register`; // Construct the complete URL + + console.log("URL:", url); // Log the constructed URL + console.log("Request Body:", { email, username, password }); + + const response = await fetch(url, { + method: "POST", + headers: { + "Content-Type": "application/json", + }, + body: JSON.stringify({ email, username, password }), + }); + + if (response.ok) { + alert("Signup was successful, please log in!"); + setEmail(""); + setUsername(""); + setPassword(""); + } else { + const data = await response.json(); + console.log(data); + alert("Signup failed: " + data.message); + } + } catch (error) { + alert("Error during registration: " + error.message); + } + }; + + return ( +
+ setEmail(e.target.value)} + /> + setUsername(e.target.value)} + /> + setPassword(e.target.value)} + /> + +
+ ); +}; + +/* +//const apiEnv = import.meta.env.VITE_BACKEND_API; + +export const SignUp = () => { + const [email, setEmail] = useState(""); + const [username, setUsername] = useState(""); + const [password, setPassword] = useState(""); + `${apiEnv} + const handleSignup = async () => { + try { + + + + const apiEnv = "https://project-auth-3.onrender.com"; // Backend API URL + + const url = `${apiEnv}/register`; // Construct the complete URL + + console.log("URL:", url); // Log the constructed URL + + console.log("Request Body:", { email, username, password }); + + const response = await fetch(`${apiEnv}/register`, { + method: "POST", + headers: { + "Content-Type": "application/json", + }, + + body: JSON.stringify({ email, username, password }), + }); + + if (response.ok) { + alert("Signup was successful, please log in!"); + setEmail(""); + setUsername(""); + setPassword(""); + } else { + const data = await response.json(); + console.log(data); + alert("Signup failed:" + data.message); + } + } catch (error) { + alert("Error during registration:", error); + } + }; + + return ( + <> +
+ setEmail(e.target.value)} + /> + setUsername(e.target.value)} + /> + setPassword(e.target.value)} + /> + +
+ + ); +}; +*/ diff --git a/frontend/src/components/UserStore.jsx b/frontend/src/components/UserStore.jsx new file mode 100644 index 000000000..d8f3c20f6 --- /dev/null +++ b/frontend/src/components/UserStore.jsx @@ -0,0 +1,15 @@ +import { create } from "zustand"; + +export const userStore = create((set) => ({ + username: "", + password: "", + accessToken: null, + user: null, + isLoggedIn: false, + + setUsername: (username) => set({ username }), + setPassword: (password) => set({ password }), + setAccessToken: (accessToken) => set({ accessToken }), + setUser: (user) => set({ user }), + setIsLoggedIn: (isLoggedIn) => set({ isLoggedIn }), +})); diff --git a/frontend/src/index.css b/frontend/src/index.css index 3e560a674..6b553b0aa 100644 --- a/frontend/src/index.css +++ b/frontend/src/index.css @@ -10,4 +10,99 @@ code { font-family: source-code-pro, Menlo, Monaco, Consolas, "Courier New", monospace; -} \ No newline at end of file +} + +body { + display: flex; + justify-content: center; + place-items: center; + min-width: 320px; + min-height: 100vh; + background-color: #aaa2a9; +} + +p { + margin: 5px; +} + +.wrapper { + display: flex; + flex-direction: column; + gap: 3rem; + padding: 2rem; +} + +.logged-in-content img { + max-width: 100%; +} + +.logged-in-wrapper { + display: flex; + flex-direction: column; + align-items: center; + gap: 1rem; + max-width: 250px; + background-color: #865959; + border-radius: 5px; + padding: 1rem; + text-align: center; +} + +.login-container { + display: flex; + flex-direction: column; + align-items: center; + padding: 1rem; + background-color: #8dab9c; + border-radius: 5px; +} + +.login-form { + display: flex; + flex-direction: column; + align-items: center; +} + +.signup-container { + display: flex; + flex-direction: column; + align-items: center; + padding: 1rem; + background-color: #8dab9c; + border-radius: 5px; +} + +.signup-form { + display: flex; + flex-direction: column; + align-items: center; +} + +input { + padding: 10px; + margin-bottom: 10px; + border-radius: 5px; + border: none; + width: 70%; +} + +button { + padding: 10px; + margin-bottom: 10px; + border-radius: 20px; + border: none; + width: 70%; + background-color: rgb(64, 0, 255); + color: rgb(255, 255, 255); + font-weight: 700; +} + +button:hover { + background-color: #c5bce0; + cursor: pointer; +} + +p { + font-weight: 700; + color: rgb(0, 0, 0); +} diff --git a/frontend/src/pages/LandingPage.jsx b/frontend/src/pages/LandingPage.jsx new file mode 100644 index 000000000..599225637 --- /dev/null +++ b/frontend/src/pages/LandingPage.jsx @@ -0,0 +1,21 @@ +// eslint-disable-next-line no-unused-vars +import React from "react"; +import { Login } from "../components/LogIn"; +import { SignUp } from "../components/SignUp"; + +export const LandingPage = () => { + return ( + <> +
+

Please login:

+ +
+ +
+

No account?

+

Please sign up:

+ +
+ + ); +}; diff --git a/frontend/src/pages/LogedInPage.jsx b/frontend/src/pages/LogedInPage.jsx new file mode 100644 index 000000000..8eeb4127d --- /dev/null +++ b/frontend/src/pages/LogedInPage.jsx @@ -0,0 +1,13 @@ +// eslint-disable-next-line no-unused-vars +import React from "react"; +import { LogedInComp } from "../components/LogedInComponet"; +import { Logout } from "../components/LogOut"; + +export const LogedInPage = () => { + return ( +
+ + +
+ ); +}; diff --git a/frontend/src/routes/RoutesComp.jsx b/frontend/src/routes/RoutesComp.jsx new file mode 100644 index 000000000..311f4c357 --- /dev/null +++ b/frontend/src/routes/RoutesComp.jsx @@ -0,0 +1,12 @@ +// eslint-disable-next-line no-unused-vars +import React from "react"; +import { Route } from "react-router-dom"; +import { LandingPage } from "../pages/LandingPage"; +import { LogedInPage } from "../pages/LogedInPage"; + +export const routes = ( + <> + }> + }> + +); diff --git a/frontend/vite.config.js b/frontend/vite.config.js index 5a33944a9..ef5932009 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()], +//}) + +import { defineConfig } from "vite"; +import reactRefresh from "@vitejs/plugin-react-refresh"; // https://vitejs.dev/config/ export default defineConfig({ - plugins: [react()], -}) + plugins: [reactRefresh()], +}); diff --git a/netlify.toml b/netlify.toml index 95443a1f3..02013ac34 100644 --- a/netlify.toml +++ b/netlify.toml @@ -1,6 +1,9 @@ -# 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" + base = "frontend/" + publish = "dist/" + command = "npm run build" + +[[redirects]] + from = "/*" + to = "/index.html" + status = 200 diff --git a/package.json b/package.json index d774b8cc3..2542e7f9b 100644 --- a/package.json +++ b/package.json @@ -2,6 +2,24 @@ "name": "project-auth-parent", "version": "1.0.0", "scripts": { + "dev": "vite", "postinstall": "npm install --prefix backend" + }, + "dependencies": { + "@babel/core": "^7.24.4", + "@babel/node": "^7.23.9", + "@babel/preset-env": "^7.24.4", + "axios": "^1.6.8", + "bcrypt": "^5.1.1", + "cors": "^2.8.5", + "crypto": "^1.0.1", + "dotenv": "^16.4.5", + "express": "^4.19.2", + "express-async-handler": "^1.2.0", + "express-list-endpoints": "^6.0.0", + "jsonwebtoken": "^9.0.2", + "mongoose": "^8.3.2", + "nodemon": "^3.1.0", + "react-router-dom": "^6.22.3" } }