diff --git a/backend/models/UploadModel.js b/backend/models/UploadModel.js index 60d2cc5451333158cbd28b6e467289299f78fb1b..1c522616cecb8f2958b5f5da4b15173f7f072a4f 100644 --- a/backend/models/UploadModel.js +++ b/backend/models/UploadModel.js @@ -1,27 +1,40 @@ const mongoose = require('mongoose') +const userModel = require('./user') const postSchema = new mongoose.Schema({ - name:{ - type:String, - required:true + name: { + type: String, + required: true }, - recipe:{ - type:String, - required:false + recipe: { + type: [String], + required: false }, - description:{ - type:String, - required:true + description: { + type: String, + required: true }, - photo:{ + author:{ + type: mongoose.Schema.Types.ObjectId, + ref:"user" + }, + profile_picture: { type: String, - required: false + required: true + }, + profile_name: { + type: String, + required: true + }, + photo: { + type: String, + required: true } - + }) -const postModel = mongoose.model("Post",postSchema) +const postModel = mongoose.model("Post", postSchema) module.exports = postModel diff --git a/backend/models/user.js b/backend/models/user.js index 0f26dc91abffb0f70d3dfb291a8a9b30b689518c..27cf264fc9dae46767301da28fb18bfbdfd21e4c 100644 --- a/backend/models/user.js +++ b/backend/models/user.js @@ -18,6 +18,11 @@ password:{ type:String, required: true }, +posts: { + type: mongoose.SchemaTypes.ObjectId, + ref: "post", + required: false +}, photo:{ type: String, required: false diff --git a/backend/node_modules/.package-lock.json b/backend/node_modules/.package-lock.json index 6a8b056d56d58de0dbaa689fdfc51587586f2b11..11e1c9fb550c4ed6912b3301ce01d37616fea538 100644 --- a/backend/node_modules/.package-lock.json +++ b/backend/node_modules/.package-lock.json @@ -671,6 +671,11 @@ "node": ">= 0.6" } }, + "node_modules/fs": { + "version": "0.0.1-security", + "resolved": "https://registry.npmjs.org/fs/-/fs-0.0.1-security.tgz", + "integrity": "sha512-3XY9e1pP0CVEUCdj5BmfIZxRBTSDycnbqhIOGec9QYtmVH2fbLpj86CFWkrNOkt/Fvty4KZG5lTglL9j/gJ87w==" + }, "node_modules/fs-minipass": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-2.1.0.tgz", diff --git a/backend/package-lock.json b/backend/package-lock.json index 9374d93fa5f74dee3afe806d5d53db279f8c2e3e..0d27bf0ef184b580472a353a71c3161e3539ee8c 100644 --- a/backend/package-lock.json +++ b/backend/package-lock.json @@ -16,6 +16,7 @@ "dotenv": "^16.0.3", "express": "^4.18.2", "express-async-handler": "^1.2.0", + "fs": "^0.0.1-security", "joi-password-complexity": "^5.1.0", "jsonwebtoken": "^9.0.0", "mongoose": "^7.0.4", @@ -691,6 +692,11 @@ "node": ">= 0.6" } }, + "node_modules/fs": { + "version": "0.0.1-security", + "resolved": "https://registry.npmjs.org/fs/-/fs-0.0.1-security.tgz", + "integrity": "sha512-3XY9e1pP0CVEUCdj5BmfIZxRBTSDycnbqhIOGec9QYtmVH2fbLpj86CFWkrNOkt/Fvty4KZG5lTglL9j/gJ87w==" + }, "node_modules/fs-minipass": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-2.1.0.tgz", @@ -2594,6 +2600,11 @@ "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", "integrity": "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==" }, + "fs": { + "version": "0.0.1-security", + "resolved": "https://registry.npmjs.org/fs/-/fs-0.0.1-security.tgz", + "integrity": "sha512-3XY9e1pP0CVEUCdj5BmfIZxRBTSDycnbqhIOGec9QYtmVH2fbLpj86CFWkrNOkt/Fvty4KZG5lTglL9j/gJ87w==" + }, "fs-minipass": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-2.1.0.tgz", diff --git a/backend/package.json b/backend/package.json index 2c164078f85ef913a1319cdc8a742e203c12ed11..a334bf0b8f8a6eda15e25e2ed76fa410d4fb7e72 100644 --- a/backend/package.json +++ b/backend/package.json @@ -17,6 +17,7 @@ "dotenv": "^16.0.3", "express": "^4.18.2", "express-async-handler": "^1.2.0", + "fs": "^0.0.1-security", "joi-password-complexity": "^5.1.0", "jsonwebtoken": "^9.0.0", "mongoose": "^7.0.4", diff --git a/backend/public/uploads/1d07174c-0687-41d3-9cdc-98fd2e4ae0a8_.jpg b/backend/public/uploads/1d07174c-0687-41d3-9cdc-98fd2e4ae0a8_.jpg deleted file mode 100644 index e2ec0afe10f29f9b718f3d77535b3eaf3e0b70e8..0000000000000000000000000000000000000000 Binary files a/backend/public/uploads/1d07174c-0687-41d3-9cdc-98fd2e4ae0a8_.jpg and /dev/null differ diff --git a/backend/public/uploads/2740e421-6b6c-4db3-be6a-1379d8dd3240_.jpg b/backend/public/uploads/2740e421-6b6c-4db3-be6a-1379d8dd3240_.jpg new file mode 100644 index 0000000000000000000000000000000000000000..d69bc90c885602fa07e13f3a0106ebe39db3e30b Binary files /dev/null and b/backend/public/uploads/2740e421-6b6c-4db3-be6a-1379d8dd3240_.jpg differ diff --git a/backend/public/uploads/4d0e6f3c-a919-489f-8e64-d60910601ed9_.JPG b/backend/public/uploads/4d0e6f3c-a919-489f-8e64-d60910601ed9_.JPG deleted file mode 100644 index 8dc59a3747049e7c0169980cd050ca8178da07b0..0000000000000000000000000000000000000000 Binary files a/backend/public/uploads/4d0e6f3c-a919-489f-8e64-d60910601ed9_.JPG and /dev/null differ diff --git a/backend/public/uploads/4d3e6514-fd66-4a7c-a508-3af24bbcb763_.jpg b/backend/public/uploads/4d3e6514-fd66-4a7c-a508-3af24bbcb763_.jpg deleted file mode 100644 index dc182c271de9432b5ae12fe43792ede6fcc80828..0000000000000000000000000000000000000000 Binary files a/backend/public/uploads/4d3e6514-fd66-4a7c-a508-3af24bbcb763_.jpg and /dev/null differ diff --git a/backend/public/uploads/7f3d200b-f57a-4c1d-9965-72c024d0338e_.PNG b/backend/public/uploads/7f3d200b-f57a-4c1d-9965-72c024d0338e_.PNG deleted file mode 100644 index 3273ce3453d19d1732ded62bda888792aef6fdd6..0000000000000000000000000000000000000000 Binary files a/backend/public/uploads/7f3d200b-f57a-4c1d-9965-72c024d0338e_.PNG and /dev/null differ diff --git a/backend/public/uploads/81976f69-cdcb-4376-820b-7db0bf090af8_.jpg b/backend/public/uploads/81976f69-cdcb-4376-820b-7db0bf090af8_.jpg deleted file mode 100644 index 226c1aea2c2a8c5e933f2716ed83fd90977326e1..0000000000000000000000000000000000000000 Binary files a/backend/public/uploads/81976f69-cdcb-4376-820b-7db0bf090af8_.jpg and /dev/null differ diff --git a/backend/public/uploads/8d419a28-5c3c-44d7-859e-014acc699dd9_.jpg b/backend/public/uploads/8d419a28-5c3c-44d7-859e-014acc699dd9_.jpg new file mode 100644 index 0000000000000000000000000000000000000000..a68abaa32e5cb9051c9d1f00e8776efb867214be Binary files /dev/null and b/backend/public/uploads/8d419a28-5c3c-44d7-859e-014acc699dd9_.jpg differ diff --git a/backend/public/uploads/8d95b2c8-587c-4a23-9dbf-2f6d2429b309_.jpg b/backend/public/uploads/8d95b2c8-587c-4a23-9dbf-2f6d2429b309_.jpg deleted file mode 100644 index 226c1aea2c2a8c5e933f2716ed83fd90977326e1..0000000000000000000000000000000000000000 Binary files a/backend/public/uploads/8d95b2c8-587c-4a23-9dbf-2f6d2429b309_.jpg and /dev/null differ diff --git a/backend/public/uploads/8f372ec1-4cf9-4a49-8b71-0b325cdb4720_.jpg b/backend/public/uploads/8f372ec1-4cf9-4a49-8b71-0b325cdb4720_.jpg deleted file mode 100644 index dc182c271de9432b5ae12fe43792ede6fcc80828..0000000000000000000000000000000000000000 Binary files a/backend/public/uploads/8f372ec1-4cf9-4a49-8b71-0b325cdb4720_.jpg and /dev/null differ diff --git a/backend/public/uploads/9f36fed7-bc98-4dc4-a1ee-8b477451bc52_.jpg b/backend/public/uploads/9f36fed7-bc98-4dc4-a1ee-8b477451bc52_.jpg deleted file mode 100644 index 226c1aea2c2a8c5e933f2716ed83fd90977326e1..0000000000000000000000000000000000000000 Binary files a/backend/public/uploads/9f36fed7-bc98-4dc4-a1ee-8b477451bc52_.jpg and /dev/null differ diff --git a/backend/public/uploads/a1ffe18f-fb52-40b4-803c-d6f1555f6f7a_.jpg b/backend/public/uploads/a1ffe18f-fb52-40b4-803c-d6f1555f6f7a_.jpg new file mode 100644 index 0000000000000000000000000000000000000000..0d88a71c78d8276cb1a0567f99cc3a0ea4de44a2 Binary files /dev/null and b/backend/public/uploads/a1ffe18f-fb52-40b4-803c-d6f1555f6f7a_.jpg differ diff --git a/backend/public/uploads/b7401caa-04a5-43c9-a348-94668f8218b6_.JPG b/backend/public/uploads/b7401caa-04a5-43c9-a348-94668f8218b6_.JPG deleted file mode 100644 index 8dc59a3747049e7c0169980cd050ca8178da07b0..0000000000000000000000000000000000000000 Binary files a/backend/public/uploads/b7401caa-04a5-43c9-a348-94668f8218b6_.JPG and /dev/null differ diff --git a/backend/public/uploads/bb539d72-f358-4056-a414-d57087a84692_.jpg b/backend/public/uploads/bb539d72-f358-4056-a414-d57087a84692_.jpg deleted file mode 100644 index 226c1aea2c2a8c5e933f2716ed83fd90977326e1..0000000000000000000000000000000000000000 Binary files a/backend/public/uploads/bb539d72-f358-4056-a414-d57087a84692_.jpg and /dev/null differ diff --git a/backend/public/uploads/c504c974-e8dd-4dbd-8441-270a85e608a3_.jpg b/backend/public/uploads/c504c974-e8dd-4dbd-8441-270a85e608a3_.jpg deleted file mode 100644 index 226c1aea2c2a8c5e933f2716ed83fd90977326e1..0000000000000000000000000000000000000000 Binary files a/backend/public/uploads/c504c974-e8dd-4dbd-8441-270a85e608a3_.jpg and /dev/null differ diff --git a/backend/public/uploads/c777c56e-9637-437a-a832-ddca6a72d4d1_.jpg b/backend/public/uploads/c777c56e-9637-437a-a832-ddca6a72d4d1_.jpg deleted file mode 100644 index 226c1aea2c2a8c5e933f2716ed83fd90977326e1..0000000000000000000000000000000000000000 Binary files a/backend/public/uploads/c777c56e-9637-437a-a832-ddca6a72d4d1_.jpg and /dev/null differ diff --git a/backend/public/uploads/d2e9f7c7-6d6a-4973-b989-7838ed629eb7_.jpg b/backend/public/uploads/d2e9f7c7-6d6a-4973-b989-7838ed629eb7_.jpg deleted file mode 100644 index 226c1aea2c2a8c5e933f2716ed83fd90977326e1..0000000000000000000000000000000000000000 Binary files a/backend/public/uploads/d2e9f7c7-6d6a-4973-b989-7838ed629eb7_.jpg and /dev/null differ diff --git a/backend/public/uploads/da0e479d-10b1-45c0-862c-836574b9694f_.PNG b/backend/public/uploads/da0e479d-10b1-45c0-862c-836574b9694f_.PNG deleted file mode 100644 index 3273ce3453d19d1732ded62bda888792aef6fdd6..0000000000000000000000000000000000000000 Binary files a/backend/public/uploads/da0e479d-10b1-45c0-862c-836574b9694f_.PNG and /dev/null differ diff --git a/backend/public/uploads/e0377313-994e-408e-a626-9d7733856418_.jpg b/backend/public/uploads/e0377313-994e-408e-a626-9d7733856418_.jpg deleted file mode 100644 index e2ec0afe10f29f9b718f3d77535b3eaf3e0b70e8..0000000000000000000000000000000000000000 Binary files a/backend/public/uploads/e0377313-994e-408e-a626-9d7733856418_.jpg and /dev/null differ diff --git a/backend/public/uploads/e1a3fbd9-df83-417d-acd5-10c8dcc5c82d_.jpg b/backend/public/uploads/e1a3fbd9-df83-417d-acd5-10c8dcc5c82d_.jpg deleted file mode 100644 index dc182c271de9432b5ae12fe43792ede6fcc80828..0000000000000000000000000000000000000000 Binary files a/backend/public/uploads/e1a3fbd9-df83-417d-acd5-10c8dcc5c82d_.jpg and /dev/null differ diff --git a/backend/public/uploads/ec9da746-239d-47e3-8446-a7ee636c1bc3_.jpg b/backend/public/uploads/ec9da746-239d-47e3-8446-a7ee636c1bc3_.jpg deleted file mode 100644 index 226c1aea2c2a8c5e933f2716ed83fd90977326e1..0000000000000000000000000000000000000000 Binary files a/backend/public/uploads/ec9da746-239d-47e3-8446-a7ee636c1bc3_.jpg and /dev/null differ diff --git a/backend/public/uploads/f941bdfb-caef-47cd-bb2c-52b7fb14e763_.jpg b/backend/public/uploads/f941bdfb-caef-47cd-bb2c-52b7fb14e763_.jpg new file mode 100644 index 0000000000000000000000000000000000000000..d62454433216ead19366d7a5e46c7d8cd8601be4 Binary files /dev/null and b/backend/public/uploads/f941bdfb-caef-47cd-bb2c-52b7fb14e763_.jpg differ diff --git a/backend/public/uploads/fecf4be9-c71c-45e2-bc99-277dfd6ffb80_.jpg b/backend/public/uploads/fecf4be9-c71c-45e2-bc99-277dfd6ffb80_.jpg deleted file mode 100644 index 226c1aea2c2a8c5e933f2716ed83fd90977326e1..0000000000000000000000000000000000000000 Binary files a/backend/public/uploads/fecf4be9-c71c-45e2-bc99-277dfd6ffb80_.jpg and /dev/null differ diff --git a/backend/routes/routes.js b/backend/routes/routes.js index 40c1a44fc6d5636eeaed415283eca30a173e5f7e..a0ae05499768938f7068ae6c61c62eefb968c239 100644 --- a/backend/routes/routes.js +++ b/backend/routes/routes.js @@ -1,5 +1,5 @@ const express = require('express') -const {Router} = require('express') +const { Router } = require('express') const userModel = require('../models/user') const postModel = require('../models/UploadModel') const uploadMiddleware = require('../middlewares/MulterMiddleware') @@ -9,117 +9,156 @@ const asyncHandler = require('express-async-handler') const router = Router() const auth = require('../middlewares/auth') const jwt = require('jsonwebtoken'); +const fs = require('fs') + require('dotenv').config() //Log in -router.post('/login',async (req,res) => { - - const {email, password} = req.body - - const user = await userModel.findOne({email}) - - if(user && (await user.matchPassword(password))){ - res.json({ - _id: user._id, - email:user.email, - username:user.username, - password:user.password, - token: generateToken(user._id) - }) - console.log("Successfully logged in") - - } - else{ - console.log("wrong Credentials") - } +router.post('/login', async (req, res) => { + + const { email, password } = req.body + + const user = await userModel.findOne({ email }) + + if (user && (await user.matchPassword(password))) { + res.json({ + _id: user._id, + email: user.email, + username: user.username, + password: user.password, + token: generateToken(user._id) + }) + console.log("Successfully logged in") + + } + else { + console.log("wrong Credentials") + } }) - +//Register +router.post("/register", uploadMiddleware.single("photo"), asyncHandler(async (req, res) => { + + const email = req.body.email + const username = req.body.username + const password = req.body.password + const photo = req.file.filename + + + const userExists = await userModel.findOne({ email }) + + if (userExists) { + res.status(404) + throw new Error("User Already exists") + } + + const user = new userModel({ email: req.body.email, username: req.body.username, password: req.body.password, photo: photo }) + + if (user) { + res.json({ + _id: user._id, + email: user.email, + username: user.username, + password: user.password, + photo: user.photo + }) + await user.save() + } else { + console.log("error occured!") + } +})) //Create post -router.post("/post", uploadMiddleware.single("photo"), (req,res) => { +router.post("/post", uploadMiddleware.single("photo"), (req, res) => { + + const photo = req.file.filename - const photo = req.file.filename - const post = new postModel({name:req.body.name, recipe: req.body.recipe,description: req.body.description, photo: photo}) - post.save() + + const post = new postModel( + { + name: req.body.name, + recipe: req.body.recipe, + description: req.body.description, + author: req.body.author, + profile_picture: req.body.profilePicture, + profile_name: req.body.profileName, + + photo: photo + }) + post.save() .then(console.log("Saved successfully")) }) - //Get posts -router.get('/posts', async (req,res) => { +router.get('/posts', async (req, res) => { - const posts = await postModel.find() - res.send(posts) + const posts = await postModel.find() + res.send(posts) }) -//Register -router.post("/register", uploadMiddleware.single("photo"),asyncHandler(async (req,res) => { - - const email = req.body.email - const username = req.body.username - const password = req.body.password - const photo = req.file.filename +//get profile posts +router.get('/profilePosts', async (req, res) => { - console.log({email}) +const userId = req.headers.author - const userExists = await userModel.findOne({email}) + postModel.find({ author: userId }) + .populate('author') + .exec() + .then(posts => { + res.json(posts) - if(userExists){ - res.status(404) - throw new Error("User Already exists") - } + }) - const user = new userModel({email:req.body.email, username: req.body.username,password: req.body.password, photo: photo}) - - if(user){ - res.json({ - _id: user._id, - email:user.email, - username:user.username, - password:user.password, - photo: user.photo - }) - await user.save() - }else{ - console.log("error occured!") - } -})) +}) //fetch profile - router.get('/profile', (req, res) => { - // Get the user's token from local storage - const token = req.headers.authorization.split(' ')[1]; - console.log(token) - // Use jwt.verify to decode the token and get the user ID - jwt.verify(token, process.env.JWT_SECRET, (err, decoded) => { - if (err) { - // If the token is invalid, send an error response - return res.status(401).json({ message: 'Invalid token' }); - } - console.log("hey") - const userId = decoded.userId; - console.log(userId) - // If the token is valid, use the user ID to fetch the user data from the database - - - userModel.findById(userId) - .then(user => { - console.log(user) + // Get the user's token from local storage + const token = req.headers.authorization.split(' ')[1]; + // Use jwt.verify to decode the token and get the user ID + jwt.verify(token, process.env.JWT_SECRET, (err, decoded) => { + if (err) { + // If the token is invalid, send an error response + return res.status(401).json({ message: 'Invalid token' }); + } + const userId = decoded.userId; + // If the token is valid, use the user ID to fetch the user data from the database + + + userModel.findById(userId) + .then(user => { res.send(user) }) .catch(err => { console.log(err) }); - }); }); +}); + +router.post('/deletePost', async (req, res) => { + + + const deletedPost = await postModel.findByIdAndDelete(req.body.id) + + if(!deletedPost){ + return res("Post not found") + }else{ + res.json("Post deleted successfully") + fs.unlinkSync(`./public/uploads/${req.body.image}`) + } + + + +}) + + + module.exports = router \ No newline at end of file diff --git a/backend/utils/generateToken.js b/backend/utils/generateToken.js index f1cb867caaae577d93413d789afb0440ba84a84b..127f9e0d83ec3efc828e65272682de8384aba51a 100644 --- a/backend/utils/generateToken.js +++ b/backend/utils/generateToken.js @@ -3,7 +3,7 @@ require('dotenv').config() const generateToken = (id) => { return jwt.sign({userId: id}, process.env.JWT_SECRET,{ - expiresIn: '10s', + expiresIn: '1h', }) } diff --git a/frontend/package-lock.json b/frontend/package-lock.json index 3b3ed1f6ef0fb9b317dfbe9041f064907c12533a..c893b4e3f789495ca56cc83efdff748ff98a994d 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -15,6 +15,7 @@ "@testing-library/react": "^13.4.0", "@testing-library/user-event": "^13.5.0", "axios": "^1.3.4", + "jwt-decode": "^3.1.2", "react": "^18.2.0", "react-dom": "^18.2.0", "react-icons": "^4.8.0", @@ -12139,6 +12140,11 @@ "node": ">=4.0" } }, + "node_modules/jwt-decode": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/jwt-decode/-/jwt-decode-3.1.2.tgz", + "integrity": "sha512-UfpWE/VZn0iP50d8cz9NrZLM9lSWhcJ+0Gt/nm4by88UL+J1SiKN8/5dkjMmbEzwL2CAe+67GsegCbIKtbp75A==" + }, "node_modules/kind-of": { "version": "6.0.3", "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", @@ -26469,6 +26475,11 @@ "object.assign": "^4.1.3" } }, + "jwt-decode": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/jwt-decode/-/jwt-decode-3.1.2.tgz", + "integrity": "sha512-UfpWE/VZn0iP50d8cz9NrZLM9lSWhcJ+0Gt/nm4by88UL+J1SiKN8/5dkjMmbEzwL2CAe+67GsegCbIKtbp75A==" + }, "kind-of": { "version": "6.0.3", "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", diff --git a/frontend/package.json b/frontend/package.json index 96b2bd3f4643213ee47d1cb9193ebfe0fa572612..c2afb67786d82232cfc74eb4dc0fd85161cdece7 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -10,6 +10,7 @@ "@testing-library/react": "^13.4.0", "@testing-library/user-event": "^13.5.0", "axios": "^1.3.4", + "jwt-decode": "^3.1.2", "react": "^18.2.0", "react-dom": "^18.2.0", "react-icons": "^4.8.0", diff --git a/frontend/src/App.js b/frontend/src/App.js index b804a7e7227e91c9601b61e9adb24fd50f53ac0f..73e94d05e3e48412dd87fb83ef8aa58a5b6b0caf 100644 --- a/frontend/src/App.js +++ b/frontend/src/App.js @@ -1,12 +1,11 @@ import Landing from './components/Landing' import Header from './components/Header' - function App() { return ( - <> + <> <Header/> <Landing/> </> diff --git a/frontend/src/api/axios.js b/frontend/src/api/axios.js deleted file mode 100644 index 228ee2c427b189afcf2ba81607bc8d74376ddc5d..0000000000000000000000000000000000000000 --- a/frontend/src/api/axios.js +++ /dev/null @@ -1,6 +0,0 @@ -import axios from 'axios'; - -export default axios.create({ - baseURL: 'http://localhost:3500' -}); - diff --git a/frontend/src/components/Loading.js b/frontend/src/components/Loading.js new file mode 100644 index 0000000000000000000000000000000000000000..42290b2b3d5e87da1e332e1be2af1b5ade6fbdac --- /dev/null +++ b/frontend/src/components/Loading.js @@ -0,0 +1,17 @@ +import React from 'react' +import styles from '../styles/loading.module.css' +const Loading = () => { + return ( + <div className={styles.background}> + <div className={styles.loadingspinner}> + <div id={styles.square1}></div> + <div id={styles.square2}></div> + <div id={styles.square3}></div> + <div id={styles.square4}></div> + <div id={styles.square5}></div> + </div> + </div> + ) +} + +export default Loading \ No newline at end of file diff --git a/frontend/src/components/Post.js b/frontend/src/components/Post.js index 523b7c576414dd2bc802cc0ea7bbad9445452f66..42403105ab6c71549ebef097b57a36d1ffb7f6a0 100644 --- a/frontend/src/components/Post.js +++ b/frontend/src/components/Post.js @@ -1,74 +1,147 @@ import React from 'react' -import { Paper } from '@mui/material' -import { useState } from 'react' +import { useState, useEffect } from 'react' import axios from 'axios' -import {AiOutlineCamera} from 'react-icons/ai' +import { AiOutlineCamera } from 'react-icons/ai' import styles from '../styles/feed.module.css' +import { useNavigate } from 'react-router-dom' +import jwt_decode from 'jwt-decode'; +import { isLoggedIn } from '../functions/Functions' const Post = () => { - - const [name,setName] = useState("") - const [description,setDescription] = useState("") - const [recipe,setRecipe] = useState("") - const [imageData,setImageData] = useState('') - const [picturePreview, setPicturePreview] = useState(null); - - const handlePictureChange = (e) => { - const file = e.target.files[0]; - setImageData(file); - - const reader = new FileReader(); - reader.onload = () => { - setPicturePreview(reader.result); - }; - reader.readAsDataURL(file); - }; - - const createPost = () => { - - const formData = new FormData() - - formData.append('name',name) - formData.append('description',description) - formData.append('recipe',recipe) - formData.append('photo',imageData) - - axios.post("http://localhost:5000/post", - formData - ) - - .then((res) => { - console.log(res.data) - }).catch(err=> console.log(err)) - console.log(imageData) - - } - const paper = { - height: '30vh', - width: '50vw', - + const [name, setName] = useState("") + const [description, setDescription] = useState("") + const [ingredient, setIngredient] = useState("") + const [imageData, setImageData] = useState("") + const [picturePreview, setPicturePreview] = useState(null); + const [recipe, setRecipe] = useState([]) + const [isLoggedIn, setIsLoggedIn] = useState(false); + const navigate = useNavigate(); + const [profileData, setProfileData] = useState() + + + const checkLoggedIn = async () => { + + const token = localStorage.getItem('token'); + if (!token) { + setIsLoggedIn(false); + navigate('/login'); + return; + } + const response = await axios.get('http://localhost:5000/profile', { + headers: { Authorization: `Bearer ${token}` }, + }).then((res) => { + setIsLoggedIn(true); + }).catch(err => { + localStorage.removeItem("token") + setIsLoggedIn(false) + navigate('/login') + }) + } + + const get_profile = () => { + + + + const token = localStorage.getItem('token'); + + axios.get('http://localhost:5000/profile', { + headers: { + Authorization: `Bearer ${token}` } - return ( + }) + .then(res => { + setProfileData(res.data) + }) + + console.log(profileData) + + } + + useEffect(() => { + checkLoggedIn() + get_profile() + + + }, []) + + const add_ingredient = () => { + + setRecipe([...recipe, ingredient]) + + + + } + + const handlePictureChange = (e) => { + const file = e.target.files[0]; + setImageData(file); + + const reader = new FileReader(); + reader.onload = () => { + setPicturePreview(reader.result); + }; + reader.readAsDataURL(file); + }; + + const createPost = () => { + + const formData = new FormData() + const token = localStorage.getItem('token'); + const decodedToken = jwt_decode(token); + const author = decodedToken.userId; + const profilePicture = profileData.photo + const profileName = profileData.username + console.log(profilePicture) + console.log(profileName) + + + formData.append('name', name) + formData.append('recipe', recipe) + formData.append('description', description) + formData.append('author', author) + formData.append('profilePicture', profilePicture) + formData.append('profileName', profileName) + formData.append('photo', imageData) + + + + + axios.post("http://localhost:5000/post", formData) + .then((res) => { + console.log(res.data) + }).catch(err => console.log(err)) + + + } + + + return ( <div className={styles.post_container}> <h1>Make your drink!</h1> - <input className={styles.post_input1} value={name} onChange={(e) => setName(e.target.value)} placeholder='Title of your drink' type='text'/> + <input className={styles.post_input1} onChange={(e) => setName(e.target.value)} placeholder='Title of your drink' type='text' /> - <textarea className={styles.post_input2} value={recipe} onChange={(e) => setRecipe(e.target.value)} placeholder='Recipe' type='text'/> - <textarea className={styles.post_input2} value={description} onChange={(e) => setDescription(e.target.value)} placeholder='How to make it...' type='text' cols = '40' rows="5"/> + <textarea className={styles.post_input2} onChange={(e) => setIngredient(e.target.value)} placeholder='Ingredient' type='text' /> + <button className={styles.button} onClick={add_ingredient}>add ingredient</button> + <div className={styles.tag_container}> + <ul>{recipe.map((item, index) => ( + <li key={index} >{item}</li> + ))}</ul> + </div> + <textarea className={styles.post_input2} value={description} onChange={(e) => setDescription(e.target.value)} placeholder='How to make it...' type='text' cols='40' rows="5" /> - <div className={styles.addpicture}> + <div className={styles.addpicture}> <p >Add a picture here 👉👉:</p> <label className={styles.pick_file} htmlFor={styles.file_picker}> - <AiOutlineCamera/> - <input hidden type="file" name={styles.file_picker} id={styles.file_picker} onChange={handlePictureChange}/> - {picturePreview && <img src={picturePreview} className={styles.preview_img_container} />} + <AiOutlineCamera /> + <input hidden type="file" name={styles.file_picker} id={styles.file_picker} onChange={handlePictureChange} /> + {picturePreview && <img src={picturePreview} className={styles.preview_img_container} />} </label> - </div> - <button onClick={createPost}>Upload</button> + </div> + <button onClick={createPost}>Upload</button> + + - - </div> ) } diff --git a/frontend/src/components/Posts.js b/frontend/src/components/Posts.js index 767367a2146fd613eec5ad7f9b8a312f3da8472e..c633a151ae3de6466d1ebfb261c6d3c56b49d2c9 100644 --- a/frontend/src/components/Posts.js +++ b/frontend/src/components/Posts.js @@ -1,80 +1,78 @@ -import React,{ useState, useEffect } from 'react' +import React, { useState, useEffect } from 'react' import styles from '../styles/feed.module.css' -import{FaSearch } from "react-icons/fa"; +import { FaSearch } from "react-icons/fa"; import axios from 'axios' import Upvote from './Upvote' -import DeletePostButton from './DeletePost' - +import Loading from './Loading' const Posts = () => { - const [posts,setPosts] = useState([]) + const [posts, setPosts] = useState([]) const [searchFilter, setSearchFilter] = useState([]); - const [result, setResult] = useState(""); - const [loading,setLoading] = useState(false) - const [drinks,setDrinks] = useState([]) + const [loading, setLoading] = useState(false) + const [drinks, setDrinks] = useState([]) const loadPosts = () => { axios.get("http://localhost:5000/posts") - .then((res) => { - console.log(res.data) - setPosts(res.data) - setSearchFilter(res.data); - }) + .then((res) => { + console.log(res.data) + setPosts(res.data) + setSearchFilter(res.data); + }) } - useEffect(() => { - - loadPosts() - - - },[]) + useEffect(() => { + + loadPosts() - useEffect(() =>{ - const results = searchFilter.filter(resp => - resp.name.toLowerCase().includes(result) - ); - setPosts(results) - },[result]) + }, []) - const handleChange = (e) => { - setResult(e.target.value); - } - - const handlePostDeleted = (postId) => { - setPosts(posts.filter(post => post._id !== postId)); - - }; - return ( + if (loading) { + return ( + <div> + <Loading/> + </div> + ) +} else + console.log(posts) +return ( <div> - <input className = {styles.searchbar} - value = {result} - type = "text" - placeholder = "Filter your drinks by name..." - - onChange ={handleChange}/> + <input className={styles.searchbar} + type="text" + placeholder="Filter your drinks by name..." + /> - <div>{posts.map((post) => { - return( - <div className={styles.posts_container} key={post._id}> + <div>{posts.map((post) => { + return ( + <div className={styles.posts_container} key={post._id}> <div className={styles.post_img_container}> - <img className={styles.img} src={`http://localhost:5000/uploads/${post.photo}`}/> + <img className={styles.img} src={`http://localhost:5000/uploads/${post.photo}`} /> </div> <div> - <h1>{post.name}</h1> - <div className = {styles.recipe}>Recipe: <li> {post.recipe}</li> </div> - - <div className = {styles.description}>Description: <p>{post.description}</p> </div> - + <h1>{post.name}</h1> + <div > + <h3>Recipe:</h3> + <div className={styles.tag_container}> + <ul> + {post.recipe[0].split(',').map((ingredient, index) => ( + <li key={index}> + {ingredient} + </li> + ))} + </ul> + </div> + </div> + + <div className={styles.description}>Description: <p>{post.description}</p> </div> + </div> - <Upvote/> - <DeletePostButton postId={post._id} onDeleted={() => handlePostDeleted(post._id)}/> + <Upvote /> </div> ) })}</div> - </div> + </div> ) } diff --git a/frontend/src/components/ProfilePosts.js b/frontend/src/components/ProfilePosts.js new file mode 100644 index 0000000000000000000000000000000000000000..c28c006d0e3da98bec3cc55ff36683358472ed13 --- /dev/null +++ b/frontend/src/components/ProfilePosts.js @@ -0,0 +1,98 @@ +import React, { useState, useEffect } from 'react' +import styles from '../styles/feed.module.css' +import { FaSearch } from "react-icons/fa"; +import axios from 'axios' +import Upvote from './Upvote' +import jwt_decode from 'jwt-decode'; +import Loading from './Loading'; + + + + + +const ProfilePosts = () => { + + + const [posts, setPosts] = useState(null) + const [searchFilter, setSearchFilter] = useState([]); + const [result, setResult] = useState(""); + const [loading, setLoading] = useState(true) + + const loadPosts = async () => { + + const token = localStorage.getItem('token'); + const decodedToken = jwt_decode(token); + + const author = decodedToken.userId; + + console.log(decodedToken.userId) + + await axios.get('http://localhost:5000/profilePosts', { headers: { author: `${author}` } }, + ) + .then((res) => { + setPosts(res.data); + + }).catch(err => console.log(err)) + + setLoading(false) + } + + const deletePost = async (image, id) => { + + console.log(image, id) + await axios.post('http://localhost:5000/deletePost', { + id: id, image: image + } + ).then((res) => { + console.log(res) + alert("sucessfully deleted") + }).catch(err => console.log(err)) + } + + useEffect(() => { + setLoading(true) + loadPosts() + }, []) + + if (loading) { + return ( + <div> + <Loading/> + </div> + ) + } else + return ( + <div className={styles.container}> + <div>{posts.map((post) => { + return ( + <div className={styles.posts_container} key={post._id}> + <div className={styles.post_img_container}> + <img className={styles.img} src={`http://localhost:5000/uploads/${post.photo}`} /> + </div> + <div> + <h1>{post.name}</h1> + <div > + <h3>Recipe:</h3> + <div className={styles.tag_container}> + <ul> + {post.recipe[0].split(',').map((ingredient, index) => ( + <li key={index}> + {ingredient} + </li> + ))} + </ul> + </div> + </div> + + <div className={styles.description}>Description: <p>{post.description}</p> </div> + <button className={styles.delete} onClick={() => deletePost(post.photo, post._id)}>delete</button> + </div> + <Upvote /> + </div> + ) + })}</div> + </div> + ) +} + +export default ProfilePosts \ No newline at end of file diff --git a/frontend/src/components/context/AuthProvider.js b/frontend/src/components/context/AuthProvider.js deleted file mode 100644 index 5442c04e91852fb180d453037f030477bd3edfb1..0000000000000000000000000000000000000000 --- a/frontend/src/components/context/AuthProvider.js +++ /dev/null @@ -1,14 +0,0 @@ -import {createContext, useState} from 'react'; - -const AuthContext = createContext({}); - -export const AuthProvider = ({children}) => { - const [auth, setAuth] = useState({}); - return ( - <AuthContext.Provider value ={{auth, setAuth}}> - {children} - </AuthContext.Provider> - ) -} - -export default AuthContext; \ No newline at end of file diff --git a/frontend/src/functions/Functions.js b/frontend/src/functions/Functions.js new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/frontend/src/index.css b/frontend/src/index.css index 08a0f535f7bee181f870a436ff14a965a27a9b0c..b678ce193c4c52edb2c9de612d799fc2be55df0c 100644 --- a/frontend/src/index.css +++ b/frontend/src/index.css @@ -1,12 +1,14 @@ @import url('https://fonts.googleapis.com/css2?family=Poppins:wght@300;400;700;900&display=swap'); @import url('https://fonts.googleapis.com/css2?family=Inter:wght@900&display=swap'); +@import url('https://fonts.googleapis.com/css2?family=Questrial&display=swap'); +@import url('https://fonts.googleapis.com/css2?family=Outfit:wght@300;600;900&display=swap'); + body { margin: 0; - font-family: 'Poppins', sans-serif; box-sizing: border-box; background: rgb(49, 117, 121); color: white; - + font-family: 'Outfit', sans-serif; } .img{ margin-top: 10px; @@ -22,10 +24,14 @@ h1{ font-weight: bold; } p{ - font-family: 'Poppins', sans-serif; + font-family: 'Outfit', sans-serif; } h2{ - font-family: 'Poppins', sans-serif; + font-family: 'Outfit', sans-serif; +} +h3{ + font-family: 'Outfit', sans-serif; + } code { diff --git a/frontend/src/pages/Feed.js b/frontend/src/pages/Feed.js index 9e8722deb02672f9912bd20f01b418da7df9830b..391454333bfaa66df94901383f6780ad7ffe4b3b 100644 --- a/frontend/src/pages/Feed.js +++ b/frontend/src/pages/Feed.js @@ -15,7 +15,7 @@ return( <div> <Post/> <div className = {styles.container} > - <Posts/> + <Posts/> </div> </div> diff --git a/frontend/src/pages/Profile.js b/frontend/src/pages/Profile.js index 123af3c49f4ad838afcb44604957692afc21e974..9f29e9335a9f41acc41c57c4b88b1ce7aebe767d 100644 --- a/frontend/src/pages/Profile.js +++ b/frontend/src/pages/Profile.js @@ -1,10 +1,12 @@ import React from 'react' import { useEffect, useState } from 'react'; import axios from 'axios'; -import { useNavigate } from 'react-router-dom'; +import { useNavigate, Link } from 'react-router-dom'; import styles from '../styles/profile.module.css' import Post from '../components/Post' -import Posts from '../components/Posts' +import ProfilePosts from '../components/ProfilePosts' +import Loading from '../components/Loading'; + const Profile = () => { const [profileData, setProfileData] = useState() @@ -17,8 +19,7 @@ const Profile = () => { const token = localStorage.getItem('token'); if (!token) { - setIsLoggedIn(false); - navigate('/login'); + logout() return; } const response = await axios.get('http://localhost:5000/profile', { @@ -27,8 +28,7 @@ const Profile = () => { setIsLoggedIn(true); }).catch(err => { localStorage.removeItem("token") - setIsLoggedIn(false) - navigate('/login') + logout() }) } @@ -45,26 +45,31 @@ const Profile = () => { } }).then((res) => { setProfileData(res.data); - console.log(profileData) + }).catch(err => console.log(err)) setLoading(false) + } - + const logout = () => { + localStorage.removeItem("token") + setIsLoggedIn(false) + navigate('/') } useEffect(() => { checkLoggedIn() fetchProfile() - }, []) if (!profileData) { return ( - <div>Loading...</div> + <Loading/> ) } else if (profileData) { + console.log(profileData) + return ( <> <div className={styles.header}> @@ -72,30 +77,37 @@ const Profile = () => { <h3>Redirect through these links ðŸ‘</h3> <div className={styles.text_container}> - <h3>Discover</h3> + <Link to='/feed'> + <div className={styles.button}>discover</div> + </Link> + + <h3>|</h3> - <h3>Settings</h3> + <Link to='/'> + <div className={styles.button}>home</div> + </Link> <h3>|</h3> - <h3>Log out</h3> + + <div className={styles.button} onClick={logout}>log out</div> + </div> </div> <div className={styles.profile}> <img className={styles.picture} src={`http://localhost:5000/uploads/${profileData.photo}`} /> <h2>{profileData.username}</h2> - <h3>{profileData.email}</h3> + <p>{profileData.email}</p> <div className={styles.text_container}> <h3>Posts: 0</h3> <h3>Upvotes: 0</h3> </div> </div> <div> - <Post/> </div> <div> - <h1>Your Posts: - <Posts/> - </h1> - </div> + + </div> <h1>Your Posts:</h1> + <ProfilePosts /> + </> ) } diff --git a/frontend/src/styles.css b/frontend/src/styles.css deleted file mode 100644 index 9d34497757ae78aa912463f25b5aa5b8982f1fb3..0000000000000000000000000000000000000000 --- a/frontend/src/styles.css +++ /dev/null @@ -1,81 +0,0 @@ - -.Header{ - width: 100vw; - height: 100vh; - display: flex; - justify-content: center; - align-items: center; - background-color: rgb(49, 117, 121); - color: rgb(255, 255, 255); - flex-wrap: wrap; /* Add flex-wrap property to allow text to wrap */ -} -.Header p{ - margin: 0; - width: 90%; - font-size: 110%; -} -.Header h1{ - margin: 0; - color: rgb(255, 240, 153); - font-size: 350%; -} - - -.image-container { - width: 500px; /* set width of image container */ - height: 500px; /* set height of image container */ - border-radius: 50%; /* make image container circular */ - overflow: hidden; - display: flex; /* Add display flex to center image vertically */ - align-items: center; /* Center image vertically */ - justify-content: center; /* Center image horizontally */ - margin: 2px; - } - -.image-container img { -height: 100%; -width: 100%; -object-fit: cover; - - -} -.text-container{ - display: flex; - flex-direction: column; - justify-content: center; - text-align: left; - width: 40%; - -} - -.Header2{ - width: 100vw; - height: 60vh; - display: flex; - justify-content: center; - align-items: center; - background-color: rgb(49, 117, 121); - flex-wrap: wrap; /* Add flex-wrap property to allow text to wrap */ -} -.card { - flex: 1; - margin: 0 45px; - max-width: 400px; - aspect-ratio: 1/1; /* Set aspect ratio to 1:1 */ - background: rgb(94, 138, 141); - border-radius: 10px; - box-shadow: 0 8px 13px 0 rgba(41, 41, 43, 0.548); - text-align: center; - color: rgb(253, 235, 133); - } - .list{ - list-style: none; - padding: 0; - margin: 0; - color: rgb(255, 255, 255); - } - .item{ - margin-top: 30px; - margin-bottom: 15px; - - } \ No newline at end of file diff --git a/frontend/src/styles/feed.module.css b/frontend/src/styles/feed.module.css index 8b752fbf1bfc197988980cdc2acb0bf34320ec94..feff1b54a7bc0190f0d565ac4792326f966a34b5 100644 --- a/frontend/src/styles/feed.module.css +++ b/frontend/src/styles/feed.module.css @@ -1,7 +1,9 @@ + input{ - font-family: 'Poppins', sans-serif; text-align: start; margin-left:10px; + font-family: 'Outfit', sans-serif; + } :focus::placeholder { @@ -10,10 +12,11 @@ input{ textarea{ - font-family: 'Poppins', sans-serif; text-align: start; margin-left:10px; resize: none; + font-family: 'Outfit', sans-serif; + } .pick_file { color: rgb(67, 1, 128); @@ -47,9 +50,9 @@ margin: 10px; } .image_container { - width: 500px; /* set width of image container */ - height: 500px; /* set height of image container */ - border-radius: 50%; /* make image container circular */ + width: 300px; /* set width of image container */ + height: 300px; /* set height of image container */ + border-radius: 20px; /* make image container circular */ overflow: hidden; display: flex; /* Add display flex to center image vertically */ align-items: center; /* Center image vertically */ @@ -136,43 +139,32 @@ object-fit: cover; .post_container button{ background: rgb(150, 172, 110); color: white; - font-weight: bold; font-size: 18px; border: none; - width: 200px; - height: 80px; - margin-left: 35%; + min-width: 100px; + height: 50px; + margin-left: 50px; margin-bottom: 25px; - - font-family: 'Poppins', sans-serif; + font-family: 'Outfit', sans-serif; border-radius: 5px; } - .deletePost{ - height: 40px; - width:80px; - position: relative; - margin-top: 25px; - margin-left:145px; - margin-bottom: 20px; - - } - - .deletePost button{ - background: rgb(136, 14, 14); - height: 40px; - width:100px; - margin: auto; - border-radius: 5px; - border: none; - font-size: 14px; - font-family: 'Poppins', sans-serif; - color: white; + .delete{ + background: rgb(177, 79, 61); + color: white; + font-size: 18px; + border: none; + min-width: 100px; + height: 50px; + margin-left: 50px; + margin-bottom: 25px; + font-family: 'Outfit', sans-serif; + border-radius: 5px; + } - .upvote{ background-color: rgb(25, 100, 100); @@ -213,7 +205,7 @@ object-fit: cover; .preview_img_container{ width: 60px; /* set width of image container */ height: 60px; - border-radius: 40%; /* make image container circular */ + border-radius: 50%; /* make image container circular */ overflow: hidden; /* Add display flex to center image vertically */ align-items: center; /* Center image vertically */ @@ -222,20 +214,20 @@ object-fit: cover; } .post_img_container{ width: 300px; /* set width of image container */ - height: 300px; /* set height of image container */ - border-radius: 50%; /* make image container circular */ + height: 35vh; /* set height of image container */ + border-top-left-radius: 10px; + border-bottom-left-radius: 10px; + overflow: hidden; display: flex; /* Add display flex to center image vertically */ align-items: center; /* Center image vertically */ justify-content: center; /* Center image horizontally */ - margin-left: 5%; margin-right: 10%; - margin-top:5%; - margin-bottom:5%; + } .post_img_container img{ - height: 100%; + height: 100%; width: 100%; object-fit: cover; } @@ -252,5 +244,23 @@ object-fit: cover; ::placeholder { color:aliceblue; text-align: start; - + } + + .tag_container { + display: flex; + flex-direction: row; + margin: 5px; + } + .tag_container ul { + list-style: none; + margin: 0; + padding: 0; + } + .tag_container li { + background-color: rgb(26, 100, 100); + border-radius: 3px; + padding: 5px; + margin-right: 10px; + margin-bottom: 10px; + display: inline-block; } \ No newline at end of file diff --git a/frontend/src/styles/loading.module.css b/frontend/src/styles/loading.module.css new file mode 100644 index 0000000000000000000000000000000000000000..d623e08f87617833de79c7c46d1a949e12d67416 --- /dev/null +++ b/frontend/src/styles/loading.module.css @@ -0,0 +1,257 @@ +.background{ + width: 100vw; + height: 100vh; + position: fixed; + background-color: rgba(0, 0, 0, 0.342); +} +.loadingspinner { + --square: 26px; + --offset: 30px; + --duration: 2.4s; + --delay: 0.2s; + --timing-function: ease-in-out; + --in-duration: 0.4s; + --in-delay: 0.1s; + --in-timing-function: ease-out; + width: calc(3 * var(--offset) + var(--square)); + height: calc(2 * var(--offset) + var(--square)); + padding: 0px; + margin-left: auto; + margin-right: auto; + margin-top: 10px; + margin-bottom: 30px; + position: fixed; + top: 50%; + left: 50%; + transform: translate(-50%, -50%); +} + +.loadingspinner div { + display: inline-block; + background: rgb(255, 255, 255); + /*background: var(--text-color);*/ + /*box-shadow: 1px 1px 1px rgba(0, 0, 0, 0.4);*/ + border: none; + border-radius: 2px; + width: var(--square); + height: var(--square); + position: absolute; + padding: 0px; + margin: 0px; + font-size: 6pt; + color: black; +} + +.loadingspinner #square1 { + left: calc(0 * var(--offset)); + top: calc(0 * var(--offset)); + animation: square1 var(--duration) var(--delay) var(--timing-function) infinite, + squarefadein var(--in-duration) calc(1 * var(--in-delay)) var(--in-timing-function) both; +} + +.loadingspinner #square2 { + left: calc(0 * var(--offset)); + top: calc(1 * var(--offset)); + animation: square2 var(--duration) var(--delay) var(--timing-function) infinite, + squarefadein var(--in-duration) calc(1 * var(--in-delay)) var(--in-timing-function) both; +} + +.loadingspinner #square3 { + left: calc(1 * var(--offset)); + top: calc(1 * var(--offset)); + animation: square3 var(--duration) var(--delay) var(--timing-function) infinite, + squarefadein var(--in-duration) calc(2 * var(--in-delay)) var(--in-timing-function) both; +} + +.loadingspinner #square4 { + left: calc(2 * var(--offset)); + top: calc(1 * var(--offset)); + animation: square4 var(--duration) var(--delay) var(--timing-function) infinite, + squarefadein var(--in-duration) calc(3 * var(--in-delay)) var(--in-timing-function) both; +} + +.loadingspinner #square5 { + left: calc(3 * var(--offset)); + top: calc(1 * var(--offset)); + animation: square5 var(--duration) var(--delay) var(--timing-function) infinite, + squarefadein var(--in-duration) calc(4 * var(--in-delay)) var(--in-timing-function) both; +} + +@keyframes square1 { + 0% { + left: calc(0 * var(--offset)); + top: calc(0 * var(--offset)); + } + + 8.333% { + left: calc(0 * var(--offset)); + top: calc(1 * var(--offset)); + } + + 100% { + left: calc(0 * var(--offset)); + top: calc(1 * var(--offset)); + } +} + +@keyframes square2 { + 0% { + left: calc(0 * var(--offset)); + top: calc(1 * var(--offset)); + } + + 8.333% { + left: calc(0 * var(--offset)); + top: calc(2 * var(--offset)); + } + + 16.67% { + left: calc(1 * var(--offset)); + top: calc(2 * var(--offset)); + } + + 25.00% { + left: calc(1 * var(--offset)); + top: calc(1 * var(--offset)); + } + + 83.33% { + left: calc(1 * var(--offset)); + top: calc(1 * var(--offset)); + } + + 91.67% { + left: calc(1 * var(--offset)); + top: calc(0 * var(--offset)); + } + + 100% { + left: calc(0 * var(--offset)); + top: calc(0 * var(--offset)); + } +} + +@keyframes square3 { + + 0%, + 100% { + left: calc(1 * var(--offset)); + top: calc(1 * var(--offset)); + } + + 16.67% { + left: calc(1 * var(--offset)); + top: calc(1 * var(--offset)); + } + + 25.00% { + left: calc(1 * var(--offset)); + top: calc(0 * var(--offset)); + } + + 33.33% { + left: calc(2 * var(--offset)); + top: calc(0 * var(--offset)); + } + + 41.67% { + left: calc(2 * var(--offset)); + top: calc(1 * var(--offset)); + } + + 66.67% { + left: calc(2 * var(--offset)); + top: calc(1 * var(--offset)); + } + + 75.00% { + left: calc(2 * var(--offset)); + top: calc(2 * var(--offset)); + } + + 83.33% { + left: calc(1 * var(--offset)); + top: calc(2 * var(--offset)); + } + + 91.67% { + left: calc(1 * var(--offset)); + top: calc(1 * var(--offset)); + } +} + +@keyframes square4 { + 0% { + left: calc(2 * var(--offset)); + top: calc(1 * var(--offset)); + } + + 33.33% { + left: calc(2 * var(--offset)); + top: calc(1 * var(--offset)); + } + + 41.67% { + left: calc(2 * var(--offset)); + top: calc(2 * var(--offset)); + } + + 50.00% { + left: calc(3 * var(--offset)); + top: calc(2 * var(--offset)); + } + + 58.33% { + left: calc(3 * var(--offset)); + top: calc(1 * var(--offset)); + } + + 100% { + left: calc(3 * var(--offset)); + top: calc(1 * var(--offset)); + } +} + +@keyframes square5 { + 0% { + left: calc(3 * var(--offset)); + top: calc(1 * var(--offset)); + } + + 50.00% { + left: calc(3 * var(--offset)); + top: calc(1 * var(--offset)); + } + + 58.33% { + left: calc(3 * var(--offset)); + top: calc(0 * var(--offset)); + } + + 66.67% { + left: calc(2 * var(--offset)); + top: calc(0 * var(--offset)); + } + + 75.00% { + left: calc(2 * var(--offset)); + top: calc(1 * var(--offset)); + } + + 100% { + left: calc(2 * var(--offset)); + top: calc(1 * var(--offset)); + } +} + +@keyframes squarefadein { + 0% { + transform: scale(0.75); + opacity: 0.0; + } + + 100% { + transform: scale(1.0); + opacity: 1.0; + } +} \ No newline at end of file diff --git a/frontend/src/styles/login.module.css b/frontend/src/styles/login.module.css index cf790f401f53ebc9d168546808926441a65532f1..ec39ee5cb4bb669b118f9ccb8720758c4bf9dc14 100644 --- a/frontend/src/styles/login.module.css +++ b/frontend/src/styles/login.module.css @@ -1,7 +1,6 @@ .parent{ display: flex; height: 100vh; - font-family: 'Poppins', sans-serif; } .left{ width: 30%; @@ -17,7 +16,6 @@ font-size: 300%; color: rgb(255, 240, 153); text-align: center; - font-family: 'Inter', sans-serif; } .right{ @@ -63,6 +61,7 @@ .input:hover, .input:focus, .input-group:hover .input { outline: none; border-color: #05060f; + } .input-group:hover .label, .input:focus { @@ -103,8 +102,8 @@ touch-action: manipulation; will-change: transform; margin: 5px; - font-family: 'Poppins', sans-serif; - } + font-family: 'Questrial', sans-serif; +} .button:disabled { pointer-events: none; diff --git a/frontend/src/styles/profile.module.css b/frontend/src/styles/profile.module.css index dddb89da5e45551a8b01bb23289355809e09d216..00305dc1fd3b14b368466a2a0f10c3f1dc164509 100644 --- a/frontend/src/styles/profile.module.css +++ b/frontend/src/styles/profile.module.css @@ -4,8 +4,7 @@ body{ } h1{ color: rgb(255, 240, 153); - font-size: 300%; - font-weight: 900; + } h2{ margin: 0; @@ -15,13 +14,14 @@ h3{ } .picture { - width: 150px; - height: 150px; + width: 250px; + height: 250px; border-radius: 50%; object-fit: cover; display: block; overflow: hidden; margin: 20px auto; + border: 2px solid rgba(211, 188, 113, 0.664); } .profile{ @@ -50,4 +50,44 @@ h3{ justify-content: center; text-align: center; -} \ No newline at end of file +} +.button { + appearance: none; + background-color: rgb(255, 240, 153); + border: 0.125em solid #383838; + border-radius: 0.9375em; + box-sizing: border-box; + color: #383838; + cursor: pointer; + display: inline-block; + font-size: 16px; + font-weight: 600; + line-height: normal; + margin: 0; + min-height: 3.75em; + min-width: 0; + outline: none; + padding: 1em 2.3em; + text-align: center; + transition: all 300ms cubic-bezier(.23, 1, 0.32, 1); + user-select: none; + -webkit-user-select: none; + touch-action: manipulation; + will-change: transform; + margin: 5px; + } + .button:disabled { + pointer-events: none; + } + + .button:hover { + color: #fff; + background-color: #1A1A1A; + box-shadow: rgba(0, 0, 0, 0.25) 0 8px 15px; + transform: translateY(-2px); + } + + .button:active { + box-shadow: none; + transform: translateY(0); + } \ No newline at end of file diff --git a/frontend/src/styles/styles.module.css b/frontend/src/styles/styles.module.css index 0d2a474731aa2230eabdc28b9f62fce0855150e8..e1a7c5369825e433c302870d3970857bca699b0c 100644 --- a/frontend/src/styles/styles.module.css +++ b/frontend/src/styles/styles.module.css @@ -1,16 +1,15 @@ p{ color:white; - + font-family: 'Outfit', sans-serif; + } input{ - font-family: 'Poppins', sans-serif; text-align: start; margin-left:10px; } textarea{ - font-family: 'Poppins', sans-serif; text-align: start; margin-left:10px; } @@ -159,7 +158,6 @@ object-fit: cover; height: 80px; margin-left: 35%; margin-bottom: 25px; - font-family: 'Poppins', sans-serif; border-radius: 5px; @@ -172,7 +170,6 @@ object-fit: cover; box-align: center; font-size: 18px; - font-family: 'Poppins', sans-serif; border-radius: 5px; border: none; color: white;