Movie.tsx 6.79 KB
Newer Older
Daniel Puchala's avatar
Daniel Puchala committed
1
2
import Header from './Header';
import MovieCard from './MovieCard';
3
import { MovieCardMode, MovieDto, ReviewDto } from '../models/types';
4
import { useState } from 'react';
Daniel Puchala's avatar
Daniel Puchala committed
5
import { useForm } from 'react-hook-form';
Daniel Puchala's avatar
Daniel Puchala committed
6
7
import { useParams } from 'react-router-dom';
import instance from '../models/axios';
8
import useSWR from 'swr';
Daniel Puchala's avatar
Daniel Puchala committed
9
import { getToken, getUser } from '../services/auth';
10
import formatDuration from '../services/formatDuration';
Daniel Puchala's avatar
Daniel Puchala committed
11
import Review from './Review';
12
13
import LoadingPage from './LoadingPage';
import ErrorPage from './ErrorPage';
Daniel Puchala's avatar
Daniel Puchala committed
14
15

function getAverageRating(review: any) {
Daniel Puchala's avatar
Daniel Puchala committed
16
  return (review.actingRating + review.ideaRating + review.scriptRating + review.musicRating + review.visualsEditRating) / 5;
Daniel Puchala's avatar
Daniel Puchala committed
17
}
Daniel Puchala's avatar
Daniel Puchala committed
18

