User edit/delete comment function

This commit is contained in:
Rykkel
2024-08-13 10:07:24 +08:00
parent 0e9e7121b0
commit 82f564f8ce
3 changed files with 175 additions and 5 deletions

View File

@@ -9,7 +9,6 @@ import { retrieveUserInformation } from "../security/users";
import { Button } from "@nextui-org/react";
import { PaperAirplaneIcon } from "../icons";
const validationSchema = Yup.object({
content: Yup.string()
.trim()

View File

@@ -2,13 +2,16 @@ import instance from "../security/http";
import config from "../config";
import { useParams } from "react-router-dom";
import { useEffect, useState } from "react";
import { Avatar, Button, Dropdown, DropdownItem, DropdownMenu, DropdownTrigger, User } from "@nextui-org/react";
import { ChatBubbleOvalLeftEllipsisIcon, EllipsisHorizontalIcon, HandThumbsUpIcon } from "../icons";
import { Avatar, Button, Dropdown, DropdownItem, DropdownMenu, DropdownTrigger, Modal, ModalBody, ModalContent, ModalFooter, ModalHeader, useDisclosure, User } from "@nextui-org/react";
import { ChatBubbleOvalLeftEllipsisIcon, EllipsisHorizontalIcon, HandThumbsUpIcon, PaperAirplaneIcon } from "../icons";
import * as Yup from "yup";
import NextUIFormikTextarea from "./NextUIFormikTextarea";
import { Form, Formik, FormikHelpers } from "formik";
interface Comment {
id: string;
content: string;
user: User; // Make user optional
user: User;
}
interface User {
@@ -17,9 +20,21 @@ interface User {
lastName: string;
}
const validationSchema = Yup.object({
content: Yup.string()
.trim()
.min(3, "Content must be at least 3 characters")
.max(500, "Content must be at most 500 characters")
.required("Content is required"),
});
export default function CommentsModule() {
const { id } = useParams();
const [commentList, setCommentList] = useState<Comment[]>([]);
// To track/manage comment being edited
const [editingCommentId, setEditingCommentId] = useState<string | null>(null);
const { isOpen, onOpen, onOpenChange } = useDisclosure();
const [commentToDelete, setCommentToDelete] = useState<string | null>(null);
let postId = id
@@ -39,6 +54,53 @@ export default function CommentsModule() {
getComments();
}, [id]);
const handleEditClick = (comment: Comment) => {
setEditingCommentId(comment.id);
};
const submitComment = async (values: { content: string }, { resetForm }: FormikHelpers<{ content: string }>) => {
// Find the comment that matches the `editingCommentId` to get userId and postId
const commentBeingEdited = commentList.find(comment => comment.id === editingCommentId);
if (!commentBeingEdited) {
console.error("Comment not found");
return;
}
const data = {
content: values.content,
userId: commentBeingEdited.user.id, // Include the userId
postId: postId // Include the postId
};
const response = await instance.put(`${config.serverAddress}/post/comments/${editingCommentId}`, data);
if (response.status === 200) {
console.log("Comment updated successfully", response.data);
resetForm();
setEditingCommentId(null);
getComments();
} else {
console.error("Failed to update the comment", response.data);
}
};
const handleDeleteClick = (commentId: string) => {
setCommentToDelete(commentId);
onOpen();
};
const handleDeleteConfirm = async () => {
if (!commentToDelete) return;
const response = await instance.delete(`${config.serverAddress}/post/comments/${commentToDelete}`);
if (response.status === 200) {
console.log("Comment deleted successfully", response.data);
onOpenChange();
setCommentToDelete(null);
getComments();
} else {
console.error("Failed to delete the comment", response.data);
}
};
return (
<>
<div className="flex w-full">
@@ -71,7 +133,66 @@ export default function CommentsModule() {
</div>
<div className="flex flex-col w-10/12 flex-grow text-sm ml-3">
<div className="font-bold">{user.firstName} {user.lastName}</div>
<div className="break-words whitespace-pre-wrap">{comment.content}</div>
{editingCommentId === comment.id ? (
<Formik
initialValues={{ content: comment.content }}
validationSchema={validationSchema}
onSubmit={submitComment}
>
{({ isValid, dirty }) => (
<Form className="w-full">
<div className="flex items-center">
<NextUIFormikTextarea
label="Edit Comment"
name="content"
placeholder="Edit your comment here"
/>
<Button isIconOnly
type="submit"
disabled={!isValid || !dirty}
className="ml-2 bg-primary-950 text-white">
<PaperAirplaneIcon />
</Button>
</div>
</Form>
)}
</Formik>
) : (
<div>{comment.content}</div>
)}
</div>
<div className="flex-shrink-0 ml-10">
<div className="flex flex-row-reverse justify-center items-center size-7">
<Dropdown>
<div>
<DropdownTrigger
className="justify-center items-center"
>
<Button isIconOnly variant="light">
<EllipsisHorizontalIcon />
</Button>
</DropdownTrigger>
</div>
<DropdownMenu aria-label="Static Actions">
<DropdownItem
key="edit"
textValue="Edit"
onClick={() => handleEditClick(comment)}
>
Edit
</DropdownItem>
<DropdownItem
key="delete"
textValue="Delete"
className="text-danger"
color="danger"
onClick={() => handleDeleteClick(comment.id)}
>
Delete
</DropdownItem>
</DropdownMenu>
</Dropdown>
</div>
</div>
</div>
<div className="flex flex-row ml-14 mt-2 gap-3 w-11/12">
@@ -86,6 +207,28 @@ export default function CommentsModule() {
</div>
<div className="w-2/12"></div>
</div>
<Modal isOpen={isOpen} onOpenChange={onOpenChange}>
<ModalContent>
{(onClose) => (
<>
<ModalHeader className="flex flex-col gap-1">
Confirm Delete
</ModalHeader>
<ModalBody>
<p>Are you sure you want to delete this comment?</p>
</ModalBody>
<ModalFooter>
<Button color="danger" variant="light" onPress={onClose}>
Close
</Button>
<Button color="primary" onPress={handleDeleteConfirm}>
Confirm
</Button>
</ModalFooter>
</>
)}
</ModalContent>
</Modal>
</>
);
};

View File

@@ -301,6 +301,34 @@ router.post("/:id/comments", async (req, res) => {
}
});
router.put("/comments/:id", async (req, res) => {
let { id } = req.params;
let data = req.body;
// Validate request body
let validationSchema = yup.object({
content: yup.string().trim().min(3).max(500).required(),
userId: yup.string().required(),
postId: yup.string().required(),
});
try {
console.log("Validating schema...");
data = await validationSchema.validate(data, { abortEarly: false });
// Ensure comment exists
let comment = await Comment.findByPk(id);
if (!comment) {
res.sendStatus(404); // Comment not found
return;
}
let result = await comment.update(data);
res.json({ message: "Comment updated successfully", comment });
} catch (err) {
res.status(400).json({ errors: err.errors });
}
})
router.get("/:id/getComments", async (req, res) => {
let id = req.params.id;