From 1ded734583bd2f1fa14126451a933853167ec32f Mon Sep 17 00:00:00 2001 From: canisterism Date: Thu, 27 Jul 2023 22:37:13 +0900 Subject: [PATCH] =?UTF-8?q?=E3=83=AC=E3=83=93=E3=83=A5=E3=83=BC=E8=A6=8B?= =?UTF-8?q?=E3=82=8C=E3=82=8B=E3=82=88=E3=81=86=E3=81=AB=E3=81=97=E3=81=9F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- frontend/components/Game/RatingStars.tsx | 12 ++- frontend/components/Review/ListItem.tsx | 25 ------ frontend/components/Review/ReviewListItem.tsx | 81 +++++++++++++++++++ frontend/graphql/generated/gql.ts | 6 +- frontend/graphql/generated/graphql.ts | 30 +++++++ frontend/pages/games/[id].tsx | 27 +++++-- 6 files changed, 141 insertions(+), 40 deletions(-) delete mode 100644 frontend/components/Review/ListItem.tsx create mode 100644 frontend/components/Review/ReviewListItem.tsx diff --git a/frontend/components/Game/RatingStars.tsx b/frontend/components/Game/RatingStars.tsx index d903fc7..1029840 100644 --- a/frontend/components/Game/RatingStars.tsx +++ b/frontend/components/Game/RatingStars.tsx @@ -2,10 +2,10 @@ import { classNames } from "@/lib/classNames"; import { StarIcon } from "@heroicons/react/20/solid"; export default function RatingStars({ - ratingAverage, + rating, size = "md", }: { - ratingAverage: number; + rating: number; size: "sm" | "md" | "lg"; }) { const sizeClass = { @@ -16,13 +16,11 @@ export default function RatingStars({ return (
- {[0, 1, 2, 3, 4].map((rating) => ( + {[0, 1, 2, 3, 4].map((n) => ( rating - ? "text-yellow-400" - : "text-gray-100", + Math.floor(rating) > n ? "text-yellow-400" : "text-gray-100", `${sizeClass} flex-shrink-0` )} aria-hidden="true" diff --git a/frontend/components/Review/ListItem.tsx b/frontend/components/Review/ListItem.tsx deleted file mode 100644 index 2765aa9..0000000 --- a/frontend/components/Review/ListItem.tsx +++ /dev/null @@ -1,25 +0,0 @@ -import { FragmentType, graphql, useFragment } from "@/graphql/generated"; - -export const ReviewListItemFragment = graphql(` - fragment ReviewListItemFragment on Review { - id - body - rating - createdAt - } -`); - -type Props = { - review: FragmentType; -}; - -export function ListItem(props: Props) { - const review = useFragment(ReviewListItemFragment, props.review); - return ( -
-

{review.body}

-

{review.rating}

-

{review.createdAt}

-
- ); -} diff --git a/frontend/components/Review/ReviewListItem.tsx b/frontend/components/Review/ReviewListItem.tsx new file mode 100644 index 0000000..2e2c95f --- /dev/null +++ b/frontend/components/Review/ReviewListItem.tsx @@ -0,0 +1,81 @@ +import RatingStars from "@/components/Game/RatingStars"; +import { FragmentType, graphql, useFragment } from "@/graphql/generated"; +import { format } from "date-fns"; +import Image from "next/image"; +import Link from "next/link"; + +export const ReviewListItemFragment = graphql(` + fragment ReviewListItemFragment on Review { + id + body + rating + createdAt + profile { + id + displayName + photoUrl + } + } +`); + +type Props = { + review: FragmentType; +}; + +export function ReviewListItem(props: Props) { + const review = useFragment(ReviewListItemFragment, props.review); + console.log({ review }); + return ( +
+
+ +
+
+
+ + + {review.rating.toFixed(1)} + +
+
+

{review.body}

+ + 投稿日:{format(new Date(review.createdAt), "yyyy-MM-dd")} + +
+
+ ); +} + +function ProfileHeading({ + id, + photoUrl, + displayName, +}: { + id: string; + photoUrl: string | null | undefined; + displayName: string | null | undefined; +}) { + return ( + + +
+ profile icon + + + {displayName ?? "退会済みユーザー"} + +
+
+ + ); +} diff --git a/frontend/graphql/generated/gql.ts b/frontend/graphql/generated/gql.ts index 020edb1..4626259 100644 --- a/frontend/graphql/generated/gql.ts +++ b/frontend/graphql/generated/gql.ts @@ -13,7 +13,7 @@ import { TypedDocumentNode as DocumentNode } from "@graphql-typed-document-node/ * Therefore it is highly recommended to use the babel or swc plugin for production. */ const documents = { - "\n fragment ReviewListItemFragment on Review {\n id\n body\n rating\n createdAt\n }\n": + "\n fragment ReviewListItemFragment on Review {\n id\n body\n rating\n createdAt\n profile {\n id\n displayName\n photoUrl\n }\n }\n": types.ReviewListItemFragmentFragmentDoc, "\n query me {\n me {\n id\n displayName\n photoUrl\n }\n }\n": types.MeDocument, @@ -39,8 +39,8 @@ export function graphql(source: string): unknown; * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. */ export function graphql( - source: "\n fragment ReviewListItemFragment on Review {\n id\n body\n rating\n createdAt\n }\n" -): (typeof documents)["\n fragment ReviewListItemFragment on Review {\n id\n body\n rating\n createdAt\n }\n"]; + source: "\n fragment ReviewListItemFragment on Review {\n id\n body\n rating\n createdAt\n profile {\n id\n displayName\n photoUrl\n }\n }\n" +): (typeof documents)["\n fragment ReviewListItemFragment on Review {\n id\n body\n rating\n createdAt\n profile {\n id\n displayName\n photoUrl\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 bb5615b..98196a8 100644 --- a/frontend/graphql/generated/graphql.ts +++ b/frontend/graphql/generated/graphql.ts @@ -251,6 +251,12 @@ export type ReviewListItemFragmentFragment = { body: string; rating: number; createdAt: string; + profile: { + __typename?: "Profile"; + id: string; + displayName: string; + photoUrl: string; + }; } & { " $fragmentName"?: "ReviewListItemFragmentFragment" }; export type MeQueryVariables = Exact<{ [key: string]: never }>; @@ -315,6 +321,18 @@ export const ReviewListItemFragmentFragmentDoc = { { kind: "Field", name: { kind: "Name", value: "body" } }, { kind: "Field", name: { kind: "Name", value: "rating" } }, { kind: "Field", name: { kind: "Name", value: "createdAt" } }, + { + kind: "Field", + name: { kind: "Name", value: "profile" }, + selectionSet: { + kind: "SelectionSet", + selections: [ + { kind: "Field", name: { kind: "Name", value: "id" } }, + { kind: "Field", name: { kind: "Name", value: "displayName" } }, + { kind: "Field", name: { kind: "Name", value: "photoUrl" } }, + ], + }, + }, ], }, }, @@ -466,6 +484,18 @@ export const GameDocument = { { kind: "Field", name: { kind: "Name", value: "body" } }, { kind: "Field", name: { kind: "Name", value: "rating" } }, { kind: "Field", name: { kind: "Name", value: "createdAt" } }, + { + kind: "Field", + name: { kind: "Name", value: "profile" }, + selectionSet: { + kind: "SelectionSet", + selections: [ + { kind: "Field", name: { kind: "Name", value: "id" } }, + { kind: "Field", name: { kind: "Name", value: "displayName" } }, + { kind: "Field", name: { kind: "Name", value: "photoUrl" } }, + ], + }, + }, ], }, }, diff --git a/frontend/pages/games/[id].tsx b/frontend/pages/games/[id].tsx index 1c2dba3..192c968 100644 --- a/frontend/pages/games/[id].tsx +++ b/frontend/pages/games/[id].tsx @@ -1,5 +1,6 @@ import GameImage from "@/components/Game/GameImage"; import RatingStars from "@/components/Game/RatingStars"; +import { ReviewListItem } from "@/components/Review/ReviewListItem"; import StatButton from "@/components/StatButton"; import { createApolloClient } from "@/graphql/client"; import { GameDocument, GameQuery } from "@/graphql/generated/graphql"; @@ -54,15 +55,18 @@ export function Game({ game }: PageProps) { - +
+ + +
); } function GameInfoHero({ game }: { game: GameQuery["game"] }) { return ( -
-
+
+
-
+
{/* Title */}

{game.title}

@@ -103,7 +107,7 @@ function GameInfoHero({ game }: { game: GameQuery["game"] }) {
{/* Rating */}
- +
{game.ratingAverage.toFixed(1)}
@@ -137,6 +141,19 @@ function GameInfoHero({ game }: { game: GameQuery["game"] }) { ); } +function ReviewsArea({ reviews }: { reviews: GameQuery["game"]["reviews"] }) { + return ( +
+

レビュー

+
+ {reviews.map((review, i) => ( + + ))} +
+
+ ); +} + export const getServerSideProps: GetServerSideProps = withUserTokenSSR()( async ({ user, query }) => { const { id } = query;