評価値コンポーネントの作成
画像ファイルの準備
- 下記ファイルをダウンロードする。
    
- recsyslab / recsys_full / src / frontend / public / img / 
        
star_00.pngstar_01.pngstar_10.pngstar_11.png
 
 - recsyslab / recsys_full / src / frontend / public / img / 
        
 
frontend$ mv ~/Downloads/star*.png public/img/
データ型
frontend/src/types/data.d.ts
...(略)...
// 映画
export type Movie = {
  id: number;
  title: string;
  year: number;
  genres: string[];
  imdb_id: number;
  tmdb_id: number;
  rating: Rating; // <- 追加
};
// ↓追加
// 評価値
export type Rating = {
  id: string;
  user_id: string;
  movie_id: number;
  rating: number;
  rated_at: string;
};
// ↑追加
コンポーネント
スターコンポーネント
frontend/src/app/components/rating/Star.tsx
import Image from 'next/image';
import React from 'react';
type Props = {
  index: number;
  width: number;
  rating: number;
  setRating: Function;
};
const Star = (props: Props) => {
  const handleRatingClick = async () => {
    const rating = (props.index + 1) / 2;
    await props.setRating(rating);
  };
  return (
    <>
      <button onClick={() => handleRatingClick()}>
        <Image
          className="opacity-75 hover:opacity-100 active:scale-125 active:opacity-100"
          src={`/img/star_${props.index % 2}${props.index < props.rating * 2 ? 1 : 0}.png`}
          alt=""
          width={props.width / 2}
          height={props.width}
        />
      </button>
    </>
  );
};
export default Star;
評価値コンポーネント
frontend/src/app/components/rating/StarRating.tsx
'use client';
import React, { useState } from 'react';
import Star from './Star';
type Props = {
  starWidth: number;
  rating: number;
};
const StarRating = (props: Props) => {
  const [rating, setRating] = useState<number>(props.rating);
  return (
    <>
      <div className="flex">
        {(function () {
          const stars = [];
          for (let i = 0; i < 10; i++) {
            stars.push(
              <Star
                key={i}
                index={i}
                width={props.starWidth}
                rating={rating}
                setRating={setRating}
              />
            );
          }
          return <div>{stars}</div>;
        })()}
      </div>
    </>
  );
};
export default StarRating;
映画詳細カードコンポーネント
frontend/src/app/components/movie/MovieCardDetail.tsx
import { Movie, User } from '@/types/data'; // <- Userを追加
import Image from 'next/image';
import React from 'react';
import StarRating from '../rating/StarRating'; // <- 追加
const STAR_WIDTH = 48; // <- 追加
type Props = {
  movie: Movie;
  user: User; // <- 追加
};
const MovieCardDetail = (props: Props) => {
  const img_url = '/img/dummy_poster.png';
  return (
    <>
      <article key={props.movie.id}>
        <div className="mx-4 my-4 flex">
...(略)...
        </div>
        {/* ↓追加 */}
        {props.user ? (
          <StarRating starWidth={STAR_WIDTH} rating={props.movie.rating?.rating} />
        ) : (
          <></>
        )}
        {/* ↑追加 */}
      </article>
    </>
  );
};
export default MovieCardDetail;
ページ
映画詳細ページ
frontend/src/app/movies/[id]/page.tsx
import MovieCardDetail from '@/app/components/movie/MovieCardDetail';
import { auth } from '@/auth'; // <- 追加
import getMovie from '@/services/movies/getMovie';
import connectUser from '@/services/users/connectUser';
import getUser from '@/services/users/getUser'; // <- 追加
const Movie = async ({ params }: { params: Promise<{ id: number }> }) => {
  await connectUser();
  const session = await auth(); // <- 追加
  const user = session ? await getUser(session?.user?.email!) : null; // <- 追加
  const { id } = await params;
  const movieId = id;
  const { movie } = await getMovie(movieId);
  return (
    <>
      <MovieCardDetail movie={movie} user={user!} /> {/* <- userを追加 */}
    </>
  );
};
export default Movie;
ブラウザで下記URLにアクセスしてください。
サインインすると、映画詳細カードに五つのスターで構成される評価値コンポーネントが表示されます。評価値コンポーネント上で任意の評価値をクリックすると、その評価値までのスターが黄色く表示されます。ただし、現時点では、評価値は記憶されないため、ブラウザを更新すると元に戻ります。また、現時点では、ユーザ情報は評価値コンポーネントの表示/非表示の判定のために参照しているだけですので、ユーザ依存の評価値は取得できません。