評価値の登録
API
評価値登録 API
src/frontend/src/api/ratings/postRating.ts
import { ApiContext } from "@/types/data";
import { ERROR_MESSAGES } from "@/constants";
import { fetcher } from "@/utils";
const context: ApiContext = {
apiRootUrl: process.env.NEXT_PUBLIC_API_BASE_URL,
};
/**
* 評価値登録API
* @param movieId - 映画ID
* @param rating - 評価値
*/
const postRating = async (movieId: number, rating: number): Promise<void> => {
const access =
typeof window !== "undefined" ? localStorage.getItem("access") : null;
if (!access) throw new Error(ERROR_MESSAGES.USER_NOT_AUTHENTICATED);
const url = `${context.apiRootUrl?.replace(/\/$/g, "")}/online/ratings/`;
const headers: Record<string, string> = {
Accept: "application/json",
"Content-Type": "application/json",
Authorization: `Bearer ${access}`,
};
const body = JSON.stringify({
movie_id: movieId,
rating: rating,
});
return await fetcher(url, {
method: "POST",
headers: headers,
body: body,
});
};
export default postRating;
コンポーネント
スターコンポーネント
src/frontend/src/app/components/ui/rating/Star.tsx
...(略)...
interface Props {
index: number;
width: number;
rating: number;
setRating: Function;
handleRatingClick: (rating: number) => void; // <- 追加
}
const Star = (props: Props) => {
const handleRatingClick = useCallback(() => {
const rating = (props.index + 1) / 2;
props.setRating(rating);
props.handleRatingClick(rating); // <- 追加
}, [props.setRating, props.handleRatingClick]); // <- props.handleRatingClickを追加
...(略)...
};
export default Star;
評価値コンポーネント
src/frontend/src/app/components/ui/rating/StarRating.tsx
...(略)...
interface Props {
starWidth: number;
rating: number;
handleRatingClick: (rating: number) => void; // <- 追加
}
const StarRating = (props: Props) => {
const [rating, setRating] = useState<number>(props.rating);
return (
<>
<div className={`${STYLES.STAR_RATING}`}>
{(function () {
const stars = [];
for (let i = 0; i < 10; i++) {
stars.push(
<Star
key={i}
index={i}
width={props.starWidth}
rating={rating}
setRating={setRating}
handleRatingClick={props.handleRatingClick} // <- 追加
/>
);
}
return <div>{stars}</div>;
})()}
</div>
</>
);
};
export default StarRating;
映画詳細カードコンポーネント
src/frontend/src/app/components/ui/card/CardMovieDetail.tsx
...(略)...
import { Movie, User } from "@/types/data";
import { MESSAGES, STYLES, ERROR_MESSAGES } from "@/constants";
import getMovie from "@/api/movies/getMovie";
import getMyAccount from "@/api/auth/getMyAccount";
import postRating from "@/api/ratings/postRating"; // <- 追加
...(略)...
/**
* 映画(詳細)カードコンポーネント
*/
const CardMovieDetail = (props: Props) => {
...(略)...
if (!movie) {
notFound();
}
// ↓追加
const handleRatingClick = async (rating: number) => {
try {
await postRating(movie.movie_id, rating);
} catch (e) {
console.error("Failed to post rating:", e);
}
};
// ↑追加
return (
<div className={`${STYLES.MOVIE_DETAIL_PAGE}`}>
<article className={`${STYLES.MOVIE_DETAIL_CARD}`} key={movie.movie_id}>
...(略)...
{!loadingUser && user && (
<StarRating
starWidth={STYLES.MOVIE_DETAIL_STAR_WIDTH}
rating={movie.rating?.rating!}
handleRatingClick={handleRatingClick} // <- 追加
/>
)}
</article>
</div>
);
};
export default CardMovieDetail;
映画カードコンポーネント
src/frontend/src/app/components/ui/card/CardMovie.tsx
...(略)...
import { Movie, User } from '@/types/data';
import { STYLES, MESSAGES } from '@/constants';
import postRating from '@/api/ratings/postRating'; // <- 追加
...(略)...
/**
* 映画カードコンポーネント
*/
const CardMovie = (props: Props) => {
...(略)...
// ↓追加
const handleRatingClick = async (rating: number) => {
try {
await postRating(props.movie.movie_id, rating);
} catch (e) {
console.error('Failed to post rating:', e);
}
};
// ↑追加
return (
<article className={`${STYLES.MOVIE_CARD}`} key={props.movie.movie_id}>
...(略)...
{props.user ? (
<StarRating
starWidth={STYLES.MOVIE_STAR_WIDTH}
rating={props.movie.rating?.rating!}
handleRatingClick={handleRatingClick} // <- 追加
/>
) : (
<></>
)}
</article>
);
};
export default CardMovie;
実行確認
ブラウザで下記 URL にアクセスしてください。
サインイン後、任意の評価値をクリックすると、下記のようにratingsテーブルに評価値が登録されます。下記の例では、movie_id=1の映画に対して、評価値3.5を与えています。
recsys_full=# SELECT * FROM t_users_movies_rating ORDER BY rated_at DESC;
id | rating | rated_at | movie_id | user_id
---------------------------------------------+--------+-------------------------------+----------+--------------------------------------
<USER_ID>_000001 | 3.5 | 2026-08-30 10:45:07.612773+09 | 1 | <USER_ID>
...(略)...
ブラウザで下記 URL にアクセスしてください。
同様に、映画リスト上でも任意の評価値をクリックすることで、ratingsテーブルに評価値が登録されます。ただし、現時点では、バックエンドサーバから評価値を取得していませんので、映画リスト上で評価値を更新しても、ブラウザを更新したり、ページを切り替えると、元の表示に戻ります。