diff --git a/app/(content)/(user)/[userid]/followers/page.tsx b/app/(content)/(user)/[userid]/followers/page.tsx index 487621473dbbfa03f1e9c4260140440f3cf4a07b..4c361b2adaaa51f9f466223ebf5638764c54d82c 100644 --- a/app/(content)/(user)/[userid]/followers/page.tsx +++ b/app/(content)/(user)/[userid]/followers/page.tsx @@ -1,7 +1,60 @@ -export default async function Followers() { + +import { UserAvatar } from "@/components/user-avatar"; +import { db } from "@/lib/db"; +import { User } from "@prisma/client"; +import { getServerSession } from "next-auth"; + +export default async function UserFollowers({ params }: { params: { userid: string } }) { + // const session = await getServerSession(authOptions); + + // if (!session) { + // return <div>Loading...</div>; + // } + + const fullUser = await db.user.findFirst({ + where: { + username: params.userid + }, + include: { + following: true, + followers: true + } + }) + + + const followers = await db.user.findMany({ + where: { + following: { + every: { + followerId: { not: undefined } + } + }, + followers: { + every: { + followingId: fullUser?.id + } + } + } + }) + console.log(fullUser?.id) + console.log(followers) + return ( <div> <h1>Followers Page WIP</h1> + {followers?.map((follower: User) => ( + <div key={follower.id}> {follower.id} <UserAvatar + user={{ username: follower.name || null, image: follower.image || null }} + className="h-20 w-20 -mt-50" /> + + <div className="ml-6 md:ml-12 space-y-3"> + <h1 className="text-2xl font-bold">{follower.name}</h1> + <h1 className="text-md text-sky-500">@{follower.username}</h1> + </div> + </div> + ))} </div> ) -} \ No newline at end of file +} + + diff --git a/app/(content)/(user)/[userid]/page.tsx b/app/(content)/(user)/[userid]/page.tsx index 35f635bb6b95e6f119fb7dd9de3c2778ac976d00..62fdacdcaadfbae2e6571760db6a5ba13a94d005 100644 --- a/app/(content)/(user)/[userid]/page.tsx +++ b/app/(content)/(user)/[userid]/page.tsx @@ -1,3 +1,4 @@ +import FollowButton from "@/components/following-button" import GameItem from "@/components/game-item" import { AspectRatio } from "@/components/ui/aspect-ratio" import { Card } from "@/components/ui/card" @@ -10,23 +11,37 @@ import { redirect } from "next/navigation" export default async function User({ params }: { params: { userid: string } }) { - - const user = await db.user.findFirst({ + const user = await getCurrentUser() + + /* if (user?.username !== params.userid) { + redirect('/') + } */ + + const sessionUser = await db.user.findFirst({ where: { - username: params.userid + id: user?.id + }, + include: { + following: true, + followers: true } }) - if(!user){ - redirect('/') - } - const fullUser = await db.user.findFirst({ where: { - id: user.id + username: params.userid + }, + include: { + following: true, + followers: true } }) + if (!fullUser) { + redirect('/') + } + + let favoritegames = undefined let playingGames = undefined let finishedGames = undefined @@ -44,6 +59,7 @@ export default async function User({ params }: { params: { userid: string } }) { if (fullUser?.planningGameList?.length !== 0) { planningGames = await getFavoriteGames(fullUser?.planningGameList!) } + return ( <> <div className="main-content h-full"> @@ -61,15 +77,19 @@ export default async function User({ params }: { params: { userid: string } }) { </div> <div className="p-6 md:p-12 ss:flex"> <UserAvatar - user={{ username: user.username, image: user.image || null }} + user={{ username: fullUser.username, image: fullUser.image || null }} className="h-52 w-52 -mt-36" /> <div className="ml-6 md:ml-12 space-y-3"> - <h1 className="text-2xl font-bold">{user.name}</h1> - <h1 className="text-md text-sky-500">@{user.username}</h1> - {/* <h1 className="pt-3">{user.bio}</h1> */} + <h1 className="text-2xl font-bold">{fullUser.name}</h1> + <h1 className="text-md text-sky-500">@{fullUser.username}</h1> + {/* <h1 className="pt-3">{fullUser.bio}</h1> */} + </div> + <div className="flex justify-start ml-6 md:ml-12 space-y-3"> + <FollowButton user={sessionUser!} followingId={fullUser?.id!} /> </div> </div> + <div className="px-6 md:px-12"> {/* <div className="border-b border-gray-400 dark:border-gray-200" /> */} {/* gweets */} diff --git a/app/api/followers/route.ts b/app/api/followers/route.ts new file mode 100644 index 0000000000000000000000000000000000000000..524a88d3c0a69af19be71a22740a1cbc074a27b0 --- /dev/null +++ b/app/api/followers/route.ts @@ -0,0 +1,85 @@ +import { db } from "@/lib/db"; +import { getCurrentUser } from "@/lib/session"; +import { User } from "@prisma/client"; +import { revalidatePath } from "next/cache"; +import { NextRequest, NextResponse } from "next/server"; + +export async function GET(req: NextRequest) { + const sessionUser = await getCurrentUser(); + + if (!sessionUser) { + return NextResponse.json({ status: 401, message: 'Unauthorized' }); + } + let follows = undefined; + + try { + follows = await db.follows.findMany({ + where: { + followerId: sessionUser.id + } + }); + } catch (error) { + console.log(error) + } + + return NextResponse.json({ status: 200, message: "fetched follows", follows }) +} + +export async function PUT(req: NextRequest) { + const sessionUser = await getCurrentUser(); + + const data = await req.json() + + if (!sessionUser) { + return NextResponse.json({ status: 401, message: 'Unauthorized' }); + } + + try { + const dbUser = await db.user.findFirst({ + where: { + id: sessionUser.id + } + }); + + const follow = await db.follows.findFirst({ + where: { + followerId: sessionUser.id, + followingId: data.followingId + } + }); + console.log(follow) + + if (follow) { + // User is already following, so unfollow + console.log("delete follow") + const delfollow = await db.follows.delete({ + where: { + followerId_followingId: { + followerId: sessionUser.id, + followingId: data.followingId + } + + } + }) + console.log("del follow:", delfollow) + } else { + // User is not following, so follow + console.log("create follow") + await db.follows.create({ + data: { + followerId: sessionUser.id, + followingId: data.followingId + }, + }); + + } + } catch (error) { + console.log(error) + } + const path = req.nextUrl.searchParams.get('path') || '/'; + revalidatePath(path); + + return NextResponse.json({ status: 200, message: 'Follow handled' }) + + +} \ No newline at end of file diff --git a/components/following-button.tsx b/components/following-button.tsx new file mode 100644 index 0000000000000000000000000000000000000000..7ddef4470e496cabf935f33d73c9f9b53c9f5950 --- /dev/null +++ b/components/following-button.tsx @@ -0,0 +1,70 @@ +"use client" + +// import { PrismaClient } from '@prisma/client'; +import { startTransition, useEffect, useState } from 'react'; +import { Button } from './ui/button'; +import { Prisma, User, Follows } from '@prisma/client'; +import { useRouter } from "next/navigation"; + +// 1: Define a type that includes the relation to `Post` +const userWithFollows = Prisma.validator<Prisma.UserArgs>()({ + include: { followers: true, following: true }, +}) + +// 2: Define a type that only contains a subset of the scalar fields +const userPersonalData = Prisma.validator<Prisma.UserArgs>()({ + select: { email: true, name: true }, +}) + +// 3: This type will include a user and all their posts +type UserWithFollows = Prisma.UserGetPayload<typeof userWithFollows> + + +export default function FollowButton({ user, followingId }: { user: UserWithFollows; followingId: string }) { + const [isFollowing, setIsFollowing] = useState(false); + const [follows, setFollows] = useState([]); + const [buttonPressed, setButtonPress] = useState(false); + const router = useRouter(); + + async function fetchFollows() { + + try { + const response = await fetch('/api/followers') + + const data = await response.json() + setFollows(data.follows) + setIsFollowing(false) + data.follows?.forEach((f: Follows) => { + + if (f.followerId == user.id && f.followingId == followingId) { + setIsFollowing(true) + return; + } + }) + } catch (error) { + + } + } + useEffect(() => { + fetchFollows() + }, [buttonPressed]) + + async function handleFollow(e: any) { + e.preventDefault() + + const response = await fetch('/api/followers', { + method: 'PUT', + body: JSON.stringify({ user, followingId }) + }) + + setButtonPress(!buttonPressed) + } + + console.log(isFollowing) + + return ( + <Button onClick={handleFollow}> + {isFollowing ? 'Unfollow' : 'Follow'} + </Button> + ); +} \ No newline at end of file