
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.");
}
}

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

