diff --git a/.gitignore b/.gitignore index 3d70248ba..78651256b 100644 --- a/.gitignore +++ b/.gitignore @@ -12,4 +12,5 @@ npm-debug.log* yarn-debug.log* yarn-error.log* -package-lock.json \ No newline at end of file +package-lock.json +note.md diff --git a/README.md b/README.md index dfa05e177..8d869b80e 100644 --- a/README.md +++ b/README.md @@ -1,13 +1,21 @@ # 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. +For this project, the focus was on connecting the frontend and backend by creating a registration form that not only registers the user but also logs them in and returns an access token used to authenticate the user. Since we are developing an application for children aged 7-9 years old to help them improve their learning skills in English, Swedish, and math, we wanted to implement these functionalities in this project using MongoDB as the database, and ReactJS and ExpressJS to handle the frontend and fetch data from the API. In this project, we are able to register, log in, and log out a user. ## 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? +We had some problems deploying both the frontend and backend, but we worked together and solved them. We also found some difficulty adding the user data to the database after deployment. However, after adding the correct endpoints and using the correct connection string to MongoDB, we were able to start registering new users and use that to log i ## View it live -Every project should be deployed somewhere. Be sure to include the link to the deployed project so that the viewer can click around and see what it's all about. +[Frontend](https://technigo-project-auth.netlify.app/) + +[Backend](https://technigo-project-auth.onrender.com/) + +## Contributors + +Thanks to these great people for contributing to this project: + +- [@Tejpex](https://github.com/Tejpex) +- [@fridaforser](https://github.com/fridaforser) +- [@KatSjolin](https://github.com/KatSjolin) diff --git a/backend/package.json b/backend/package.json index 8de5c4ce0..588b5a6fe 100644 --- a/backend/package.json +++ b/backend/package.json @@ -12,9 +12,14 @@ "@babel/core": "^7.17.9", "@babel/node": "^7.16.8", "@babel/preset-env": "^7.16.11", + "bcrypt-nodejs": "^0.0.3", "cors": "^2.8.5", "express": "^4.17.3", - "mongoose": "^8.0.0", + "mongodb": "^6.6.2", + "mongoose": "^8.4.0", "nodemon": "^3.0.1" + }, + "devDependencies": { + "@types/bcrypt-nodejs": "^0.0.31" } } diff --git a/backend/server.js b/backend/server.js index dfe86fb8e..ffe3ceda2 100644 --- a/backend/server.js +++ b/backend/server.js @@ -1,24 +1,142 @@ import cors from "cors"; import express from "express"; import mongoose from "mongoose"; +import bcrypt from "bcrypt-nodejs"; +import crypto from "crypto"; -const mongoUrl = process.env.MONGO_URL || "mongodb://localhost/project-mongo"; +// Defining port and connecting to mongoose +const port = process.env.PORT || 8000; +const app = express(); +const mongoUrl = process.env.MONGO_URL || "mongodb://localhost/auth"; + +console.log("Connecting to MongoDB at:", mongoUrl); 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 -const port = process.env.PORT || 8080; -const app = express(); +// Defining schema for a User +const User = mongoose.model("User", { + username: { + type: String, + unique: true, + required: true, + }, + password: { + type: String, + required: true, + }, + firstName: { + type: String, + required: true, + }, + lastName: { + type: String, + required: true, + }, + age: { + type: String, + required: true, + }, + email: { + type: String, + unique: true, + required: true, + }, + accessToken: { + type: String, + default: () => crypto.randomBytes(128).toString("hex"), + }, +}); -// Add middlewares to enable cors and json body parsing +//Authenticate user as middleware +const authenticateUser = async (req, res, next) => { + const accessToken = req.header("Authorization"); + if (!accessToken) { + return res.status(401).json({ error: "Unauthorized: Missing access token" }); + } + + const user = await User.findOne({ accessToken }) + if (user) { + console.log("User is found", user); + req.user = user; + next(); + } else { + return res.status(403).json({ error: "Forbidden: Invalid access token" }); + } +}; + +// Middlewares to enable cors and json body parsing app.use(cors()); app.use(express.json()); +app.use((req, res, next) => { + if (mongoose.connection.readyState === 1) { + next(); + } else { + res.status(503).json({ error: "Service unavailable." }); + } +}); -// Start defining your routes here +// Defining routes app.get("/", (req, res) => { - res.send("Hello Technigo!"); + res.send("Hello friend!"); +}); + +//User-endpoint for developing purpose +app.get("/users", async (req, res) => { + const allUsers = await User.find().exec(); + if (allUsers.length > 0) { + res.status(200).json(allUsers); + } else { + res.status(404).send("No users found"); + } +}); + +//Create user with username, password etc. +app.post("/users", async (req, res) => { + try { + const { username, firstName, lastName, age, email, password } = req.body; + const salt = bcrypt.genSaltSync(10); + const user = new User({ + username, + firstName, + lastName, + age, + email, + password: bcrypt.hashSync(password, salt), + }); + await user.save(); + res.status(201).json({ id: user._id, accessToken: user.accessToken }); + } catch (error) { + res + .status(400) + .json({ response: error, message: "Could not create user." }); + } +}); + +//Endpoint for login +app.post("/sessions", async (req, res) => { + const userByUsername = await User.findOne({ username: req.body.username }); + const userByEmail = await User.findOne({ email: req.body.email }); + if ( + userByUsername && + bcrypt.compareSync(req.body.password, userByUsername.password) + ) { + res.status(200).json({userId: userByUsername._id, accessToken: userByUsername.accessToken, + }); + } else if ( + userByEmail && + bcrypt.compareSync(req.body.password, userByEmail.password) + ) { + res.status(200).json({ userId: userByEmail._id, accessToken: userByEmail.accessToken }); + } else { + res.status(404).json({ notFound: true }); + } +}); + +app.get("/games", authenticateUser); +app.get("/games", async (req, res) => { + res + .status(200) + .json({ message: "Secret message only for logged in users to see!" }); }); // Start the server diff --git a/frontend/index.html b/frontend/index.html index 0c589eccd..cd0a6f8c1 100644 --- a/frontend/index.html +++ b/frontend/index.html @@ -4,7 +4,10 @@ - Vite + React + + + + Pluggin
diff --git a/frontend/package.json b/frontend/package.json index e9c95b79f..d74ed8395 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -10,8 +10,13 @@ "preview": "vite preview" }, "dependencies": { + "dotenv": "^16.4.5", "react": "^18.2.0", - "react-dom": "^18.2.0" + "react-dom": "^18.2.0", + "react-hook-form": "^7.51.5", + "react-router": "^6.23.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..c4f4206e2 100644 --- a/frontend/src/App.jsx +++ b/frontend/src/App.jsx @@ -1,3 +1,33 @@ +import { BrowserRouter, Routes, Route } from "react-router-dom"; +import { Header } from "./components/Header"; +import { RegistrationForm } from "./components/RegistrationForm"; +import { Login } from "./components/Login"; +import { Play } from "./components/Play"; +import { Math } from "./components/Games/Math"; +import { Swedish } from "./components/Games/Swedish"; +import { English } from "./components/Games/English"; +import { Progress } from "./components/MyProgress"; +import { WelcomeText } from "./components/WelcomeText"; +import { UserProvider } from "./contexts/UserContext"; + export const App = () => { - return
Find me in src/app.jsx!
; + return ( + + +
+
+ + } /> + } /> + } /> + } /> + } /> + } /> + } /> + } /> + +
+ + + ); }; diff --git a/frontend/src/assets/react.svg b/frontend/src/assets/react.svg deleted file mode 100644 index 6c87de9bb..000000000 --- a/frontend/src/assets/react.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/frontend/src/assets/signouticon.png b/frontend/src/assets/signouticon.png new file mode 100644 index 000000000..d088f7122 Binary files /dev/null and b/frontend/src/assets/signouticon.png differ diff --git a/frontend/src/components/Button.jsx b/frontend/src/components/Button.jsx new file mode 100644 index 000000000..43bbebe36 --- /dev/null +++ b/frontend/src/components/Button.jsx @@ -0,0 +1,25 @@ +import styled from "styled-components"; + +export const Button = styled.button` + background-color: var(--raspberry); + color: #fff; + border-radius: 30px; + border: none; + padding: 10px 20px; + font-size: 16px; + font-weight: 500; + transition: 0.2s ease; + text-decoration: none; + margin-top: 20px; + + &:hover { + background-color: var(--raspberryhover); + cursor: pointer; + } + + &:active { + background-color: var(--raspberryactive); + } +`; + +export default Button; diff --git a/frontend/src/components/Games/English.jsx b/frontend/src/components/Games/English.jsx new file mode 100644 index 000000000..0bd211374 --- /dev/null +++ b/frontend/src/components/Games/English.jsx @@ -0,0 +1,8 @@ +import styled from "styled-components"; + +export const English = () => { + return Let's play an English game!; +}; +const EnglishTitle = styled.h2` + color: black; +`; diff --git a/frontend/src/components/Games/Math.jsx b/frontend/src/components/Games/Math.jsx new file mode 100644 index 000000000..64ef5e59a --- /dev/null +++ b/frontend/src/components/Games/Math.jsx @@ -0,0 +1,8 @@ +import styled from "styled-components"; + +export const Math = () => { + return Let's play a math game!; +}; +const MathTitle = styled.h2` + color: black; +`; diff --git a/frontend/src/components/Games/Swedish.jsx b/frontend/src/components/Games/Swedish.jsx new file mode 100644 index 000000000..3c585eebc --- /dev/null +++ b/frontend/src/components/Games/Swedish.jsx @@ -0,0 +1,8 @@ +import styled from "styled-components"; + +export const Swedish = () => { + return Let's play a Swedish game!; +}; +const SwedishTitle = styled.h2` + color: black; +`; diff --git a/frontend/src/components/Header.jsx b/frontend/src/components/Header.jsx new file mode 100644 index 000000000..55c6f5d73 --- /dev/null +++ b/frontend/src/components/Header.jsx @@ -0,0 +1,156 @@ +import { Link } from "react-router-dom"; +import styled from "styled-components"; +import { useLogin } from "../contexts/UserContext"; +import signoutIcon from "/src/assets/signouticon.png"; + +export const Header = () => { + const { authenticated, signout } = useLogin(); + + if (authenticated.auth) { + return ( + + + + Play + + + My progress + + + Sign out + + + + + ); + } else { + return ( + + + + Register here + + + Log in + + + + ); + } +}; + +const HeaderContainer = styled.div` + background-color: var( --sunset); + width: 100%; + height: 30px; + position: absolute; + margin: -8px; + display: flex; + flex-direction: row; + justify-content: space-evenly; + align-items: center; + padding: 10px; + font-weight: 500; +`; + +const StartPage = styled.div` + display: flex; + flex-direction: row; + justify-content: space-evenly; + width: 100vh; +`; + +const Register = styled.p` + color: var( --ocean); + cursor: pointer; + + &:hover { + color: var( --oceanhover); + } + + &:active { + color: var( --oceanactive); + } +`; + +const Login = styled.p` + color: var( --ocean); + cursor: pointer; + + &:hover { + color: var( --oceanhover); + } + + &:active { + color: var( --oceanactive); + } +`; + +const LoggedIn = styled.div` + display: flex; + flex-direction: row; + justify-content: space-between; + padding: 10px; + width: 100vh; + color: white; + +`; + +const Play = styled.p` + color: var( --ocean); + cursor: pointer; + + &:hover { + color: var( --oceanhover); + } + + &:active { + color: var( --oceanactive); + } +`; + +const MyProgress = styled.p` + color: var( --ocean); + cursor: pointer; + + &:hover { + color: var( --oceanhover); + } + + &:active { + color: var( --oceanactive); + } +`; + +const SignOut = styled.div` + display: flex; + justify-content: center; + gap: 7px; + cursor: pointer; + + &:hover { + opacity: 70%; + } +`; + +const SignOutText = styled.p` + color: var( --ocean); + cursor: pointer; + + + &:active { + color: var( --oceanactive); + } +`; + +const SignOutIcon = styled.img` + width: 17px; + height: 22px; + align-items: center; + padding-top: 17px; + opacity: 100%; + + + +`; + diff --git a/frontend/src/components/Input.jsx b/frontend/src/components/Input.jsx new file mode 100644 index 000000000..574a53c15 --- /dev/null +++ b/frontend/src/components/Input.jsx @@ -0,0 +1,3 @@ +export const Input = () => { + return
Input
; +}; diff --git a/frontend/src/components/Login.jsx b/frontend/src/components/Login.jsx new file mode 100644 index 000000000..b5e7cae21 --- /dev/null +++ b/frontend/src/components/Login.jsx @@ -0,0 +1,95 @@ +import styled from "styled-components"; +import { useState } from "react"; +import { useLogin } from "../contexts/UserContext"; +import { Button } from "./Button"; +import { useNavigate } from "react-router-dom"; + +export const Login = () => { + const [username, setUsername] = useState(""); + const [password, setPassword] = useState(""); + const [error, setError] = useState(""); + const { login } = useLogin(); + const navigate = useNavigate(); + + const handleSubmit = async (e) => { + e.preventDefault(); + try { + await login({ username, password }); + navigate("/play"); + } catch (error) { + setError("Invalid username or password"); + } + }; + + return ( + +
+ Login + {error && {error}} + + + +
+
+ ); +}; + +const LoginContainer = styled.div` + border-radius: 20px; + max-width: fit-content; + height: fit-content; + margin: 0 auto; + + @media (min-width: 700px){ + padding-top: 50px; + +} +`; + +const Heading = styled.h1` + color: var(--vanilla); + text-align: center; + margin-top: 0; +`; + +const Form = styled.form` + display: flex; + flex-direction: column; + padding: 2rem; + background-color: var(--teal); + border-radius: 20px; + + @media (min-width: 700px){ + padding: 2rem 2.5rem; + +} +`; + +const Input = styled.input` + border-radius: 20px; + padding: 10px 30px; + border: none; + background-color: var(--vanilla); +`; + +const Error = styled.h3` + color: black; +`; diff --git a/frontend/src/components/MyProgress.jsx b/frontend/src/components/MyProgress.jsx new file mode 100644 index 000000000..46f871728 --- /dev/null +++ b/frontend/src/components/MyProgress.jsx @@ -0,0 +1,10 @@ +import styled from "styled-components"; + +export const Progress = () => { + return Hi Name, here you can see your progress!; +}; + +const ProgressTitle = styled.h2` + color: black; + margin: 0 auto; +`; diff --git a/frontend/src/components/Play.jsx b/frontend/src/components/Play.jsx new file mode 100644 index 000000000..95e6b50f5 --- /dev/null +++ b/frontend/src/components/Play.jsx @@ -0,0 +1,166 @@ +import { useState, useEffect } from "react"; +import { Link } from "react-router-dom"; +import styled, { css } from "styled-components"; +import { useLogin } from "../contexts/UserContext"; + +export const Play = () => { + const { authenticated, setAuthenticated } = useLogin(); + const [message, setMessage] = useState("") + + const getContent = async () => { + const accessToken = localStorage.getItem("accessToken"); + try { + // Ensure this points to the correct backend URL + const response = await fetch( + //"http://localhost:8000/games", + "https://technigo-project-auth.onrender.com/games", + { + method: "GET", + headers: { + "Content-Type": "application/json", + Authorization: accessToken, + }, + } + ); + console.log(response); + if (!response.ok) { + setAuthenticated({ + auth: false, + }); + throw new Error("Failed to get user"); + } + + const data = await response.json(); + console.log("Login success", data); + setMessage(data.message) + setAuthenticated({ + auth: true, + }); + } catch (err) { + console.error("No user was found:", err); + } + }; + + useEffect(() => { + getContent(); + // eslint-disable-next-line react-hooks/exhaustive-deps + }, []); + + if (authenticated.auth) { + return ( + + + Welcome to Pluggin, Name. Ready to play some games? + + {message && {message}} + + + Play a math game! + + + Play a Swedish game! + + + Play an English game! + + + + ); + } else { + return You need to log in!; + } +}; + +const PlayContainer = styled.div` + display: flex; + flex-direction: column; + height: 100vh; + justify-content: space-evenly; + align-items: center; + margin: 0 auto; +`; + +const PlayTitle = styled.h2` + color: black; + display: flex; + flex-wrap: wrap; + flex-direction: column; + text-align: center; + margin-top: 70px; +`; + +const GamesCards = styled.div` + display: flex; + flex-wrap: wrap; + justify-content: space-evenly; + align-items: center; + width: 100%; +`; + +const GameCard = styled.div` + display: flex; + flex-direction: column; + flex-wrap: wrap; + justify-content: center; + align-items: center; + border-radius: 30px; + width: 290px; + height: 220px; + margin: 20px; + color: var(--vanilla); + background-color: var(--teal); + font-size: 20px; + + &:hover { + transition: 0.2s ease; + } + + ${({ math }) => + math && + css` + box-shadow: 10px 10px var(--oceanactive); + background-color: var(--ocean); + + &:hover { + box-shadow: 15px 15px var(--oceanactive); + } + `} + + ${({ swedish }) => + swedish && + css` + background-color: var(--raspberry); + box-shadow: 10px 10px var(--raspberryactive); + + &:hover { + box-shadow: 15px 15px var(--raspberryactive); + } + `} + + ${({ english }) => + english && + css` + background-color: var(--teal); + box-shadow: 10px 10px var(--tealactive); + + &:hover { + box-shadow: 15px 15px var(--tealactive); + } + `} + + @media (min-width: 900px) { + margin: 40px; + } +`; + +const Text = styled.p` + font-size: 36px; + text-align: center; + width: 100vw; +`; + +const SecretText = styled.p` + font-size: 14px; + text-align: center; + color: red; +` diff --git a/frontend/src/components/RegistrationForm.jsx b/frontend/src/components/RegistrationForm.jsx new file mode 100644 index 000000000..2a0747187 --- /dev/null +++ b/frontend/src/components/RegistrationForm.jsx @@ -0,0 +1,215 @@ +import { useState } from "react"; +import { useLogin } from "../contexts/UserContext"; +import { Button } from "./Button"; +import { useNavigate } from "react-router-dom"; +import { FormProvider, useForm } from "react-hook-form"; + +import styled from "styled-components"; + +export const RegistrationForm = () => { + // Set starting point for handling user data + + // This method gives access to different form hooks + const methods = useForm(); + const { registerUser } = useLogin(); + const [errorMessage, setErrorMessage] = useState(""); + + // Destructes register, handleSubmit and errors from useForm + const { + register, // validation and tracking + handleSubmit, // function that will run when the form is submitted + formState: { errors }, // object with validation errors for each input field + } = methods; + + const navigate = useNavigate(); + + // Send the request to /users with the updated form data + const onSubmit = async (data) => { + const { password, confirmPassword } = data; + + // Check if password is correct + if (password !== confirmPassword) { + // Add error message and return; + setErrorMessage("The passwords are not identical"); + return; + } + + // Send code to backend -> do some stuff using try and catch + try { + await registerUser(data); + + // Redirect to login page + navigate("/play"); + } catch (err) { + console.error("Error registration user", err); + } + }; + + return ( + + +
+ {/* disables browser validation */} + Register + + + + + + + + {errorMessage} + +
+
+
+ ); +}; + +const RegistrationContainer = styled.div` + border-radius: 20px; + max-width: fit-content; + height: fit-content; + padding-top: 80px; + margin: 0 auto; + + @media (min-width: 700px) { + padding-top: 50px; + } +`; + +const Heading = styled.h1` + color: var(--vanilla); + text-align: center; + margin-top: 0; +`; + +const Form = styled.form` + display: flex; + flex-direction: column; + padding: 2rem; + background-color: var(--ocean); + border-radius: 20px; + + @media (min-width: 700px) { + padding: 2rem 2.5rem; + } +`; + +const Input = styled.input` + border-radius: 20px; + padding: 10px 30px; + border: none; + background-color: var(--vanilla); +`; + +const ErrorMessage = styled.div` + color: #fff; + font-size: 13px; +`; diff --git a/frontend/src/components/WelcomeText.jsx b/frontend/src/components/WelcomeText.jsx new file mode 100644 index 000000000..b90467a01 --- /dev/null +++ b/frontend/src/components/WelcomeText.jsx @@ -0,0 +1,28 @@ +import styled from "styled-components"; + +export const WelcomeText = () => { + return ( + + Welcome to PluggIn' + + The site were you can up your game in different school subjects. + + + ); +}; + +const WelcomeContainer = styled.div` + background: rgba(255, 255, 255, 0.5); + border-radius: 20px; + max-width: fit-content; + height: fit-content; + margin: 0 auto; +`; + +const Heading = styled.h1` + margin: 0; +`; + +const Text = styled.p` + margin: 0; +`; diff --git a/frontend/src/contexts/UserContext.jsx b/frontend/src/contexts/UserContext.jsx new file mode 100644 index 000000000..97d88e9ff --- /dev/null +++ b/frontend/src/contexts/UserContext.jsx @@ -0,0 +1,111 @@ +import { createContext, useContext, useState } from "react"; +import { useNavigate } from "react-router-dom"; +// import dotenv from "dotenv"; + +// Load environment variables from .env file +// dotenv.config(); + +const UserContext = createContext(); + +export const UserProvider = ({ children }) => { + const [user, setUser] = useState(null); + const [authenticated, setAuthenticated] = useState({ + accessToken: localStorage.getItem("accessToken"), + auth: false, + }); + const navigate = useNavigate(); + + //Uses password and username or email to do a login-request + const login = async (loginData, accessToken) => { + try { + // Ensure this points to the correct backend URL + const response = await fetch( + //"http://localhost:8000/sessions", + "https://technigo-project-auth.onrender.com/sessions", + { + method: "POST", + headers: { + "Content-Type": "application/json", + }, + body: JSON.stringify(loginData), + } + ); + //Not successful + if (!response.ok) { + console.log("Login failed"); + throw new Error("Failed to get user"); + } + //Successful + const data = await response.json(); + console.log("Login success", data); + + // Save accesstoken in local storage + localStorage.setItem("accessToken", data.accessToken); + setAuthenticated({ + accessToken, + auth: true, + }); + } catch (err) { + console.error("No user was found:", err); + } + }; + + + const signout = () => { + localStorage.removeItem("accessToken") + setAuthenticated({ + auth: false, + }) + navigate("/login"); + } + + // Function that sends userData to MongoDB to create a new user + const registerUser = async (userData) => { + try { + // Ensure this points to the correct backend URL + const response = await fetch( + //"http://localhost:8000/users", + "https://technigo-project-auth.onrender.com/users", + { + method: "POST", + headers: { + "Content-Type": "application/json", + }, + body: JSON.stringify(userData), + } + ); + if (!response.ok) { + throw new Error("Failed to register user"); + } + + const data = await response.json(); + console.log("Registration success", data); + + // Save accesstoken in local storage + localStorage.setItem("accessToken", data.accessToken); + setAuthenticated({ + //accessToken: data.accessToken, + auth: true, + }); + } catch (err) { + console.error("Error registering new user:", err); + } + }; + + return ( + + {children} + + ); +}; +export const useLogin = () => useContext(UserContext); diff --git a/frontend/src/index.css b/frontend/src/index.css index 3e560a674..436157c8a 100644 --- a/frontend/src/index.css +++ b/frontend/src/index.css @@ -1,13 +1,48 @@ :root { margin: 0; - font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", "Roboto", "Oxygen", + font-family: "Poppins", -apple-system, BlinkMacSystemFont, "Segoe UI", "Roboto", "Oxygen", "Ubuntu", "Cantarell", "Fira Sans", "Droid Sans", "Helvetica Neue", sans-serif; -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; + --vanilla: #fef9ef; + --ocean: #227c9d; + --oceanhover: #4095b4; + --oceanactive: #1a5f79; + --teal: #17c3b2; + --tealhover: #2fd5c5; + --tealactive: #119285; + --sunset: #ffcb77; + --sunsethover: #ffd798; + --sunsetactive: #c59d5d; + --raspberry: #fe6d73; + --raspberryhover: #ff9296; + --raspberryactive: #c15457; } code { - font-family: source-code-pro, Menlo, Monaco, Consolas, "Courier New", + font-family: "Poppins", source-code-pro, Menlo, Monaco, Consolas, "Courier New", monospace; -} \ No newline at end of file +} + +body { + background-color: var( --vanilla); +} + +main { + width: 100vw; + height: 100vh; + display: flex; + align-items: center; +} + +/* Remove this code. Should be global and in a separate component folder */ +input { + margin: 10px 0; + font-family: "Poppins", source-code-pro, Menlo, Monaco, Consolas, "Courier New", + monospace; +} + +a { + text-decoration: none; +} diff --git a/netlify.toml b/netlify.toml deleted file mode 100644 index 95443a1f3..000000000 --- a/netlify.toml +++ /dev/null @@ -1,6 +0,0 @@ -# This file tells netlify where the code for this project is and -# how it should build the JavaScript assets to deploy from. -[build] - base = "frontend/" - publish = "build/" - command = "npm run build" diff --git a/package.json b/package.json index d774b8cc3..731a81f62 100644 --- a/package.json +++ b/package.json @@ -2,6 +2,12 @@ "name": "project-auth-parent", "version": "1.0.0", "scripts": { + "dev": "node server.js", "postinstall": "npm install --prefix backend" + }, + "dependencies": { + "dotenv": "^16.4.5", + "react-router": "^6.23.1", + "styled-components": "^6.1.11" } } diff --git a/pull_request_template.md b/pull_request_template.md deleted file mode 100644 index d92c89b51..000000000 --- a/pull_request_template.md +++ /dev/null @@ -1,7 +0,0 @@ -## Netlify link -Add your Netlify link here. -PS. Don't forget to add it in your readme as well. - -## Collaborators -Add your collaborators here. Write their GitHub usernames in square brackets. If there's more than one, separate them with a comma, like this: -[github-username-1, github-username-2]