From 5fd4276bc74d24d5855e5960e4972cde5acc76a1 Mon Sep 17 00:00:00 2001 From: "DESKTOP-9FO96TP\\hehexd" <davidjakszta@outlook.de> Date: Tue, 6 Jun 2023 05:12:04 +0200 Subject: [PATCH] added (post)comment button, comment api, actual name to Posts --- app/(content)/(home)/home/[postid]/page.tsx | 109 ++++++++++++++++++++ app/(content)/(home)/home/page.tsx | 59 +++-------- app/api/comments/route.ts | 64 ++++++++++++ components/comment-button.tsx | 28 +++++ components/like-button.tsx | 10 +- components/post-comment.tsx | 64 ++++++++++++ components/post-item.tsx | 48 +++++++++ 7 files changed, 331 insertions(+), 51 deletions(-) create mode 100644 app/(content)/(home)/home/[postid]/page.tsx create mode 100644 app/api/comments/route.ts create mode 100644 components/comment-button.tsx create mode 100644 components/post-comment.tsx create mode 100644 components/post-item.tsx diff --git a/app/(content)/(home)/home/[postid]/page.tsx b/app/(content)/(home)/home/[postid]/page.tsx new file mode 100644 index 0000000..5345184 --- /dev/null +++ b/app/(content)/(home)/home/[postid]/page.tsx @@ -0,0 +1,109 @@ +import CommentButton from "@/components/comment-button"; +import LikeButton from "@/components/like-button"; +import PostCommentForm from "@/components/post-comment"; +import PostItem from "@/components/post-item"; +import { db } from "@/lib/db"; +import { Prisma } from "@prisma/client"; +/* export const revalidate = 5; */ // revalidate this page every 5 seconds + + + +type commentType = Prisma.CommentUncheckedCreateInput +type messageType = any // Prisma.PostUncheckedCreateInput +type messageItemProps = { + msg: messageType; +}; + +export default async function PostDetail({ params }: { params: { postid: string } }) { + const postid = params.postid + let comments = null + let message: messageType | null = null + + try { + comments = await db.comment.findMany({ + where: { + postId: postid + }, + orderBy: { + createdAt: "desc" + }, + include: { + user: true, + }, + }) + + message = await db.post.findUnique({ + where: { + id: postid + }, + include: { + user: true, + Comment: true, + }, + }) + + } catch (error) { + console.log("the database is not running, try: 'npx prisma migrate dev --name init' if you want to use the database") + } + + return ( + <div> + <h1>Post Section</h1> + <p>This will be where all comments show up.</p> + <p>Needs a reload after posting!!</p> + <PostItem msg={message} /> + + <PostCommentForm postid={postid} /> + + {comments ? + <> + {comments.map((msg) => ( + <CommentItem msg={msg} key={msg.id} /> + ))} + + </> + : + <p>no comments / no database</p>} + </div> + ) +} + +const CommentItem = ({ msg }: messageItemProps) => { + if (!msg.id) { + return <div></div>; + } + return ( + <div className="flex border-b border-gray-200 py-4"> + <div className="flex-shrink-0"> + <div className="h-10 w-10 rounded-full bg-gray-300"></div> {/* Profile picture */} + </div> + <div className="ml-4 flex flex-col flex-grow"> + <div> + <div className="flex items-center"> + <span className="font-bold mr-2">{msg.user.name}</span> + <span className="text-gray-500 text-sm"> + {formatDate(new Date(msg.createdAt!))} + </span> + </div> + <div className="text-gray-800">{msg.message}</div> + </div> + <div className="mt-4 flex"> + <div className="bg-gray-200 rounded-lg py-10 px-20 mr-2"> + {/* potential Image */} + </div> + </div> + <div className="flex justify-end" > + <LikeButton data={msg} /> + </div> + </div> + </div> + ); +}; + +function formatDate(date: Date) { + return date.toLocaleDateString("en-US", { + day: "numeric", + month: "short", + year: "numeric" + }); +} \ No newline at end of file diff --git a/app/(content)/(home)/home/page.tsx b/app/(content)/(home)/home/page.tsx index d50aa7c..862917b 100644 --- a/app/(content)/(home)/home/page.tsx +++ b/app/(content)/(home)/home/page.tsx @@ -1,10 +1,14 @@ + +import CommentButton from "@/components/comment-button"; import LikeButton from "@/components/like-button"; +import PostItem from "@/components/post-item"; +import MessageItem from "@/components/post-item"; import PostMessageForm from "@/components/post-messages"; import { db } from "@/lib/db"; import { Prisma } from "@prisma/client"; /* export const revalidate = 5; */ // revalidate this page every 60 seconds -type messageType = Prisma.PostUncheckedCreateInput +type messageType = any // Prisma.PostUncheckedCreateInput type messageItemProps = { msg: messageType; }; @@ -15,7 +19,11 @@ export default async function HomePage() { messages = await db.post.findMany({ orderBy: { createdAt: "desc" - } + }, + include: { + user: true, + Comment: true + }, }) } catch (error) { @@ -25,13 +33,13 @@ export default async function HomePage() { return ( <div> <h1>Home WIP</h1> - <p>This will be where all messages show up.</p> + <p>This will be where all Posts show up.</p> <p>Needs a reload after posting!!</p> <PostMessageForm data={messages} /> {messages ? <> {messages.map((msg) => ( - <MessageItem msg={msg} key={msg.id} /> + <PostItem msg={msg} key={msg.id} /> ))} </> @@ -41,46 +49,3 @@ export default async function HomePage() { ) } -const MessageItem = ({ msg }: messageItemProps) => { - if (!msg.id) { - return <div></div> - } - return ( - <div className="flex border-b border-gray-200 py-4"> - <div className="flex-shrink-0"> - <div className="h-10 w-10 rounded-full bg-gray-300"></div> {/* Profile picture */} - </div> - <div className="ml-4 flex flex-col"> - <div> - <div className="flex items-center"> - <span className="font-bold mr-2">{msg.userId}</span> - <span className="text-gray-500 text-sm"> - {formatDate(new Date(msg.createdAt!))} - </span> - </div> - <div className="text-gray-800">{msg.content}</div> - </div> - <div className="mt-4"> - <div className="flex items-center"> - <div className="bg-gray-200 rounded-lg py-10 px-20 mr-2"> - {/* potential Image */} - </div> - </div> - </div> - <LikeButton data={{ - postId: msg.id, - userId: msg.userId - }} /> - <span className="text-gray-600">Like Count: {msg.likeCount} | <span className="text-gray-600">ReplyButton (Number of Replies)</span></span> - </div> - </div> - ); -}; - -function formatDate(date: Date) { - return date.toLocaleDateString("en-US", { - day: "numeric", - month: "short", - year: "numeric" - }); -} \ No newline at end of file diff --git a/app/api/comments/route.ts b/app/api/comments/route.ts new file mode 100644 index 0000000..93429aa --- /dev/null +++ b/app/api/comments/route.ts @@ -0,0 +1,64 @@ +import { authOptions } from "@/lib/auth"; +import { db } from "@/lib/db"; +import { Prisma } from "@prisma/client"; +import { getServerSession } from "next-auth/next"; +import { revalidatePath } from "next/cache"; +import { NextRequest, NextResponse } from "next/server"; + +type comment = Prisma.CommentUncheckedCreateInput + +export async function POST(req: NextRequest) { + const session = await getServerSession(authOptions); + + if (!session) { + return NextResponse.json({ status: 401 }); + } + + const userId = session.user.id + const data: comment = await req.json() + + console.log("router data: " + data.message, "status:") + + try { + await db.comment.create({ + /* data: data */ + data: { + message: data.message, + postId: data.postId, + userId: userId, + } + }) + console.log("created") + const path = req.nextUrl.searchParams.get('path') || '/'; + revalidatePath(path); + + return NextResponse.json({ status: 201, message: 'Message Created' }) + + } catch (error: any) { + console.log("fail" + error); + } + console.log("post") +} + +export async function GET(req: NextRequest, res: NextResponse) { + try { + const data = await req.json() + console.log("router data: " + data, "status:") + } catch (error) { + + } + + try { + const messages = await db.comment.findMany({ + orderBy: { + createdAt: "desc" + } + }) + + return NextResponse.json({ status: 200, messages: messages }) + } catch (error) { + console.log("fail" + error); + // res.status(400) + } + console.log("get") +} \ No newline at end of file diff --git a/components/comment-button.tsx b/components/comment-button.tsx new file mode 100644 index 0000000..a1c71ba --- /dev/null +++ b/components/comment-button.tsx @@ -0,0 +1,28 @@ +"use client" + +import { Prisma } from "@prisma/client"; +import { useRouter } from "next/navigation"; +import { startTransition } from "react"; +import { Icons } from "./icons"; +import { Button } from "./ui/button"; +import Link from "next/link"; + +type commentType = Prisma.CommentUncheckedCreateInput +type postType = Prisma.PostSelect + +export default function CommentButton(props: { data: any }) { + + const postid = props.data.id + const replyCount = props.data.Comment.length + + return ( + <div> + <Link href={`/home/${postid}`}> + <Button type="submit" variant="ghost" size="lg" className="float-right" > + {replyCount} + <Icons.messagecircle className="h-3 w-3" /> + </Button> + </Link> + </div> + ) +} \ No newline at end of file diff --git a/components/like-button.tsx b/components/like-button.tsx index 6a08934..1cbc47a 100644 --- a/components/like-button.tsx +++ b/components/like-button.tsx @@ -7,16 +7,17 @@ import { Icons } from "./icons"; import { Button } from "./ui/button"; type likeType = Prisma.LikeUncheckedCreateInput +type postType = Prisma.PostUncheckedCreateInput -export default function LikeButton(props: { data: likeType }) { +export default function LikeButton(props: { data: any }) { const router = useRouter(); async function postLike(e: any) { e.preventDefault() - const msgLikeData = props.data; + const postLikeData = props.data; const likeData = {} as likeType - likeData.userId = msgLikeData.userId - likeData.postId = msgLikeData.postId + likeData.userId = postLikeData.userId + likeData.postId = postLikeData.id! const response = await fetch('http://localhost:3000/api/likes', { method: 'PUT', @@ -35,6 +36,7 @@ export default function LikeButton(props: { data: likeType }) { <div> <form onSubmit={postLike}> <Button type="submit" variant="ghost" size="lg" className="float-right" > + {props.data.likeCount} <Icons.heart className="h-3 w-3" /> </Button> </form> diff --git a/components/post-comment.tsx b/components/post-comment.tsx new file mode 100644 index 0000000..6f80ff3 --- /dev/null +++ b/components/post-comment.tsx @@ -0,0 +1,64 @@ +"use client" + +import { Post, Prisma } from "@prisma/client"; +import { useRouter } from "next/navigation"; +import { startTransition, useEffect, useState } from "react"; + +type commentType = Prisma.CommentUncheckedCreateInput + +export default function PostCommentForm(props: { postid: string }) { + + const [formData, setFormData] = useState<commentType>({ message: "" } as commentType); + const router = useRouter(); + const postid = props.postid + + async function postComment(e: any) { + e.preventDefault() + + formData.postId = postid; + + const response = await fetch('http://localhost:3000/api/comments', { + method: 'POST', + body: JSON.stringify(formData) + }) + + startTransition(() => { + // Refresh the current route and fetch new data from the server without + // losing client-side browser or React state. + router.refresh(); + }); + return await response.json() + } + + const characterCount = formData.message.length; + const isOverLimit = characterCount >= 1000; + + const handleInputChange = (e: React.ChangeEvent<HTMLTextAreaElement>) => { + const { value } = e.target; + setFormData({ ...formData, message: value }); + }; + + return ( + <div className="p-4 pb-20"> + <form onSubmit={postComment}> + <textarea + placeholder="Write something..." + name="message" + value={formData.message} + onChange={handleInputChange} + className="w-full p-2 border border-gray-600 rounded-xl resize-none" + rows={5} + maxLength={1000} + ></textarea> + <div className="flex justify-end mt-2"> + <span className={`${isOverLimit ? "text-red-500" : "text-gray-500"} text-sm`}> + {characterCount}/{1000} + </span> + </div> + <button type="submit" className="mt-2 bg-gray-300 text-gray-800 px-4 py-2 rounded float-right"> + Post + </button> + </form> + </div> + ) +} \ No newline at end of file diff --git a/components/post-item.tsx b/components/post-item.tsx new file mode 100644 index 0000000..f2cbce7 --- /dev/null +++ b/components/post-item.tsx @@ -0,0 +1,48 @@ +import CommentButton from "./comment-button"; +import LikeButton from "./like-button"; + +type messageType = any // Prisma.PostUncheckedCreateInput +type messageItemProps = { + msg: messageType; +}; + +export default function PostItem({ msg }: messageItemProps) { + if (!msg.id) { + return <div></div>; + } + return ( + <div className="flex border-b border-gray-200 py-4"> + <div className="flex-shrink-0"> + <div className="h-10 w-10 rounded-full bg-gray-300"></div> {/* Profile picture */} + </div> + <div className="ml-4 flex flex-col flex-grow"> + <div> + <div className="flex items-center"> + <span className="font-bold mr-2">{msg.user.name}</span> + <span className="text-gray-500 text-sm"> + {formatDate(new Date(msg.createdAt!))} + </span> + </div> + <div className="text-gray-800">{msg.content}</div> + </div> + <div className="mt-4 flex"> + <div className="bg-gray-200 rounded-lg py-10 px-20 mr-2"> + {/* potential Image */} + </div> + </div> + <div className="flex justify-end" > + <LikeButton data={msg} /> + <CommentButton data={msg} /> + </div> + </div> + </div> + ) +}; + +function formatDate(date: Date) { + return date.toLocaleDateString("en-US", { + day: "numeric", + month: "short", + year: "numeric" + }); +} \ No newline at end of file -- GitLab