From fcb6148e416a87ee0cd1d4be50254877efa53fbd Mon Sep 17 00:00:00 2001 From: Devesh Shukla Date: Sun, 25 Aug 2024 16:54:10 +0530 Subject: [PATCH] bugs --- backend/src/controller/comment.js | 36 +++++++++ backend/src/controller/posts.js | 40 +++++++++- backend/src/controller/search.js | 2 + backend/src/routes/posts.js | 6 +- frontend/src/components/Codeforces.jsx | 17 ++++ frontend/src/components/Comments.jsx | 66 ++++++++++++++- frontend/src/components/Notification.jsx | 1 + frontend/src/components/Postdetail.jsx | 37 +++++---- frontend/src/components/Posts.jsx | 97 ++++++++++++++++++++++- frontend/src/components/ProfileLayout.jsx | 2 + frontend/src/components/Profilecard.jsx | 12 ++- frontend/src/components/Sidenav.jsx | 3 +- frontend/src/pages/CreateRoom.jsx | 2 +- frontend/src/pages/Home.jsx | 13 --- frontend/src/pages/Overview.jsx | 1 + frontend/src/pages/ProfilePosts.jsx | 2 +- frontend/src/pages/Profileupvoted.jsx | 2 +- frontend/src/pages/Room.jsx | 1 - frontend/src/pages/Settings.jsx | 6 +- frontend/src/redux/Postdetail.js | 11 ++- 20 files changed, 306 insertions(+), 51 deletions(-) create mode 100644 frontend/src/components/Codeforces.jsx diff --git a/backend/src/controller/comment.js b/backend/src/controller/comment.js index 13258d9..23637b6 100644 --- a/backend/src/controller/comment.js +++ b/backend/src/controller/comment.js @@ -96,6 +96,42 @@ export const getAllComment = async (req,res)=>{ }); } } +export const deleteComment = async(req,res)=>{ + const userId = req.userId; + const id = req.body.id; + + try{ + const cmnt = await prisma.comment.findFirst({ + where:{ + id + } + }); + console.log(cmnt.userId); + console.log(userId); + if(cmnt.userId !== userId) + { + return res.status(403).json({ + msg:"You Are Not Authorised" + }) + } + await prisma.comment.delete({ + where:{ + id + } + }); + return res.status(201).json({ + msg:"Success" + }); + } + catch(err) + { + return res.status(500).json({ + msg:"Server Issue", + err + }) + } + +} export const getUserComment = async (req,res)=>{ const { uId } = req.userId; diff --git a/backend/src/controller/posts.js b/backend/src/controller/posts.js index 38fd650..aa9bf23 100644 --- a/backend/src/controller/posts.js +++ b/backend/src/controller/posts.js @@ -2,7 +2,6 @@ import prisma from "../../db/db.config.js"; import zod from "zod"; import uploadOnCloudinary from "../utils/cloudinary.js"; import { stringify } from "bigint-json"; -import fs from "fs"; const post = zod.object({ topic: zod.string().optional(), title: zod.string(), @@ -186,6 +185,43 @@ export const getHotPost = async (req, res) => { } }; +export const deletePost = async(req,res) =>{ + const userId = req.userId; + const id = req.body.id; + console.log(id); + try{ + + const post = await prisma.post.findFirst({ + where:{ + id + } + }) + if(post.userId != userId) + { + return res.status(403).json({ + msg:'Unautorised' + }) + } + console.log(post); + const data = await prisma.post.delete({ + where:{ + id + } + }); + return res.status(201).json({ + msg:"Success", + data + }) + } + catch(err){ + return res.status(500).json({ + msg:"Server Issue", + err + }); + } +} + + export const getPopularPosts = async (req, res) => { const page = parseInt(req.query.page) || 1; const limit = parseInt(req.query.limit) || 10; @@ -227,7 +263,7 @@ export const getPopularPosts = async (req, res) => { LEFT JOIN "User" u ON u."userID" = p."userId" ORDER BY "popularityScore" DESC, p."createdAt" DESC LIMIT ${limit} OFFSET ${offset}; - `; +`; let posts = JSON.parse(stringify(result)); diff --git a/backend/src/controller/search.js b/backend/src/controller/search.js index 6529336..309a548 100644 --- a/backend/src/controller/search.js +++ b/backend/src/controller/search.js @@ -60,6 +60,8 @@ export const getUser = async (req, res) => { createdAt: true, leetcode: true, showLC: true, + showCf:true, + codeforces:true, _count: { select: { posts: true, diff --git a/backend/src/routes/posts.js b/backend/src/routes/posts.js index 033b6b6..d9b009a 100644 --- a/backend/src/routes/posts.js +++ b/backend/src/routes/posts.js @@ -1,8 +1,8 @@ import express from "express" import { verifyToken } from "../middlewares/verifytoken.js"; -import { createPost, getPost,getAPost,getHotPost, getPopularPosts } from "../controller/posts.js"; +import { createPost, getPost,getAPost,getHotPost, getPopularPosts, deletePost } from "../controller/posts.js"; import { upload } from "../middlewares/multer.js"; -import { createComment, getAllComment, getUserComment } from "../controller/comment.js"; +import { createComment, deleteComment, getAllComment, getUserComment } from "../controller/comment.js"; import { upvoteNumber, vote } from "../controller/upvotes.js"; const postRoutes = express.Router(); @@ -21,6 +21,7 @@ postRoutes.get("/getPost",getPost); postRoutes.get("/getaPost",getAPost); postRoutes.post("/postWithImg",verifyToken,upload.single('postImg'),createPost); postRoutes.post("/post",verifyToken,createPost); +postRoutes.delete("/delete",verifyToken,deletePost); //hotTopicsPost postRoutes.get("/q/hottopic", getHotPost); @@ -31,6 +32,7 @@ postRoutes.get('/popular',getPopularPosts); postRoutes.post('/createcomment',verifyToken,createComment); postRoutes.post('/getallcomment',getAllComment); postRoutes.get('/comment',getUserComment); +postRoutes.delete('/deleteComment',verifyToken,deleteComment); //create getComment according to postID diff --git a/frontend/src/components/Codeforces.jsx b/frontend/src/components/Codeforces.jsx new file mode 100644 index 0000000..dd8623d --- /dev/null +++ b/frontend/src/components/Codeforces.jsx @@ -0,0 +1,17 @@ +export default function Codeforces({ rating }){ + const getItem = { + "newbie":

newbie

, + "pupil":

pupil

, + "specialist":

specialist

, + "expert":

expert

, + "candidate master":

Candidate master

, + "master":

master

, + "international master":

International master

, + "grandmaster":

Grandmaster

, + "international grandmaster":

International Grandmaster

, + "legendary grandmaster":

legendary Grandmaster

+ + } + + return getItem[rating]; +} \ No newline at end of file diff --git a/frontend/src/components/Comments.jsx b/frontend/src/components/Comments.jsx index e8817f0..b5af066 100644 --- a/frontend/src/components/Comments.jsx +++ b/frontend/src/components/Comments.jsx @@ -1,12 +1,12 @@ import axios from 'axios'; -import React, { useEffect, useState } from 'react' +import React, { useEffect, useRef, useState } from 'react' import { useDispatch, useSelector } from 'react-redux'; import toast from 'react-hot-toast'; import SmallLoader from './SmallLoader'; -import { setComment } from '../redux/Postdetail'; +import { clearPostDetail, delComment, setComment } from '../redux/Postdetail'; import { setUserPostComment } from '../redux/userposts'; -import { setPostComment } from '../redux/Post'; +import { clearPostsInfo, setPostComment } from '../redux/Post'; import { BiDownvote, BiUpvote } from 'react-icons/bi'; import { GoComment } from 'react-icons/go'; import { RiShareForwardLine } from 'react-icons/ri'; @@ -29,6 +29,9 @@ import { getTime } from './Posts'; import ReadMore from './ReadMore'; import baseAddress from '../utils/localhost'; import { useNavigate } from 'react-router-dom'; +import { BsThreeDotsVertical } from 'react-icons/bs'; +import SmoothLoader from '../assets/SmoothLoader'; +import { MdDelete } from 'react-icons/md'; @@ -137,9 +140,44 @@ export function CommentBody2({ id, dp, body, user, createdAt, getTime, getChildr const [showChild, setShowChild] = useState(false); const childs = getChildren(id) == undefined ? [] : getChildren(id); const userInfo = useSelector(state => state.user.userInfo); + const isLogin = useSelector(state => state.login.value); const Navigate= useNavigate(); + const [isOpen,setOpen] = useState(false); + const [delLoading,setLoading] = useState(false); + const dropdownRef = useRef(null); + const dispatch = useDispatch(); + const handleToggle = ()=>{ + setOpen((v)=>!v) + } + const handleClickOutside = (event) => { + if (dropdownRef.current && !dropdownRef.current.contains(event.target)) { + setOpen(false); + } - + }; + useEffect(() => { + document.addEventListener('mousedown', handleClickOutside); + return () => { + document.removeEventListener('mousedown', handleClickOutside); + }; + }, []); + async function deleteComment(id){ + setLoading(true); + // console.log(userInfo?.userID); + try { + const res = await axios.delete(`${baseAddress}posts/deleteComment`,{ + data:{ + id + } + }) + dispatch(delComment(id)); + toast.success(res?.data.msg); + } catch (error) { + toast.error(error.response?.data.msg); + console.log(error); + } + setLoading(false); + } function handleComment(id) { setOpenBox((openBox) => !openBox); @@ -258,6 +296,26 @@ export function CommentBody2({ id, dp, body, user, createdAt, getTime, getChildr {/* */}

{getTime(createdAt)} ago

+ {isLogin&& +
+ + + {isOpen && ( +
+
    +
  • + +
  • +
+ +
+ )} +
+ + }
diff --git a/frontend/src/components/Notification.jsx b/frontend/src/components/Notification.jsx index b3768c9..dbed5db 100644 --- a/frontend/src/components/Notification.jsx +++ b/frontend/src/components/Notification.jsx @@ -32,6 +32,7 @@ const Notification = ({setIsNfnOpen}) => { } const getUserNotification = async()=>{ + try { const res = await axios.get(baseAddress+"u/notification", { withCredentials: true }); dispatch(setNotification(res.data.data)) diff --git a/frontend/src/components/Postdetail.jsx b/frontend/src/components/Postdetail.jsx index f5fc839..1c5cdce 100644 --- a/frontend/src/components/Postdetail.jsx +++ b/frontend/src/components/Postdetail.jsx @@ -13,6 +13,7 @@ import Postskelton from './Postskelton'; import { setUserPostComment } from '../redux/userposts'; import { CommentBody, CommentBody2, CommentBox } from './Comments'; import baseAddress from '../utils/localhost'; +import ForbiddenPage from '../pages/ForbiddenPage'; @@ -30,17 +31,21 @@ const Postdetail = ({ myRooms }) => { const location = useLocation(); const {id}= useParams(); const {roomid} = useParams(); - + const [room,setRoom] = useState({}); + const [displayPost,setDisp] = useState(true); + const [loading,setLoading] = useState(false); const getApost=async()=>{ - if(myRooms){ + if(roomid){ let found = false; - // console.log(myRooms); - // console.log(roomid); myRooms.map((room)=>{ - if(room.room.id === roomid)found = true; + if(room.room.id === roomid) + { + found = true; + setRoom(room.room); + } }); if(!found){ - toast.error("Unauthorised"); + setDisp(false); return; } } @@ -60,9 +65,11 @@ const Postdetail = ({ myRooms }) => { } useEffect(() => { + setLoading(true) dispatch(clearPostDetail()) - getApost() - },[]) + getApost() + setLoading(false); + },[isLogin]) @@ -96,11 +103,11 @@ const Postdetail = ({ myRooms }) => { function getChildren(id){ return groupComments[id] } - // console.log("Groupd Comments = "+JSON.stringify(groupComments)); - return (<> + if(!displayPost && !loading)return + else return (<>
- {post?:} - + {post?:} +
{isLogin? @@ -111,9 +118,9 @@ const Postdetail = ({ myRooms }) => {
Comments:
- {/* {console.log(post?.comments)}; */} - - {/* */} + + +
diff --git a/frontend/src/components/Posts.jsx b/frontend/src/components/Posts.jsx index b2bfaf3..4025244 100644 --- a/frontend/src/components/Posts.jsx +++ b/frontend/src/components/Posts.jsx @@ -11,7 +11,10 @@ import ReadMore, { linkDecorator } from './ReadMore'; import { clearPostsInfo } from '../redux/Post'; import baseAddress from '../utils/localhost'; import Linkify from 'react-linkify'; - +import { BsThreeDotsVertical } from "react-icons/bs"; +import { MdDelete } from 'react-icons/md'; +import SmoothLoader from '../assets/SmoothLoader'; +import { clearHotPostsInfo } from '../redux/Hotposts'; const Posts = ({ id, post, title,topic, body, media, countComment, inRoom, room, createdAt, user, upvotes,joined,postDetails }) => { @@ -25,7 +28,44 @@ const Posts = ({ id, post, title,topic, body, media, countComment, inRoom, room, const [upvoted, setUpvoted] = useState(false); const [downvoteNum, setDownvotenum] = useState(0); const [downvote, setDownVote] = useState(false); + const [isOpen,setOpen] = useState(false); + const [delLoading,setLoading] = useState(false); + const dropdownRef = useRef(null); + const handleToggle = ()=>{ + setOpen((v)=>!v) + } + const handleClickOutside = (event) => { + if (dropdownRef.current && !dropdownRef.current.contains(event.target)) { + setOpen(false); + } + }; + async function deletePost(id){ + // console.log(id); + setLoading(true); + try{ + const res = await axios.delete(`${baseAddress}posts/delete`,{ + data:{ + id + } + }); + toast.success(res.data.msg); + dispatch(clearPostsInfo()); + dispatch(clearHotPostsInfo()); + // console.log(res); + } + catch(err){ + console.log(err); + toast.error(err.response.data.msg); + } + setLoading(false); + } + useEffect(() => { + document.addEventListener('mousedown', handleClickOutside); + return () => { + document.removeEventListener('mousedown', handleClickOutside); + }; + }, []); useEffect(() => { const getUpvote = async () => { const upvoteArr = await upvotes?.filter(vote => (vote.upvotes == 1 && vote.commentId == null)); @@ -144,8 +184,39 @@ const Posts = ({ id, post, title,topic, body, media, countComment, inRoom, room, } }; + const shareFunction = async(id,room)=>{ + console.log("Clicked Share Button") + if(inRoom) + { + if(!joined){ + toast.error("First Join The Room"); + return; + } + console.log(room); + console.log("Clicked Share Button inside room"); + } + if (navigator.share) { + + try { + await navigator.share({ + title: title, + text: `Check out ${user?.username}'s latest post on our site!`, + url: inRoom?`${window.location.origin}/post/${room?.id}/${id}`:`${window.location.origin}/post/${id}`, + }); + } catch (error) { + console.error('Error in post sharing', error); + } + } else { + navigator.clipboard.writeText(inRoom?`${window.location.origin}/post/${room?.id}/${id}`:`${window.location.origin}/post/${id}`) + .then(() => { + alert('Post link copied to clipboard'); + }) + .catch((error) => { + console.error('Error in Post copying link to clipboard', error); + }); + } - + } return ( <> @@ -157,6 +228,24 @@ const Posts = ({ id, post, title,topic, body, media, countComment, inRoom, room, || (topic && <> Navigate(`/q/${topic}`)} className=' cursor-pointer hover:text-rose-900 text-sm font-semibold'>q/{topic} )}{`${getTime(createdAt)} ago`}
+ { user?.username===userInfo?.username? +
+ + + {isOpen && ( +
+
    +
  • + +
  • +
+ +
+ )} +
:<>}
{title}
@@ -181,10 +270,12 @@ const Posts = ({ id, post, title,topic, body, media, countComment, inRoom, room, {countComment ? countComment : 0} + {!room?.privateRoom?
- + shareFunction(id,room)} className='text-2xl' /> Share
+ :<>} diff --git a/frontend/src/components/ProfileLayout.jsx b/frontend/src/components/ProfileLayout.jsx index fa2affe..2685d46 100644 --- a/frontend/src/components/ProfileLayout.jsx +++ b/frontend/src/components/ProfileLayout.jsx @@ -13,6 +13,7 @@ import { ProfileSkelton } from './Postskelton'; import baseAddress from '../utils/localhost'; import LeetCode from './LeetCode'; import LeetCodeLogo from '../assets/LeetCodeLogo' +import Codeforces from './Codeforces'; axios.defaults.withCredentials = true @@ -144,6 +145,7 @@ const ProfileLayout = ({ isLoading, user }) => {
{user.username}
u/{user.username}
{userInfo?.bio}
+ {user?.showCf&&
} diff --git a/frontend/src/components/Profilecard.jsx b/frontend/src/components/Profilecard.jsx index a1d9027..ebf57d9 100644 --- a/frontend/src/components/Profilecard.jsx +++ b/frontend/src/components/Profilecard.jsx @@ -2,22 +2,22 @@ import React, { useEffect } from 'react' import banner from '../assets/banner.png' import { useSelector } from 'react-redux'; import { PiShareFat } from "react-icons/pi"; +import { CiEdit } from "react-icons/ci"; +import { useNavigate } from 'react-router-dom'; const Profilecard = ({room}) => { - + const nav = useNavigate(); + const currUser = useSelector((state) => state.user.userInfo); let profileInfo; if(room) { - profileInfo = useSelector(state => state.room.roomInfo) - console.log("Fetched Details Inside Profile Info"); - } else profileInfo = useSelector(state => state.profile.profileInfo) @@ -96,6 +96,10 @@ const Profilecard = ({room}) => {
+ {!room&& profileInfo?.username===currUser?.username?
+ +
:<> + } diff --git a/frontend/src/components/Sidenav.jsx b/frontend/src/components/Sidenav.jsx index 74bf0d6..10eec4e 100644 --- a/frontend/src/components/Sidenav.jsx +++ b/frontend/src/components/Sidenav.jsx @@ -17,6 +17,7 @@ import SmoothLoader from '../assets/SmoothLoader'; import { RiHomeWifiFill } from "react-icons/ri"; import { CiCircleChevUp } from "react-icons/ci"; import { CiCircleChevDown } from "react-icons/ci"; +import { BsInfoCircle } from 'react-icons/bs'; const Sidenav = () => { @@ -111,7 +112,7 @@ const Sidenav = () => {
dispatch(setShowSideNav(false))} to={"/"} className={(e) => { return e.isActive ? 'w-full flex rounded-2xl items-center gap-2 px-4 py-2 bg-[#65692375]' : 'w-full flex rounded items-center gap-2 px-4 py-2' }}>Home dispatch(setShowSideNav(false))} to={"/popular"} className={(e) => { return e.isActive ? 'flex w-full rounded-2xl items-center gap-2 px-4 py-2 bg-[#65692375]' : 'flex w-full rounded items-center gap-2 px-4 py-2' }}>Popular - {/* dispatch(setShowSideNav(false))} to={"/all"} className={(e) => { return e.isActive ? 'flex w-full rounded-2xl items-center gap-2 px-4 py-2 bg-[#65692375]' : 'flex w-full rounded items-center gap-2 px-4 py-2' }}>All */} + {!isLogin&&dispatch(setShowSideNav(false))} to={"/about/"} className={(e) => { return e.isActive ? 'flex w-full rounded-2xl items-center gap-2 px-4 py-2 bg-[#65692375]' : 'flex w-full rounded items-center gap-2 px-4 py-2' }}>About}
{isLogin&&
diff --git a/frontend/src/pages/CreateRoom.jsx b/frontend/src/pages/CreateRoom.jsx index da204e1..d5bebc2 100644 --- a/frontend/src/pages/CreateRoom.jsx +++ b/frontend/src/pages/CreateRoom.jsx @@ -182,7 +182,7 @@ export default function CreateRoom({showRoom1,setShow,setShow2,heading}) >Room name setTitle(e.target.value)}/>

diff --git a/frontend/src/pages/Home.jsx b/frontend/src/pages/Home.jsx index e271898..7b304bb 100644 --- a/frontend/src/pages/Home.jsx +++ b/frontend/src/pages/Home.jsx @@ -71,7 +71,6 @@ const Home = () => { } useEffect(() => { - // if (posts.length > 0) return; getPost(1); }, [posts.length]); @@ -81,18 +80,6 @@ const Home = () => { dispatch(increment()); }; - // if(posts.length > 0)return; - // getPost(); - // }, []); - - // const fetchMoreData = () => { - // if (isLoading || !hasMore) return; - // console.clear(); - // setPage((prevPages)=>prevPages+1); - // getPost(); - // // >>>>>>> master - - return (

{ key={`post-${e.id}-${uuidv4()}`} inRoom={e.subCommunity} room={e.room} + joined={true} topic={e.topic} id={e.id} title={e.title} diff --git a/frontend/src/pages/ProfilePosts.jsx b/frontend/src/pages/ProfilePosts.jsx index b94bf81..66d4b3a 100644 --- a/frontend/src/pages/ProfilePosts.jsx +++ b/frontend/src/pages/ProfilePosts.jsx @@ -95,7 +95,7 @@ const ProfilePosts = () => {
{(isSkelton && userPost.length === 0) ? : userPost.map(post => ( - + )) }
diff --git a/frontend/src/pages/Profileupvoted.jsx b/frontend/src/pages/Profileupvoted.jsx index 96c4f95..0a5d89f 100644 --- a/frontend/src/pages/Profileupvoted.jsx +++ b/frontend/src/pages/Profileupvoted.jsx @@ -91,7 +91,7 @@ const fetchMoreData = () => {
{(isSkelton && userPost.length === 0) ? <> : userPost.map(post => ( - + )) }
diff --git a/frontend/src/pages/Room.jsx b/frontend/src/pages/Room.jsx index ffedc7a..2ce3b3b 100644 --- a/frontend/src/pages/Room.jsx +++ b/frontend/src/pages/Room.jsx @@ -267,7 +267,6 @@ const Room = function () { if (dropdownRef.current && !dropdownRef.current.contains(event.target)) { setisOpen(false); } - }; useEffect(() => { document.addEventListener('mousedown', handleClickOutside); diff --git a/frontend/src/pages/Settings.jsx b/frontend/src/pages/Settings.jsx index 1435c83..82f2286 100644 --- a/frontend/src/pages/Settings.jsx +++ b/frontend/src/pages/Settings.jsx @@ -405,8 +405,10 @@ function Settings() {
- -
+

+ Edit Your Information Here +

+