diff --git a/app/(content)/(home)/home/page.tsx b/app/(content)/(home)/home/page.tsx index 6413a9e2c37ce3f8c91a266b87ab01725a131ac7..c0ce5746dfd6fab464c277d1ca8324b21a6ab98b 100644 --- a/app/(content)/(home)/home/page.tsx +++ b/app/(content)/(home)/home/page.tsx @@ -1,10 +1,22 @@ +import LikeButton from "@/components/LikeButton"; import PostMessageForm from "@/components/post-messages"; import { prisma } from "@/prisma/db"; +import { Prisma} from "@prisma/client" +type likeType = Prisma.LikeUncheckedCreateInput +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 +26,69 @@ 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> */} + <PostMessageForm data={messages}/> {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) => { + 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.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> + <LikeButton data={{ + postId: msg.id, + author: msg.author + }}/> + <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 0000000000000000000000000000000000000000..7b5b87f1ec81cfe2ffdd14a5df29b51f4c8b9f0e --- /dev/null +++ b/app/api/likes/likeService.ts @@ -0,0 +1,69 @@ +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): Promise<likeType | undefined> { +//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){ + console.log("like is null") + throw Error("Message was not liked by this user") + } + + await prisma.like.delete({ + where: { + id: actualLike.id + } + }) + + const msg = await prisma.message.update({ + where: { + id: like.postId + }, + data:{ + likeCount: {increment: -1} + } + }) + + return undefined; + + } catch{ + + const createdLike = await prisma.like.create({ + data:{ + postId: like.postId, + author: like.author + } + }) + + const updatedMessage = await prisma.message.update({ + where: { + id: like.postId + }, + data:{ + likeCount: {increment: 1} + } + }) + + return createdLike + } + + +} diff --git a/app/api/likes/route.ts b/app/api/likes/route.ts new file mode 100644 index 0000000000000000000000000000000000000000..15c6d33000e90db02e37fbc3deb48c296d3f9a99 --- /dev/null +++ b/app/api/likes/route.ts @@ -0,0 +1,21 @@ +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:") + try { + + const msg = await putLike(data) + return NextResponse.json({ status: 200, message: 'Like handled' }) + + } catch (error) { + console.log("fail" + error); + return NextResponse.json(error, { status: 500 }); + } +} \ No newline at end of file diff --git a/app/api/messages/route.ts b/app/api/messages/route.ts index aa12a6ff6e7c4ef2dd0aabe6d1ed86b2cac33f3d..4f648aef330021faf89f9794b761229807cddef8 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/LikeButton.tsx b/components/LikeButton.tsx new file mode 100644 index 0000000000000000000000000000000000000000..c99f7d3072a5f5fb310de42afee4b7015b74dec1 --- /dev/null +++ b/components/LikeButton.tsx @@ -0,0 +1,43 @@ +"use client" + +import { Message } from "@prisma/client" +import { useRouter } from "next/navigation"; +import { prisma } from "@/prisma/db"; +import { Prisma} from "@prisma/client" +type likeType = Prisma.LikeUncheckedCreateInput + +import { startTransition, useState } from "react" + +export default function LikeButton(props: { data: likeType }) { + const router = useRouter(); + + async function postLike(e: any) { + e.preventDefault() + const msgLikeData = props.data; + const likeData = {} as likeType + likeData.author = msgLikeData.author + likeData.postId = msgLikeData.postId + + const response = await fetch('http://localhost:3000/api/likes', { + method: 'PUT', + body: JSON.stringify(likeData) + }) + + 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() + } + + return ( + <div> + <form onSubmit={postLike}> + <button type="submit" className="mt-2 bg-gray-300 text-gray-800 px-4 py-2 rounded float-right"> + Like + </button> + </form> + </div> + ) +} \ No newline at end of file diff --git a/components/post-messages.tsx b/components/post-messages.tsx index cccfdcb84d8bedb7db54d71e2c358d453b51f5dc..e45e09bd0faf53cb23609e267b26ef1f748b90df 100644 --- a/components/post-messages.tsx +++ b/components/post-messages.tsx @@ -1,28 +1,64 @@ "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" 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 deac6a96cc0413b47f3591405382410518e70887..7be1448ba5d3e2658d593cd2f189b198bd8c536c 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