File size: 8,915 Bytes
cc2caf9
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
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
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
import React, { useEffect, useState } from 'react';
import { useParams, Link } from 'react-router-dom';
import { Play, Plus, ThumbsUp, Share2 } from 'lucide-react';
import { getMovieMetadata, getGenresItems, getMovieCard } from '../lib/api';
import ContentRow from '../components/ContentRow';
import { useToast } from '@/hooks/use-toast';

const MovieDetailPage = () => {
  const { title } = useParams<{ title: string }>();
  const [movie, setMovie] = useState<any>(null);
  const [loading, setLoading] = useState(true);
  const [similarMovies, setSimilarMovies] = useState<any[]>([]);
  const { toast } = useToast();

  useEffect(() => {
    const fetchMovieData = async () => {
      if (!title) return;

      try {
        setLoading(true);
        const data = await getMovieMetadata(title);
        setMovie(data);
        const movieData = data.data;
        console.log(movieData);

        // Fetch similar movies based on individual genres
        if (movieData.genres && movieData.genres.length > 0) {
          const currentMovieName = movieData.name;
          const moviesByGenre = await Promise.all(
            movieData.genres.map(async (genre: any) => {
              // Pass a single genre name for each call
              const genreResult = await getGenresItems([genre.name], 'movie', 10, 1);
              if (genreResult.movies && Array.isArray(genreResult.movies)) {
                return genreResult.movies.map((movieItem: any) => {
                  const { title: similarTitle } = movieItem;
                  // Skip current movie
                  if (similarTitle === currentMovieName) return null;
                  return {
                    type: 'movie',
                    title: similarTitle,
                  };
                });
              }
              return [];
            })
          );
          // Flatten the array of arrays and remove null results
          const flattenedMovies = moviesByGenre.flat().filter(Boolean);
          // Remove duplicates based on the title
          const uniqueMovies = Array.from(
            new Map(flattenedMovies.map(movie => [movie.title, movie])).values()
          );
          setSimilarMovies(uniqueMovies);
        }
      } catch (error) {
        console.error(`Error fetching movie details for ${title}:`, error);
        toast({
          title: "Error loading movie details",
          description: "Please try again later",
          variant: "destructive"
        });
      } finally {
        setLoading(false);
      }
    };

    fetchMovieData();
  }, [title, toast]);

  if (loading) {
    return (
      <div className="flex items-center justify-center min-h-screen">
        <div className="animate-spin rounded-full h-12 w-12 border-t-2 border-b-2 border-netflix-red"></div>
      </div>
    );
  }

  if (!movie) {
    return (
      <div className="pt-24 px-4 md:px-8 text-center min-h-screen">
        <h1 className="text-3xl font-bold mb-4">Movie Not Found</h1>
        <p className="text-netflix-gray mb-6">We couldn't find the movie you're looking for.</p>
        <Link to="/movies" className="bg-netflix-red px-6 py-2 rounded font-medium">
          Back to Movies
        </Link>
      </div>
    );
  }

  // Use movieData fields from the new structure
  const movieData = movie.data;
  const runtime = movieData.runtime
    ? `${Math.floor(movieData.runtime / 60)}h ${movieData.runtime % 60}m`
    : '';
  const releaseYear = movieData.year || '';
  const movieName = (movieData.translations?.nameTranslations?.find((t: any) => t.language === 'eng')?.name || movieData.name || '');
  const overview =
    movieData.overview ||
    (movieData.translations?.overviewTranslations?.find((t: any) => t.language === 'eng')?.overview || '');

  return (
    <div className="pb-12 animate-fade-in">
      {/* Hero backdrop */}
      <div className="relative w-full h-[500px] md:h-[600px]">
        <div className="absolute inset-0">
          <img
            src={movieData.image}
            alt={movieName}
            className="w-full h-full object-cover"
            onError={(e) => {
              const target = e.target as HTMLImageElement;
              target.src = '/placeholder.svg';
            }}
          />
          <div className="absolute inset-0 bg-gradient-to-t from-netflix-black via-netflix-black/60 to-transparent" />
          <div className="absolute inset-0 bg-gradient-to-r from-netflix-black/80 via-netflix-black/40 to-transparent" />
        </div>
      </div>

      {/* Movie details */}
      <div className="px-4 md:px-8 -mt-60 relative z-10 max-w-7xl mx-auto">
        <div className="flex flex-col md:flex-row gap-8">
          {/* Poster */}
          <div className="flex-shrink-0 hidden md:block">
            <img
              src={movieData.image}
              alt={movieName}
              className="w-64 h-96 object-cover rounded-md shadow-lg"
              onError={(e) => {
                const target = e.target as HTMLImageElement;
                target.src = '/placeholder.svg';
              }}
            />
          </div>

          {/* Details */}
          <div className="flex-grow">
            <h1 className="text-3xl md:text-4xl lg:text-5xl font-bold mb-3">{movieName}</h1>

            <div className="flex flex-wrap items-center text-sm text-gray-300 mb-6">
              {releaseYear && <span className="mr-3">{releaseYear}</span>}
              {runtime && <span className="mr-3">{runtime}</span>}
              {movieData.contentRatings && movieData.contentRatings.length > 0 && (
                <span className="mr-3 bg-netflix-red/80 px-2 py-0.5 rounded text-xs">
                  {movieData.contentRatings[0].name}+
                </span>
              )}
            </div>

            <div className="flex flex-wrap items-center gap-2 my-4">
              {movieData.genres &&
                movieData.genres.map((genre: any) => (
                  <Link
                    key={genre.id}
                    to={`/movies?genre=${genre.name}`}
                    className="px-3 py-1 bg-netflix-gray/20 rounded-full text-sm hover:bg-netflix-gray/40 transition"
                  >
                    {genre.name}
                  </Link>
                ))}
            </div>

            <p className="text-gray-300 mb-8 max-w-3xl">{overview}</p>

            <div className="flex flex-wrap gap-3 mb-8">
              <Link
                to={`/movie/${encodeURIComponent(title!)}/watch`}
                className="flex items-center px-6 py-2 rounded bg-netflix-red text-white font-semibold hover:bg-red-700 transition"
              >
                <Play className="w-5 h-5 mr-2" /> Play
              </Link>

              <button className="flex items-center px-4 py-2 rounded bg-gray-700 text-white hover:bg-gray-600 transition">
                <Plus className="w-5 h-5 mr-2" /> My List
              </button>

              <button className="flex items-center justify-center w-10 h-10 rounded-full bg-gray-700 text-white hover:bg-gray-600 transition">
                <ThumbsUp className="w-5 h-5" />
              </button>

              <button className="flex items-center justify-center w-10 h-10 rounded-full bg-gray-700 text-white hover:bg-gray-600 transition">
                <Share2 className="w-5 h-5" />
              </button>
            </div>

            {/* Additional details */}
            <div className="mb-6">
              {movieData.translations?.nameTranslations?.find((t: any) => t.isPrimary) && (
                <p className="text-gray-400 italic mb-4">
                  "{movieData.translations.nameTranslations.find((t: any) => t.isPrimary).tagline}"
                </p>
              )}

              <div className="grid grid-cols-1 md:grid-cols-2 gap-4">
                {movieData.production_companies && movieData.production_companies.length > 0 && (
                  <div>
                    <h3 className="text-gray-400 font-semibold mb-1">Production</h3>
                    <p className="text-white">
                      {movieData.production_companies.map((company: any) => company.name).join(', ')}
                    </p>
                  </div>
                )}

                {movieData.spoken_languages && movieData.spoken_languages.length > 0 && (
                  <div>
                    <h3 className="text-gray-400 font-semibold mb-1">Languages</h3>
                    <p className="text-white">{movieData.spoken_languages.join(', ')}</p>
                  </div>
                )}
              </div>
            </div>
          </div>
        </div>

        {/* Similar Movies */}
        {similarMovies.length > 0 && (
          <div className="mt-16">
            <ContentRow title="More Like This" items={similarMovies} />
          </div>
        )}
      </div>
    </div>
  );
};

export default MovieDetailPage;