diff --git a/app/(content)/(gaming)/games/[gameid]/page.tsx b/app/(content)/(gaming)/games/[gameid]/page.tsx index 9decb17582e3cff2bd46fda773cd1937e10926b7..b3f19242f215ad24b24d85c8f29fdc6604a6e0df 100644 --- a/app/(content)/(gaming)/games/[gameid]/page.tsx +++ b/app/(content)/(gaming)/games/[gameid]/page.tsx @@ -1,4 +1,8 @@ -import AddGameToList from "@/components/addGameToList"; +import AddGameDropdown from "@/components/add-game-dropdown"; +import AddGameToFinishedList from "@/components/add-game-to-finished-list"; +import AddGameToPlanList from "@/components/add-game-to-plan-list"; +import AddGameToPlayingList from "@/components/add-game-to-playing-list"; +import AddGameToFavList from "@/components/addGameToFavList"; import { AspectRatio } from "@/components/ui/aspect-ratio"; import { Button } from "@/components/ui/button"; import { Card } from "@/components/ui/card"; @@ -52,7 +56,11 @@ export default async function GameDetail({ params }: { params: { gameid: string priority className="object-cover rounded-lg" /> </Card> + <div className="flex justify-start p-6"> + <AddGameDropdown fullUser={fullUser!} gameid={params.gameid} /> + </div> </div> + <div className="ml-6 md:ml-12 space-y-3"> <h1 className="text-2xl font-bold">{data[0].name}</h1> <h1>released on{' '} @@ -62,6 +70,7 @@ export default async function GameDetail({ params }: { params: { gameid: string <h1 className="pt-3">{data[0].summary}</h1> <div className="pt-6"> + <h1 className="mb-2">Genres</h1> <div className="flex flex-wrap gap-2"> {data[0].genres.map((genre, i) => { @@ -82,7 +91,7 @@ export default async function GameDetail({ params }: { params: { gameid: string <div className="px-6 md:px-12"> <div className="border-b border-gray-400 dark:border-gray-200" /> <div className="p-6 w-full flex justify-center"> - {user && <AddGameToList userGameList={fullUser?.favGameList!} gameId={params.gameid} />} + {user && <AddGameToFavList userGameList={fullUser?.favGameList!} gameId={params.gameid} />} </div> {/* comments */} </div> diff --git a/app/(content)/(user)/[userid]/page.tsx b/app/(content)/(user)/[userid]/page.tsx index 6b88b4ca3d8ce7b6318acae30604211a920a2c9a..2698ce45c3acb879ecf39e1f936b93d2bfa39c1a 100644 --- a/app/(content)/(user)/[userid]/page.tsx +++ b/app/(content)/(user)/[userid]/page.tsx @@ -21,66 +21,115 @@ export default async function User({ params }: { params: { userid: string } }) { } }) + let favoritegames = undefined + let playingGames = undefined + let finishedGames = undefined + let planningGames = undefined + if (fullUser?.favGameList?.length !== 0) { favoritegames = await getFavoriteGames(fullUser?.favGameList!) } - + if (fullUser?.favGameList?.length !== 0) { + playingGames = await getFavoriteGames(fullUser?.playingGameList!) + } + if (fullUser?.favGameList?.length !== 0) { + finishedGames = await getFavoriteGames(fullUser?.finishedGameList!) + } + if (fullUser?.favGameList?.length !== 0) { + planningGames = await getFavoriteGames(fullUser?.planningGameList!) + } return ( - <div className="main-content h-full"> - <Card className="w-full h-full overflow-hidden"> - <div className="h-64 overflow-hidden"> - <AspectRatio ratio={889 / 500} className="bg-slate-600 dark:bg-slate-400"> - {/* profile banner */} - {/* <Image + <> + <div className="main-content h-full"> + <Card className="w-full h-full overflow-hidden"> + <div className="h-64 overflow-hidden"> + <AspectRatio ratio={889 / 500} className="bg-slate-600 dark:bg-slate-400"> + {/* profile banner */} + {/* <Image src={ } alt={ } fill priority className="object-center" /> */} - </AspectRatio> - </div> - <div className="p-6 md:p-12 ss:flex"> - <UserAvatar - user={{ username: user.username, image: user.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> */} + </AspectRatio> </div> + <div className="p-6 md:p-12 ss:flex"> + <UserAvatar + user={{ username: user.username, image: user.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> */} + </div> + </div> + <div className="px-6 md:px-12"> + {/* <div className="border-b border-gray-400 dark:border-gray-200" /> */} + {/* gweets */} + </div> + </Card > + <div className="side-content"> + <Card className="p-6 grid items-start gap-2 bg-secondary"> + <h1>Media</h1> + <div className="grid grid-cols-1 gap-4"> + {Array.from({ length: 2 }, (_, i) => i + 1).map((i) => { + return ( + <Skeleton key={i} className="aspect-[264/374] bg-gray-300" /> + ) + })} + </div> + </Card> </div> - <div className="px-6 md:px-12"> - {/* <div className="border-b border-gray-400 dark:border-gray-200" /> */} - {/* gweets */} - </div> - </Card > - <div className="side-content"> - <Card className="p-6 grid items-start gap-2 bg-secondary"> - <h1>Media</h1> - <div className="grid grid-cols-1 gap-4"> - {Array.from({ length: 2 }, (_, i) => i + 1).map((i) => { - return ( - <Skeleton key={i} className="aspect-[264/374] bg-gray-300" /> - ) - })} + + + </div > + <div className="main-content"> + <Card className="w-full h-full overflow-hidden p-6 md:p-12" > + <h1 className="text-2xl font-bold pb-3">Your Favorite Games</h1> + <div className="grid grid-cols-1 ss:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4 2xl:grid-cols-5 gap-4 lg:gap-8 items-center"> + {favoritegames ? favoritegames.map((game: IGame) => ( + <GameItem id={game.id} name={game.name} cover={game.cover} key={game.id} /> + )) + : + <p>You have no favorites currently</p>} </div> </Card> - </div> - <Card className="w-full h-full overflow-hidden p-6 md:p-12" > - <h1 className="text-2xl font-bold pb-3">Your Favorite Games</h1> - <div className="grid grid-cols-1 ss:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4 2xl:grid-cols-5 gap-4 lg:gap-8 items-center"> - {favoritegames ? favoritegames.map((game: IGame) => ( - <GameItem id={game.id} name={game.name} cover={game.cover} key={game.id} /> - )) - : - <p>You have no favorites currently</p>} - </div> - </Card> - </div > + <Card className="w-full h-full overflow-hidden p-6 md:p-12" > + <h1 className="text-2xl font-bold pb-3">Currently Playing</h1> + <div className="grid grid-cols-1 ss:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4 2xl:grid-cols-5 gap-4 lg:gap-8 items-center"> + {playingGames ? playingGames.map((game: IGame) => ( + <GameItem id={game.id} name={game.name} cover={game.cover} key={game.id} /> + )) + : + <p>You are currently not playing any games</p>} + </div> + </Card> + <Card className="w-full h-full overflow-hidden p-6 md:p-12" > + <h1 className="text-2xl font-bold pb-3">Planning on Playing</h1> + <div className="grid grid-cols-1 ss:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4 2xl:grid-cols-5 gap-4 lg:gap-8 items-center"> + {planningGames ? planningGames.map((game: IGame) => ( + <GameItem id={game.id} name={game.name} cover={game.cover} key={game.id} /> + )) + : + <p>You are currently not planning on playing any games</p>} + </div> + </Card> + <Card className="w-full h-full overflow-hidden p-6 md:p-12" > + <h1 className="text-2xl font-bold pb-3">Finished Games</h1> + <div className="grid grid-cols-1 ss:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4 2xl:grid-cols-5 gap-4 lg:gap-8 items-center"> + {finishedGames ? finishedGames.map((game: IGame) => ( + <GameItem id={game.id} name={game.name} cover={game.cover} key={game.id} /> + )) + : + <p>You have no Games in your finished-Games-List </p>} + </div> + </Card> + </div> + </> ) } \ No newline at end of file diff --git a/app/api/gamelists/route.ts b/app/api/gamelists/route.ts new file mode 100644 index 0000000000000000000000000000000000000000..fa9640edae83082c5d78b918a304dbb37eae900d --- /dev/null +++ b/app/api/gamelists/route.ts @@ -0,0 +1,54 @@ +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 PUT(req: NextRequest) { + const sessionUser = await getCurrentUser(); + + const data: User = await req.json() + console.log("userid", sessionUser!.id, "formdataid", data.id) + if (!sessionUser || sessionUser.id != data.id) { + return NextResponse.json({ status: 401, message: 'Unauthorized' }); + } + console.log("put list") + try { + const dbUser = await db.user.findFirst({ + where: { + id: sessionUser.id + }, + select: { + planningGameList: true, + playingGameList: true, + finishedGameList: true + }, + }); + + if (dbUser) { + if (!data.finishedGameList) data.finishedGameList = dbUser?.finishedGameList + if (!data.planningGameList) data.planningGameList = dbUser?.planningGameList + if (!data.playingGameList) data.playingGameList = dbUser?.playingGameList + + await db.user.update({ + where: { + id: sessionUser.id + }, + data: { + finishedGameList: data.finishedGameList, + planningGameList: data.planningGameList, + playingGameList: data.playingGameList + } + }) + } + } catch (error) { + + } + const path = req.nextUrl.searchParams.get('path') || '/'; + revalidatePath(path); + + return NextResponse.json({ status: 201, message: 'Game Hinzugefügt' }) + + +} \ No newline at end of file diff --git a/app/page.tsx b/app/page.tsx index 473b33336e888c8b57607b0ebc04e944d92c4357..783eccea21b13263bb379f7c8e4a036a3efdab44 100644 --- a/app/page.tsx +++ b/app/page.tsx @@ -13,7 +13,7 @@ export default async function IndexPage() { <section className="space-y-6 pb-8 pt-6 md:pb-12 md:pt-10 lg:py-32"> <div className="container flex max-w-[64rem] flex-col items-center gap-4 text-center"> <div className="flex items-center"> - <Link href="/" className={cn("rounded-full p-3 hover:bg-accent")}> + <Link href="/home" className={cn("rounded-full p-3 hover:bg-accent")}> <GameUnityLogo className="h-8 w-8" /> </Link> </div> diff --git a/components/add-game-dropdown.tsx b/components/add-game-dropdown.tsx new file mode 100644 index 0000000000000000000000000000000000000000..e8fb0d44fb746aa0552f26828262011c031c39b7 --- /dev/null +++ b/components/add-game-dropdown.tsx @@ -0,0 +1,33 @@ +"use client" + +import { useState } from "react"; +import { Card } from "./ui/card"; +import GameItem from "./game-item"; +import { IGame } from "@/types/igdb-types"; +import { User } from "@prisma/client"; +import AddGameToPlanList from "./add-game-to-plan-list"; +import AddGameToPlayingList from "./add-game-to-playing-list"; +import AddGameToFinishedList from "./add-game-to-finished-list"; +import { Select, SelectContent, SelectGroup, SelectItem, SelectLabel, SelectTrigger, SelectValue } from "./ui/select"; + +export default function AddGameDropdown(props: { gameid: string, fullUser: User }) { + return ( + <> + <Select> + <SelectTrigger className={`bg-background border-full w-32 h-8}`}> + <SelectValue placeholder="Status" /> + </SelectTrigger> + <SelectContent> + <SelectGroup> + <SelectLabel>Status</SelectLabel> + <AddGameToPlanList user={props.fullUser!} gameId={props.gameid} /> + <AddGameToFinishedList user={props.fullUser!} gameId={props.gameid} /> + <AddGameToPlayingList user={props.fullUser!} gameId={props.gameid} /> + </SelectGroup> + </SelectContent> + </Select> + + </> + ) + +} diff --git a/components/add-game-to-finished-list.tsx b/components/add-game-to-finished-list.tsx new file mode 100644 index 0000000000000000000000000000000000000000..40b4e1dbf77977388d0a43295237314f5b921f33 --- /dev/null +++ b/components/add-game-to-finished-list.tsx @@ -0,0 +1,96 @@ +"use client" + +import { User } from "@prisma/client"; +import { useRouter } from "next/navigation"; +import { startTransition } from "react"; +import { Button } from "./ui/button"; + +export default function AddGameToFinishedList(props: { gameId: string, user: User }) { + + const router = useRouter(); + const gameId = parseFloat(props.gameId); + const user = props.user; + + let formData: { + id: String; + gameId: Number; + add: boolean; + planningGameList: number[] | undefined; + playingGameList: number[] | undefined; + finishedGameList: number[] | undefined; + } = { + id: "", + gameId: -1, + add: true, + planningGameList: undefined, + playingGameList: undefined, + finishedGameList: undefined + }; + + async function removeGame(e: any) { + e.preventDefault() + + formData.id = user.id; + formData.finishedGameList = props.user.finishedGameList.filter((id) => id !== gameId) + console.log(formData.finishedGameList) + const response = await fetch('/api/gamelists', { + method: 'PUT', + 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() + } + + async function addGame(e: any) { + e.preventDefault() + + formData.id = user.id; + props.user.finishedGameList.push(gameId) + formData.finishedGameList = props.user.finishedGameList; + const response = await fetch('/api/gamelists', { + method: 'PUT', + 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() + } + + + let button = <div></div>; + try { + if (!props.user.finishedGameList.includes(parseFloat(props.gameId))) { + button = ( + <form onSubmit={addGame}> + <Button type="submit" size="lg"> + Add Game To finished-playing-List + </Button> + </form> + ) + } else { + button = ( + <form onSubmit={removeGame}> + <Button type="submit" size="lg" variant={"secondary"}> + Remove Game From finished-playing-List + </Button> + </form> + ) + } + } catch (error) { + // throw new Error("Failed to check finished-playing-List"); + } + + return ( + button + ) +} + diff --git a/components/add-game-to-plan-list.tsx b/components/add-game-to-plan-list.tsx new file mode 100644 index 0000000000000000000000000000000000000000..b2c1e45426adea91cc01f81df1f43307588ee6ca --- /dev/null +++ b/components/add-game-to-plan-list.tsx @@ -0,0 +1,96 @@ +"use client" + +import { User } from "@prisma/client"; +import { useRouter } from "next/navigation"; +import { startTransition } from "react"; +import { Button } from "./ui/button"; + +export default function AddGameToPlanList(props: { gameId: string, user: User }) { + + const router = useRouter(); + const gameId = parseFloat(props.gameId); + const user = props.user; + + let formData: { + id: String; + gameId: Number; + add: boolean; + planningGameList: number[] | undefined; + playingGameList: number[] | undefined; + finishedGameList: number[] | undefined; + } = { + id: "", + gameId: -1, + add: true, + planningGameList: undefined, + playingGameList: undefined, + finishedGameList: undefined + }; + + async function removeGame(e: any) { + e.preventDefault() + + formData.id = user.id; + formData.planningGameList = props.user.planningGameList.filter((id) => id !== gameId) + console.log(formData.planningGameList) + const response = await fetch('/api/gamelists', { + method: 'PUT', + 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() + } + + async function addGame(e: any) { + e.preventDefault() + + formData.id = user.id; + props.user.planningGameList.push(gameId) + formData.planningGameList = props.user.planningGameList; + const response = await fetch('/api/gamelists', { + method: 'PUT', + 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() + } + + + let button = <div></div>; + try { + if (!props.user.planningGameList.includes(parseFloat(props.gameId))) { + button = ( + <form onSubmit={addGame}> + <Button type="submit" size="lg"> + Add Game To Planning-to-play-List + </Button> + </form> + ) + } else { + button = ( + <form onSubmit={removeGame}> + <Button type="submit" size="lg" variant={"secondary"}> + Remove Game From Planning-to-play-List + </Button> + </form> + ) + } + } catch (error) { + // throw new Error("Failed to check Planning-to-play-List"); + } + + return ( + button + ) +} + diff --git a/components/add-game-to-playing-list.tsx b/components/add-game-to-playing-list.tsx new file mode 100644 index 0000000000000000000000000000000000000000..befa763ba9d55009cc9204bfc64e4588d92c42b8 --- /dev/null +++ b/components/add-game-to-playing-list.tsx @@ -0,0 +1,96 @@ +"use client" + +import { User } from "@prisma/client"; +import { useRouter } from "next/navigation"; +import { startTransition } from "react"; +import { Button } from "./ui/button"; + +export default function AddGameToPlayingList(props: { gameId: string, user: User }) { + + const router = useRouter(); + const gameId = parseFloat(props.gameId); + const user = props.user; + + let formData: { + id: String; + gameId: Number; + add: boolean; + planningGameList: number[] | undefined; + playingGameList: number[] | undefined; + finishedGameList: number[] | undefined; + } = { + id: "", + gameId: -1, + add: true, + planningGameList: undefined, + playingGameList: undefined, + finishedGameList: undefined + }; + + async function removeGame(e: any) { + e.preventDefault() + + formData.id = user.id; + formData.playingGameList = props.user.playingGameList.filter((id) => id !== gameId) + console.log(formData.playingGameList) + const response = await fetch('/api/gamelists', { + method: 'PUT', + 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() + } + + async function addGame(e: any) { + e.preventDefault() + + formData.id = user.id; + props.user.playingGameList.push(gameId) + formData.playingGameList = props.user.playingGameList; + const response = await fetch('/api/gamelists', { + method: 'PUT', + body: JSON.stringify(formData) + }) + console.log("add game") + 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() + } + + + let button = <div></div>; + try { + if (!props.user.playingGameList.includes(parseFloat(props.gameId))) { + button = ( + <form onSubmit={addGame}> + <Button type="submit" size="lg"> + Add Game To currently-playing-List + </Button> + </form> + ) + } else { + button = ( + <form onSubmit={removeGame}> + <Button type="submit" size="lg" variant={"secondary"}> + Remove Game From currently-playing-List + </Button> + </form> + ) + } + } catch (error) { + // throw new Error("Failed to check playing-to-play-List"); + } + + return ( + button + ) +} + diff --git a/components/addGameToList.tsx b/components/addGameToFavList.tsx similarity index 88% rename from components/addGameToList.tsx rename to components/addGameToFavList.tsx index e6fa3aa672f893ad0936fd07c009e781172b0baa..9500d4d422a4daeb2cc578db608cad4b5411126c 100644 --- a/components/addGameToList.tsx +++ b/components/addGameToFavList.tsx @@ -4,7 +4,7 @@ import { useRouter } from "next/navigation"; import { startTransition } from "react"; import { Button } from "./ui/button"; -export default function AddGameToList(props: { userGameList: Number[], gameId: string }) { +export default function AddGameToFavList(props: { userGameList: Number[], gameId: string }) { const router = useRouter(); const gameId = props.gameId @@ -53,7 +53,7 @@ export default function AddGameToList(props: { userGameList: Number[], gameId: s button = ( <form onSubmit={addGame}> <Button type="submit" size="lg"> - Add Game To List + Add Game To Favorite List </Button> </form> ) @@ -61,13 +61,13 @@ export default function AddGameToList(props: { userGameList: Number[], gameId: s button = ( <form onSubmit={removeGame}> <Button type="submit" size="lg" variant={"secondary"}> - Remove Game From List + Remove Game From Favorite List </Button> </form> ) } } catch (error) { - throw new Error("Failed to fetch comments"); + // throw new Error("Failed to check list"); } return ( diff --git a/prisma/schema.prisma b/prisma/schema.prisma index cddebeaacf457174b34b98a06a6f6ececdd10269..341c014062452d6c924dd249dab700a2c0d64a16 100644 --- a/prisma/schema.prisma +++ b/prisma/schema.prisma @@ -62,7 +62,10 @@ model User { createdAt DateTime @default(now()) @map("created_at") updatedAt DateTime @default(now()) @map("updated_at") - favGameList Int[] + favGameList Int[] + planningGameList Int[] + playingGameList Int[] + finishedGameList Int[] accounts Account? sessions Session?