diff --git a/.env.example b/.env.example new file mode 100644 index 0000000000000000000000000000000000000000..a362d123d3c0ccf1b789b77a69bc42bf4e29b613 --- /dev/null +++ b/.env.example @@ -0,0 +1,13 @@ +# Example .env file + +# Database for connecting to Prisma +DATABASE_URL="file:./dev.db" + +# Some URLs +TWITCH_AUTH_BASE_URL="https://id.twitch.tv/oauth2" +IGDB_BASE_URL="https://api.igdb.com/v4" +IGDB_IMG_BASE_URL="https://images.igdb.com/igdb/image/upload" + +# For Authentication +TWITCH_CLIENT_ID="imdb_client_id" +TWITCH_CLIENT_SECRET="imdb_auth_id" \ No newline at end of file diff --git a/.env.sample b/.env.sample deleted file mode 100644 index 1c34c9dbe25be35997cf8aca0c4effe7c6a3741e..0000000000000000000000000000000000000000 --- a/.env.sample +++ /dev/null @@ -1,10 +0,0 @@ -# Environment variables declared in this file are automatically made available to Prisma. -# See the documentation for more detail: https://pris.ly/d/prisma-schema#accessing-environment-variables-from-the-schema - -# Prisma supports the native connection string format for PostgreSQL, MySQL, SQLite, SQL Server, MongoDB and CockroachDB. -# See the documentation for all the connection string options: https://pris.ly/d/connection-strings - -DATABASE_URL="file:./dev.db" - -IMDB_CLIENT_ID="imdb-client-id" -IMDB_AUTH="Bearer imdb-auth-id" \ No newline at end of file diff --git a/.gitignore b/.gitignore index 45c1abce864b4fd390a16f4a8650a9c0d37827c6..56674d5e498bfd920840f6ad56136490bb696d14 100644 --- a/.gitignore +++ b/.gitignore @@ -25,12 +25,13 @@ yarn-debug.log* yarn-error.log* # local env files -.env*.local .env +.env*.local +.env*.production # vercel .vercel # typescript *.tsbuildinfo -next-env.d.ts +next-env.d.ts \ No newline at end of file diff --git a/app/(auth)/login/page.tsx b/app/(auth)/login/page.tsx new file mode 100644 index 0000000000000000000000000000000000000000..da79264235d5f369a8c2d88a3ae71262cd24ef22 --- /dev/null +++ b/app/(auth)/login/page.tsx @@ -0,0 +1,7 @@ +export default function Login() { + return ( + <div> + <h1>Login WIP</h1> + </div> + ) +} \ No newline at end of file diff --git a/app/(auth)/signup/page.tsx b/app/(auth)/signup/page.tsx new file mode 100644 index 0000000000000000000000000000000000000000..abc06fc66c85b5e86f38f6cff3fe7f8c914f19f9 --- /dev/null +++ b/app/(auth)/signup/page.tsx @@ -0,0 +1,7 @@ +export default function Signup() { + return ( + <div> + <h1>Signup WIP</h1> + </div> + ) +} \ No newline at end of file diff --git a/app/(content)/(blog)/blogs/page.tsx b/app/(content)/(blog)/blogs/page.tsx new file mode 100644 index 0000000000000000000000000000000000000000..1b234b59261298d038e98d9925c2d19fcdc938fd --- /dev/null +++ b/app/(content)/(blog)/blogs/page.tsx @@ -0,0 +1,7 @@ +export default function BlogsPage() { + return ( + <div> + <h1>Blog WIP</h1> + </div> + ) +} \ No newline at end of file diff --git a/app/(content)/(community)/communities/page.tsx b/app/(content)/(community)/communities/page.tsx new file mode 100644 index 0000000000000000000000000000000000000000..7a1e2cfa04c7c5585326afa281e80d9b89cc765d --- /dev/null +++ b/app/(content)/(community)/communities/page.tsx @@ -0,0 +1,7 @@ +export default function CommunitiesPage() { + return ( + <div> + <h1>Community WIP</h1> + </div> + ) +} \ No newline at end of file diff --git a/app/games/[gameid]/loading.tsx b/app/(content)/(gaming)/games/[gameid]/loading.tsx similarity index 64% rename from app/games/[gameid]/loading.tsx rename to app/(content)/(gaming)/games/[gameid]/loading.tsx index 21df37bfccfa1d93ac617419f02d6d2c214504f4..794f6fd21a84ecca83eb93d9385c4a04d4d930b8 100644 --- a/app/games/[gameid]/loading.tsx +++ b/app/(content)/(gaming)/games/[gameid]/loading.tsx @@ -1,3 +1,4 @@ +// loading component, this renders when loading in /games happens export default function Loading() { return ( <div> diff --git a/app/(content)/(gaming)/games/[gameid]/page.tsx b/app/(content)/(gaming)/games/[gameid]/page.tsx new file mode 100644 index 0000000000000000000000000000000000000000..31e205bfa9106eb36b59fb1edc1ade071cecb8cd --- /dev/null +++ b/app/(content)/(gaming)/games/[gameid]/page.tsx @@ -0,0 +1,26 @@ +import { getGame, getGames } from "@/lib/igdb"; +import { IGame } from "@/types/types"; +import Image from "next/image"; + +// renders a single game detail page +export default async function GameDetail({ params }: { params: { gameid: string } }) { + const data: IGame[] = await getGame(parseInt(params.gameid)) + + return ( + <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} /> + <p>{data[0].summary}</p> + </div> + ) +} + +// pre-renders static paths for all fetched games for faster page loads +export async function generateStaticParams() { + const games = await getGames() + + return games.map((game) => ({ + gameid: game.id.toString(), + })); +} \ No newline at end of file diff --git a/app/(content)/(gaming)/games/layout.tsx b/app/(content)/(gaming)/games/layout.tsx new file mode 100644 index 0000000000000000000000000000000000000000..41e3240f329de189b889f2c823def6fe62d59b59 --- /dev/null +++ b/app/(content)/(gaming)/games/layout.tsx @@ -0,0 +1,31 @@ +"use client" + +import Dashboard from "@/components/Dashboard"; +import Sort from "@/components/Sort"; +import { Grid, Hidden } from "@mui/material"; + +export default function DashboardLayout({ + children, +}: { + children: React.ReactNode; +}) { + return ( + <section> + <Grid container spacing={2}> + <Grid item xs={2}> + <Dashboard /> + </Grid> + + <Grid item xs={10} md={8}> + {children} + </Grid> + + <Hidden mdDown> + <Grid item xs={2}> + <Sort /> + </Grid> + </Hidden> + </Grid> + </section> + ); +} \ No newline at end of file diff --git a/app/games/loading.tsx b/app/(content)/(gaming)/games/loading.tsx similarity index 65% rename from app/games/loading.tsx rename to app/(content)/(gaming)/games/loading.tsx index 9d1c0576dc15204c01a5555f3f6719da8321ee36..abebd225f3eab27d0100dde9d15d857432af216a 100644 --- a/app/games/loading.tsx +++ b/app/(content)/(gaming)/games/loading.tsx @@ -1,3 +1,4 @@ +// root loading component, this renders when any loading happens export default function Loading() { return ( <div> diff --git a/app/(content)/(gaming)/games/page.tsx b/app/(content)/(gaming)/games/page.tsx new file mode 100644 index 0000000000000000000000000000000000000000..6a88f6ab768fc7e8bfaa34ca13d6c35f906cbc13 --- /dev/null +++ b/app/(content)/(gaming)/games/page.tsx @@ -0,0 +1,70 @@ +"use client" + +import Game from "@/components/Game"; +import Search from "@/components/Search"; +import { getBaseURL } from "@/lib/utils"; +import { IGame } from "@/types/types"; +import { Card, CardContent, Grid, Stack } from "@mui/material"; +import { Fragment } from "react"; +import InfiniteScroll from "react-infinite-scroll-component"; +import { useInfiniteQuery } from "react-query"; + +// renders a list of games infinitely (presumably) +export default function GamesPage() { + const { + data, + error, + fetchNextPage, + hasNextPage, + isFetching, + isFetchingNextPage, + status, + } = useInfiniteQuery( + 'infiniteGames', + async ({ pageParam = 1 }) => + await fetch( + `${getBaseURL()}/api/games/?page=${pageParam}`, + { cache: 'force-cache', } + ).then((result) => result.json() as Promise<IGame[]>), + { + getNextPageParam: (lastPage, pages) => { + return lastPage.length > 0 ? pages.length + 1 : undefined; + }, + } + ); + + return ( + <Stack spacing={2}> + <Search /> + <Card> + <CardContent> + {status === 'success' && ( + <InfiniteScroll + dataLength={data?.pages.length * 20} + next={fetchNextPage} + hasMore={hasNextPage ? true : false} + loader={<h4>Loading...</h4>} + endMessage={ + <p style={{ textAlign: 'center' }}> + <b>Yay! You have seen it all</b> + </p> + } + > + <Grid container spacing={2} justifyContent="center"> + {data?.pages.map((page, i) => ( + <Fragment key={i}> + {page.map((game: IGame) => ( + <Grid item xs={12} ss={6} sm={4} md={3} lg={2} key={game.id}> + <Game id={game.id} name={game.name} cover={game.cover} key={game.id} /> + </Grid> + ))} + </Fragment> + ))} + </Grid> + </InfiniteScroll> + )} + </CardContent> + </Card> + </Stack> + ) +} \ No newline at end of file diff --git a/app/(content)/(thread)/threads/page.tsx b/app/(content)/(thread)/threads/page.tsx new file mode 100644 index 0000000000000000000000000000000000000000..d9a8ea4a16e1c6a9350f98d09cd0ca09e9501661 --- /dev/null +++ b/app/(content)/(thread)/threads/page.tsx @@ -0,0 +1,7 @@ +export default function ThreadsPage() { + return ( + <div> + <h1>Threads WIP</h1> + </div> + ) +} \ No newline at end of file diff --git a/app/(content)/(user)/[userid]/page.tsx b/app/(content)/(user)/[userid]/page.tsx new file mode 100644 index 0000000000000000000000000000000000000000..73bad3ce7170ecae9bb8f25e26485f6e53d47f04 --- /dev/null +++ b/app/(content)/(user)/[userid]/page.tsx @@ -0,0 +1,8 @@ +export default function User({ params }: { params: { userid: string } }) { + return ( + <div> + <h1>User Profile Page WIP</h1> + <p>Unique UserName: {params.userid}</p> + </div> + ) +} \ No newline at end of file diff --git a/app/(content)/(user)/friends/page.tsx b/app/(content)/(user)/friends/page.tsx new file mode 100644 index 0000000000000000000000000000000000000000..85a520c8e7b3a7f367ba5bef841fb9d26a20f968 --- /dev/null +++ b/app/(content)/(user)/friends/page.tsx @@ -0,0 +1,7 @@ +export default function Friends() { + return ( + <div> + <h1>Friends Page WIP</h1> + </div> + ) +} \ No newline at end of file diff --git a/app/(content)/(user)/notifications/page.tsx b/app/(content)/(user)/notifications/page.tsx new file mode 100644 index 0000000000000000000000000000000000000000..df96b5f6c71e2a1b3e6218cfb568613cf6931267 --- /dev/null +++ b/app/(content)/(user)/notifications/page.tsx @@ -0,0 +1,7 @@ +export default function Notifications() { + return ( + <div> + <h1>Notifications Page WIP</h1> + </div> + ) +} \ No newline at end of file diff --git a/app/(content)/(user)/settings/page.tsx b/app/(content)/(user)/settings/page.tsx new file mode 100644 index 0000000000000000000000000000000000000000..b72aec206f16aa905a986d1a1c0ecfa136052b44 --- /dev/null +++ b/app/(content)/(user)/settings/page.tsx @@ -0,0 +1,7 @@ +export default function Settings() { + return ( + <div> + <h1>Settings Page WIP</h1> + </div> + ) +} \ No newline at end of file diff --git a/app/api/games/route.ts b/app/api/games/route.ts new file mode 100644 index 0000000000000000000000000000000000000000..842198fe639044332f6c6fd4c8b96b76c8f5648e --- /dev/null +++ b/app/api/games/route.ts @@ -0,0 +1,8 @@ +import { getGames } from "@/lib/igdb"; +import { NextRequest, NextResponse } from "next/server"; + +export async function GET(req: NextRequest) { + const p = req.nextUrl.searchParams; + const games = await getGames(p.get('page') ? parseInt(p.get('page') as string) : undefined); + return NextResponse.json(games); +} \ No newline at end of file diff --git a/app/games/Game.tsx b/app/games/Game.tsx deleted file mode 100644 index 505c865242f55051ed449b693f5dc6bac6e9418a..0000000000000000000000000000000000000000 --- a/app/games/Game.tsx +++ /dev/null @@ -1,13 +0,0 @@ -import Image from "next/image"; -import Link from "next/link"; - -export default function Game({ id, name, cover }: { id: any, name: any, cover: any }) { - return ( - <div> - <h1>{name}</h1> - <Link href={`/games/${id}`}> - <Image src={"https:" + cover.url} alt={name} width={200} height={200} /> - </Link> - </div> - ) -} diff --git a/app/games/[gameid]/page.tsx b/app/games/[gameid]/page.tsx deleted file mode 100644 index c385146eba130718ad893e2be94dfe6368acaab0..0000000000000000000000000000000000000000 --- a/app/games/[gameid]/page.tsx +++ /dev/null @@ -1,35 +0,0 @@ -import Image from "next/image"; - -type DetailView = { - id: number; - name: string; - cover: { url: string }; - summary: string; -} - -type DetailViewArray = DetailView[]; - - - -export default async function GameDetail({ params }: { params: any }) { - const res = await fetch("https://api.igdb.com/v4/games", { - method: 'POST', - headers: { - 'Accept': 'application/json', - 'Content-Type': 'application/json', - 'Client-ID': `${process.env.IMDB_CLIENT_ID}`, - 'Authorization': `${process.env.IMDB_AUTH}`, - }, - body: `fields name,cover.*,summary; where cover != null; where id = ${params.gameid};`, - }); - const data: DetailViewArray = await res.json() - - return ( - <div> - Game Detail - <h1>{data[0].name}</h1> - <Image src={"https:" + data[0].cover.url} alt={data[0].name} width={200} height={200} priority /> - <p>{data[0].summary}</p> - </div> - ) -} diff --git a/app/games/page.tsx b/app/games/page.tsx deleted file mode 100644 index 7cdd9908d17b12d61c7f63982938ae8c2f780c54..0000000000000000000000000000000000000000 --- a/app/games/page.tsx +++ /dev/null @@ -1,33 +0,0 @@ -import Game from "./Game"; - -type DetailView = { - id: number; - name: string; - cover: { url: string }; - summary: string; -} - -type DetailViewArray = DetailView[]; - -export default async function GamesList() { - const res = await fetch("https://api.igdb.com/v4/games", { - method: 'POST', - headers: { - 'Accept': 'application/json', - 'Content-Type': 'application/json', - 'Client-ID': `${process.env.IMDB_CLIENT_ID}`, - 'Authorization': `${process.env.IMDB_AUTH}`, - }, - body: `fields name,cover.*; limit 40; where cover != null;`, - }); - const data: DetailViewArray = await res.json() - - return ( - <div> - Games List Page - {data.map((game: any) => ( - <Game key={game.id} id={game.id} name={game.name} cover={game.cover} /> - ))} - </div> - ) -} diff --git a/app/layout.tsx b/app/layout.tsx index b7c5cfdd8d808d86b9ec61aad456d5e9838147c4..2e2a0aaa65b7dfb9b6b484583609821f969c1d2d 100644 --- a/app/layout.tsx +++ b/app/layout.tsx @@ -1,20 +1,52 @@ -import { Inter } from 'next/font/google' +"use client" -const inter = Inter({ subsets: ['latin'] }) +import { Container, CssBaseline, ThemeProvider } from "@mui/material" +import { createContext, useState } from "react" +import { QueryClient, QueryClientProvider } from "react-query" +import Header from "../components/Header" +import { Theme } from "./theme" +// metadata for the website export const metadata = { - title: 'Create Next App', - description: 'Generated by create next app', + title: 'GameUnity', + description: 'Soon', } +// for dark mode global context +export const ColorModeContext = createContext({ toggleColorMode: () => { } }); + +// this is the root layout for all pages ({children}) export default function RootLayout({ children, }: { children: React.ReactNode }) { + const [queryClient] = useState(() => new QueryClient()); + + const [theme, colorMode] = Theme(); + return ( <html lang="en"> - <body className={inter.className}>{children}</body> + <QueryClientProvider client={queryClient}> + <ColorModeContext.Provider value={colorMode}> + <ThemeProvider theme={theme}> + <CssBaseline /> + <body> + <Container maxWidth={false}> + <Header /> + {children} + </Container> + </body> + </ThemeProvider> + </ColorModeContext.Provider> + </QueryClientProvider> </html> ) } + +// custom super small breakpoint for responsive design +declare module '@mui/material/styles' { + interface BreakpointOverrides { + ss: true; + } +} \ No newline at end of file diff --git a/app/page.tsx b/app/page.tsx index b98f3fa8061b5ee45ad6b98f2734a9d1396c3d20..bca80d64f653278e0dbc026966da87b02b451e5c 100644 --- a/app/page.tsx +++ b/app/page.tsx @@ -1,9 +1,14 @@ +import Link from "next/link"; + +// renders home page export default function Home() { return ( <main> <div> - Hello World! + <h1>Welcome to GameUnity!</h1> + <p>This will be our Home Page and is still WIP</p> + <Link href="/games">Games List Progress</Link> </div> </main> ) -} +} \ No newline at end of file diff --git a/app/theme.tsx b/app/theme.tsx new file mode 100644 index 0000000000000000000000000000000000000000..07f336c8cb6424eb4d64a48bcf6710ddb2619654 --- /dev/null +++ b/app/theme.tsx @@ -0,0 +1,36 @@ +import { Theme, createTheme } from "@mui/material"; +import { useMemo, useState } from "react"; + +// this is the main theme for the website +export function Theme(): [Theme, { toggleColorMode: () => void }] { + const [mode, setMode] = useState<'light' | 'dark'>('dark'); + + const colorMode = useMemo( + () => ({ + toggleColorMode: () => { + setMode((prevMode) => (prevMode === 'dark' ? 'light' : 'dark')); + }, + }), + [], + ); + + return [useMemo(() => + createTheme({ + palette: { + mode: mode, + }, + breakpoints: { + values: { + xs: 0, + ss: 300, + sm: 600, + md: 900, + lg: 1200, + xl: 1536, + }, + }, + }), + [mode], + ), + colorMode]; +} \ No newline at end of file diff --git a/components/Dashboard.tsx b/components/Dashboard.tsx new file mode 100644 index 0000000000000000000000000000000000000000..520ee746b247e0cc30a6eb9c975e0ed0b608819e --- /dev/null +++ b/components/Dashboard.tsx @@ -0,0 +1,99 @@ +import AccountCircleIcon from '@mui/icons-material/AccountCircle'; +import ExploreIcon from '@mui/icons-material/Explore'; +import GroupIcon from '@mui/icons-material/Group'; +import HelpIcon from '@mui/icons-material/Help'; +import NotificationsIcon from '@mui/icons-material/Notifications'; +import PeopleIcon from '@mui/icons-material/People'; +import SettingsIcon from '@mui/icons-material/Settings'; +import SportsEsportsIcon from '@mui/icons-material/SportsEsports'; +import { Box, Button, Hidden, Stack, Typography } from "@mui/material"; +import Link from "next/link"; + +export default function Dashboard() { + const loggedIn = false; + const username = "coolguy123"; + + return ( + <Box sx={{ position: 'sticky', top: 0 }}> + {loggedIn ? + <Stack spacing={2}> + <Link href={`/${username}`}> + <Button variant="text" size="large" startIcon={<AccountCircleIcon />} sx={{ borderRadius: "999px" }}> + <Hidden lgDown> + My Profile + </Hidden> + </Button> + </Link> + <Link href="/notifications"> + <Button variant="text" size="large" startIcon={<NotificationsIcon />} sx={{ borderRadius: "999px" }}> + <Hidden lgDown> + Notifications + </Hidden> + </Button> + </Link> + <Link href="/friends"> + <Button variant="text" size="large" startIcon={<PeopleIcon />} sx={{ borderRadius: "999px" }}> + <Hidden lgDown> + Friends + </Hidden> + </Button> + </Link> + <Link href="/games"> + <Button variant="text" size="large" startIcon={<SportsEsportsIcon />} sx={{ borderRadius: "999px" }}> + <Hidden lgDown> + Games + </Hidden> + </Button> + </Link> + <Link href="/communities"> + <Button variant="text" size="large" startIcon={<GroupIcon />} sx={{ borderRadius: "999px" }}> + <Hidden lgDown> + Communities + </Hidden> + </Button> + </Link> + <Link href="/blogs"> + <Button variant="text" size="large" startIcon={<ExploreIcon />} sx={{ borderRadius: "999px" }}> + <Hidden lgDown> + Explore + </Hidden> + </Button> + </Link> + + <Box height={30} /> + + <Link href="/settings"> + <Button variant="text" size="large" startIcon={<SettingsIcon />} sx={{ borderRadius: "999px" }}> + <Hidden lgDown> + Settings + </Hidden> + </Button> + </Link> + <Link href="/blogs"> + <Button variant="text" size="large" startIcon={<HelpIcon />} sx={{ borderRadius: "999px" }}> + <Hidden lgDown> + Help + </Hidden> + </Button> + </Link> + </Stack> + : + <Stack spacing={2} sx={{ justifyContent: "center", textAlign: "center" }}> + <Link href="/login"> + <Button variant="contained" size="large" sx={{ borderRadius: "999px" }}> + Log In + </Button> + </Link> + <Link href="/signup"> + <Button variant="outlined" size="large" sx={{ borderRadius: "999px" }}> + Sign Up + </Button> + </Link> + <Typography variant="subtitle1"> + Unlock endless possibilities - register or log in to unleash the full potential of our website. + </Typography> + </Stack> + } + </Box> + ) +} \ No newline at end of file diff --git a/components/Game.tsx b/components/Game.tsx new file mode 100644 index 0000000000000000000000000000000000000000..4f72f6879c8fb9611b12aaf314341965e0123111 --- /dev/null +++ b/components/Game.tsx @@ -0,0 +1,17 @@ +import { Card, CardContent, Typography } from "@mui/material"; +import Image from "next/image"; +import Link from "next/link"; + +// this is a single game helper-component, only for design purposes +export default function Game({ id, name, cover }: { id: number, name: string, cover: { url: string } }) { + return ( + <Card sx={{ maxWidth: 264 }} variant="outlined" > + <Link href={`/games/${id}`}> + <Image src={cover.url} alt={name} width={264} height={374} priority={true} style={{ width: '100%', height: '100%' }} /> + </Link> + <CardContent> + <Typography noWrap={true}>{name}</Typography> + </CardContent> + </Card> + ) +} \ No newline at end of file diff --git a/components/Header.tsx b/components/Header.tsx new file mode 100644 index 0000000000000000000000000000000000000000..4d1eae3dfe50459b5e85a98599c7b94b6c7eb15b --- /dev/null +++ b/components/Header.tsx @@ -0,0 +1,54 @@ +import { ColorModeContext } from "@/app/layout"; +import Brightness4Icon from '@mui/icons-material/Brightness4'; +import Brightness7Icon from '@mui/icons-material/Brightness7'; +import { Button, Container, Grid, IconButton, useTheme } from "@mui/material"; +import Image from "next/image"; +import Link from "next/link"; +import { useContext } from "react"; +import logoSvg from "../public/logo.svg"; + +export default function Header() { + const theme = useTheme(); + const colorMode = useContext(ColorModeContext); + + return ( + <Container> + <Grid container spacing={2} height={100} sx={{ alignItems: "center" }}> + <Grid item xs={2}> + <Link href="/"> + <Image src={logoSvg} alt="GameUnity" width={50} height={50} priority /> + </Link> + </Grid> + + <Grid item xs={8} sx={{ justifyContent: "center", textAlign: "center" }}> + <Link href="/games"> + <Button variant="text" size="large" sx={{ borderRadius: "999px" }}> + Games + </Button> + </Link> + <Link href="/threads"> + <Button variant="text" size="large" sx={{ borderRadius: "999px" }}> + Threads + </Button> + </Link> + <Link href="/communities"> + <Button variant="text" size="large" sx={{ borderRadius: "999px" }}> + Communities + </Button> + </Link> + <Link href="/blogs"> + <Button variant="text" size="large" sx={{ borderRadius: "999px" }}> + Blog + </Button> + </Link> + </Grid> + + <Grid item xs={2} sx={{ display: 'flex', justifyContent: 'flex-end' }}> + <IconButton sx={{ ml: 1 }} onClick={colorMode.toggleColorMode} color="inherit"> + {theme.palette.mode === 'dark' ? <Brightness7Icon /> : <Brightness4Icon />} + </IconButton> + </Grid> + </Grid> + </Container> + ) +} \ No newline at end of file diff --git a/components/Search.tsx b/components/Search.tsx new file mode 100644 index 0000000000000000000000000000000000000000..01532ab7f201a5e63e190f12f7aeb58fda8a2cad --- /dev/null +++ b/components/Search.tsx @@ -0,0 +1,38 @@ +import ArrowCircleRightRoundedIcon from '@mui/icons-material/ArrowCircleRightRounded'; +import SearchIcon from '@mui/icons-material/Search'; +import { Container, IconButton, InputAdornment, TextField } from '@mui/material'; + +export default function SearchInput() { + const handleSearch = (event: { target: { value: any; }; }) => { + const searchText = event.target.value; + console.log('Search:', searchText); + }; + + return ( + <Container maxWidth="sm" sx={{ justifyContent: "center", textAlign: "center" }}> + <TextField + placeholder="Search" + variant="outlined" + size="small" + onChange={handleSearch} + InputProps={{ + startAdornment: ( + <InputAdornment position="start"> + <SearchIcon /> + </InputAdornment> + ), + endAdornment: ( + <InputAdornment position="end"> + <IconButton edge="end" aria-label="start search"> + <ArrowCircleRightRoundedIcon /> + </IconButton> + </InputAdornment> + ), + style: { + borderRadius: '999px', + }, + }} + /> + </Container> + ); +}; \ No newline at end of file diff --git a/components/Sort.tsx b/components/Sort.tsx new file mode 100644 index 0000000000000000000000000000000000000000..a21fd608a2922ac48e8bdf237042ca342ce74b0c --- /dev/null +++ b/components/Sort.tsx @@ -0,0 +1,37 @@ +import { Box, Card, CardContent, FormControl, FormHelperText, MenuItem, Select, SelectChangeEvent, Typography } from "@mui/material"; +import { useState } from "react"; + +// this is a single sorting helper-component, only for design purposes +export default function Sort() { + const [select, setSelct] = useState(''); + + const handleChange = (event: SelectChangeEvent) => { + setSelct(event.target.value); + }; + + return ( + <Box sx={{ position: 'sticky', top: 0 }}> + <Card variant="outlined" > + <CardContent> + <Typography>Filter</Typography> + + <FormControl fullWidth> + <FormHelperText>Sorty By</FormHelperText> + <Select + value={select} + onChange={handleChange} + displayEmpty + inputProps={{ 'aria-label': 'Without label' }} + > + <MenuItem value=""> + <em>Any</em> + </MenuItem> + <MenuItem value={1}>Rating</MenuItem> + <MenuItem value={2}>Release Date</MenuItem> + </Select> + </FormControl> + </CardContent> + </Card> + </Box> + ) +} \ No newline at end of file diff --git a/lib/igdb.ts b/lib/igdb.ts new file mode 100644 index 0000000000000000000000000000000000000000..82e3f411ae739ede067b5b797e2cb628e9c36ed4 --- /dev/null +++ b/lib/igdb.ts @@ -0,0 +1,76 @@ +import { IAuth, IGame } from "@/types/types" +import { calculateOffset, getImageURL } from "./utils" + +const TWITCH_AUTH_BASE_URL = process.env.TWITCH_AUTH_BASE_URL ?? '' +const IGDB_BASE_URL = process.env.IGDB_BASE_URL ?? '' + +const CLIENT_ID = process.env.TWITCH_CLIENT_ID ?? '' +const CLIENT_SECRET = process.env.TWITCH_CLIENT_SECRET ?? '' + +const limit = 200 + +let _auth: IAuth +let _lastUpdate = 0 + +// fetches a new token if the current one is expired +async function getToken(): Promise<IAuth> { + if (!_auth || Date.now() - _lastUpdate > _auth.expires_in) { + const url = new URL(`${TWITCH_AUTH_BASE_URL}/token`) + url.searchParams.set('client_id', CLIENT_ID) + url.searchParams.set('client_secret', CLIENT_SECRET) + url.searchParams.set('grant_type', 'client_credentials') + + const response = await fetch(url, { method: 'POST' }) + _auth = await response.json() as IAuth + _lastUpdate = Date.now() + } + return _auth +} + +// fetches the top 200 games with a rating of 96 or higher +export async function getGames(page = 1): Promise<IGame[]> { + const auth = await getToken() + const url = new URL(`${IGDB_BASE_URL}/games`) + + let offset = calculateOffset(page, limit) + + const response = await fetch(url, { + method: 'POST', + headers: { + '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;` + }) + const games = await response.json() as IGame[] + + games.forEach(game => { + game.cover.url = getImageURL(game.cover.image_id, 'cover_big') + }) + + return games +} + +// fetches a single game by id +export async function getGame(id: number): Promise<IGame[]> { + const auth = await getToken() + const url = new URL(`${IGDB_BASE_URL}/games`) + + const response = await fetch(url, { + method: 'POST', + headers: { + 'Client-ID': CLIENT_ID, + 'Authorization': `Bearer ${auth.access_token}` + }, + body: `fields name, cover.*, summary; where cover != null; where id = ${id};` + }) + const games = await response.json() as IGame[] + + games.forEach(game => { + game.cover.url = getImageURL(game.cover.image_id, 'cover_big') + }) + + return games +} \ No newline at end of file diff --git a/lib/utils.ts b/lib/utils.ts new file mode 100644 index 0000000000000000000000000000000000000000..1aebb959232883d237e08ef11bfdf6063931f559 --- /dev/null +++ b/lib/utils.ts @@ -0,0 +1,20 @@ +const IGDB_IMG_BASE_URL = process.env.IGDB_IMG_BASE_URL ?? '' + +// changes the default size of the image to be fetched +export function getImageURL(hashId: string, size: string): string { + return `${IGDB_IMG_BASE_URL}/t_${size}_2x/${hashId}.jpg` +} + +// returns the base url for the current environment, even considering current port +export function getBaseURL(): string { + return process.env.NODE_ENV === 'production' + ? process.env.PROD_URL ?? '' + : (typeof window !== 'undefined' + ? `http://${window.location.hostname}:${window.location.port}` + : 'http://localhost:3000') +} + +// calculates the offset for the query +export function calculateOffset(page: number, limit: number): number { + return (page - 1) * limit +} \ No newline at end of file diff --git a/package-lock.json b/package-lock.json index 71b380cd071793eb05353b6d89b2c07e502fd3e4..0dfe3c726fc174ea479bc054358fa7f344a51a40 100644 --- a/package-lock.json +++ b/package-lock.json @@ -8,23 +8,25 @@ "name": "project_ss23", "version": "0.1.0", "dependencies": { - "@clerk/nextjs": "^4.17.1", + "@clerk/nextjs": "^4.18.2", "@emotion/react": "^11.11.0", "@emotion/styled": "^11.11.0", - "@mui/material": "^5.12.3", - "@prisma/client": "^4.13.0", - "@types/node": "20.1.0", + "@mui/icons-material": "^5.11.16", + "@mui/material": "^5.13.1", + "@types/node": "20.2.1", "@types/react": "18.2.6", "@types/react-dom": "18.2.4", - "eslint": "8.40.0", - "eslint-config-next": "13.4.1", - "next": "13.4.1", + "eslint": "8.41.0", + "eslint-config-next": "13.4.3", + "next": "13.4.3", "react": "18.2.0", "react-dom": "18.2.0", + "react-infinite-scroll-component": "^6.1.0", + "react-query": "^3.39.3", "typescript": "5.0.4" }, "devDependencies": { - "prisma": "^4.13.0" + "prisma": "^4.14.1" } }, "node_modules/@babel/code-frame": { @@ -167,11 +169,11 @@ } }, "node_modules/@clerk/backend": { - "version": "0.18.0", - "resolved": "https://registry.npmjs.org/@clerk/backend/-/backend-0.18.0.tgz", - "integrity": "sha512-d3YoDBK56XLdoAkLq7wCyY9B3Qxd1DG0+snXTXE7qWQtG6AFJEQ7FKFRFEsNzMZaWRfiiE9jQ9GJMjWEVvLAUA==", + "version": "0.19.2", + "resolved": "https://registry.npmjs.org/@clerk/backend/-/backend-0.19.2.tgz", + "integrity": "sha512-9zzhoX5IwcIrwIwZxgkyYctTUoj0phFjKuq4+IwYra9jZ8+NUEZcI/RATRbDl6WcZcnoW7qChL1OH6QXRv3u+A==", "dependencies": { - "@clerk/types": "^3.36.0", + "@clerk/types": "^3.38.1", "@peculiar/webcrypto": "1.4.1", "@types/node": "16.18.6", "deepmerge": "4.2.2", @@ -194,12 +196,12 @@ "integrity": "sha512-tGyy4dAjRIEwI7BzsB0lynWgOpfqjUdq91XXAlIWD2OwKBH7oCl/GZG/HT4BOHrTlPMOASlMQ7veyTqpmRcrNA==" }, "node_modules/@clerk/clerk-react": { - "version": "4.15.4", - "resolved": "https://registry.npmjs.org/@clerk/clerk-react/-/clerk-react-4.15.4.tgz", - "integrity": "sha512-OSimB3ua3hJtlau3qUWIhIGIOoRZVEUMBuyVSkCkEEyjCGhHnSyO81Vcbv9slUtlP3DWlxeppMpdA62KZ6L1iA==", + "version": "4.16.2", + "resolved": "https://registry.npmjs.org/@clerk/clerk-react/-/clerk-react-4.16.2.tgz", + "integrity": "sha512-7WNmIlTKtNTzo5u7iHQqjWH/qzX22AY9iGM/zND2kCbCLKD39l5A2iecJ3aNLnWmxrz9xpgYVfTVbaVYWnEzPA==", "dependencies": { - "@clerk/shared": "^0.15.7", - "@clerk/types": "^3.36.0", + "@clerk/shared": "^0.16.2", + "@clerk/types": "^3.38.1", "swr": "1.3.0", "tslib": "2.4.1" }, @@ -216,12 +218,12 @@ "integrity": "sha512-tGyy4dAjRIEwI7BzsB0lynWgOpfqjUdq91XXAlIWD2OwKBH7oCl/GZG/HT4BOHrTlPMOASlMQ7veyTqpmRcrNA==" }, "node_modules/@clerk/clerk-sdk-node": { - "version": "4.8.7", - "resolved": "https://registry.npmjs.org/@clerk/clerk-sdk-node/-/clerk-sdk-node-4.8.7.tgz", - "integrity": "sha512-fOlfPOL7XhBR9Jg9RnUnYqRB6yXlE+3/kVZ4RG0CcWNVLwLwGIgHz0C3+Sa3e3g+UAVpuvvnXq2/42rstm/ADA==", + "version": "4.9.2", + "resolved": "https://registry.npmjs.org/@clerk/clerk-sdk-node/-/clerk-sdk-node-4.9.2.tgz", + "integrity": "sha512-JibCbTiRZZ8hkgRMiGYVip7ogI2picZ6NaTed/d+QqvziRsE5M3wyfEUOIUSeO3hfaKUytGvofczikH6AAaCyA==", "dependencies": { - "@clerk/backend": "^0.18.0", - "@clerk/types": "^3.36.0", + "@clerk/backend": "^0.19.2", + "@clerk/types": "^3.38.1", "@types/cookies": "0.7.7", "@types/express": "4.17.14", "@types/node-fetch": "2.6.2", @@ -252,14 +254,14 @@ "integrity": "sha512-tGyy4dAjRIEwI7BzsB0lynWgOpfqjUdq91XXAlIWD2OwKBH7oCl/GZG/HT4BOHrTlPMOASlMQ7veyTqpmRcrNA==" }, "node_modules/@clerk/nextjs": { - "version": "4.17.1", - "resolved": "https://registry.npmjs.org/@clerk/nextjs/-/nextjs-4.17.1.tgz", - "integrity": "sha512-v6UPYUkwktUmZT01nJFWQvrWSyVJx6CYa/KVHo6gmSTyUFX7p7Tpfoknq1VCvqp6DCHdbJC1uHbXmjUd4AhwBQ==", - "dependencies": { - "@clerk/backend": "^0.18.0", - "@clerk/clerk-react": "^4.15.4", - "@clerk/clerk-sdk-node": "^4.8.7", - "@clerk/types": "^3.36.0", + "version": "4.18.2", + "resolved": "https://registry.npmjs.org/@clerk/nextjs/-/nextjs-4.18.2.tgz", + "integrity": "sha512-m0cXwAPhT3yUJsNyl1leAUMu/AoX46cEx/FADU/tX/D4Vf68YuB8uCivTrPSO4luASIVi/noLFQYJIo3W96qhQ==", + "dependencies": { + "@clerk/backend": "^0.19.2", + "@clerk/clerk-react": "^4.16.2", + "@clerk/clerk-sdk-node": "^4.9.2", + "@clerk/types": "^3.38.1", "path-to-regexp": "6.2.1", "tslib": "2.4.1" }, @@ -278,17 +280,20 @@ "integrity": "sha512-tGyy4dAjRIEwI7BzsB0lynWgOpfqjUdq91XXAlIWD2OwKBH7oCl/GZG/HT4BOHrTlPMOASlMQ7veyTqpmRcrNA==" }, "node_modules/@clerk/shared": { - "version": "0.15.7", - "resolved": "https://registry.npmjs.org/@clerk/shared/-/shared-0.15.7.tgz", - "integrity": "sha512-8kinCWFF28K8N/OCqfZYIEzxpyH8+HFZ1BmfloQLDSsiy8kpUljk3qbKkBRoHAxJKohSjZL6ax+IpBzt2FmkZw==", + "version": "0.16.2", + "resolved": "https://registry.npmjs.org/@clerk/shared/-/shared-0.16.2.tgz", + "integrity": "sha512-TiMw3MB1daQc0CIVolstOIkuDURo1BteHDdKIUUU8ZKTsD9p2Kdb488pYo6jMi08YZ639Yov7dhoedclcDAMHw==", + "dependencies": { + "glob-to-regexp": "0.4.1" + }, "peerDependencies": { "react": ">=16" } }, "node_modules/@clerk/types": { - "version": "3.36.0", - "resolved": "https://registry.npmjs.org/@clerk/types/-/types-3.36.0.tgz", - "integrity": "sha512-bsOIud1h3Tkvd9F0CGTqqD7NicvAF3O0hFQ2lGjuETFrNqV8houorrGM9d0ZMU72vsyzwTQ/Jw8vB4mIHIXHMQ==", + "version": "3.38.1", + "resolved": "https://registry.npmjs.org/@clerk/types/-/types-3.38.1.tgz", + "integrity": "sha512-/gBeFp3f7r23uU0ag5qxmwGKUc222YokgiPCusU8NE+AFbg1PIfudrw/0eKRbSZbz6DI7E+mxVz4M3mVkTJVlQ==", "dependencies": { "csstype": "3.1.1" }, @@ -479,9 +484,9 @@ } }, "node_modules/@eslint/js": { - "version": "8.40.0", - "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.40.0.tgz", - "integrity": "sha512-ElyB54bJIhXQYVKjDSvCkPO1iU1tSAeVQJbllWJq1XQSmmA4dgFk8CbiBGpiOPxleE48vDogxCtmMYku4HSVLA==", + "version": "8.41.0", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.41.0.tgz", + "integrity": "sha512-LxcyMGxwmTh2lY9FwHPGWOHmYFCZvbrFCBZL4FzSSsxsRPuhrYUg/49/0KDfW8tnIEaEHtfmn6+NPN+1DqaNmA==", "engines": { "node": "^12.22.0 || ^14.17.0 || >=16.0.0" } @@ -517,14 +522,14 @@ "integrity": "sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==" }, "node_modules/@mui/base": { - "version": "5.0.0-alpha.128", - "resolved": "https://registry.npmjs.org/@mui/base/-/base-5.0.0-alpha.128.tgz", - "integrity": "sha512-wub3wxNN+hUp8hzilMlXX3sZrPo75vsy1cXEQpqdTfIFlE9HprP1jlulFiPg5tfPst2OKmygXr2hhmgvAKRrzQ==", + "version": "5.0.0-beta.1", + "resolved": "https://registry.npmjs.org/@mui/base/-/base-5.0.0-beta.1.tgz", + "integrity": "sha512-xrkDCeu3JQE+JjJUnJnOrdQJMXwKhbV4AW+FRjMIj5i9cHK3BAuatG/iqbf1M+jklVWLk0KdbgioKwK+03aYbA==", "dependencies": { "@babel/runtime": "^7.21.0", "@emotion/is-prop-valid": "^1.2.0", "@mui/types": "^7.2.4", - "@mui/utils": "^5.12.3", + "@mui/utils": "^5.13.1", "@popperjs/core": "^2.11.7", "clsx": "^1.2.1", "prop-types": "^15.8.1", @@ -554,26 +559,51 @@ "integrity": "sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==" }, "node_modules/@mui/core-downloads-tracker": { - "version": "5.12.3", - "resolved": "https://registry.npmjs.org/@mui/core-downloads-tracker/-/core-downloads-tracker-5.12.3.tgz", - "integrity": "sha512-yiJZ+knaknPHuRKhRk4L6XiwppwkAahVal3LuYpvBH7GkA2g+D9WLEXOEnNYtVFUggyKf6fWGLGnx0iqzkU5YA==", + "version": "5.13.1", + "resolved": "https://registry.npmjs.org/@mui/core-downloads-tracker/-/core-downloads-tracker-5.13.1.tgz", + "integrity": "sha512-qDHtNDO72NcBQMhaWBt9EZMvNiO+OXjPg5Sdk/6LgRDw6Zr3HdEZ5n2FJ/qtYsaT/okGyCuQavQkcZCOCEVf/g==", "funding": { "type": "opencollective", "url": "https://opencollective.com/mui" } }, + "node_modules/@mui/icons-material": { + "version": "5.11.16", + "resolved": "https://registry.npmjs.org/@mui/icons-material/-/icons-material-5.11.16.tgz", + "integrity": "sha512-oKkx9z9Kwg40NtcIajF9uOXhxiyTZrrm9nmIJ4UjkU2IdHpd4QVLbCc/5hZN/y0C6qzi2Zlxyr9TGddQx2vx2A==", + "dependencies": { + "@babel/runtime": "^7.21.0" + }, + "engines": { + "node": ">=12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/mui" + }, + "peerDependencies": { + "@mui/material": "^5.0.0", + "@types/react": "^17.0.0 || ^18.0.0", + "react": "^17.0.0 || ^18.0.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, "node_modules/@mui/material": { - "version": "5.12.3", - "resolved": "https://registry.npmjs.org/@mui/material/-/material-5.12.3.tgz", - "integrity": "sha512-xNmKlrEN4HsTaKFNLZfc7ie7CXx2YqEeO//hsXZx2p3MGtDdeMr2sV3jC4hsFs57RhQlF79weY7uVvC8xSuVbg==", + "version": "5.13.1", + "resolved": "https://registry.npmjs.org/@mui/material/-/material-5.13.1.tgz", + "integrity": "sha512-qSnbJZer8lIuDYFDv19/t3s0AXYY9SxcOdhCnGvetRSfOG4gy3TkiFXNCdW5OLNveTieiMpOuv46eXUmE3ZA6A==", "dependencies": { "@babel/runtime": "^7.21.0", - "@mui/base": "5.0.0-alpha.128", - "@mui/core-downloads-tracker": "^5.12.3", - "@mui/system": "^5.12.3", + "@mui/base": "5.0.0-beta.1", + "@mui/core-downloads-tracker": "^5.13.1", + "@mui/system": "^5.13.1", "@mui/types": "^7.2.4", - "@mui/utils": "^5.12.3", - "@types/react-transition-group": "^4.4.5", + "@mui/utils": "^5.13.1", + "@types/react-transition-group": "^4.4.6", "clsx": "^1.2.1", "csstype": "^3.1.2", "prop-types": "^15.8.1", @@ -612,12 +642,12 @@ "integrity": "sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==" }, "node_modules/@mui/private-theming": { - "version": "5.12.3", - "resolved": "https://registry.npmjs.org/@mui/private-theming/-/private-theming-5.12.3.tgz", - "integrity": "sha512-o1e7Z1Bp27n4x2iUHhegV4/Jp6H3T6iBKHJdLivS5GbwsuAE/5l4SnZ+7+K+e5u9TuhwcAKZLkjvqzkDe8zqfA==", + "version": "5.13.1", + "resolved": "https://registry.npmjs.org/@mui/private-theming/-/private-theming-5.13.1.tgz", + "integrity": "sha512-HW4npLUD9BAkVppOUZHeO1FOKUJWAwbpy0VQoGe3McUYTlck1HezGHQCfBQ5S/Nszi7EViqiimECVl9xi+/WjQ==", "dependencies": { "@babel/runtime": "^7.21.0", - "@mui/utils": "^5.12.3", + "@mui/utils": "^5.13.1", "prop-types": "^15.8.1" }, "engines": { @@ -669,15 +699,15 @@ } }, "node_modules/@mui/system": { - "version": "5.12.3", - "resolved": "https://registry.npmjs.org/@mui/system/-/system-5.12.3.tgz", - "integrity": "sha512-JB/6sypHqeJCqwldWeQ1MKkijH829EcZAKKizxbU2MJdxGG5KSwZvTBa5D9qiJUA1hJFYYupjiuy9ZdJt6rV6w==", + "version": "5.13.1", + "resolved": "https://registry.npmjs.org/@mui/system/-/system-5.13.1.tgz", + "integrity": "sha512-BsDUjhiO6ZVAvzKhnWBHLZ5AtPJcdT+62VjnRLyA4isboqDKLg4fmYIZXq51yndg/soDK9RkY5lYZwEDku13Ow==", "dependencies": { "@babel/runtime": "^7.21.0", - "@mui/private-theming": "^5.12.3", + "@mui/private-theming": "^5.13.1", "@mui/styled-engine": "^5.12.3", "@mui/types": "^7.2.4", - "@mui/utils": "^5.12.3", + "@mui/utils": "^5.13.1", "clsx": "^1.2.1", "csstype": "^3.1.2", "prop-types": "^15.8.1" @@ -721,13 +751,13 @@ } }, "node_modules/@mui/utils": { - "version": "5.12.3", - "resolved": "https://registry.npmjs.org/@mui/utils/-/utils-5.12.3.tgz", - "integrity": "sha512-D/Z4Ub3MRl7HiUccid7sQYclTr24TqUAQFFlxHQF8FR177BrCTQ0JJZom7EqYjZCdXhwnSkOj2ph685MSKNtIA==", + "version": "5.13.1", + "resolved": "https://registry.npmjs.org/@mui/utils/-/utils-5.13.1.tgz", + "integrity": "sha512-6lXdWwmlUbEU2jUI8blw38Kt+3ly7xkmV9ljzY4Q20WhsJMWiNry9CX8M+TaP/HbtuyR8XKsdMgQW7h7MM3n3A==", "dependencies": { "@babel/runtime": "^7.21.0", "@types/prop-types": "^15.7.5", - "@types/react-is": "^16.7.1 || ^17.0.0", + "@types/react-is": "^18.2.0", "prop-types": "^15.8.1", "react-is": "^18.2.0" }, @@ -748,22 +778,22 @@ "integrity": "sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==" }, "node_modules/@next/env": { - "version": "13.4.1", - "resolved": "https://registry.npmjs.org/@next/env/-/env-13.4.1.tgz", - "integrity": "sha512-eD6WCBMFjLFooLM19SIhSkWBHtaFrZFfg2Cxnyl3vS3DAdFRfnx5TY2RxlkuKXdIRCC0ySbtK9JXXt8qLCqzZg==" + "version": "13.4.3", + "resolved": "https://registry.npmjs.org/@next/env/-/env-13.4.3.tgz", + "integrity": "sha512-pa1ErjyFensznttAk3EIv77vFbfSYT6cLzVRK5jx4uiRuCQo+m2wCFAREaHKIy63dlgvOyMlzh6R8Inu8H3KrQ==" }, "node_modules/@next/eslint-plugin-next": { - "version": "13.4.1", - "resolved": "https://registry.npmjs.org/@next/eslint-plugin-next/-/eslint-plugin-next-13.4.1.tgz", - "integrity": "sha512-tVPS/2FKlA3ANCRCYZVT5jdbUKasBU8LG6bYqcNhyORDFTlDYa4cAWQJjZ7msIgLwMQIbL8CAsxrOL8maa/4Lg==", + "version": "13.4.3", + "resolved": "https://registry.npmjs.org/@next/eslint-plugin-next/-/eslint-plugin-next-13.4.3.tgz", + "integrity": "sha512-5B0uOnh7wyUY9vNNdIA6NUvWozhrZaTMZOzdirYAefqD0ZBK5C/h3+KMYdCKrR7JrXGvVpWnHtv54b3dCzwICA==", "dependencies": { "glob": "7.1.7" } }, "node_modules/@next/swc-darwin-arm64": { - "version": "13.4.1", - "resolved": "https://registry.npmjs.org/@next/swc-darwin-arm64/-/swc-darwin-arm64-13.4.1.tgz", - "integrity": "sha512-eF8ARHtYfnoYtDa6xFHriUKA/Mfj/cCbmKb3NofeKhMccs65G6/loZ15a6wYCCx4rPAd6x4t1WmVYtri7EdeBg==", + "version": "13.4.3", + "resolved": "https://registry.npmjs.org/@next/swc-darwin-arm64/-/swc-darwin-arm64-13.4.3.tgz", + "integrity": "sha512-yx18udH/ZmR4Bw4M6lIIPE3JxsAZwo04iaucEfA2GMt1unXr2iodHUX/LAKNyi6xoLP2ghi0E+Xi1f4Qb8f1LQ==", "cpu": [ "arm64" ], @@ -776,9 +806,9 @@ } }, "node_modules/@next/swc-darwin-x64": { - "version": "13.4.1", - "resolved": "https://registry.npmjs.org/@next/swc-darwin-x64/-/swc-darwin-x64-13.4.1.tgz", - "integrity": "sha512-7cmDgF9tGWTgn5Gw+vP17miJbH4wcraMHDCOHTYWkO/VeKT73dUWG23TNRLfgtCNSPgH4V5B4uLHoZTanx9bAw==", + "version": "13.4.3", + "resolved": "https://registry.npmjs.org/@next/swc-darwin-x64/-/swc-darwin-x64-13.4.3.tgz", + "integrity": "sha512-Mi8xJWh2IOjryAM1mx18vwmal9eokJ2njY4nDh04scy37F0LEGJ/diL6JL6kTXi0UfUCGbMsOItf7vpReNiD2A==", "cpu": [ "x64" ], @@ -791,9 +821,9 @@ } }, "node_modules/@next/swc-linux-arm64-gnu": { - "version": "13.4.1", - "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-13.4.1.tgz", - "integrity": "sha512-qwJqmCri2ie8aTtE5gjTSr8S6O8B67KCYgVZhv9gKH44yvc/zXbAY8u23QGULsYOyh1islWE5sWfQNLOj9iryg==", + "version": "13.4.3", + "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-13.4.3.tgz", + "integrity": "sha512-aBvtry4bxJ1xwKZ/LVPeBGBwWVwxa4bTnNkRRw6YffJnn/f4Tv4EGDPaVeYHZGQVA56wsGbtA6nZMuWs/EIk4Q==", "cpu": [ "arm64" ], @@ -806,9 +836,9 @@ } }, "node_modules/@next/swc-linux-arm64-musl": { - "version": "13.4.1", - "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-13.4.1.tgz", - "integrity": "sha512-qcC54tWNGDv/VVIFkazxhqH1Bnagjfs4enzELVRlUOoJPD2BGJTPI7z08pQPbbgxLtRiu8gl2mXvpB8WlOkMeA==", + "version": "13.4.3", + "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-13.4.3.tgz", + "integrity": "sha512-krT+2G3kEsEUvZoYte3/2IscscDraYPc2B+fDJFipPktJmrv088Pei/RjrhWm5TMIy5URYjZUoDZdh5k940Dyw==", "cpu": [ "arm64" ], @@ -821,9 +851,9 @@ } }, "node_modules/@next/swc-linux-x64-gnu": { - "version": "13.4.1", - "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-13.4.1.tgz", - "integrity": "sha512-9TeWFlpLsBosZ+tsm/rWBaMwt5It9tPH8m3nawZqFUUrZyGRfGcI67js774vtx0k3rL9qbyY6+3pw9BCVpaYUA==", + "version": "13.4.3", + "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-13.4.3.tgz", + "integrity": "sha512-AMdFX6EKJjC0G/CM6hJvkY8wUjCcbdj3Qg7uAQJ7PVejRWaVt0sDTMavbRfgMchx8h8KsAudUCtdFkG9hlEClw==", "cpu": [ "x64" ], @@ -836,9 +866,9 @@ } }, "node_modules/@next/swc-linux-x64-musl": { - "version": "13.4.1", - "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-13.4.1.tgz", - "integrity": "sha512-sNDGaWmSqTS4QRUzw61wl4mVPeSqNIr1OOjLlQTRuyInxMxtqImRqdvzDvFTlDfdeUMU/DZhWGYoHrXLlZXe6A==", + "version": "13.4.3", + "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-13.4.3.tgz", + "integrity": "sha512-jySgSXE48shaLtcQbiFO9ajE9mqz7pcAVLnVLvRIlUHyQYR/WyZdK8ehLs65Mz6j9cLrJM+YdmdJPyV4WDaz2g==", "cpu": [ "x64" ], @@ -851,9 +881,9 @@ } }, "node_modules/@next/swc-win32-arm64-msvc": { - "version": "13.4.1", - "resolved": "https://registry.npmjs.org/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-13.4.1.tgz", - "integrity": "sha512-+CXZC7u1iXdLRudecoUYbhbsXpglYv8KFYsFxKBPn7kg+bk7eJo738wAA4jXIl8grTF2mPdmO93JOQym+BlYGA==", + "version": "13.4.3", + "resolved": "https://registry.npmjs.org/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-13.4.3.tgz", + "integrity": "sha512-5DxHo8uYcaADiE9pHrg8o28VMt/1kR8voDehmfs9AqS0qSClxAAl+CchjdboUvbCjdNWL1MISCvEfKY2InJ3JA==", "cpu": [ "arm64" ], @@ -866,9 +896,9 @@ } }, "node_modules/@next/swc-win32-ia32-msvc": { - "version": "13.4.1", - "resolved": "https://registry.npmjs.org/@next/swc-win32-ia32-msvc/-/swc-win32-ia32-msvc-13.4.1.tgz", - "integrity": "sha512-vIoXVVc7UYO68VwVMDKwJC2+HqAZQtCYiVlApyKEeIPIQpz2gpufzGxk1z3/gwrJt/kJ5CDZjlhYDCzd3hdz+g==", + "version": "13.4.3", + "resolved": "https://registry.npmjs.org/@next/swc-win32-ia32-msvc/-/swc-win32-ia32-msvc-13.4.3.tgz", + "integrity": "sha512-LaqkF3d+GXRA5X6zrUjQUrXm2MN/3E2arXBtn5C7avBCNYfm9G3Xc646AmmmpN3DJZVaMYliMyCIQCMDEzk80w==", "cpu": [ "ia32" ], @@ -881,9 +911,9 @@ } }, "node_modules/@next/swc-win32-x64-msvc": { - "version": "13.4.1", - "resolved": "https://registry.npmjs.org/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-13.4.1.tgz", - "integrity": "sha512-n8V5ImLQZibKTu10UUdI3nIeTLkliEXe628qxqW9v8My3BAH2a7H0SaCqkV2OgqFnn8sG1wxKYw9/SNJ632kSA==", + "version": "13.4.3", + "resolved": "https://registry.npmjs.org/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-13.4.3.tgz", + "integrity": "sha512-jglUk/x7ZWeOJWlVoKyIAkHLTI+qEkOriOOV+3hr1GyiywzcqfI7TpFSiwC7kk1scOiH7NTFKp8mA3XPNO9bDw==", "cpu": [ "x64" ], @@ -1012,10 +1042,10 @@ } }, "node_modules/@prisma/engines": { - "version": "4.13.0", - "resolved": "https://registry.npmjs.org/@prisma/engines/-/engines-4.13.0.tgz", - "integrity": "sha512-HrniowHRZXHuGT9XRgoXEaP2gJLXM5RMoItaY2PkjvuZ+iHc0Zjbm/302MB8YsPdWozAPHHn+jpFEcEn71OgPw==", - "devOptional": true, + "version": "4.14.1", + "resolved": "https://registry.npmjs.org/@prisma/engines/-/engines-4.14.1.tgz", + "integrity": "sha512-APqFddPVHYmWNKqc+5J5SqrLFfOghKOLZxobmguDUacxOwdEutLsbXPVhNnpFDmuQWQFbXmrTTPoRrrF6B1MWA==", + "dev": true, "hasInstallScript": true }, "node_modules/@prisma/engines-version": { @@ -1076,9 +1106,9 @@ } }, "node_modules/@types/express-serve-static-core": { - "version": "4.17.34", - "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.17.34.tgz", - "integrity": "sha512-fvr49XlCGoUj2Pp730AItckfjat4WNb0lb3kfrLWffd+RLeoGAMsq7UOy04PAPtoL01uKwcp6u8nhzpgpDYr3w==", + "version": "4.17.35", + "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.17.35.tgz", + "integrity": "sha512-wALWQwrgiB2AWTT91CB62b6Yt0sNHpznUXeZEcnPU3DRdlDIz74x8Qg1UUYKSVFi+va5vKOLYRBI1bRKiLLKIg==", "dependencies": { "@types/node": "*", "@types/qs": "*", @@ -1102,9 +1132,9 @@ "integrity": "sha512-YATxVxgRqNH6nHEIsvg6k2Boc1JHI9ZbH5iWFFv/MTkchz3b1ieGDa5T0a9RznNdI0KhVbdbWSN+KWWrQZRxTw==" }, "node_modules/@types/node": { - "version": "20.1.0", - "resolved": "https://registry.npmjs.org/@types/node/-/node-20.1.0.tgz", - "integrity": "sha512-O+z53uwx64xY7D6roOi4+jApDGFg0qn6WHcxe5QeqjMaTezBO/mxdfFXIVAVVyNWKx84OmPB3L8kbVYOTeN34A==" + "version": "20.2.1", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.2.1.tgz", + "integrity": "sha512-DqJociPbZP1lbZ5SQPk4oag6W7AyaGMO6gSfRwq3PWl4PXTwJpRQJhDq4W0kzrg3w6tJ1SwlvGZ5uKFHY13LIg==" }, "node_modules/@types/node-fetch": { "version": "2.6.2", @@ -1154,21 +1184,11 @@ } }, "node_modules/@types/react-is": { - "version": "17.0.4", - "resolved": "https://registry.npmjs.org/@types/react-is/-/react-is-17.0.4.tgz", - "integrity": "sha512-FLzd0K9pnaEvKz4D1vYxK9JmgQPiGk1lu23o1kqGsLeT0iPbRSF7b76+S5T9fD8aRa0B8bY7I/3DebEj+1ysBA==", - "dependencies": { - "@types/react": "^17" - } - }, - "node_modules/@types/react-is/node_modules/@types/react": { - "version": "17.0.59", - "resolved": "https://registry.npmjs.org/@types/react/-/react-17.0.59.tgz", - "integrity": "sha512-gSON5zWYIGyoBcycCE75E9+r6dCC2dHdsrVkOEiIYNU5+Q28HcBAuqvDuxHcCbMfHBHdeT5Tva/AFn3rnMKE4g==", + "version": "18.2.0", + "resolved": "https://registry.npmjs.org/@types/react-is/-/react-is-18.2.0.tgz", + "integrity": "sha512-1vz2yObaQkLL7YFe/pme2cpvDsCwI1WXIfL+5eLz0MI9gFG24Re16RzUsI8t9XZn9ZWvgLNDrJBmrqXJO7GNQQ==", "dependencies": { - "@types/prop-types": "*", - "@types/scheduler": "*", - "csstype": "^3.0.2" + "@types/react": "*" } }, "node_modules/@types/react-transition-group": { @@ -1559,6 +1579,21 @@ "node": ">=8" } }, + "node_modules/broadcast-channel": { + "version": "3.7.0", + "resolved": "https://registry.npmjs.org/broadcast-channel/-/broadcast-channel-3.7.0.tgz", + "integrity": "sha512-cIAKJXAxGJceNZGTZSBzMxzyOn72cVgPnKx4dc6LRjQgbaJUQqhy5rzL3zbMxkMWsGKkv2hSFkPRMEXfoMZ2Mg==", + "dependencies": { + "@babel/runtime": "^7.7.2", + "detect-node": "^2.1.0", + "js-sha3": "0.8.0", + "microseconds": "0.2.0", + "nano-time": "1.0.0", + "oblivious-set": "1.0.0", + "rimraf": "3.0.2", + "unload": "2.2.0" + } + }, "node_modules/bundle-name": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/bundle-name/-/bundle-name-3.0.0.tgz", @@ -1881,6 +1916,11 @@ "node": ">=0.4.0" } }, + "node_modules/detect-node": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/detect-node/-/detect-node-2.1.0.tgz", + "integrity": "sha512-T0NIuQpnTvFDATNuHN5roPwSBG83rFsuO+MXXH9/3N1eFbn4wcPjttvjMLEPWJ0RGUYgQE7cGgS3tNxbqCGM7g==" + }, "node_modules/dir-glob": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", @@ -2061,14 +2101,14 @@ } }, "node_modules/eslint": { - "version": "8.40.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.40.0.tgz", - "integrity": "sha512-bvR+TsP9EHL3TqNtj9sCNJVAFK3fBN8Q7g5waghxyRsPLIMwL73XSKnZFK0hk/O2ANC+iAoq6PWMQ+IfBAJIiQ==", + "version": "8.41.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.41.0.tgz", + "integrity": "sha512-WQDQpzGBOP5IrXPo4Hc0814r4/v2rrIsB0rhT7jtunIalgg6gYXWhRMOejVO8yH21T/FGaxjmFjBMNqcIlmH1Q==", "dependencies": { "@eslint-community/eslint-utils": "^4.2.0", "@eslint-community/regexpp": "^4.4.0", "@eslint/eslintrc": "^2.0.3", - "@eslint/js": "8.40.0", + "@eslint/js": "8.41.0", "@humanwhocodes/config-array": "^0.11.8", "@humanwhocodes/module-importer": "^1.0.1", "@nodelib/fs.walk": "^1.2.8", @@ -2088,13 +2128,12 @@ "find-up": "^5.0.0", "glob-parent": "^6.0.2", "globals": "^13.19.0", - "grapheme-splitter": "^1.0.4", + "graphemer": "^1.4.0", "ignore": "^5.2.0", "import-fresh": "^3.0.0", "imurmurhash": "^0.1.4", "is-glob": "^4.0.0", "is-path-inside": "^3.0.3", - "js-sdsl": "^4.1.4", "js-yaml": "^4.1.0", "json-stable-stringify-without-jsonify": "^1.0.1", "levn": "^0.4.1", @@ -2117,11 +2156,11 @@ } }, "node_modules/eslint-config-next": { - "version": "13.4.1", - "resolved": "https://registry.npmjs.org/eslint-config-next/-/eslint-config-next-13.4.1.tgz", - "integrity": "sha512-ajuxjCkW1hvirr0EQZb3/B/bFH52Z7CT89uCtTcICFL9l30i5c8hN4p0LXvTjdOXNPV5fEDcxBgGHgXdzTj1/A==", + "version": "13.4.3", + "resolved": "https://registry.npmjs.org/eslint-config-next/-/eslint-config-next-13.4.3.tgz", + "integrity": "sha512-1lXwdFi29fKxzeugof/TUE7lpHyJQt5+U4LaUHyvQfHjvsWO77vFNicJv5sX6k0VDVSbnfz0lw+avxI+CinbMg==", "dependencies": { - "@next/eslint-plugin-next": "13.4.1", + "@next/eslint-plugin-next": "13.4.3", "@rushstack/eslint-patch": "^1.1.3", "@typescript-eslint/parser": "^5.42.0", "eslint-import-resolver-node": "^0.3.6", @@ -2746,6 +2785,11 @@ "node": ">=10.13.0" } }, + "node_modules/glob-to-regexp": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/glob-to-regexp/-/glob-to-regexp-0.4.1.tgz", + "integrity": "sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw==" + }, "node_modules/globals": { "version": "13.20.0", "resolved": "https://registry.npmjs.org/globals/-/globals-13.20.0.tgz", @@ -2809,10 +2853,10 @@ "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==" }, - "node_modules/grapheme-splitter": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/grapheme-splitter/-/grapheme-splitter-1.0.4.tgz", - "integrity": "sha512-bzh50DW9kTPM00T8y4o8vQg89Di9oLJVLW/KaOGIXJWP/iqCN6WKYkbNOF04vFLJhwcpYUh9ydh/+5vpOqV4YQ==" + "node_modules/graphemer": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/graphemer/-/graphemer-1.4.0.tgz", + "integrity": "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==" }, "node_modules/has": { "version": "1.0.3", @@ -3313,14 +3357,10 @@ "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==" }, - "node_modules/js-sdsl": { - "version": "4.4.0", - "resolved": "https://registry.npmjs.org/js-sdsl/-/js-sdsl-4.4.0.tgz", - "integrity": "sha512-FfVSdx6pJ41Oa+CF7RDaFmTnCaFhua+SNYQX74riGOpl96x+2jQCqEfQ2bnXu/5DPCqlRuiqyvTJM0Qjz26IVg==", - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/js-sdsl" - } + "node_modules/js-sha3": { + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/js-sha3/-/js-sha3-0.8.0.tgz", + "integrity": "sha512-gF1cRrHhIzNfToc802P800N8PpXS+evLLXfsVpowqmAFR9uwbi89WvXg2QspOmXL8QL86J4T1EpFu+yUkwJY3Q==" }, "node_modules/js-tokens": { "version": "4.0.0", @@ -3466,6 +3506,15 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/match-sorter": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/match-sorter/-/match-sorter-6.3.1.tgz", + "integrity": "sha512-mxybbo3pPNuA+ZuCUhm5bwNkXrJTbsk5VWbR5wiwz/GC6LIiegBGn2w3O08UG/jdbYLinw51fSQ5xNU1U3MgBw==", + "dependencies": { + "@babel/runtime": "^7.12.5", + "remove-accents": "0.4.2" + } + }, "node_modules/merge-stream": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", @@ -3491,6 +3540,11 @@ "node": ">=8.6" } }, + "node_modules/microseconds": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/microseconds/-/microseconds-0.2.0.tgz", + "integrity": "sha512-n7DHHMjR1avBbSpsTBj6fmMGh2AGrifVV4e+WYc3Q9lO+xnSZ3NyhcBND3vzzatt05LFhoKFRxrIyklmLlUtyA==" + }, "node_modules/mime-db": { "version": "1.52.0", "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", @@ -3545,6 +3599,14 @@ "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" }, + "node_modules/nano-time": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/nano-time/-/nano-time-1.0.0.tgz", + "integrity": "sha512-flnngywOoQ0lLQOTRNexn2gGSNuM9bKj9RZAWSzhQ+UJYaAFG9bac4DW9VHjUAzrOaIcajHybCTHe/bkvozQqA==", + "dependencies": { + "big-integer": "^1.6.16" + } + }, "node_modules/nanoid": { "version": "3.3.6", "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.6.tgz", @@ -3568,11 +3630,11 @@ "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==" }, "node_modules/next": { - "version": "13.4.1", - "resolved": "https://registry.npmjs.org/next/-/next-13.4.1.tgz", - "integrity": "sha512-JBw2kAIyhKDpjhEWvNVoFeIzNp9xNxg8wrthDOtMctfn3EpqGCmW0FSviNyGgOSOSn6zDaX48pmvbdf6X2W9xA==", + "version": "13.4.3", + "resolved": "https://registry.npmjs.org/next/-/next-13.4.3.tgz", + "integrity": "sha512-FV3pBrAAnAIfOclTvncw9dDohyeuEEXPe5KNcva91anT/rdycWbgtu3IjUj4n5yHnWK8YEPo0vrUecHmnmUNbA==", "dependencies": { - "@next/env": "13.4.1", + "@next/env": "13.4.3", "@swc/helpers": "0.5.1", "busboy": "1.6.0", "caniuse-lite": "^1.0.30001406", @@ -3587,15 +3649,15 @@ "node": ">=16.8.0" }, "optionalDependencies": { - "@next/swc-darwin-arm64": "13.4.1", - "@next/swc-darwin-x64": "13.4.1", - "@next/swc-linux-arm64-gnu": "13.4.1", - "@next/swc-linux-arm64-musl": "13.4.1", - "@next/swc-linux-x64-gnu": "13.4.1", - "@next/swc-linux-x64-musl": "13.4.1", - "@next/swc-win32-arm64-msvc": "13.4.1", - "@next/swc-win32-ia32-msvc": "13.4.1", - "@next/swc-win32-x64-msvc": "13.4.1" + "@next/swc-darwin-arm64": "13.4.3", + "@next/swc-darwin-x64": "13.4.3", + "@next/swc-linux-arm64-gnu": "13.4.3", + "@next/swc-linux-arm64-musl": "13.4.3", + "@next/swc-linux-x64-gnu": "13.4.3", + "@next/swc-linux-x64-musl": "13.4.3", + "@next/swc-win32-arm64-msvc": "13.4.3", + "@next/swc-win32-ia32-msvc": "13.4.3", + "@next/swc-win32-x64-msvc": "13.4.3" }, "peerDependencies": { "@opentelemetry/api": "^1.1.0", @@ -3772,6 +3834,11 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/oblivious-set": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/oblivious-set/-/oblivious-set-1.0.0.tgz", + "integrity": "sha512-z+pI07qxo4c2CulUHCDf9lcqDlMSo72N/4rLUpRXf6fu+q8vjt8y0xS+Tlf8NTJDdTXHbdeO1n3MlbctwEoXZw==" + }, "node_modules/once": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", @@ -3973,13 +4040,13 @@ } }, "node_modules/prisma": { - "version": "4.13.0", - "resolved": "https://registry.npmjs.org/prisma/-/prisma-4.13.0.tgz", - "integrity": "sha512-L9mqjnSmvWIRCYJ9mQkwCtj4+JDYYTdhoyo8hlsHNDXaZLh/b4hR0IoKIBbTKxZuyHQzLopb/+0Rvb69uGV7uA==", - "devOptional": true, + "version": "4.14.1", + "resolved": "https://registry.npmjs.org/prisma/-/prisma-4.14.1.tgz", + "integrity": "sha512-z6hxzTMYqT9SIKlzD08dhzsLUpxjFKKsLpp5/kBDnSqiOjtUyyl/dC5tzxLcOa3jkEHQ8+RpB/fE3w8bgNP51g==", + "dev": true, "hasInstallScript": true, "dependencies": { - "@prisma/engines": "4.13.0" + "@prisma/engines": "4.14.1" }, "bin": { "prisma": "build/index.js", @@ -4073,11 +4140,47 @@ "react": "^18.2.0" } }, + "node_modules/react-infinite-scroll-component": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/react-infinite-scroll-component/-/react-infinite-scroll-component-6.1.0.tgz", + "integrity": "sha512-SQu5nCqy8DxQWpnUVLx7V7b7LcA37aM7tvoWjTLZp1dk6EJibM5/4EJKzOnl07/BsM1Y40sKLuqjCwwH/xV0TQ==", + "dependencies": { + "throttle-debounce": "^2.1.0" + }, + "peerDependencies": { + "react": ">=16.0.0" + } + }, "node_modules/react-is": { "version": "16.13.1", "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==" }, + "node_modules/react-query": { + "version": "3.39.3", + "resolved": "https://registry.npmjs.org/react-query/-/react-query-3.39.3.tgz", + "integrity": "sha512-nLfLz7GiohKTJDuT4us4X3h/8unOh+00MLb2yJoGTPjxKs2bc1iDhkNx2bd5MKklXnOD3NrVZ+J2UXujA5In4g==", + "dependencies": { + "@babel/runtime": "^7.5.5", + "broadcast-channel": "^3.4.1", + "match-sorter": "^6.0.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/tannerlinsley" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0" + }, + "peerDependenciesMeta": { + "react-dom": { + "optional": true + }, + "react-native": { + "optional": true + } + } + }, "node_modules/react-transition-group": { "version": "4.4.5", "resolved": "https://registry.npmjs.org/react-transition-group/-/react-transition-group-4.4.5.tgz", @@ -4114,6 +4217,11 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/remove-accents": { + "version": "0.4.2", + "resolved": "https://registry.npmjs.org/remove-accents/-/remove-accents-0.4.2.tgz", + "integrity": "sha512-7pXIJqJOq5tFgG1A2Zxti3Ht8jJF337m4sowbuHsW30ZnkQFnDzy9qBNhgzX8ZLW4+UBcXiiR7SwR6pokHsxiA==" + }, "node_modules/resolve": { "version": "1.22.2", "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.2.tgz", @@ -4613,6 +4721,14 @@ "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==" }, + "node_modules/throttle-debounce": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/throttle-debounce/-/throttle-debounce-2.3.0.tgz", + "integrity": "sha512-H7oLPV0P7+jgvrk+6mwwwBDmxTaxnu9HMXmloNLXwnNO0ZxZ31Orah2n8lU1eMPvsaowP2CX+USCgyovXfdOFQ==", + "engines": { + "node": ">=8" + } + }, "node_modules/titleize": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/titleize/-/titleize-3.0.0.tgz", @@ -4760,6 +4876,15 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/unload": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/unload/-/unload-2.2.0.tgz", + "integrity": "sha512-B60uB5TNBLtN6/LsgAf3udH9saB5p7gqJwcFfbOEZ8BcBHnGwCf6G/TGiEqkRAxX7zAFIUtzdrXQSdL3Q/wqNA==", + "dependencies": { + "@babel/runtime": "^7.6.2", + "detect-node": "^2.0.4" + } + }, "node_modules/untildify": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/untildify/-/untildify-4.0.0.tgz", diff --git a/package.json b/package.json index d31f10a9542c4d43f7ed9f7b1b59c812c4eaf9cc..bdaa2dcca07cf94008b15a86362b2d13910376dc 100644 --- a/package.json +++ b/package.json @@ -9,22 +9,24 @@ "lint": "next lint" }, "dependencies": { - "@clerk/nextjs": "^4.17.1", + "@clerk/nextjs": "^4.18.2", "@emotion/react": "^11.11.0", "@emotion/styled": "^11.11.0", - "@mui/material": "^5.12.3", - "@prisma/client": "^4.13.0", - "@types/node": "20.1.0", + "@mui/icons-material": "^5.11.16", + "@mui/material": "^5.13.1", + "@types/node": "20.2.1", "@types/react": "18.2.6", "@types/react-dom": "18.2.4", - "eslint": "8.40.0", - "eslint-config-next": "13.4.1", - "next": "13.4.1", + "eslint": "8.41.0", + "eslint-config-next": "13.4.3", + "next": "13.4.3", "react": "18.2.0", "react-dom": "18.2.0", + "react-infinite-scroll-component": "^6.1.0", + "react-query": "^3.39.3", "typescript": "5.0.4" }, "devDependencies": { - "prisma": "^4.13.0" + "prisma": "^4.14.1" } } diff --git a/public/logo.svg b/public/logo.svg new file mode 100644 index 0000000000000000000000000000000000000000..a98fd482fb5f7aa3003214ea8187288a5f107c75 --- /dev/null +++ b/public/logo.svg @@ -0,0 +1,10 @@ +<svg width="32" height="32" viewBox="0 0 32 32" fill="none" xmlns="http://www.w3.org/2000/svg"> +<path d="M18.2756 22.8622H9.13782V30C9.13782 31.1046 10.0332 32 11.1378 32H16.2756C17.3802 32 18.2756 31.1046 18.2756 30V22.8622Z" fill="black"/> +<path d="M18.2934 22.8622L13.7067 18.2934L9.13782 22.8622H18.2934Z" fill="black"/> +<path d="M20.8444 0H15.7067C14.6021 0 13.7067 0.895431 13.7067 2V9.13785H22.8444V2C22.8444 0.89543 21.949 0 20.8444 0Z" fill="black"/> +<path d="M13.7067 9.15555L18.2933 13.7245L22.8622 9.15555H13.7067Z" fill="black"/> +<path d="M9.13776 9.15555H2C0.89543 9.15555 0 10.051 0 11.1555V16.2934C0 17.398 0.895432 18.2934 2 18.2934H9.13776V9.15555Z" fill="#8E4CC2"/> +<path d="M9.13782 18.2934L13.7067 13.7245L9.13782 9.15555V18.2934Z" fill="#8E4CC2"/> +<path d="M29.9999 13.7245H22.8622V22.8622H29.9999C31.1045 22.8622 31.9999 21.9667 31.9999 20.8622V15.7245C31.9999 14.6199 31.1045 13.7245 29.9999 13.7245Z" fill="black"/> +<path d="M22.8623 13.7245L18.2933 18.2934L22.8623 22.8622V13.7245Z" fill="black"/> +</svg> diff --git a/types/types.ts b/types/types.ts new file mode 100644 index 0000000000000000000000000000000000000000..2cecc0034485173a6844f0200f1c7f4912d9e6c9 --- /dev/null +++ b/types/types.ts @@ -0,0 +1,159 @@ +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; + token_type: 'bearer'; +} + +export interface IGame { + id: number; + age_ratings: EAgeRatingCategory[]; + aggregrated_rating: number; + aggregrated_rating_count: number; + alternative_names: number[]; + artworks: number[]; + bundles: number[]; + category: EGameCategory; + checksum: string; + collection: number; + cover: ICover; + created_at: number; + dlcs: number[]; + expanded_games: number[]; + expansions: number[]; + external_games: number[]; + first_release_date: number; + follows: number; + forks: number[]; + franchise: number; + franchises: number[]; + game_engines: number[]; + game_localizations: number[]; + game_modes: number[]; + genres: number[]; + hypes: number; + involved_companies: number[]; + keywords: number[]; + language_supports: number[]; + multiplayer_modes: number[]; + name: string; + parent_game: string; + platforms: number[]; + player_perspectives: number[]; + ports: number[]; + rating: number; + rating_count: number; + release_dates: number[]; + remakes: number[]; + remasters: number[]; + screenshots: number[]; + similar_games: number[]; + slug: string; + standalone_expansions: number[]; + status: EGameStatus; + storyline: string; + summary: string; + tags: number[]; + themes: number[]; + total_rating: number; + total_rating_count: number; + updated_at: number; + url: string; + version_parent: number; + version_title: string; + videos: number[]; + websites: number[]; +} + +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; +} \ No newline at end of file