Skip to content

Commit

Permalink
複数のゲームを取得できるようにした
Browse files Browse the repository at this point in the history
  • Loading branch information
canisterism committed Jul 22, 2023
1 parent ae8915f commit bec1dbe
Show file tree
Hide file tree
Showing 5 changed files with 247 additions and 75 deletions.
112 changes: 64 additions & 48 deletions frontend/components/GameList.tsx
Original file line number Diff line number Diff line change
@@ -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 <div>loading...</div>;
}
return (
<div className="mx-auto max-w-10xl overflow-hidden sm:px-6 lg:px-3">
<h2 className="sr-only">Products</h2>

<div className="-mx-px grid grid-cols-2 sm:mx-0 md:grid-cols-3 lg:grid-cols-4 xl:lg:grid-cols-8">
{games.map((game) => (
<div key={game.id} className="group relative p-2">
<div className="aspect-h-4 aspect-w-3 overflow-hidden rounded-lg bg-gray-200 group-hover:opacity-75">
<Image
src={
game.imageUrl
? `${game.imageUrl}`
: "https://placeimg.com/320/400/any"
}
alt={`${game.title}`}
className="h-full w-full object-cover object-center"
layout="fill"
objectFit="cover"
/>
</div>
<div className="pb-4 pt-2 ">
<h3 className="text-sm text-gray-300">
<a href={`games/${game.id}`}>
<span aria-hidden="true" className="absolute inset-0" />
{game.title}
</a>
</h3>
<div className="mt-3 flex flex-col items-start">
<p className="sr-only">{game.ratingAverage} out of 5 stars</p>
<div className="flex items-start">
{[0, 1, 2, 3, 4].map((rating) => (
<StarIcon
key={rating}
className={classNames(
game.ratingAverage > rating
? "text-yellow-400"
: "text-gray-100",
"h-5 w-5 flex-shrink-0"
)}
aria-hidden="true"
/>
))}
{games.map(
(game) =>
game && (
<div key={game.id} className="group relative p-2">
<div className="aspect-h-4 aspect-w-3 overflow-hidden rounded-lg bg-gray-200 group-hover:opacity-75">
<Image
src={
game.imageUrl
? `${game.imageUrl}`
: "https://placeimg.com/320/400/any"
}
alt={`${game.title}`}
className="h-full w-full object-cover object-center"
layout="fill"
objectFit="cover"
/>
</div>
<div className="pb-4 pt-2 ">
<h3 className="text-sm text-gray-300">
<a href={`games/${game.id}`}>
<span aria-hidden="true" className="absolute inset-0" />
{game.title}
</a>
</h3>
<div className="mt-3 flex flex-col items-start">
<p className="sr-only">
{game.ratingAverage} out of 5 stars
</p>
<RatingStars ratingAverage={game.ratingAverage} />
<p className="mt-1 text-sm text-gray-500">
{game.reviewsCount || 0} reviews
</p>
<p className="mt-1 text-sm text-gray-500">
{game.clipsCount || 0} reviews
</p>
</div>
</div>
<p className="mt-1 text-sm text-gray-500">
{game.reviewsCount || 0} reviews
</p>
<p className="mt-1 text-sm text-gray-500">
{game.clipsCount || 0} reviews
</p>
</div>
</div>
</div>
))}
)
)}
</div>
</div>
);
}

function RatingStars({ ratingAverage }: { ratingAverage: number }) {
return (
<div className="flex items-start">
{[0, 1, 2, 3, 4].map((rating) => (
<StarIcon
key={rating}
className={classNames(
ratingAverage > rating ? "text-yellow-400" : "text-gray-100",
"h-5 w-5 flex-shrink-0"
)}
aria-hidden="true"
/>
))}
</div>
);
}
8 changes: 8 additions & 0 deletions frontend/graphql/generated/gql.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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,
};
Expand All @@ -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.
*/
Expand Down
144 changes: 144 additions & 0 deletions frontend/graphql/generated/graphql.ts
Original file line number Diff line number Diff line change
Expand Up @@ -269,6 +269,30 @@ export type GameQuery = {
};
};

export type GamesQueryVariables = Exact<{
first?: InputMaybe<Scalars["Int"]>;
last?: InputMaybe<Scalars["Int"]>;
before?: InputMaybe<Scalars["String"]>;
after?: InputMaybe<Scalars["String"]>;
}>;

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 = {
Expand Down Expand Up @@ -359,6 +383,126 @@ export const GameDocument = {
},
],
} as unknown as DocumentNode<GameQuery, GameQueryVariables>;
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<GamesQuery, GamesQueryVariables>;
export const MeDocument = {
kind: "Document",
definitions: [
Expand Down
16 changes: 16 additions & 0 deletions frontend/graphql/queries/games.ts
Original file line number Diff line number Diff line change
@@ -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
}
}
}
`;
42 changes: 15 additions & 27 deletions frontend/pages/index.tsx
Original file line number Diff line number Diff line change
@@ -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 (
<div>
<Head>
Expand All @@ -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,
},
};
});
Expand Down

0 comments on commit bec1dbe

Please sign in to comment.