diff --git a/app/(content)/(user)/[userid]/followers/page.tsx b/app/(content)/(user)/[userid]/followers/page.tsx new file mode 100644 index 0000000000000000000000000000000000000000..2f59b81c09d4efb025d0bcef7ad9c29af0ccfe9a --- /dev/null +++ b/app/(content)/(user)/[userid]/followers/page.tsx @@ -0,0 +1,56 @@ +import FollowersList from "@/components/following-users"; +import { UserAvatar } from "@/components/user-avatar"; +import { db } from "@/lib/db"; +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: { + followers: { + every: { + followingId: fullUser?.id + } + } + } + }) + console.log(fullUser?.id) + console.log(followers) + + return ( + <div> + <h1>Followers Page WIP</h1> + {followers?.map((follower: any) => ( + <div key={follower.id}> {follower.id} <UserAvatar + user={{ name: 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> + {/* <h1 className="pt-3">{fullUser.bio}</h1> */} + </div> + </div> + + ))} + </div> + ) +} + + diff --git a/app/(content)/(user)/[userid]/page.tsx b/app/(content)/(user)/[userid]/page.tsx index f7eb0fe2efd3cac8d313b3a0ffc9164db8d6a719..f84f6b5000717431a6f9563009a4faaf90b7cebd 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" @@ -12,33 +13,53 @@ import { redirect } from "next/navigation" export default async function User({ params }: { params: { userid: string } }) { const user = await getCurrentUser() - if (user?.username !== params.userid) { - redirect('/') - } - const fullUser = await db.user.findFirst({ + /* if (user?.username !== params.userid) { + redirect('/') + } */ + + const sessionUser = await db.user.findFirst({ where: { id: user?.id + }, + include: { + following: true, + followers: true } }) + const fullUser = await db.user.findFirst({ + where: { + username: params.userid + }, + include: { + following: true, + followers: true + } + }) + + if (!fullUser) { + redirect('/') + } + let favoritegames = undefined let playingGames = undefined let finishedGames = undefined let planningGames = undefined - if (fullUser?.favGameList?.length !== 0) { + if (fullUser?.favGameList?.length !== 0 && fullUser?.favGameList?.length != undefined) { favoritegames = await getFavoriteGames(fullUser?.favGameList!) } - if (fullUser?.favGameList?.length !== 0) { + if (fullUser?.playingGameList?.length !== 0) { playingGames = await getFavoriteGames(fullUser?.playingGameList!) } - if (fullUser?.favGameList?.length !== 0) { + if (fullUser?.finishedGameList?.length !== 0) { finishedGames = await getFavoriteGames(fullUser?.finishedGameList!) } - if (fullUser?.favGameList?.length !== 0) { + if (fullUser?.planningGameList?.length !== 0) { planningGames = await getFavoriteGames(fullUser?.planningGameList!) } + return ( <> <div className="main-content h-full"> @@ -56,15 +77,19 @@ export default async function User({ params }: { params: { userid: string } }) { </div> <div className="p-6 md:p-12 ss:flex"> <UserAvatar - user={{ name: user.name || null, image: user.image || null }} + user={{ name: fullUser.name || null, 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" /> */} {/* tweets */} 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 index 420ecdc016ea82d2f78da72783b66dee0ac07c28..7ddef4470e496cabf935f33d73c9f9b53c9f5950 100644 --- a/components/following-button.tsx +++ b/components/following-button.tsx @@ -1,55 +1,70 @@ "use client" // import { PrismaClient } from '@prisma/client'; -import { useState } from 'react'; +import { startTransition, useEffect, useState } from 'react'; import { Button } from './ui/button'; +import { Prisma, User, Follows } from '@prisma/client'; +import { useRouter } from "next/navigation"; -// Muss in die API route -// const prisma = new PrismaClient(); +// 1: Define a type that includes the relation to `Post` +const userWithFollows = Prisma.validator<Prisma.UserArgs>()({ + include: { followers: true, following: true }, +}) -// async function getFollower(userId: number, followerId: number) { -// const follower = await prisma.follows.findFirst({ -// where: { -// followerId: followerId, -// followingId: userId, -// }, -// }); +// 2: Define a type that only contains a subset of the scalar fields +const userPersonalData = Prisma.validator<Prisma.UserArgs>()({ + select: { email: true, name: true }, +}) -// return follower; -// } +// 3: This type will include a user and all their posts +type UserWithFollows = Prisma.UserGetPayload<typeof userWithFollows> -export default function FollowButton({ userId, followerId }: { userId: number; followerId: number }) { + +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) + } - const handleFollow = async () => { - // const follower = await getFollower(userId, followerId); - - // if (follower) { - // // User is already following, so unfollow - // await prisma.follows.delete({ - // where: { - // followerId_followingId: { - // followerId: followerId, - // followingId: userId, - // }, - // }, - // }); - // setIsFollowing(false); - // } else { - // // User is not following, so follow - // await prisma.follows.create({ - // data: { - // followerId: followerId, - // followingId: userId, - // }, - // }); - // setIsFollowing(true); - // } - }; + console.log(isFollowing) return ( <Button onClick={handleFollow}> {isFollowing ? 'Unfollow' : 'Follow'} </Button> ); -} \ No newline at end of file +} \ No newline at end of file