View on GitHub

評価値コンポーネントの作成

Home

評価値コンポーネントの作成

画像ファイルの準備

  1. 下記ファイルをダウンロードする。
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にアクセスしてください。

サインインすると、映画詳細カードに五つのスターで構成される評価値コンポーネントが表示されます。評価値コンポーネント上で任意の評価値をクリックすると、その評価値までのスターが黄色く表示されます。ただし、現時点では、評価値は記憶されないため、ブラウザを更新すると元に戻ります。また、現時点では、ユーザ情報は評価値コンポーネントの表示/非表示の判定のために参照しているだけですので、ユーザ依存の評価値は取得できません。