diff --git a/backend/src/controllers/postController.ts b/backend/src/controllers/postController.ts index 353866c..9e41908 100644 --- a/backend/src/controllers/postController.ts +++ b/backend/src/controllers/postController.ts @@ -220,6 +220,7 @@ const fetchSinglePost = asyncHandler(async (req: Request, res: Response) => { }, User: { select: { + user_id: true, username: true, pic: true, }, @@ -231,6 +232,7 @@ const fetchSinglePost = asyncHandler(async (req: Request, res: Response) => { user_id: true, User: { select: { + user_id: true, username: true, pic: true, }, @@ -260,17 +262,31 @@ const deletePost = asyncHandler(async (req: Request, res: Response) => { }, where: { post_id: postId }, }); + // @ts-ignore const user_id = req.user.user_id; if (!post) { return res.status(404).json({ message: "Post not found" }); } + if (post.User.user_id !== user_id) { return res.status(401).json({ message: "Unauthorized" }); } + await prisma.$transaction(async (prisma) => { + await prisma.comment.deleteMany({ + where: { post_id: postId }, + }); + await prisma.like.deleteMany({ + where: { post_id: postId }, + }); - return res.status(200).json({ message: "Post deleted" }); + await prisma.post.delete({ + where: { post_id: postId }, + }); + }); + + return res.status(200).json({ message: "Post and comments deleted" }); }); // @ts-ignore @@ -374,6 +390,10 @@ const deleteComment = asyncHandler(async (req: Request, res: Response) => { return res.status(401).json({ message: "Unauthorized" }); } + await prisma.comment.delete({ + where: { comment_id: commentId }, + }); + return res.status(200).json({ message: "Comment deleted" }); }); diff --git a/frontend/src/components/DeleteConfirmation.jsx b/frontend/src/components/DeleteConfirmation.jsx new file mode 100644 index 0000000..9b596e9 --- /dev/null +++ b/frontend/src/components/DeleteConfirmation.jsx @@ -0,0 +1,36 @@ +import React from "react"; +import { + Modal, + ModalOverlay, + ModalContent, + ModalHeader, + ModalBody, + ModalFooter, + Button, + Text, +} from "@chakra-ui/react"; + +const DeleteConfirmation = ({ isOpen, onClose, onConfirm, message }) => { + return ( + + + + {" "} + Confirm Deletion + + {message} + + + + + + + + ); +}; + +export default DeleteConfirmation; diff --git a/frontend/src/components/SinglePost.jsx b/frontend/src/components/SinglePost.jsx index a00f890..1b504dd 100644 --- a/frontend/src/components/SinglePost.jsx +++ b/frontend/src/components/SinglePost.jsx @@ -1,5 +1,6 @@ import React, { useEffect, useState } from "react"; import { GrLike } from "react-icons/gr"; +import { useNavigate } from "react-router-dom"; import { AiFillLike } from "react-icons/ai"; import { useParams, Navigate } from "react-router-dom"; import { @@ -13,12 +14,15 @@ import { Center, VStack, useToast, + Icon, } from "@chakra-ui/react"; import { gsap } from "gsap"; import axios from "axios"; import CreateComment from "./CreateComment"; import { useUser } from "../hook/useUser"; import { InfinitySpin } from "react-loader-spinner"; +import DeleteConfirmation from "./DeleteConfirmation"; +import { FaTrash } from "react-icons/fa"; const SinglePost = () => { const { id } = useParams(); @@ -26,11 +30,15 @@ const SinglePost = () => { const [loading, setLoading] = useState(true); const [postLiked, setPostLiked] = useState(false); const { userDetails, loadingUser } = useUser(); + const [isDeletePostOpen, setIsDeletePostOpen] = useState(false); + const [isDeleteCommentOpen, setIsDeleteCommentOpen] = useState(false); + const [commentToDelete, setCommentToDelete] = useState(null); // Refs for the animations const likeButtonRef = React.useRef(null); const likeFloodRef = React.useRef(null); const toast = useToast(); + const navigate = useNavigate(); useEffect(() => { const fetchPost = async () => { @@ -43,6 +51,7 @@ const SinglePost = () => { } catch (err) { setLoading(false); alert("Error fetching post"); + console.error("Error fetching post:", err); } }; @@ -163,6 +172,47 @@ const SinglePost = () => { ); + const handleDeleteComment = async (comment) => { + try { + await axios.post( + "/api/post/deletecomment", + { commentId: comment.comment_id }, + { withCredentials: true } + ); + setPost((prevPost) => ({ + ...prevPost, + Comments: prevPost.Comments.filter( + (c) => c.comment_id !== comment.comment_id + ), + })); + setIsDeleteCommentOpen(false); + } catch (error) { + console.error("Error deleting comment:", error); + } + }; + + const handleDeletePost = async () => { + try { + setLoading(true); + await axios.post( + "/api/post/deletepost", + { postId: post.post_id }, + { withCredentials: true } + ); + setIsDeletePostOpen(false); + setLoading(false); + toast({ + title: "Post deleted successfully", + status: "success", + duration: 5000, + isClosable: true, + }); + navigate("/posts"); + } catch (error) { + console.error("Error deleting post:", error); + } + }; + return ( { {post.likes} {post.likes === 1 ? "like" : "likes"} - + + {post.User.user_id === userDetails.user_id && ( + + )} + + setIsDeletePostOpen(false)} + onConfirm={handleDeletePost} + message="Are you sure you want to delete this post?" + /> { - - {/* Displaying Comments */} {post.Comments.length > 0 ? ( post.Comments.map((comment) => ( { {comment.User.username} - + {comment.content} + {comment.User.user_id === userDetails.user_id && ( + + + setIsDeleteCommentOpen(false)} + onConfirm={() => handleDeleteComment(commentToDelete)} + message="Are you sure you want to delete this comment?" + /> + + )} )) ) : (