Skip to content

Commit

Permalink
レビュー見れるようにした
Browse files Browse the repository at this point in the history
  • Loading branch information
canisterism committed Jul 27, 2023
1 parent 6e436e3 commit 1ded734
Show file tree
Hide file tree
Showing 6 changed files with 141 additions and 40 deletions.
12 changes: 5 additions & 7 deletions frontend/components/Game/RatingStars.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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 = {
Expand All @@ -16,13 +16,11 @@ export default function RatingStars({

return (
<div className="flex items-start">
{[0, 1, 2, 3, 4].map((rating) => (
{[0, 1, 2, 3, 4].map((n) => (
<StarIcon
key={rating}
key={n}
className={classNames(
Math.floor(ratingAverage) > rating
? "text-yellow-400"
: "text-gray-100",
Math.floor(rating) > n ? "text-yellow-400" : "text-gray-100",
`${sizeClass} flex-shrink-0`
)}
aria-hidden="true"
Expand Down
25 changes: 0 additions & 25 deletions frontend/components/Review/ListItem.tsx

This file was deleted.

81 changes: 81 additions & 0 deletions frontend/components/Review/ReviewListItem.tsx
Original file line number Diff line number Diff line change
@@ -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<typeof ReviewListItemFragment>;
};

export function ReviewListItem(props: Props) {
const review = useFragment(ReviewListItemFragment, props.review);
console.log({ review });
return (
<div
key={review.id}
className="text-gray-100 flex flex-col gap-2 p-4 bg-gray-800 rounded-md border border-gray-600"
>
<div className="flex">
<ProfileHeading {...review.profile} />
<div className="flex-grow" aria-hidden></div>
</div>
<div className="flex items-center gap-2">
<RatingStars rating={review.rating} size="md" />
<span className="text-xl font-semibold flex ">
{review.rating.toFixed(1)}
</span>
</div>
<div className="gap-1">
<p>{review.body}</p>
<span className="text-gray-400 text-sm">
投稿日:{format(new Date(review.createdAt), "yyyy-MM-dd")}
</span>
</div>
</div>
);
}

function ProfileHeading({
id,
photoUrl,
displayName,
}: {
id: string;
photoUrl: string | null | undefined;
displayName: string | null | undefined;
}) {
return (
<Link href={`/users/${id}`} passHref>
<a>
<div className="flex gap-4">
<Image
className="h-8 w-8 rounded-full bg-gray-50"
src={photoUrl ?? ""}
alt="profile icon"
width="40"
height="40"
/>

<span className="text-lg font-semibold text-gray-300 flex items-center">
{displayName ?? "退会済みユーザー"}
</span>
</div>
</a>
</Link>
);
}
6 changes: 3 additions & 3 deletions frontend/graphql/generated/gql.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand All @@ -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.
*/
Expand Down
30 changes: 30 additions & 0 deletions frontend/graphql/generated/graphql.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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 }>;
Expand Down Expand Up @@ -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" } },
],
},
},
],
},
},
Expand Down Expand Up @@ -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" } },
],
},
},
],
},
},
Expand Down
27 changes: 22 additions & 5 deletions frontend/pages/games/[id].tsx
Original file line number Diff line number Diff line change
@@ -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";
Expand Down Expand Up @@ -54,15 +55,18 @@ export function Game({ game }: PageProps) {
<link rel="icon" href="/favicon.ico" />
</Head>

<GameInfoHero game={game} />
<div className="flex flex-col gap-10">
<GameInfoHero game={game} />
<ReviewsArea reviews={game.reviews} />
</div>
</div>
);
}

function GameInfoHero({ game }: { game: GameQuery["game"] }) {
return (
<div className="flex justify-between ">
<div className="w-2/5flex flex-col gap-4">
<div className="flex gap-10">
<div className="w-2/5 flex flex-col gap-4">
<GameImage imageUrl={game.imageUrl || undefined} title={game.title} />
<div className="flex gap-4">
<StatButton
Expand Down Expand Up @@ -90,7 +94,7 @@ function GameInfoHero({ game }: { game: GameQuery["game"] }) {
/>
</div>
</div>
<div className="flex flex-col w-3/5 gap-3 text-gray-100 ">
<div className="flex flex-col w-3/5 gap-3 text-gray-100">
<div className="flex flex-col gap-2">
{/* Title */}
<h1 className="text-3xl font-bold">{game.title}</h1>
Expand All @@ -103,7 +107,7 @@ function GameInfoHero({ game }: { game: GameQuery["game"] }) {
</div>
{/* Rating */}
<div className="flex gap-2 items-end">
<RatingStars ratingAverage={game.ratingAverage} size="lg" />
<RatingStars rating={game.ratingAverage} size="lg" />
<div className="text-3xl font-bold">
{game.ratingAverage.toFixed(1)}
</div>
Expand Down Expand Up @@ -137,6 +141,19 @@ function GameInfoHero({ game }: { game: GameQuery["game"] }) {
);
}

function ReviewsArea({ reviews }: { reviews: GameQuery["game"]["reviews"] }) {
return (
<div className="flex flex-col gap-4">
<h2 className="text-3xl font-bold text-gray-100">レビュー</h2>
<div className="flex flex-col gap-4">
{reviews.map((review, i) => (
<ReviewListItem key={`review-${i}`} review={review} />
))}
</div>
</div>
);
}

export const getServerSideProps: GetServerSideProps = withUserTokenSSR()(
async ({ user, query }) => {
const { id } = query;
Expand Down

0 comments on commit 1ded734

Please sign in to comment.