Built Twitter Like App - 26

Add Comments Function

  1. Add Comments API
  2. Modify Form Component
  3. Modify Post page
  4. Add CommentFeed Component
  5. Add CommentItem Component

Add Comments API

Add file pages/api/comments.ts :

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
import { NextApiRequest, NextApiResponse } from "next";
import prisma from '@/libs/prismadb';

export default async function handler(
req: NextApiRequest,
res: NextApiResponse
) {
if ( req.method !== 'POST'){
return res.status(405).end();
}

try{
const { body } = req.body;
const { user, postId } = req.query;

if(!postId || !user || !body) {
throw new Error('Invalid postId/userId/body');
}

const userId = Number(user);

const comment = await prisma.comment.create({
data: {
body,
userId,
postId: Number(postId)
}
})

return res.status(200).json(comment);
} catch(error){
console.log(error);
return res.status(400).end();
}
}

Modify Form Component

Modify file components/Form.tsx :

1
2
3
4
5
6
...
const url = isComment ? `/api/comments?postId=${postId}&user=${currentUser.id}`
: `/api/posts?user=${currentUser.id}`;
...
},[body,isComment,postId, mutatePosts,mutatePost]);
...

Modify Post page

Modify pages/posts/[postId.tsx , add CommentFeed:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
...
return (
<>
<Header label={"Tweet"} showBackArrow />
<PostItem data={fetchedPost} userId={fetchedPost.user.id} />
<Form
postId={postId as string}
isComment
placeholder="Tweet your reply"
/>
<CommentFeed comments={fetchedPost?.comments} />
</>
)
...

Add CommentFeed Component

Add file components/posts/CommentFeed.tsx :

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
import React from "react";
import CommentItem from "./CommentItem";

interface CommentFeedProps {
comments?:Record<string, any>[]
}
const CommentFeed: React.FC<CommentFeedProps> =( { comments = []}) =>{
return (
<>
{ comments.map (( comment ) =>(
<CommentItem key={comment.id} data={comment} />
))}
</>
);
}

export default CommentFeed

Add CommentItem Component

Add file components/posts/CommentItem.tsx :

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
import { formatDistanceToNowStrict } from "date-fns";
import { useRouter } from "next/router"
import { useCallback, useMemo } from "react";
import Avatar from "../Avatar";

interface CommentItemProps {
data: Record<string, any>
};

const CommentItem: React.FC<CommentItemProps> = ( { data }) => {
const router = useRouter();

const goToUser = useCallback((event: any) => {
event.stopPropagation();

router.push(`/users/${data.user.id}`);
}, [ router, data.user.id ]);

const createdAt = useMemo(() => {
if(!data?.createdAt) {
return null;
}

return formatDistanceToNowStrict(new Date(data.createdAt));
}, [data.createdAt]);

return (
<div
className="
border-b-[1px]
border-nuetral-800
p-5
cursor-pointer
hover:bg-neutral-900
transition
"
>
<div className="flex flex-row items-start gap-3">
<Avatar userId={data.user.id} />
<div>
<div className="flex flex-row items-center gap-2">
<p
onClick={goToUser}
className="
text-white
font-semibold
cursor-pointer
hover:underline
"
>
{data.user.name}
</p>
<span
className="
text-neutral-800
cursor-point
hover:underline
hidden
md:block
"
>
{data.user.username}
</span>
<span className="text-neutral-500 text-sm">
{createdAt}
</span>
</div>
<div
className="
text-white
mt-1
"
>
{data.body}
</div>
</div>

</div>
</div>
);
}

export default CommentItem

Demo

请我喝杯咖啡吧~

支付宝
微信