diff --git a/app/(content)/(gaming)/games/[gameid]/page.tsx b/app/(content)/(gaming)/games/[gameid]/page.tsx index 9bd42b940c855e8ba538fe036cb9b64667764599..74c4ac9dfb8f53a0a7014a474dedca1cfb5a6f30 100644 --- a/app/(content)/(gaming)/games/[gameid]/page.tsx +++ b/app/(content)/(gaming)/games/[gameid]/page.tsx @@ -1,4 +1,4 @@ -import { getGame, getGames } from "@/lib/igdb"; +import { getGame } from "@/lib/igdb"; import { IGame } from "@/types/igdb-types"; import Image from "next/image"; @@ -10,7 +10,13 @@ export default async function GameDetail({ params }: { params: { gameid: string <div> <h1>Game Detail</h1> <h1>{data[0].name}</h1> - <Image src={data[0].cover.url} alt={data[0].name} width={264} height={374} priority={true} style={{ width: 'auto', height: 'auto' }} /> + <Image + src={data[0].cover.url} + alt={data[0].name} + width={264} + height={374} + priority={true} + style={{ width: 'auto', height: 'auto' }} /> <p>{data[0].summary}</p> </div> ) diff --git a/app/(content)/(gaming)/games/page.tsx b/app/(content)/(gaming)/games/page.tsx index a9c4a63b9da67cddb4d539f113f67c957d52bead..cacec504f4e0851e6f435fb3ff096d95b3d7f7b8 100644 --- a/app/(content)/(gaming)/games/page.tsx +++ b/app/(content)/(gaming)/games/page.tsx @@ -1,6 +1,6 @@ -import { InfiniteScrollGames } from "@/components/InfiniteScroll"; +import Sort from "@/components/filter-sort-games"; +import { InfiniteScrollGames } from "@/components/infinity-scroll"; import SearchInput from "@/components/search-input"; -import Sort from "@/components/sort-games"; // renders a list of games infinitely (presumably) export default async function GamesPage() { diff --git a/app/(content)/(home)/home/page.tsx b/app/(content)/(home)/home/page.tsx index 9e2171592672784fa90f82f1e9d3fa0399a6b925..c0ce5746dfd6fab464c277d1ca8324b21a6ab98b 100644 --- a/app/(content)/(home)/home/page.tsx +++ b/app/(content)/(home)/home/page.tsx @@ -1,5 +1,5 @@ import LikeButton from "@/components/LikeButton"; -import PostMessageForm from "@/components/PostMessageForm"; +import PostMessageForm from "@/components/post-messages"; import { prisma } from "@/prisma/db"; import { Prisma} from "@prisma/client" type likeType = Prisma.LikeUncheckedCreateInput diff --git a/app/(content)/layout.tsx b/app/(content)/layout.tsx index 63ac13663724c8099104ccfaef606dfee27ee603..0e27a5e2484fc79b7061b26b072adb93f36cda51 100644 --- a/app/(content)/layout.tsx +++ b/app/(content)/layout.tsx @@ -10,8 +10,8 @@ export default async function ContentLayout({ children, }: DashboardLayoutProps) { return ( - <div className="flex min-h-screen flex-col"> - <div className="flex-1 md:grid md:grid-cols-[220px_1fr] md:gap-6 lg:grid-cols-[240px_1fr] lg:gap-10"> + <div className="flex flex-col min-h-screen"> + <div className="mx-32 my-6 flex-1 md:grid md:grid-cols-[220px_1fr] md:gap-6 lg:grid-cols-[240px_1fr] lg:gap-10"> <aside className="hidden w-[200px] flex-col md:flex"> <div className="sticky top-0"> <DashboardNav items={dashboardConfig.sidebarNav} /> diff --git a/app/api/games/route.ts b/app/api/games/route.ts index f9191ca47e5455c03cd13fb6c9e727b1f41155fd..f411fce9454181f205c9f0e4c39bb27a8be2d4e4 100644 --- a/app/api/games/route.ts +++ b/app/api/games/route.ts @@ -1,13 +1,42 @@ +import { platforms } from "@/lib/config/platform"; import { getGames } from "@/lib/igdb"; +import { EGameCategory, EGameGenres, EGamePlatform } from "@/types/constants"; +import { IPlatformCategrory } from "@/types/igdb-types"; + import { NextRequest, NextResponse } from "next/server"; export async function GET(req: NextRequest) { const p = req.nextUrl.searchParams; try { const page = parseInt(p.get('page') as string) + const search = p.get('search') + const category = p.get('category') + const genre = p.get('genre') + const platform = p.get('platform') + const sortby = p.get('sortby') + const order = p.get('order') + + let filteredPlatforms: EGamePlatform[] | undefined; + + if (platform) { + const selectedCategory = platforms.find( + (platformCategory: IPlatformCategrory) => + platformCategory.category === platform + ); + filteredPlatforms = selectedCategory + ? selectedCategory.platforms + : undefined; + } - const games = await getGames(page, search ? search : ''); + const games = await getGames(page, + search ? search : '', + category ? EGameCategory[category as keyof typeof EGameCategory] : undefined, + genre ? EGameGenres[genre as keyof typeof EGameGenres] : undefined, + filteredPlatforms, + sortby ? sortby : '', + order ? order : '' + ); return NextResponse.json(games); } catch (error) { return NextResponse.json(error, { status: 500 }); diff --git a/app/globals.css b/app/globals.css index c8b693cbf5b22ae41fca9aa91d82c090b1474260..6ae9916a41b6669bafed4c6a755627c752e8b197 100644 --- a/app/globals.css +++ b/app/globals.css @@ -1,81 +1,87 @@ @tailwind base; @tailwind components; @tailwind utilities; - + @layer base { :root { --background: 0 0% 100%; --foreground: 222.2 47.4% 11.2%; - + --muted: 210 40% 96.1%; --muted-foreground: 215.4 16.3% 46.9%; - + --popover: 0 0% 100%; --popover-foreground: 222.2 47.4% 11.2%; - + --card: 0 0% 100%; --card-foreground: 222.2 47.4% 11.2%; - + --border: 214.3 31.8% 91.4%; --input: 214.3 31.8% 91.4%; - + --primary: 222.2 47.4% 11.2%; --primary-foreground: 210 40% 98%; - + --secondary: 210 40% 96.1%; --secondary-foreground: 222.2 47.4% 11.2%; - + --accent: 210 40% 96.1%; --accent-foreground: 222.2 47.4% 11.2%; - + --destructive: 0 100% 50%; --destructive-foreground: 210 40% 98%; - + --ring: 215 20.2% 65.1%; - + --radius: 0.5rem; } - + .dark { --background: 224 71% 4%; --foreground: 213 31% 91%; - + --muted: 223 47% 11%; --muted-foreground: 215.4 16.3% 56.9%; - + --popover: 224 71% 4%; --popover-foreground: 215 20.2% 65.1%; - + --card: 224 71% 4%; --card-foreground: 213 31% 91%; - + --border: 216 34% 17%; --input: 216 34% 17%; - + --primary: 210 40% 98%; --primary-foreground: 222.2 47.4% 1.2%; - + --secondary: 222.2 47.4% 11.2%; --secondary-foreground: 210 40% 98%; - + --accent: 216 34% 17%; --accent-foreground: 210 40% 98%; - + --destructive: 0 63% 31%; --destructive-foreground: 210 40% 98%; - + --ring: 216 34% 17%; - + --radius: 0.5rem; } } - + @layer base { * { @apply border-border; } + body { @apply bg-background text-foreground; font-feature-settings: "rlig" 1, "calt" 1; } +} + +body { + width: 100vw; + overflow-x: hidden; } \ No newline at end of file diff --git a/app/layout.tsx b/app/layout.tsx index 269ee4d9db74b4bc16e1c94e26f83ed5f86ffd7e..db79611d17e54885e18e0888233f270838ed9856 100644 --- a/app/layout.tsx +++ b/app/layout.tsx @@ -27,9 +27,7 @@ export default function RootLayout({ <Suspense fallback={<SiteLoad />}> <ClerkProvider> <Providers> - <div className="mx-32 my-6"> - {children} - </div> + {children} </Providers> </ClerkProvider> </Suspense> diff --git a/components/filter-sort-games.tsx b/components/filter-sort-games.tsx new file mode 100644 index 0000000000000000000000000000000000000000..19ef6c36aeed4873489a72fc242a98d6bd1fc779 --- /dev/null +++ b/components/filter-sort-games.tsx @@ -0,0 +1,147 @@ +"use client" + +import { Select, SelectContent, SelectGroup, SelectItem, SelectLabel, SelectTrigger, SelectValue } from "@/components/ui/select"; +import { usePathname, useRouter, useSearchParams } from "next/navigation"; +import { useEffect, useState } from "react"; +import { Button } from "./ui/button"; +import { Card } from "./ui/card"; +import { Icons } from "./ui/icons"; + +export default function Sort() { + const [selectedCategory, setSelectedCategory] = useState(''); + const [selectedGenre, setSelectedGenre] = useState(''); + const [selectedPlatform, setSelectedPlatform] = useState(''); + const [selectedSortMethod, setSelectedSortMethod] = useState('total_rating_count'); + const [selectedSortOrder, setSelectedSortOrder] = useState('desc'); + + const router = useRouter(); + const pathname = usePathname(); + const searchParams = useSearchParams(); + + const search = searchParams.get('search'); + + const urlParams = { + search: search ? `search=${search}` : '', + category: selectedCategory ? `category=${selectedCategory}` : '', + genre: selectedGenre ? `genre=${selectedGenre}` : '', + platform: selectedPlatform ? `platform=${selectedPlatform}` : '', + sortMethod: selectedSortMethod ? `sortby=${selectedSortMethod}` : '', + sortOrder: selectedSortOrder ? `order=${selectedSortOrder}` : '', + }; + + const queryParamString = Object.values(urlParams) + .filter(Boolean) + .map((param, index) => (index === 0 ? `?${param}` : `&${param}`)) + .join(''); + + const queryString = `${queryParamString ? `${queryParamString}` : ''}`; + + const url = `${pathname}${queryString ? `${queryString}` : ''}`; + + useEffect(() => { + router.push(url); + }, [router, url]); + + function toggleSortOrder() { + const newSortOrder = selectedSortOrder === 'desc' ? 'asc' : 'desc'; + setSelectedSortOrder(newSortOrder); + } + + function onReset() { + router.replace(pathname + (search ? `?search=${search}` : '')); + setSelectedCategory(''); + setSelectedGenre(''); + setSelectedPlatform(''); + setSelectedSortMethod('total_rating_count'); + } + + return ( + <Card className="p-6 grid items-start gap-2"> + <h1>Filter</h1> + <Select value={selectedCategory ? selectedCategory : undefined} key={selectedCategory[0]} onValueChange={(value) => setSelectedCategory(value)}> + <SelectTrigger className={`w-full ${selectedCategory[0] ? 'font-extrabold' : ''}`}> + <SelectValue placeholder="By category..." /> + </SelectTrigger> + <SelectContent> + <SelectGroup> + <SelectLabel>Category</SelectLabel> + <SelectItem value="main_game">Main Game</SelectItem> + <SelectItem value="dlc_addon">DLC Addon</SelectItem> + <SelectItem value="expansion">Expansion</SelectItem> + <SelectItem value="remake">Remake</SelectItem> + <SelectItem value="remaster">Remaster</SelectItem> + <SelectItem value="port">Port</SelectItem> + </SelectGroup> + </SelectContent> + </Select> + + <Select value={selectedGenre ? selectedGenre : undefined} key={selectedGenre[0]} onValueChange={(value) => setSelectedGenre(value)}> + <SelectTrigger className={`w-full ${selectedGenre[0] ? 'font-extrabold' : ''}`}> + <SelectValue placeholder="By genre..." /> + </SelectTrigger> + <SelectContent> + <SelectGroup> + <SelectLabel>Genre</SelectLabel> + <SelectItem value="fighting">Fighting</SelectItem> + <SelectItem value="shooter">Shooter</SelectItem> + <SelectItem value="music">Music</SelectItem> + <SelectItem value="platform">Platformer</SelectItem> + <SelectItem value="puzzle">Puzzle</SelectItem> + <SelectItem value="real-time-strategy-rts">Real Time Strategy</SelectItem> + <SelectItem value="role-playing-rpg">Role-playing</SelectItem> + <SelectItem value="simulator">Simulation</SelectItem> + <SelectItem value="sport">Sport</SelectItem> + <SelectItem value="turn-based-strategy-tbs">Turn-based strategy</SelectItem> + <SelectItem value="tactical">Tactical</SelectItem> + <SelectItem value="quiz-trivia">Quiz/Trivia</SelectItem> + <SelectItem value="hack-and-slash-beat-em-up">Hack and slash</SelectItem> + <SelectItem value="pinball">Pinball</SelectItem> + <SelectItem value="adventure">Adventure</SelectItem> + <SelectItem value="arcade">Arcade</SelectItem> + <SelectItem value="visual-novel">Visual Novel</SelectItem> + <SelectItem value="card-and-board-game">Card & Board Game</SelectItem> + <SelectItem value="adventure">Adventure</SelectItem> + <SelectItem value="moba">Moba</SelectItem> + <SelectItem value="point-and-click">Point-and-click</SelectItem> + </SelectGroup> + </SelectContent> + </Select> + + <Select value={selectedPlatform ? selectedPlatform : undefined} key={selectedPlatform[0]} onValueChange={(value) => setSelectedPlatform(value)}> + <SelectTrigger className={`w-full ${selectedPlatform[0] ? 'font-extrabold' : ''}`}> + <SelectValue placeholder="By Platform..." /> + </SelectTrigger> + <SelectContent> + <SelectGroup> + <SelectLabel>Platform</SelectLabel> + <SelectItem value="pc">PC</SelectItem> + <SelectItem value="playstation">Playstation</SelectItem> + <SelectItem value="xbox">Xbox</SelectItem> + <SelectItem value="nintendo">Nintendo</SelectItem> + </SelectGroup> + </SelectContent> + </Select> + + <h1 className="pt-6">Sort by</h1> + <div className="flex space-x-2 pb-1"> + <Select value={selectedSortMethod} onValueChange={(value) => setSelectedSortMethod(value)}> + <SelectTrigger className="w-full"> + <SelectValue placeholder="Rating" /> + </SelectTrigger> + <SelectContent> + <SelectGroup> + <SelectLabel>Sorting</SelectLabel> + <SelectItem value="name">Name</SelectItem> + <SelectItem value="total_rating_count">Rating</SelectItem> + </SelectGroup> + </SelectContent> + </Select> + <Button variant="ghost" onClick={toggleSortOrder}> + <Icons.arrowdown className={`h-4 w-4 transition-all transform ${selectedSortOrder === 'asc' ? 'rotate-180' : ''}`} /> + </Button> + </div> + + <Button variant="outline" onClick={() => onReset()}>Reset to Default</Button> + </Card> + ) +} \ No newline at end of file diff --git a/components/Game.tsx b/components/game-item.tsx similarity index 66% rename from components/Game.tsx rename to components/game-item.tsx index 2e35e73db23c3c1819152ce8d10081c3a9dc8005..4fcc90d1e7b61959475fba33103437fdf58d8f2a 100644 --- a/components/Game.tsx +++ b/components/game-item.tsx @@ -8,7 +8,13 @@ export default function Game({ id, name, cover }: { id: number, name: string, co <Card> <Link href={`/games/${id}`}> <div className="rounded-lg flex items-center justify-center overflow-hidden"> - <Image src={cover.url} alt={name} width={264} height={374} priority={true} style={{ width: '100%', height: '100%' }} /> + <Image + src={cover.url} + alt={name} + width={264} + height={374} + priority={true} + style={{ width: '100%', height: '100%' }} /> </div> </Link> <p className="truncate">{name}</p> diff --git a/components/InfiniteScroll.tsx b/components/infinity-scroll.tsx similarity index 71% rename from components/InfiniteScroll.tsx rename to components/infinity-scroll.tsx index f7d88c28bca8410e87229e8a141127dcbf17bc9a..d59b27ba67b705e043d44d96fe77a4a4fceb8840 100644 --- a/components/InfiniteScroll.tsx +++ b/components/infinity-scroll.tsx @@ -1,6 +1,6 @@ "use client" -import Game from "@/components/Game"; +import Game from "@/components/game-item"; import { Card } from "@/components/ui/card"; import { IGame } from "@/types/igdb-types"; import { useInfiniteQuery } from "@tanstack/react-query"; @@ -9,10 +9,23 @@ import { Fragment } from "react"; import InfiniteScroll from "react-infinite-scroll-component"; export function InfiniteScrollGames() { - const search = useSearchParams() - const searchQuery = search.get('search'); + const searchParams = useSearchParams() + + const searchQuery = searchParams.get('search'); + const categoryQuery = searchParams.get('category'); + const genreQuery = searchParams.get('genre'); + const platformQuery = searchParams.get('platform'); + const sortbyQuery = searchParams.get('sortby'); + const orderQuery = searchParams.get('order'); const searchURL = searchQuery ? `&search=${searchQuery}` : ""; + const categoryURL = categoryQuery ? `&category=${categoryQuery}` : ""; + const genreURL = genreQuery ? `&genre=${genreQuery}` : ""; + const platformURL = platformQuery ? `&platform=${platformQuery}` : ""; + const sortbyURL = sortbyQuery ? `&sortby=${sortbyQuery}` : ""; + const orderURL = orderQuery ? `&order=${orderQuery}` : ""; + + const params = searchURL + categoryURL + genreURL + platformURL + sortbyURL + orderURL; const { status, @@ -21,10 +34,9 @@ export function InfiniteScrollGames() { fetchNextPage, hasNextPage, } = useInfiniteQuery( - ['infiniteGames', searchQuery], + ['infiniteGames', params], async ({ pageParam = 1 }) => - await fetch(`/api/games/?page=${pageParam}` + searchURL, - { cache: 'no-cache' } + await fetch(`/api/games/?page=${pageParam}${params}`, ).then((result) => result.json() as Promise<IGame[]>), { getNextPageParam: (lastPage, pages) => { diff --git a/components/PostMessageForm.tsx b/components/post-messages.tsx similarity index 100% rename from components/PostMessageForm.tsx rename to components/post-messages.tsx diff --git a/components/search-input.tsx b/components/search-input.tsx index c3d04d06f2a3088835642bb320dbe165c3c11b6d..38f17f68f0449abe0b2cca143b18a94ca63b9b40 100644 --- a/components/search-input.tsx +++ b/components/search-input.tsx @@ -17,8 +17,13 @@ export default function SearchInput({ className, ...props }: DocsSearchProps) { function onSearch(event: React.FormEvent) { event.preventDefault() + if (!searchQuery) { + router.push(pathname) + return + } + const encoededQuery = encodeURIComponent(searchQuery) - router.push(`${pathname}?search=${encoededQuery}`) + router.push(`${pathname}?search=${encoededQuery}`) // add useSearchParams }; return ( diff --git a/components/sort-games.tsx b/components/sort-games.tsx deleted file mode 100644 index 76f380eef5126e30f5009bca260900981755c9ca..0000000000000000000000000000000000000000 --- a/components/sort-games.tsx +++ /dev/null @@ -1,63 +0,0 @@ -"use client" - -import { Select, SelectContent, SelectGroup, SelectItem, SelectLabel, SelectTrigger, SelectValue } from "@/components/ui/select"; -import { useState } from "react"; -import { Card } from "./ui/card"; - -export default function Sort() { - const [select, setSelect] = useState<string>(''); - - const handleChange = (event: any) => { - const selectedOption = event.target.value as string; - setSelect(selectedOption); - }; - - return ( - <Card className="p-6 grid items-start gap-2"> - <Select> - <SelectTrigger className="w-full"> - <SelectValue placeholder="Sort by..." /> - </SelectTrigger> - <SelectContent> - <SelectGroup> - <SelectLabel>Sorting</SelectLabel> - <SelectItem value="">Any</SelectItem> - <SelectItem value="name">Name</SelectItem> - <SelectItem value="rating">Rating</SelectItem> - </SelectGroup> - </SelectContent> - </Select> - - <h1 className="pt-3">Filter</h1> - <Select> - <SelectTrigger className="w-full"> - <SelectValue placeholder="By genre..." /> - </SelectTrigger> - <SelectContent> - <SelectGroup> - <SelectLabel>Genre</SelectLabel> - <SelectItem value="">Any</SelectItem> - <SelectItem value="action">Action</SelectItem> - <SelectItem value="simulation">Simulation</SelectItem> - </SelectGroup> - </SelectContent> - </Select> - - <Select> - <SelectTrigger className="w-full"> - <SelectValue placeholder="By platform..." /> - </SelectTrigger> - <SelectContent> - <SelectGroup> - <SelectLabel>Platform</SelectLabel> - <SelectItem value="">Any</SelectItem> - <SelectItem value="pc">PC</SelectItem> - <SelectItem value="playstation">Playstation</SelectItem> - <SelectItem value="xbox">Xbox</SelectItem> - <SelectItem value="nintendo">Nintendo</SelectItem> - </SelectGroup> - </SelectContent> - </Select> - </Card> - ) -} \ No newline at end of file diff --git a/components/ui/icons.tsx b/components/ui/icons.tsx index 363b7f1745477f9e088ff0ab72e136201f9eb17e..93769ace6d9b2266d367ff5871275e0f177c501d 100644 --- a/components/ui/icons.tsx +++ b/components/ui/icons.tsx @@ -1,5 +1,6 @@ import { AlertTriangle, + ArrowDown, ArrowRight, BellRing, Check, @@ -68,6 +69,7 @@ export const Icons: IconsType = { help: HelpCircle, // Help Nav sun: SunMedium, // Light Mode Toggle Nav moon: Moon, // Dark Mode Toggle Nav + arrowdown: ArrowDown, // Descending Sort close: X, spinner: Loader2, chevronLeft: ChevronLeft, diff --git a/lib/config/platform.ts b/lib/config/platform.ts new file mode 100644 index 0000000000000000000000000000000000000000..f6fda65270f282e123aa9bf38e5f76e22e9549f5 --- /dev/null +++ b/lib/config/platform.ts @@ -0,0 +1,53 @@ +import { EGamePlatform } from "@/types/constants"; +import { IPlatformCategrory } from "@/types/igdb-types"; + +export const platforms: IPlatformCategrory[] = [ + { + category: 'pc', + platforms: [EGamePlatform.win] + }, + { + category: 'playstation', + platforms: [ + EGamePlatform.ps, + EGamePlatform.ps2, + EGamePlatform.ps3, + EGamePlatform["ps4--1"], + EGamePlatform.ps5, + EGamePlatform.psp, + EGamePlatform.psvita, + EGamePlatform.psvr2, + EGamePlatform["playstation-vr"] + ] + }, + { + category: 'xbox', + platforms: [ + EGamePlatform.xbox, + EGamePlatform.xbox360, + EGamePlatform.xboxone, + EGamePlatform['series-x'] + ] + }, + { + category: 'nintendo', + platforms: [ + EGamePlatform.switch, + EGamePlatform.wii, + EGamePlatform.wiiu, + EGamePlatform['new-nintendo-3ds'], + EGamePlatform['3ds'], + EGamePlatform.nds, + EGamePlatform['nintendo-dsi'], + EGamePlatform['nintendo-64dd'], + EGamePlatform['nintendo-playstation'], + EGamePlatform.ngc, + EGamePlatform.n64, + EGamePlatform.nes, + EGamePlatform.snes, + EGamePlatform.gba, + EGamePlatform.gbc, + EGamePlatform.gb + ] + } +]; \ No newline at end of file diff --git a/lib/igdb.ts b/lib/igdb.ts index 90dcddfd10afdd2f0e2041fc0667a07d194e85b9..c33959864889bb0cf7714af42a5ec1f00cf5074a 100644 --- a/lib/igdb.ts +++ b/lib/igdb.ts @@ -28,7 +28,7 @@ async function getToken(): Promise<IAuth> { } // fetches the top 200 games with a rating of 96 or higher -export async function getGames(page: number, search: string): Promise<IGame[]> { +export async function getGames(page = 1, search?: string, category?: number, genre?: number, platform?: number[], sortby?: string, order?: string): Promise<IGame[]> { const auth = await getToken(); const url = new URL(`${IGDB_BASE_URL}/games`); @@ -40,10 +40,16 @@ export async function getGames(page: number, search: string): Promise<IGame[]> { 'Client-ID': CLIENT_ID, 'Authorization': `Bearer ${auth.access_token}` }, - body: `fields name, cover.*; limit ${limit}; offset ${offset}; - sort total_rating desc; where total_rating_count > 2 - & cover != null & total_rating != null & rating != null - & name ~ *"${search}"*;` + body: + `fields name, cover.image_id; limit ${limit}; offset ${offset}; + sort ${sortby ? sortby : "total_rating_count"} ${order ? order : "desc"}; + where total_rating_count > 3 + & cover != null & total_rating != null & rating != null & age_ratings != null + & name ~ *"${search ? search : ""}"* + ${category ? `& category = ${category}` : ""} + ${genre ? `& genres = [${genre}]` : ""} + ${platform ? `& platforms = (${platform.join(',')})` : ""} + ;` }); if (!response.ok) { @@ -72,6 +78,11 @@ export async function getGame(id: number): Promise<IGame[]> { }, body: `fields name, cover.*, summary; where cover != null; where id = ${id};` }) + + if (!response.ok) { + throw new Error(`Error fetching game: ${response.statusText}`); + } + const games = await response.json() as IGame[] games.forEach(game => { diff --git a/next.config.js b/next.config.js index 3faa915c58d36c8138a2218bc7adfef470f99c65..ce446f933cb195909959e77d630afa1c11962306 100644 --- a/next.config.js +++ b/next.config.js @@ -1,6 +1,7 @@ /** @type {import('next').NextConfig} */ const nextConfig = { images: { + unoptimized: true, domains: ["images.igdb.com"] } } diff --git a/tsconfig.json b/tsconfig.json index e06a4454ab0627b0a0cc46229eaf4bac8379deb2..a9145499e4b8723dd56d28afa1d098a2bec3ef5b 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -1,7 +1,11 @@ { "compilerOptions": { "target": "es5", - "lib": ["dom", "dom.iterable", "esnext"], + "lib": [ + "dom", + "dom.iterable", + "esnext" + ], "allowJs": true, "skipLibCheck": true, "strict": true, @@ -20,9 +24,18 @@ } ], "paths": { - "@/*": ["./*"] + "@/*": [ + "./*" + ] } }, - "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"], - "exclude": ["node_modules"] -} + "include": [ + "next-env.d.ts", + "**/*.ts", + "**/*.tsx", + ".next/types/**/*.ts" + ], + "exclude": [ + "node_modules" + ] +} \ No newline at end of file diff --git a/types/constants.ts b/types/constants.ts new file mode 100644 index 0000000000000000000000000000000000000000..c2855c337ed624656fba66c5f80f99a0e9c4858c --- /dev/null +++ b/types/constants.ts @@ -0,0 +1,139 @@ +export enum EAgeRatingCategory { + 'ESRB' = 0, + 'PEGI' = 2, + 'CERO' = 3, + 'USK' = 4, + 'GRAC' = 5, + 'CLASS_IND' = 6, + 'ACB' = 7, +} + +export enum EAgeRatingRating { + 'Three' = 1, + 'Seven' = 2, + 'Twelve' = 3, + 'Sixteen' = 4, + 'Eighteen' = 5, + 'RP' = 6, + 'EC' = 7, + 'E' = 8, + 'E10' = 9, + 'T' = 10, + 'M' = 11, + 'AO' = 12, + 'CERO_A' = 13, + 'CERO_B' = 14, + 'CERO_C' = 15, + 'CERO_D' = 16, + 'CERO_Z' = 17, + 'USK_0' = 18, + 'USK_6' = 19, + 'USK_12' = 20, + 'USK_16' = 21, + 'USK_18' = 22, + 'GRAC_ALL' = 23, + 'GRAC_Twelve' = 24, + 'GRAC_Fifteen' = 25, + 'GRAC_Eighteen' = 26, + 'GRAC_TESTING' = 27, + 'CLASS_IND_L' = 28, + 'CLASS_IND_Ten' = 29, + 'CLASS_IND_Twelve' = 30, + 'CLASS_IND_Fourteen' = 31, + 'CLASS_IND_Sixteen' = 32, + 'CLASS_IND_Eighteen' = 33, + 'ACB_G' = 34, + 'ACB_PG' = 35, + 'ACB_M' = 36, + 'ACB_MA15' = 37, + 'ACB_R18' = 38, + 'ACB_RC' = 39, +} + +export enum EGameCategory { + 'main_game' = 0, + 'dlc_addon' = 1, + 'expansion' = 2, + 'bundle' = 3, + 'standalone_expansion' = 4, + 'mod' = 5, + 'episode' = 6, + 'season' = 7, + 'remake' = 8, + 'remaster' = 9, + 'expanded_game' = 10, + 'port' = 11, + 'fork' = 12, + 'pack' = 13, + 'update' = 14, +} + +export enum EGamePlatform { + 'released' = 0, + 'alpha' = 2, + 'beta' = 3, + 'early_access' = 4, + 'offline' = 5, + 'cancelled' = 6, + 'rumored' = 7, + 'delisted' = 8, +} + +export enum EGameGenres { + 'point-and-click' = 2, + 'fighting' = 4, + 'shooter' = 5, + 'music' = 7, + 'platform' = 8, + 'puzzle' = 9, + 'racing' = 10, + 'real-time-strategy-rts' = 11, + 'role-playing-rpg' = 12, + 'simulator' = 13, + 'sport' = 14, + 'strategy' = 15, + 'turn-based-strategy-tbs' = 16, + 'tactical' = 24, + 'hack-and-slash-beat-em-up' = 25, + 'quiz-trivia' = 26, + 'pinball' = 30, + 'adventure' = 31, + 'indie' = 32, + 'arcade' = 33, + 'visual-novel' = 34, + 'card-board-game' = 35, + 'moba' = 36, +} + +export enum EGamePlatform { + 'win' = 6, + 'ps' = 7, + 'ps2' = 8, + 'ps3' = 9, + 'ps4--1' = 48, + 'ps5' = 167, + 'psp' = 38, + 'psvita' = 46, + 'psvr2' = 390, + 'playstation-vr' = 165, + 'xbox' = 11, + 'xbox360' = 12, + 'xboxone' = 49, + 'series-x' = 169, + 'switch' = 130, + 'wii' = 5, + 'wiiu' = 41, + 'new-nintendo-3ds' = 137, + '3ds' = 37, + 'nds' = 20, + 'nintendo-dsi' = 159, + 'nintendo-64dd' = 416, + 'nintendo-playstation' = 131, + 'ngc' = 21, + 'n64' = 4, + 'nes' = 18, + 'snes' = 19, + 'gba' = 24, + 'gbc' = 22, + 'gb' = 33, +} \ No newline at end of file diff --git a/types/igdb-types.d.ts b/types/igdb-types.d.ts index 2cecc0034485173a6844f0200f1c7f4912d9e6c9..311c0fbaf0ab02a29fc1418b812bc8521a70302c 100644 --- a/types/igdb-types.d.ts +++ b/types/igdb-types.d.ts @@ -1,84 +1,3 @@ -export enum EAgeRatingCategory { - 'ESRB' = 0, - 'PEGI' = 2, - 'CERO' = 3, - 'USK' = 4, - 'GRAC' = 5, - 'CLASS_IND' = 6, - 'ACB' = 7, -} - -export enum EAgeRatingRating { - 'Three' = 1, - 'Seven' = 2, - 'Twelve' = 3, - 'Sixteen' = 4, - 'Eighteen' = 5, - 'RP' = 6, - 'EC' = 7, - 'E' = 8, - 'E10' = 9, - 'T' = 10, - 'M' = 11, - 'AO' = 12, - 'CERO_A' = 13, - 'CERO_B' = 14, - 'CERO_C' = 15, - 'CERO_D' = 16, - 'CERO_Z' = 17, - 'USK_0' = 18, - 'USK_6' = 19, - 'USK_12' = 20, - 'USK_16' = 21, - 'USK_18' = 22, - 'GRAC_ALL' = 23, - 'GRAC_Twelve' = 24, - 'GRAC_Fifteen' = 25, - 'GRAC_Eighteen' = 26, - 'GRAC_TESTING' = 27, - 'CLASS_IND_L' = 28, - 'CLASS_IND_Ten' = 29, - 'CLASS_IND_Twelve' = 30, - 'CLASS_IND_Fourteen' = 31, - 'CLASS_IND_Sixteen' = 32, - 'CLASS_IND_Eighteen' = 33, - 'ACB_G' = 34, - 'ACB_PG' = 35, - 'ACB_M' = 36, - 'ACB_MA15' = 37, - 'ACB_R18' = 38, - 'ACB_RC' = 39, -} - -export enum EGameCategory { - 'main_game' = 0, - 'dlc_addon' = 1, - 'expansion' = 2, - 'bundle' = 3, - 'standalone_expansion' = 4, - 'mod' = 5, - 'episode' = 6, - 'season' = 7, - 'remake' = 8, - 'remaster' = 9, - 'expanded_game' = 10, - 'port' = 11, - 'fork' = 12, - 'pack' = 13, - 'update' = 14, -} - -export enum EGameStatus { - 'released' = 0, - 'alpha' = 2, - 'beta' = 3, - 'early_access' = 4, - 'offline' = 5, - 'cancelled' = 6, - 'rumored' = 7, - 'delisted' = 8, -} - export interface IAuth { access_token: string; expires_in: number; @@ -87,14 +6,13 @@ export interface IAuth { export interface IGame { id: number; - age_ratings: EAgeRatingCategory[]; + age_ratings: number[]; aggregrated_rating: number; aggregrated_rating_count: number; alternative_names: number[]; artworks: number[]; bundles: number[]; - category: EGameCategory; - checksum: string; + category: number; collection: number; cover: ICover; created_at: number; @@ -130,7 +48,7 @@ export interface IGame { similar_games: number[]; slug: string; standalone_expansions: number[]; - status: EGameStatus; + status: number; storyline: string; summary: string; tags: number[]; @@ -149,11 +67,41 @@ export interface ICover { id: number; alpha_channel: boolean; animated: boolean; - checksum: string; game: number; game_localization: number; height: number; image_id: string; url: string; width: number; +} + +export interface IGenre { + id: number; + created_at: number; + name: string; + slug: string; + updated_at: number; + url: string; +} + +export interface IPlatform { + id: number; + abbreviation: string; + alternative_name: string; + category: number; + created_at: number; + generation: number; + name: string; + platform_logo: number; + platform_family: number; + slug: string; + updated_at: number; + url: string; + versions: number[]; + websites: number[]; +} + +export interface IPlatformCategrory { + category: 'pc' | 'playstation' | 'xbox' | 'nintendo'; + platforms: EGamePlatform[]; } \ No newline at end of file