Daniel Puchala's avatar
Daniel Puchala committed
19
export const Movie = () => {
20
  const [ showReviews, setShowReviews ] = useState<boolean>(false);
Daniel Puchala's avatar
Daniel Puchala committed
21
22
23
  const { register, handleSubmit, getValues, watch } = useForm();
  watch();

Daniel Puchala's avatar
Daniel Puchala committed
24
25
  const sendReview = async (data: any) => {
    const headers = {
Daniel Puchala's avatar
Daniel Puchala committed
26
27
      'Content-Type': 'application/json',
      'Authorization': getToken()
Daniel Puchala's avatar
Daniel Puchala committed
28
29
30
    };
    const reviewData = {
      ...data,
Daniel Puchala's avatar
Daniel Puchala committed
31
      movieId: id,
Daniel Puchala's avatar
Daniel Puchala committed
32
      userId: getUser()!.sub
Daniel Puchala's avatar
Daniel Puchala committed
33
    };
Daniel Puchala's avatar
Daniel Puchala committed
34
    await instance.post('reviews', reviewData, { headers });
Daniel Puchala's avatar
Daniel Puchala committed
35
    await mutateReviews();
Daniel Puchala's avatar
Daniel Puchala committed
36
37
38
    alert('Review created');
  };

Daniel Puchala's avatar
Daniel Puchala committed
39
  const { id } = useParams();
40
41
42
  const { data: movie, error: movieError } = useSWR<MovieDto>(`movies/${id}`);
  const { data: reviews, error: reviewError, mutate: mutateReviews } = useSWR<ReviewDto[]>(`reviews/search/${id}`);
  const { data: recommended, error: recommendedError } = useSWR<MovieDto[]>(`movies/${id}/recommended`);
43

44
45
  if (movieError || reviewError || recommendedError) return <ErrorPage />;
  if (!movie || !reviews || !recommended) return <LoadingPage />;
46

Daniel Puchala's avatar
Daniel Puchala committed
47
  const recommendedMovies = recommended.slice(0, 5);
Daniel Puchala's avatar
Daniel Puchala committed
48
49

  return (
Daniel Puchala's avatar
Daniel Puchala committed
50
    <div>
Daniel Puchala's avatar
Daniel Puchala committed
51
      <Header/>
Daniel Puchala's avatar
Daniel Puchala committed
52
      <div className="grid grid-cols-3 h-[90vh]">
Daniel Puchala's avatar
Daniel Puchala committed
53
        <div className="flex flex-col col-span-2 h-full">
Daniel Puchala's avatar
Daniel Puchala committed
54
55
          <div className="flex flex-row p-4 border-solid border-r-4 border-slate-900 bg-slate-300 h-full w-full">
            <div className="p-4 flex-shrink-0 h-full w-2/5">
56
              <img className="h-full w-full" src={movie.poster} alt="Poster"/>
Daniel Puchala's avatar
Daniel Puchala committed
57
            </div>
Daniel Puchala's avatar
Daniel Puchala committed
58
            <div className="flex flex-col p-4 w-full">
59
              <p className="text-2xl font-bold">{movie.name}</p>
60
              {movie.genres.length > 0 &&
Daniel Puchala's avatar
Daniel Puchala committed
61
62
                  <p><b>Genres: </b>
                    {movie.genres.slice(0, -1).map((genre: any) => `${genre}, `)}
63
                    {movie.genres.at(-1)}
Daniel Puchala's avatar
Daniel Puchala committed
64
65
                  </p>
              }
Daniel Puchala's avatar
Daniel Puchala committed
66
              <p><b>Duration: </b>{formatDuration(movie.duration)}</p>
67
              <p>{movie.description}</p>
Daniel Puchala's avatar
Daniel Puchala committed
68
              <p className="text-xl mt-auto"><b>Director: </b>{movie.director.name}</p>
69
70
71
72
73
              {movie.actors.length > 0 &&
                (<p className="text-xl"><b>Actors: </b>
                  {movie.actors.slice(0, -1).map((actor: any) => `${actor.name}, `)}
                  {`${movie.actors.at(-1)!.name}`}
                </p>)
Daniel Puchala's avatar
Daniel Puchala committed
74
              }
Daniel Puchala's avatar
Daniel Puchala committed
75
              <button className="w-max p-4 self-center bg-blue-600 border-2 rounded-3xl border-slate-900"
Daniel Puchala's avatar
Daniel Puchala committed
76
                      onClick={() => setShowReviews((prevState => !prevState))}>
Daniel Puchala's avatar
Daniel Puchala committed
77
                {showReviews ? 'Show recommended movies' : 'Show reviews'}
78
              </button>
Daniel Puchala's avatar
Daniel Puchala committed
79
80
            </div>
          </div>
Daniel Puchala's avatar
Daniel Puchala committed
81
82

        </div>
Daniel Puchala's avatar
Daniel Puchala committed
83
        <div className={`h-full ${showReviews && 'hidden'}`}>
Daniel Puchala's avatar
Daniel Puchala committed
84
          <p className="text-2xl text-center font-bold">Recommended movies</p>
85
          <div className="flex flex-row flex-wrap p-4">
Daniel Puchala's avatar
Daniel Puchala committed
86
87
            {recommendedMovies.map((movie: any) => <MovieCard key={movie.id} {...movie}
                                                              mode={MovieCardMode.Recommend}/>)}
Daniel Puchala's avatar
Daniel Puchala committed
88
89
          </div>
        </div>
90
        <div className={`h-full flex flex-col overflow-hidden ${showReviews || 'hidden'}`}>
91
          <p className="text-2xl text-center font-bold">Reviews</p>
92
          <div className="overflow-y-scroll">
Daniel Puchala's avatar
Daniel Puchala committed
93
            {reviews.map((review: any) =>
94
95
              <Review averageRating={
                getAverageRating(review)}
96
                      id={review.id}
97
                      userId={+review.user.id}
98
99
                      text={review.text}
                      userName={review.user.name}
100
                      mutate={mutateReviews}
101
102
                      key={review.id}
              />
Daniel Puchala's avatar
Daniel Puchala committed
103
            )}
104
          </div>
105
          {getUser() &&
Daniel Puchala's avatar
Daniel Puchala committed
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
              <form
                  onSubmit={handleSubmit(sendReview)}
                  className="flex flex-col p-2 m-2 mt-auto bg-slate-300 border-4 rounded-3xl border-slate-900"
              >
                  <span className="text-2xl text-center font-bold">Write your review</span>
                  <label className="flex justify-between">
                      <span className="font-bold">Script: {getValues('scriptRating')}</span>
                      <input type="range" min={1} max={10} {...register('scriptRating', { required: true })}/>
                  </label>
                  <label className="flex justify-between">
                      <span className="font-bold">Idea: {getValues('ideaRating')}</span>
                      <input type="range" min={1} max={10} {...register('ideaRating', { required: true })}/>
                  </label>
                  <label className="flex justify-between">
                      <span className="font-bold">Visual edits: {getValues('visualsEditRating')}</span>
                      <input type="range" min={1} max={10} {...register('visualsEditRating', { required: true })}/>
                  </label>
                  <label className="flex justify-between">
                      <span className="font-bold">Music: {getValues('musicRating')}</span>
                      <input type="range" min={1} max={10} {...register('musicRating', { required: true })}/>
                  </label>
                  <label className="flex justify-between">
                      <span className="font-bold">Acting: {getValues('actingRating')}</span>
                      <input type="range" min={1} max={10} {...register('actingRating', { required: true })}/>
                  </label>
                  <label>
Daniel Puchala's avatar
Daniel Puchala committed
132
              <textarea
Daniel Puchala's avatar
Daniel Puchala committed
133
134
135
                  className="w-full border-2 border-slate-900"
                  {...register('text', { required: true, minLength: 1 })}
                  placeholder={'Write your review here.'}
Daniel Puchala's avatar
Daniel Puchala committed
136
              />
Daniel Puchala's avatar
Daniel Puchala committed
137
138
139
140
141
142
                  </label>
                  <button type="submit"
                          className="w-max p-2 self-center bg-blue-600 border-2 rounded-3xl border-slate-900">
                      Send review
                  </button>
              </form>
143
          }
144
        </div>
Daniel Puchala's avatar
Daniel Puchala committed
145

Daniel Puchala's avatar
Daniel Puchala committed
146
147
148
149
150
151
      </div>
    </div>
  );
};

export default Movie;