Adding the Comment feature

Posted by : on

Category : next


Adding the Comment feature

Next.js version

"next": "13.2.4”


Goals


Make comments for a post visible in the post detail

comments → component required, create comment doc in DB


comment doc

(comment doc)
          parent: new ObjectId(parent),
          email,
          name,
					comment,
          like: []

parent → comment’s parent (post) id

email → Author’s email

name → Author name

comment → Comment content

like → array of emails of users who “like” a comment


Save to POST → DB after creating

When the Like button is clicked, add the clicked user’s email to the comment doc like field array in PUT → DB


app/detail/[uid]/page.jsx

import { ObjectId } from "mongodb";
import { connectDB } from "util/database";
import Comment from "components/Comment";
import { notFound } from "next/navigation";
/**
 * MongoDB must be running on a server.
 * To access data dynamically in React, you'll need to set up an API using something like Express or Apollo.
 * Therefore, when using USE CLIENT, a DNS-related error occurs
 */

export default async function Detail(props) {
  const db = (await connectDB).db("forum");
  let result = await db
    .collection("post")
    .findOne({ _id: new ObjectId(props.params.uid) });

  if (result == null) {
    return notFound();
  } else {
    return (
      <div>
        <h4>{result.title}</h4>
        <h4>DES</h4>
        <p>DES2</p>
        <Comment parentData={props} />
        <div></div>
      </div>
    );
  }
  // Add the ability to like posts
}

Post Detail Page


componets/Comment.jsx

"use client";

import { useEffect, useState } from "react";

export default function Comment({ parentData }) {
  let [comment, setComment] = useState("");
  let [comments, setComments] = useState([]);

  const submitComment = async () => {
    fetch("/api/post/comment", {
      method: "POST",
      headers: {
        "Content-Type": "application/json",
      },
      body: JSON.stringify({
        comment: comment,
        parent: parentData.params.uid,
      }),
    })
      .then((response) => response.json())
      .then((data) => {
        console.log(data);
        setComments(data);
        setComment("");
      })
      .catch((error) => {
        console.error(error);
      });
  };

  const onLikeClick = async (id) => {
    fetch("/api/post/comment", {
      method: "PUT",
      headers: {
        "Content-Type": "application/json",
      },
      body: JSON.stringify({
        id,
        parent: parentData.params.uid,
      }),
    })
      .then((response) => {
        if (response.status === 400) {
          throw new Error("You already liked this comment");
        }
        return response.json();
      })
      .then((data) => {
        console.log(data);
        setComments(data);
        setComment("");
      })
      .catch((error) => {
        alert(error.message);
      });
  };

  // If you want to get the data from the server on the client side, you can use the ajax
  useEffect(() => {
    fetch(`/api/comments?uid=${parentData.params.uid}`)
      .then((r) => r.json())
      .then((result) => {
        console.log(result);
        setComments(result);
      });
  }, []);

  return (
    <div id="comment">
      <div>Comment List</div>
      <input onChange={(e) => setComment(e.target.value)} />
      <button style= onClick={submitComment}>
        Forwarding comments
      </button>
      <div>
        {comments.length > 0
          ? comments.map((el, index) => (
              <div key={index}>
                <div>
                  <span>Name: </span>
                  <span>{el.name}</span>
                </div>
                <div>
                  <span>Comment: </span>
                  <span>{el.comment}</span>
                </div>
                <div>
                  <button
                    onClick={() => onLikeClick(el._id)}
                    style=
                  >
                    ♥️
                  </button>
                  <span>{el.like.length}</span>
                </div>
              </div>
            ))
          : "No comment"}
      </div>
    </div>
  );
}

-

<div>
  {comments.length > 0
    ? comments.map((el, index) => {
        <div key={index}>{el.email}</div>;
      })
    : "No comment"}
</div>

Writing the dom as {} ensures that the last JSX element is returned correctly within the map function callback.


Fetching comments

pages/api/comments.js

import { getServerSession } from "next-auth";
import { connectDB } from "util/database";
import { ObjectId } from "mongodb";
import { authOptions } from "./auth/[...nextauth]";

export default async function handler(req, res) {
  if (req.method == "GET") {
    const session = await getServerSession(req, res, authOptions);
    if (!session) {
      return res.status(400).json("Available after login");
    } else {
      try {
        const { uid } = req.query;
        const db = (await connectDB).db("forum");
        let result = await db
          .collection("comment")
          .find({ parent: new ObjectId(uid) })
          .toArray();
        return res.status(200).json(result);
      } catch (error) {
        return res.status(500);
      }
    }
  } else {
    return res.status(400).json("This is an incorrect approach.");
  }
}
ex


New comment and like

pages/api/post/comment.js

import { getServerSession } from "next-auth";
import { authOptions } from "../auth/[...nextauth]";
import { connectDB } from "util/database";
import { ObjectId } from "mongodb";

export default async function handler(req, res) {
  const session = await getServerSession(req, res, authOptions);
  if (req.method == "POST") {
    if (!session) {
      return res.status(400).json("Available after login");
    } else {
      const { comment, parent } = req.body;
      const { email, name } = session.user;
      if (!comment) {
        return res.status(400).json("Spaces are not allowed.");
      } else {
        const db = (await connectDB).db("forum");
        const result = await db.collection("comment").insertOne({
          comment,
          parent: new ObjectId(parent),
          email,
          name,
          like: [],
        });
        let resultComment = await db
          .collection("comment")
          .find({ parent: new ObjectId(parent) })
          .toArray();
        return res.status(200).json(resultComment);
      }
    }
  } else if (req.method == "PUT") {
    const { id, parent } = req.body;
    const { email } = session.user;
    const db = (await connectDB).db("forum");
    const result = await db
      .collection("comment")
      .findOne({ _id: new ObjectId(id) });
    if (result) {
      if (result.like.includes(email)) {
        return res.status(400).json("You already liked this comment");
      } else {
        const updatedResult = await db
          .collection("comment")
          .findOneAndUpdate(
            { _id: new ObjectId(id) },
            { $push: { like: email } },
            { returnOriginal: false }
          );

        if (updatedResult.value) {
          const updatedComment = await db
            .collection("comment")
            .find({ parent: new ObjectId(parent) })
            .toArray();
          return res.status(200).json(updatedComment);
        }
      }
    }
  } else {
    return res.status(400).json("This is an incorrect approach.");
  }
}

// Need to handle 500 server error
ex


ex

About George
George

I'm George, a Web Developer.

Email : kghee9612@gmail.com

Website : https://ge5rg2.github.io

About George

Hi, my name is George. This is where I record what I have studied :D

Star
Useful Links