diff --git a/backend/public/uploads/2520fee2-e0e4-4188-842f-42b725765aef_.jpg b/backend/public/uploads/2520fee2-e0e4-4188-842f-42b725765aef_.jpg new file mode 100644 index 0000000000000000000000000000000000000000..0d88a71c78d8276cb1a0567f99cc3a0ea4de44a2 Binary files /dev/null and b/backend/public/uploads/2520fee2-e0e4-4188-842f-42b725765aef_.jpg differ diff --git a/backend/routes/routes.js b/backend/routes/routes.js index b7e68cc2690d80e90c02af859eca749a0b9b716a..f9882542649654e2f5b729c0defd8e67235956a0 100644 --- a/backend/routes/routes.js +++ b/backend/routes/routes.js @@ -101,13 +101,13 @@ router.get('/posts', async (req, res) => { const loads = req.headers.loads -console.log(loads) + console.log(loads) if (req.headers.search.length == 0) { - const posts = await postModel.find().limit(loads*2).exec() + const posts = await postModel.find().limit(loads * 2).exec() return res.send(posts) - } else if(req.headers.search.length > 0){ + } else if (req.headers.search.length > 0) { const search = req.headers.search; // Get the search query from the request query parameters @@ -118,31 +118,31 @@ console.log(loads) { recipe: { $regex: search, $options: "i" } } // add as many components as needed ], - }).limit(loads*2).exec() - + }).limit(loads * 2).exec() + return res.send(posts) - + } - + }) router.get('/search', async (req, res) => { - - const search = req.headers.search; // Get the search query from the request query parameters - console.log(search) - const posts = await postModel.find({ - $or: [ - { name: { $regex: searchString, $options: "i" } }, - { recipe: { $regex: searchString, $options: "i" } } - // add as many components as needed - ], - }) - - return res.send(posts) - + const search = req.headers.search; // Get the search query from the request query parameters + + console.log(search) + const posts = await postModel.find({ + $or: [ + { name: { $regex: searchString, $options: "i" } }, + { recipe: { $regex: searchString, $options: "i" } } + // add as many components as needed + ], + }) + + return res.send(posts) + }) @@ -222,13 +222,13 @@ router.put('/upvote', async (req, res) => { post.upvotes.splice(index, 1) await post.save() return res.json("upvote deleted") - }else{ - post.upvotes.push(req.body.upvote) - await post.save() - res.send(post) + } else { + post.upvotes.push(req.body.upvote) + await post.save() + res.send(post) } - + }) @@ -255,7 +255,7 @@ router.post("/comment", (req, res) => { }) comment.save() .then(console.log("comment saved successfully")) - res.json(comment) + res.json(comment) }) @@ -269,7 +269,7 @@ router.put('/savecomment', async (req, res) => { if (!post) { return res.json("Not a valid post") - }else{ + } else { const comment = req.body.comment_id @@ -282,18 +282,33 @@ router.put('/savecomment', async (req, res) => { res.send("Success") } }) + + router.get('/getcomments', async (req, res) => { - - const postId = req.headers.author - postModel.find({ author: postId }) - .populate('comments') - .exec() - .then(comments => { - res.json(comments) + const postId = req.headers.postid - }) + const post = await postModel.findById(postId); + + if (!post) { + return res.send("Somethings up bud!"); + } + + const commentIds = post.comments + + console.log(commentIds) + + const comments = [] + + for (const commentId of commentIds) { + const comment = await commentModel.findById(commentId); + if (comment) { + comments.push(comment); + } + } + + res.send(comments) }) diff --git a/frontend/src/components/Posts.js b/frontend/src/components/Posts.js index 16008efa6950594190f2a9afc2baa80713fe2fa7..e398d82c65ebbd2b5b9d3c4eff514961399a14aa 100644 --- a/frontend/src/components/Posts.js +++ b/frontend/src/components/Posts.js @@ -55,7 +55,7 @@ const Posts = () => { get_profile() }, []) - + const handleChange = (e) => { @@ -83,33 +83,38 @@ const Posts = () => { axios.post("http://localhost:5000/comment", { profile_name: profileData.username, profile_picture: profileData.photo, comment: comment }) .then((res) => { - console.log(res.data._id) - - axios.put("http://localhost:5000/savecomment", {post_id: id, comment_id: res.data._id }) - .then((res) => { - console.log(res.data) - - }).catch(err => console.log(err)) + console.log(res.data._id) + + axios.put("http://localhost:5000/savecomment", { post_id: id, comment_id: res.data._id }) + .then((res) => { + console.log(res.data) + + }).catch(err => console.log(err)) }).catch(err => console.log(err)) - + } - const save_comment = (id) => { - + const get_comments = (id) => { + + console.log(id) + setLoading(true) - - console.log(commentData) - /* axios.put("http://localhost:5000/savecomment", {post_id: id, comment_id: comment_id._id }) + axios.get("http://localhost:5000/getcomments", { headers: { postId: id } }) .then((res) => { - console.log(res.data) - - }).catch(err => console.log(err))*/ + setCommentData(res.data) + setShowComments(true) + }) + + + setLoading(false) + } + if (loading) { return ( <div> @@ -117,6 +122,7 @@ const Posts = () => { </div> ) } else + console.log(posts) return ( @@ -156,32 +162,47 @@ const Posts = () => { ))} </ul> - + </div> </div> </div> <div> <div className={styles.description}><h3>Description:</h3>{post.description} </div> </div> - + </div> - + </div> - <div> - <input type='text' className={styles.comment_input} onChange={(e) => setComment(e.target.value)} /> - <button onClick={() => handleComment(post._id)} className={styles.comment_button} >Comment</button> - <div className={styles.comments}> - {showComments ? ( - <div >HELLO - <button onClick={() => setShowComments(false)}>hide comments</button> - </div> - + <div> + <input type='text' className={styles.comment_input} onChange={(e) => setComment(e.target.value)} /> + <button onClick={() => handleComment(post._id)} className={styles.comment_button} >Comment</button> + <div className={styles.comments}> + {showComments ? ( + <div > + <button className={buttons.button3} onClick={() => setShowComments(false)}>hide comments</button> + + {loading ? (<></>) : commentData.map((comment) => { + return( + <> + <div className={styles.comment_header}> + <img className={styles.posts_header_img} src={`http://localhost:5000/uploads/${comment.profile_picture}`} /> + <p>{comment.profile_name}</p> + </div> + <div className={styles.comment}> + <p>{comment.comment}</p> + + </div> + </> + )})} + + </div> + ) : ( - <> <button onClick={() => setShowComments(true)}>show comments</button></> + <> <button className={buttons.button3} onClick={() => get_comments(post._id)}>show comments</button></> )} - </div> - </div> + </div> + </div> </div> ) })}</div> diff --git a/frontend/src/components/ProfilePosts.js b/frontend/src/components/ProfilePosts.js index 3bbdfb629e146aa8d349e5b5279d39d579ce3e9a..862823ae234d73275447161b48c45b9f786546bc 100644 --- a/frontend/src/components/ProfilePosts.js +++ b/frontend/src/components/ProfilePosts.js @@ -65,9 +65,9 @@ const ProfilePosts = () => { return ( <div className={styles.wrapper}> <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> + + <img className={styles.post_img_container2} src={`http://localhost:5000/uploads/${post.photo}`} /> + <div> <h1>{post.name}</h1> <div > diff --git a/frontend/src/pages/Feed.js b/frontend/src/pages/Feed.js index a5c6c0d73254373189a564b2d30db4b7e26d2ca4..974dd143ae604a496c027439a6337ed4b10fc7df 100644 --- a/frontend/src/pages/Feed.js +++ b/frontend/src/pages/Feed.js @@ -74,7 +74,7 @@ const Feed = () => { } if (loading == false) { - + return ( <div className={styles.feed}> diff --git a/frontend/src/pages/Profile.js b/frontend/src/pages/Profile.js index d8a90276793f756df3a055172557b4e5c825006d..182b3a83fbb06e9b8507802ece405b17ffdd63aa 100644 --- a/frontend/src/pages/Profile.js +++ b/frontend/src/pages/Profile.js @@ -8,6 +8,7 @@ import ProfilePosts from '../components/ProfilePosts' import Loading from '../components/Loading'; import { FaArrowLeft } from 'react-icons/fa'; import buttons from '../styles/buttons.module.css' +import jwt_decode from 'jwt-decode'; const Profile = () => { const [profileData, setProfileData] = useState() @@ -15,7 +16,28 @@ const Profile = () => { const [error, setError] = useState(null); const [isLoggedIn, setIsLoggedIn] = useState(false); const navigate = useNavigate(); + const [posts, setPosts] = useState(null) + 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 checkLoggedIn = async () => { const token = localStorage.getItem('token'); @@ -61,12 +83,13 @@ const Profile = () => { useEffect(() => { checkLoggedIn() fetchProfile() + loadPosts() }, []) if (!profileData) { return ( - <Loading/> + <Loading /> ) } else if (profileData) { console.log(profileData) @@ -74,42 +97,52 @@ const Profile = () => { return ( <> <div className={styles.header}> - <div className={buttons.arrow}><Link to='/'><FaArrowLeft /> Home</Link></div> - <h1>Welcome to your profile page</h1> - <p>Redirect through these links</p> + <h1>Profile Page</h1> <div className={styles.text_container}> - <Link style={{ textDecoration:'none'}} to='/feed'> + <Link style={{ textDecoration: 'none' }} to='/feed'> <div className={buttons.button}>discover</div> </Link> - <h3>|</h3> - <Link style={{ textDecoration:'none'}} to='/'> + + <Link style={{ textDecoration: 'none' }} to='/'> <div className={buttons.button}>home</div> </Link> - <h3>|</h3> + <div className={buttons.button} onClick={logout}>log out</div> </div> </div> + <div className={buttons.arrow}><Link to='/'><FaArrowLeft /> Home</Link></div> <div className={styles.profile}> <img className={styles.picture} src={`http://localhost:5000/uploads/${profileData.photo}`} /> + <div className={styles.info_container}> + <div className={styles.info_slot}> + <div> <h1>{posts.length}</h1></div> + <div> <h3>Posts</h3></div> + </div> + <div className={styles.info_slot}> + <div> <h1>0</h1></div> + <div> <h3>Upvotes</h3></div> + </div> + </div> + </div> + <div className={styles.profile2}> <h2>{profileData.username}</h2> <p>{profileData.email}</p> - <div className={styles.text_container}> - <h3>Posts: 0</h3> - <h3>Upvotes: 0</h3> - </div> </div> + + <div> </div> <div> - - </div> <h1>Your Posts:</h1> - <ProfilePosts /> - + + </div> + <div className={styles.your}> <h1>Your posts</h1></div> + <ProfilePosts /> + </> ) } diff --git a/frontend/src/styles/buttons.module.css b/frontend/src/styles/buttons.module.css index ba579e2c1e1f7090e7002e02ae868ab8b6dc7ed4..10b3fd39bf37e2c23de16e4d4095d29857c976cc 100644 --- a/frontend/src/styles/buttons.module.css +++ b/frontend/src/styles/buttons.module.css @@ -1,6 +1,6 @@ .button { font-size: 18px; - color: #000000; + color: #ffffff; font-family: inherit; font-weight: 800; cursor: pointer; @@ -11,12 +11,13 @@ transition-timing-function: cubic-bezier(0.25, 0.8, 0.25, 1); transition-duration: 400ms; transition-property: color; + margin: 20px; } .button:focus, .button:hover { - color: #7f9ec5; + color: #fff597; } .button:focus:after, @@ -33,7 +34,7 @@ position: absolute; width: 0%; height: 2px; - background-color: #7f9ec5; + background-color: #fff597; transition-timing-function: cubic-bezier(0.25, 0.8, 0.25, 1); transition-duration: 400ms; transition-property: width, left; @@ -114,7 +115,8 @@ font-size: 18px; line-height: normal; height: 40px; - width: 100px; + width: 150px; + margin: 5px; outline: none; text-align: center; transition: all 300ms cubic-bezier(.23, 1, 0.32, 1); diff --git a/frontend/src/styles/feed.module.css b/frontend/src/styles/feed.module.css index 172d363b43749eef497c0c58773460553d9c99e3..6a8c7f592f3dac475dfae9ffbab2f5f568fb8c10 100644 --- a/frontend/src/styles/feed.module.css +++ b/frontend/src/styles/feed.module.css @@ -237,6 +237,8 @@ outline: none; border: solid 1px rgba(128, 128, 128, 0.644); border-bottom-left-radius: 5px; border-bottom-right-radius: 5px; + box-sizing: border-box; + padding: 10px; } .delete { @@ -272,7 +274,30 @@ outline: none; font-family: 'Outfit', sans-serif; } +.comment_header{ +height: 60px; +display: flex; +align-items: center; +border: solid 0.5px grey; +width: 90%; +margin: auto; +box-sizing: border-box; +padding: 5px; + + +} +.comment{ +display: flex; +padding: 5px; +box-sizing: border-box; +margin: auto; +width: 90%; +box-shadow: rgba(0, 0, 0, 0.25) 0 8px 15px; +border-bottom-left-radius: 5px; +border-bottom-right-radius: 5px; +background-color: rgba(209, 209, 209, 0.342); +} .posts_container { min-height: 300px; width: 900px; @@ -313,6 +338,13 @@ outline: none; margin-right: 10%; } +.post_img_container2 { + width: 310px; + /* set width of image container */ + height: 310px; + overflow: hidden; + object-fit: cover; +} .post_img_container img { diff --git a/frontend/src/styles/header.module.css b/frontend/src/styles/header.module.css index 41d5435a3cfb0388bdceeb12ab3df83a71309d5c..a62ec19bcfd025f3cdd24a8c0d339d00cbc47f17 100644 --- a/frontend/src/styles/header.module.css +++ b/frontend/src/styles/header.module.css @@ -10,7 +10,7 @@ align-items: center; .button { appearance: none; - background-color: #ffffff; + background-color: #ffffffa1; border: 0.125em solid #000000; border-radius: 5px; box-sizing: border-box; diff --git a/frontend/src/styles/profile.module.css b/frontend/src/styles/profile.module.css index e2a399d0cf5e16ccda0b8b8cd47539990b111f99..8f9cfea9021a6ef7adaa49eb4a11f0897cf3c1e5 100644 --- a/frontend/src/styles/profile.module.css +++ b/frontend/src/styles/profile.module.css @@ -1,59 +1,101 @@ - -h1{ - font-size: 50px; - text-align: center; +h1 { + font-size: 40px; + margin: 0; } -h2{ + +h2 { margin: 0; - + } -h3{ + +h3 { margin: 20px; + } .picture { - width: 250px; - height: 250px; - border-radius: 50%; + width: 300px; + height: 300px; + border-radius: 5px; object-fit: cover; display: block; overflow: hidden; - margin: 20px auto; - border: 1px solid rgb(156, 156, 156); + border: solid 1px rgb(139, 139, 139); + box-shadow: 0 2px 10px 0 rgba(107, 107, 107, 0.774); + +} + +.profile { + width: 100vw; + min-height: 30vh; + margin-top: 100px; + margin-left: 20px; + color: rgb(107, 107, 107); + display: flex; } -.profile{ - background: rgb(255, 255, 255); - backdrop-filter: blur(10px); - -webkit-backdrop-filter: blur(10px); - border-radius: 5px; - border: 1px solid rgb(156, 156, 156); - box-shadow: 0 8px 23px 0 rgba(37, 37, 37, 0.562); - text-align: center; - width: 40vw; - margin: 100px auto; - min-height: 50vh; - +.profile2 { + width: 100vw; + min-height: 10vh; + margin-top: 20px; + margin-left: 20px; + color: rgb(107, 107, 107); + display: flex; + flex-direction: column; + } -.header{ + +.header { max-width: 100vw; - min-height: 10vh; + background: #5cbbd8; + color: white; + height: 10vh; margin: 0; - background-color: rgb(255, 255, 255); box-sizing: border-box; - text-align: center; + display: flex; + align-items: center; + padding: 10px; + box-shadow: 0 2px 10px 0 rgba(107, 107, 107, 0.774); + } -.text_container{ + +.text_container { display: flex; - flex-direction: row; - justify-content: center; - text-align: center; - justify-content: center; - align-items: center; text-decoration: none; + margin-left: auto; + margin-right: 40px; + + + } -.text_container Link{ - text-decoration: none; +.info_container{ + display: flex; + height: 30vh; + +} +.info_slot{ + margin-left: 200px; + width: 500px; + height: 300px; + text-align: center; + display: flex; + flex-direction: column; + justify-content: end; + box-sizing: border-box; + padding: 80px; + border: solid 1px rgb(173, 173, 173); + box-shadow: 0 2px 10px 0 rgba(107, 107, 107, 0.774); + border-radius: 5px; + +} +.your{ + text-align: center; + width: 100vw; + height: 5vh; + margin-top: 100px; + color: rgb(107, 107, 107); + + }