From 01d2d9b01a6e404faf643b2e9258c5323506c0b2 Mon Sep 17 00:00:00 2001 From: "DESKTOP-9FO96TP\\hehexd" <davidjakszta@outlook.de> Date: Sun, 28 May 2023 18:10:50 +0200 Subject: [PATCH] added Like Model and Likes to Message Model, added css to Home Page --- app/(content)/(home)/home/page.tsx | 84 ++++++++++++++++++++++++++++-- app/api/likes/likeService.ts | 64 +++++++++++++++++++++++ app/api/likes/route.ts | 40 ++++++++++++++ app/api/messages/route.ts | 20 +++++++ components/PostMessageForm.tsx | 45 ++++++++++++++-- prisma/schema.prisma | 9 ++++ 6 files changed, 254 insertions(+), 8 deletions(-) create mode 100644 app/api/likes/likeService.ts create mode 100644 app/api/likes/route.ts diff --git a/app/(content)/(home)/home/page.tsx b/app/(content)/(home)/home/page.tsx index 99a7aa8..f1bc58e 100644 --- a/app/(content)/(home)/home/page.tsx +++ b/app/(content)/(home)/home/page.tsx @@ -1,10 +1,20 @@ import PostMessageForm from "@/components/PostMessageForm"; import { prisma } from "@/prisma/db"; +import { Prisma} from "@prisma/client" +type messageType = Prisma.MessageUncheckedCreateInput +type messageItemProps = { + msg: messageType; + }; export default async function HomePage() { let messages = null try { - messages = await prisma.message.findMany() + messages = await prisma.message.findMany({ + orderBy:{ + sentAt: "desc" + } + }) + } catch (error) { console.log("the database is not running, try: 'npx prisma migrate dev --name init' if you want to use the database") } @@ -14,16 +24,82 @@ export default async function HomePage() { <h1>Home WIP</h1> <p>This will be where all messages show up.</p> <p>Needs a reload after posting!!</p> - + <PostMessageForm data={messages}></PostMessageForm> {messages ? <> {messages.map((msg) => ( - <li key={msg.id}> author: {msg.author} message: {msg.content} sentAt: {msg.sentAt?.toString()} </li> + <MessageItem msg={msg} key={msg.id} /> ))} - <PostMessageForm data={messages}></PostMessageForm> + </> : <p>no messages / no database</p>} </div> ) +} + +/* const MessageItem = ({ msg }: messageItemProps) => { + 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> + </div> + <div className="ml-4"> + <div className="flex items-center"> + <span className="font-bold mr-2">{msg.author}</span> + <span className="text-gray-500 text-sm"> + {formatDate(new Date(msg.sentAt!))} + </span> + </div> + <div className="text-gray-800">{msg.content}</div> + </div> + </div> + ); + }; */ + + const MessageItem = ({ msg }: messageItemProps) => { + 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.author}</span> + <span className="text-gray-500 text-sm"> + {formatDate(new Date(msg.sentAt!))} + </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> + + <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/likes/likeService.ts b/app/api/likes/likeService.ts new file mode 100644 index 0000000..9368aaf --- /dev/null +++ b/app/api/likes/likeService.ts @@ -0,0 +1,64 @@ +import { prisma } from "@/prisma/db" +import { Prisma} from "@prisma/client" + +type likeType = Prisma.LikeUncheckedCreateInput + +/** + * Creates like if user has not liked this post. + * Deletes like if user has liked post already. + * + */ + +export async function putLike(like: likeType){ +//check if like exists by this user and for this post +// if exists delete +//if not create + try{ + const actualLike = await prisma.like.findFirst({ + where: { + id: like.id, + postId: like.postId, + author: like.author + } + }) + + if(actualLike == null){ + throw Error("Message was not liked by this user") + } + + prisma.like.delete({ + where: { + id: actualLike?.id + } + }) + + prisma.message.update({ + where: { + id: like.postId + }, + data:{ + likeCount: {increment: 1} + } + }) + + } catch{ + prisma.like.create({ + data:{ + postId: like.postId, + author: like.author, + gameId: like.gameId + } + }) + + prisma.message.update({ + where: { + id: like.postId + }, + data:{ + likeCount: {increment: -1} + } + }) + } + + +} diff --git a/app/api/likes/route.ts b/app/api/likes/route.ts new file mode 100644 index 0000000..3d144b0 --- /dev/null +++ b/app/api/likes/route.ts @@ -0,0 +1,40 @@ +import { NextRequest, NextResponse } from "next/server"; +import { prisma } from "@/prisma/db" +import { Prisma} from "@prisma/client" +import { putLike } from "./likeService"; + +type like = Prisma.LikeUncheckedCreateInput + +export async function PUT(req: NextRequest) { + const data:like = await req.json() + + console.log("router data: " + data, "status:") + + console.log(data) + try { + await putLike(data) + return NextResponse.json({ status: 200, message: 'Like handled' }) + + } catch (error) { + console.log("fail" + error); + return NextResponse.json(error, { status: 500 }); + } +} + +export async function DELETE(req: NextRequest, res:NextResponse) { + const data = await req.json() + console.log("router data: " + data, "status:") + + console.log(data) + try { + const messages = await prisma.message.findMany({ + + }) + + 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/app/api/messages/route.ts b/app/api/messages/route.ts index aa12a6f..4f648ae 100644 --- a/app/api/messages/route.ts +++ b/app/api/messages/route.ts @@ -19,4 +19,24 @@ export async function POST(req: NextRequest) { // res.status(400) } console.log("post") +} + +export async function GET(req: NextRequest, res:NextResponse) { + const data = await req.json() + console.log("router data: " + data, "status:") + + console.log(data) + try { + const messages = await prisma.message.findMany({ + orderBy:{ + sentAt: "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/PostMessageForm.tsx b/components/PostMessageForm.tsx index cccfdcb..29a2db3 100644 --- a/components/PostMessageForm.tsx +++ b/components/PostMessageForm.tsx @@ -1,28 +1,65 @@ "use client" import { Message } from "@prisma/client" -import { useState } from "react" +import { useRouter } from "next/navigation"; +import { prisma } from "@/prisma/db"; +import { Prisma} from "@prisma/client" +type messageType = Prisma.MessageUncheckedCreateInput + +import { startTransition, useState } from "react" export default function PostMessageForm(props: { data: Message[] | null }) { - const [formData, setFormData] = useState({}) + + const [formData, setFormData] = useState<messageType>({content:""} as messageType); // const [messagesState, setMessages] = useState(props.data) + const router = useRouter(); async function postMessage(e: any) { e.preventDefault() // setMessages([...messagesState, formData]) console.log(formData) + formData.author = "Default Author" + formData.likeCount = 0; const response = await fetch('http://localhost:3000/api/messages', { 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.content.length; + const isOverLimit = characterCount > 1000; + + const handleInputChange = (e: React.ChangeEvent<HTMLTextAreaElement>) => { + const { value } = e.target; + setFormData({ content: value }); + }; + return ( <div> <form onSubmit={postMessage}> - <input type="text" placeholder="content" name="content" onChange={e => setFormData({ ...formData, content: e.target.value })} /> - <button type="submit">Post Message</button> + <textarea + placeholder="Write something..." + name="content" + value={formData.content} + 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> ) diff --git a/prisma/schema.prisma b/prisma/schema.prisma index deac6a9..7be1448 100644 --- a/prisma/schema.prisma +++ b/prisma/schema.prisma @@ -16,6 +16,15 @@ model Message { gameId String? title String? content String + likeCount Int? @default (0) sentAt DateTime? @default(now()) updatedAt DateTime? @updatedAt } + +model Like { + id Int @id @default(autoincrement()) + postId Int + author String? + gameId String? + likedAt DateTime? @default(now()) +} \ No newline at end of file -- GitLab