diff --git a/frontend/components/GameList.tsx b/frontend/components/GameList.tsx index 1a19a1d..d496279 100644 --- a/frontend/components/GameList.tsx +++ b/frontend/components/GameList.tsx @@ -1,63 +1,79 @@ -import { GameQuery } from "@/graphql/generated/graphql"; +import { GamesQuery } from "@/graphql/generated/graphql"; import { classNames } from "@/lib/classNames"; import { StarIcon } from "@heroicons/react/20/solid"; import Image from "next/image"; -export default function GameList({ games }: { games: GameQuery["game"][] }) { +type Props = { + games: GamesQuery["games"]["nodes"]; +}; + +export default function GameList({ games }: Props) { + if (!games) { + return
loading...
; + } return (

Products

- {games.map((game) => ( -
-
- {`${game.title}`} -
-
-

- - -

-
-

{game.ratingAverage} out of 5 stars

-
- {[0, 1, 2, 3, 4].map((rating) => ( - rating - ? "text-yellow-400" - : "text-gray-100", - "h-5 w-5 flex-shrink-0" - )} - aria-hidden="true" - /> - ))} + {games.map( + (game) => + game && ( +
+
+ {`${game.title}`} +
+
+

+ + +

+
+

+ {game.ratingAverage} out of 5 stars +

+ +

+ {game.reviewsCount || 0} reviews +

+

+ {game.clipsCount || 0} reviews +

+
-

- {game.reviewsCount || 0} reviews -

-

- {game.clipsCount || 0} reviews -

-
-
- ))} + ) + )}
); } + +function RatingStars({ ratingAverage }: { ratingAverage: number }) { + return ( +
+ {[0, 1, 2, 3, 4].map((rating) => ( + rating ? "text-yellow-400" : "text-gray-100", + "h-5 w-5 flex-shrink-0" + )} + aria-hidden="true" + /> + ))} +
+ ); +} diff --git a/frontend/graphql/generated/gql.ts b/frontend/graphql/generated/gql.ts index 440e446..ea62d3b 100644 --- a/frontend/graphql/generated/gql.ts +++ b/frontend/graphql/generated/gql.ts @@ -15,6 +15,8 @@ import { TypedDocumentNode as DocumentNode } from "@graphql-typed-document-node/ const documents = { "\n query game($gameId: ID!) {\n game(id: $gameId) {\n id\n title\n imageUrl\n reviewsCount\n clipsCount\n publishedAt\n ratingAverage\n reviews {\n body\n rating\n createdAt\n }\n }\n }\n": types.GameDocument, + "\n query games($first: Int, $last: Int, $before: String, $after: String) {\n games(first: $first, last: $last, before: $before, after: $after) {\n nodes {\n id\n title\n imageUrl\n reviewsCount\n clipsCount\n publishedAt\n ratingAverage\n }\n }\n }\n": + types.GamesDocument, "\n query me {\n me {\n id\n displayName\n photoUrl\n }\n }\n": types.MeDocument, }; @@ -39,6 +41,12 @@ export function graphql(source: string): unknown; export function graphql( source: "\n query game($gameId: ID!) {\n game(id: $gameId) {\n id\n title\n imageUrl\n reviewsCount\n clipsCount\n publishedAt\n ratingAverage\n reviews {\n body\n rating\n createdAt\n }\n }\n }\n" ): (typeof documents)["\n query game($gameId: ID!) {\n game(id: $gameId) {\n id\n title\n imageUrl\n reviewsCount\n clipsCount\n publishedAt\n ratingAverage\n reviews {\n body\n rating\n createdAt\n }\n }\n }\n"]; +/** + * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. + */ +export function graphql( + source: "\n query games($first: Int, $last: Int, $before: String, $after: String) {\n games(first: $first, last: $last, before: $before, after: $after) {\n nodes {\n id\n title\n imageUrl\n reviewsCount\n clipsCount\n publishedAt\n ratingAverage\n }\n }\n }\n" +): (typeof documents)["\n query games($first: Int, $last: Int, $before: String, $after: String) {\n games(first: $first, last: $last, before: $before, after: $after) {\n nodes {\n id\n title\n imageUrl\n reviewsCount\n clipsCount\n publishedAt\n ratingAverage\n }\n }\n }\n"]; /** * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. */ diff --git a/frontend/graphql/generated/graphql.ts b/frontend/graphql/generated/graphql.ts index 3ae7686..5477341 100644 --- a/frontend/graphql/generated/graphql.ts +++ b/frontend/graphql/generated/graphql.ts @@ -269,6 +269,30 @@ export type GameQuery = { }; }; +export type GamesQueryVariables = Exact<{ + first?: InputMaybe; + last?: InputMaybe; + before?: InputMaybe; + after?: InputMaybe; +}>; + +export type GamesQuery = { + __typename?: "Query"; + games: { + __typename?: "GameConnection"; + nodes?: Array<{ + __typename?: "Game"; + id: string; + title: string; + imageUrl?: string | null; + reviewsCount: number; + clipsCount: number; + publishedAt?: string | null; + ratingAverage: number; + } | null> | null; + }; +}; + export type MeQueryVariables = Exact<{ [key: string]: never }>; export type MeQuery = { @@ -359,6 +383,126 @@ export const GameDocument = { }, ], } as unknown as DocumentNode; +export const GamesDocument = { + kind: "Document", + definitions: [ + { + kind: "OperationDefinition", + operation: "query", + name: { kind: "Name", value: "games" }, + variableDefinitions: [ + { + kind: "VariableDefinition", + variable: { + kind: "Variable", + name: { kind: "Name", value: "first" }, + }, + type: { kind: "NamedType", name: { kind: "Name", value: "Int" } }, + }, + { + kind: "VariableDefinition", + variable: { kind: "Variable", name: { kind: "Name", value: "last" } }, + type: { kind: "NamedType", name: { kind: "Name", value: "Int" } }, + }, + { + kind: "VariableDefinition", + variable: { + kind: "Variable", + name: { kind: "Name", value: "before" }, + }, + type: { kind: "NamedType", name: { kind: "Name", value: "String" } }, + }, + { + kind: "VariableDefinition", + variable: { + kind: "Variable", + name: { kind: "Name", value: "after" }, + }, + type: { kind: "NamedType", name: { kind: "Name", value: "String" } }, + }, + ], + selectionSet: { + kind: "SelectionSet", + selections: [ + { + kind: "Field", + name: { kind: "Name", value: "games" }, + arguments: [ + { + kind: "Argument", + name: { kind: "Name", value: "first" }, + value: { + kind: "Variable", + name: { kind: "Name", value: "first" }, + }, + }, + { + kind: "Argument", + name: { kind: "Name", value: "last" }, + value: { + kind: "Variable", + name: { kind: "Name", value: "last" }, + }, + }, + { + kind: "Argument", + name: { kind: "Name", value: "before" }, + value: { + kind: "Variable", + name: { kind: "Name", value: "before" }, + }, + }, + { + kind: "Argument", + name: { kind: "Name", value: "after" }, + value: { + kind: "Variable", + name: { kind: "Name", value: "after" }, + }, + }, + ], + selectionSet: { + kind: "SelectionSet", + selections: [ + { + kind: "Field", + name: { kind: "Name", value: "nodes" }, + selectionSet: { + kind: "SelectionSet", + selections: [ + { kind: "Field", name: { kind: "Name", value: "id" } }, + { kind: "Field", name: { kind: "Name", value: "title" } }, + { + kind: "Field", + name: { kind: "Name", value: "imageUrl" }, + }, + { + kind: "Field", + name: { kind: "Name", value: "reviewsCount" }, + }, + { + kind: "Field", + name: { kind: "Name", value: "clipsCount" }, + }, + { + kind: "Field", + name: { kind: "Name", value: "publishedAt" }, + }, + { + kind: "Field", + name: { kind: "Name", value: "ratingAverage" }, + }, + ], + }, + }, + ], + }, + }, + ], + }, + }, + ], +} as unknown as DocumentNode; export const MeDocument = { kind: "Document", definitions: [ diff --git a/frontend/graphql/queries/games.ts b/frontend/graphql/queries/games.ts new file mode 100644 index 0000000..c4d27e0 --- /dev/null +++ b/frontend/graphql/queries/games.ts @@ -0,0 +1,16 @@ +import { gql } from "@apollo/client"; +export default gql` + query games($first: Int, $last: Int, $before: String, $after: String) { + games(first: $first, last: $last, before: $before, after: $after) { + nodes { + id + title + imageUrl + reviewsCount + clipsCount + publishedAt + ratingAverage + } + } + } +`; diff --git a/frontend/pages/index.tsx b/frontend/pages/index.tsx index 507bfc8..d020deb 100644 --- a/frontend/pages/index.tsx +++ b/frontend/pages/index.tsx @@ -1,13 +1,13 @@ import GameList from "@/components/GameList"; -import { ApolloClient, InMemoryCache } from "@apollo/client"; +import { createApolloClient } from "@/graphql/client"; import { NextPage } from "next"; import { withUserTokenSSR } from "next-firebase-auth"; import Head from "next/head"; -import { GameDocument, GameQuery } from "../graphql/generated/graphql"; +import { GamesDocument, GamesQuery } from "../graphql/generated/graphql"; -type Game = GameQuery["game"]; +type Games = GamesQuery["games"]["nodes"]; -const Home: NextPage<{ games: Game[] }> = ({ games }) => { +const Home: NextPage<{ games: Games }> = ({ games }) => { return (
@@ -24,33 +24,21 @@ const Home: NextPage<{ games: Game[] }> = ({ games }) => { }; export const getServerSideProps = withUserTokenSSR()(async ({ user }) => { - const GAME_IDS: string[] = [ - "Z2lkOi8vYXBwbGljYXRpb24vR2FtZS8wQkR2OUZ3eFNCRkJ1akFUcHZkdw", - "Z2lkOi8vYXBwbGljYXRpb24vR2FtZS8wTllsbmV0ejEzRkJPeWI1MDdyTw", - "Z2lkOi8vYXBwbGljYXRpb24vR2FtZS8waGh2dGkycm40dE92OG14UVFxcQ", - ]; - - let token: string | null; - if (user) token = await user.getIdToken(true); - - const client = new ApolloClient({ - uri: process.env.NEXT_PUBLIC_GRAPHQL_ENDPOINT_URL, - cache: new InMemoryCache(), + const token = (await user?.getIdToken(true)) ?? null; + + const client = createApolloClient(token); + const { + data: { games }, + } = await client.query({ + query: GamesDocument, + variables: { + first: 5, + }, }); - const games: Game[] = await Promise.all( - GAME_IDS.map(async (gameId) => { - const { data } = await client.query({ - query: GameDocument, - variables: { gameId }, - }); - return data.game; - }) - ); - return { props: { - games, + games: games.nodes, }, }; });