From 46ceb9641928853ae640fb0d187e3677d48005ba Mon Sep 17 00:00:00 2001 From: Rykkel <220993G@mymail.nyp.edu.sg> Date: Thu, 1 Aug 2024 03:02:09 +0800 Subject: [PATCH] Retrieve post comments --- client/src/components/CommentInputModule.tsx | 86 +++++++++ client/src/components/CommentsModule.tsx | 181 +++++++++++-------- client/src/icons.tsx | 27 ++- client/src/pages/CommunityPage.tsx | 1 - client/src/pages/PostPage.tsx | 15 +- server/routes/post.js | 68 ++++--- 6 files changed, 258 insertions(+), 120 deletions(-) create mode 100644 client/src/components/CommentInputModule.tsx diff --git a/client/src/components/CommentInputModule.tsx b/client/src/components/CommentInputModule.tsx new file mode 100644 index 0000000..14235af --- /dev/null +++ b/client/src/components/CommentInputModule.tsx @@ -0,0 +1,86 @@ +import { Formik, Form, FormikHelpers } from "formik"; +import { useEffect, useState } from "react"; +import config from '../config'; +import * as Yup from "yup"; +import NextUIFormikTextarea from "./NextUIFormikTextarea"; +import instance from '../security/http'; +import { useNavigate, useParams } from "react-router-dom"; +import { retrieveUserInformation } from "../security/users"; +import { Button } from "@nextui-org/react"; +import { PaperAirplaneIcon } from "../icons"; + + +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") +}); + +export default function CommentInputModule() { + const navigate = useNavigate(); + const [userId, setUserId] = useState(null); + const { id } = useParams(); // Retrieve 'id' from the route + + const initialValues = { + content: "", + }; + + const postId = id; + + useEffect(() => { + const getUserInformation = async () => { + try { + const user = await retrieveUserInformation(); // Get the user ID + setUserId(user.id); // Set the user ID in the state + } catch (error) { + console.error(error); + } + }; + getUserInformation(); + }, []); + + const submitComment = async (values: any, { resetForm }: FormikHelpers<{ content: string }>) => { + const response = await instance.post(config.serverAddress + `/post/${postId}/comments`, + { ...values, userId, postId } + ); + console.log("Comment created succesfully", response.data); + resetForm(); // Reset the form after successful submission + }; + + return ( +
+
+
+
+ + {({ isValid, dirty }) => ( +
+
+ +
+ +
+
+
+ )} +
+
+
+
+
+ ); +} \ No newline at end of file diff --git a/client/src/components/CommentsModule.tsx b/client/src/components/CommentsModule.tsx index 1c1c214..8fdf89c 100644 --- a/client/src/components/CommentsModule.tsx +++ b/client/src/components/CommentsModule.tsx @@ -1,85 +1,118 @@ -import { Formik, Form } from "formik"; -import React, { useEffect, useState } from "react"; -import config from '../config'; import * as Yup from "yup"; -import NextUIFormikTextarea from "../components/NextUIFormikTextarea"; -import instance from '../security/http'; -import { useNavigate, useParams } from "react-router-dom"; -import { retrieveUserInformation } from "../security/users"; -import { Button } from "@nextui-org/react"; -import { PaperAirplaneIcon } from "../icons"; +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 } from "@nextui-org/react"; +import { ChatBubbleOvalLeftEllipsisIcon, EllipsisHorizontalIcon, HandThumbsUpIcon } from "../icons"; +interface Comment { + id: string; + content: 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") -}); +// type User = { +// id: string; +// firstName: string; +// lastName: string; +// }; export default function CommentsModule() { - const navigate = useNavigate(); - const [userId, setUserId] = useState(null); - const { id } = useParams(); // Retrieve 'id' from the route - - const initialValues = { - content: "", + const { id } = useParams(); + const [commentList, setCommentList] = useState([]); + + let postId = id + + const getComments = async () => { + instance + .get(config.serverAddress + `/post/${postId}/getComments`).then((res) => { + setCommentList(res.data); + }); }; - - const postId = id; - useEffect(() => { - const getUserInformation = async () => { - try { - const user = await retrieveUserInformation(); // Get the user ID - setUserId(user.id); // Set the user ID in the state - } catch (error) { - console.error(error); - } - }; - getUserInformation(); - }, []); - - const submitComment = async (values: any) => { - const response = await instance.post(config.serverAddress + `/post/${postId}/comments`, - { ...values, userId, postId } - ); - console.log("Comment created succesfully", response.data); - }; + getComments(); + }, [id]); return ( -
-
-
-
- - {({ isValid, dirty }) => ( -
-
- -
- -
-
-
- )} -
-
+ <> +
+
+
Comment Section
+
-
-
+
+
+
+ {commentList.length > 0 ? ( + commentList.map((comment) => { + return ( +
+
+
+ +
+
+
Name
+
{comment.content}
+
+
+
+ +
+ + + +
+ + + Edit + + + Delete + + +
+
+
+
+
+ + +
+
+ ); + }) + ) : ( +
No comments... It's so lonely 🥹
+ )} +
+
+
+ ); -} \ No newline at end of file +}; \ No newline at end of file diff --git a/client/src/icons.tsx b/client/src/icons.tsx index 6d99a45..2e595c1 100644 --- a/client/src/icons.tsx +++ b/client/src/icons.tsx @@ -617,18 +617,17 @@ export const TrophyIcon = () => { export const PaperAirplaneIcon = () => { return ( - - - - ) -} + className="size-6"> + + + + ); +}; diff --git a/client/src/pages/CommunityPage.tsx b/client/src/pages/CommunityPage.tsx index bbf1886..bef03a5 100644 --- a/client/src/pages/CommunityPage.tsx +++ b/client/src/pages/CommunityPage.tsx @@ -31,7 +31,6 @@ import { import { useNavigate } from "react-router-dom"; import { retrieveUserInformationById } from "../security/usersbyid"; import { retrieveUserInformation } from "../security/users"; -import { number } from "yup"; // import UserPostImage from "../components/UserPostImage"; interface Post { diff --git a/client/src/pages/PostPage.tsx b/client/src/pages/PostPage.tsx index aba9cc3..18c8b5e 100644 --- a/client/src/pages/PostPage.tsx +++ b/client/src/pages/PostPage.tsx @@ -1,5 +1,5 @@ import { useParams, useNavigate } from "react-router-dom"; -import { useEffect, useState } from "react"; +import { useCallback, useEffect, useState } from "react"; import instance from "../security/http"; import config from "../config"; import { @@ -25,6 +25,7 @@ import { ArrowUTurnLeftIcon, } from "../icons"; import { retrieveUserInformationById } from "../security/usersbyid"; +import CommentInputModule from "../components/CommentInputModule"; import CommentsModule from "../components/CommentsModule"; interface Post { @@ -114,7 +115,7 @@ const PostPage: React.FC = () => {
-
+
{
- + @@ -146,7 +148,7 @@ const PostPage: React.FC = () => { key="edit" textValue="Edit" onClick={() => { - navigate(`edit/${post.id}`); + navigate(`../edit/${post.id}`); }} > Edit @@ -201,10 +203,13 @@ const PostPage: React.FC = () => {
+
+ +
- + {(onClose) => ( diff --git a/server/routes/post.js b/server/routes/post.js index 5834b9e..ea4ee03 100644 --- a/server/routes/post.js +++ b/server/routes/post.js @@ -45,32 +45,6 @@ router.post("/", async (req, res) => { } }); -router.post("/:id/comments", async (req, res) => { - 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 }); - - console.log("Creating comment..."); - let result = await Comment.create(data); - - res.json(result); - console.log("Success!"); - } catch (err) { - console.log("Error caught! Info: " + err); - res.status(400).json({ errors: err.errors }); - } -}); - - // // sequelize method findAll is used to generate a standard SELECT query which will retrieve all entries from the table // router.get("/", async (req, res) => { // let list = await Tutorial.findAll({ @@ -180,4 +154,46 @@ router.delete("/:id", async (req, res) => { } }); +router.post("/:id/comments", async (req, res) => { + 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 }); + + console.log("Creating comment..."); + let result = await Comment.create(data); + + res.json(result); + console.log("Success!"); + } catch (err) { + console.log("Error caught! Info: " + err); + res.status(400).json({ errors: err.errors }); + } +}); + +router.get("/:id/getComments", async (req, res) => { + let id = req.params.id; + + let condition = { + where: { postId: id }, + order: [['createdAt', 'DESC']] + }; + + // Check id not found + let comments = await Comment.findAll(condition); + if (!comments) { + res.sendStatus(404); + return; + } + res.json(comments); +}); + module.exports = router; \ No newline at end of file