|
|
import React, { useState, useEffect } from 'react'; |
|
|
import './App.css'; |
|
|
|
|
|
function App() { |
|
|
const [movies, setMovies] = useState([]); |
|
|
const [selectedMovie, setSelectedMovie] = useState(''); |
|
|
const [recommendations, setRecommendations] = useState([]); |
|
|
const [loading, setLoading] = useState(false); |
|
|
const [error, setError] = useState(''); |
|
|
|
|
|
|
|
|
useEffect(() => { |
|
|
fetch('/api/movies') |
|
|
.then(response => response.json()) |
|
|
.then(data => { |
|
|
console.log("Movies fetched:", data.movies); |
|
|
if(Array.isArray(data.movies)){ |
|
|
setMovies(data.movies); |
|
|
if(data.movies.length > 0){ |
|
|
setSelectedMovie(data.movies[0]); |
|
|
} |
|
|
} else { |
|
|
console.error("Movies data is not an array:", data.movies); |
|
|
} |
|
|
}) |
|
|
.catch(err => { |
|
|
console.error("Failed to fetch movies:", err); |
|
|
setError('Failed to fetch movie list'); |
|
|
}); |
|
|
}, []); |
|
|
|
|
|
const handleRecommend = () => { |
|
|
if (!selectedMovie) return; |
|
|
setLoading(true); |
|
|
setError(''); |
|
|
setRecommendations([]); |
|
|
|
|
|
fetch(`/api/recommend?title=${encodeURIComponent(selectedMovie)}`) |
|
|
.then(response => { |
|
|
if (!response.ok) throw new Error('Network response was not ok'); |
|
|
return response.json(); |
|
|
}) |
|
|
.then(data => { |
|
|
setRecommendations(data.recommendations || []); |
|
|
setLoading(false); |
|
|
}) |
|
|
.catch(err => { |
|
|
setError('Failed to get recommendations. Please try again.'); |
|
|
setLoading(false); |
|
|
console.error("Error fetching recommendations:", err); |
|
|
}); |
|
|
}; |
|
|
|
|
|
|
|
|
const fetchPosterUrl = async (movieId) => { |
|
|
const apiKey = "4f26810245b768489a195238ffe92a0b"; |
|
|
const url = `https://api.themoviedb.org/3/movie/${movieId}?api_key=${apiKey}`; |
|
|
try { |
|
|
const response = await fetch(url); |
|
|
if (!response.ok) throw new Error('Failed fetching poster'); |
|
|
const data = await response.json(); |
|
|
if (data.poster_path) { |
|
|
return `https://image.tmdb.org/t/p/w500/${data.poster_path}`; |
|
|
} |
|
|
} catch (err) { |
|
|
console.error("Failed to fetch poster for movie ID:", movieId); |
|
|
} |
|
|
return "https://via.placeholder.com/500x750.png?text=No+Poster"; |
|
|
}; |
|
|
|
|
|
|
|
|
const Poster = ({ movieId, title }) => { |
|
|
const [posterUrl, setPosterUrl] = useState("https://via.placeholder.com/500x750.png?text=Loading..."); |
|
|
|
|
|
useEffect(() => { |
|
|
let mounted = true; |
|
|
fetchPosterUrl(movieId).then(url => { |
|
|
if (mounted) setPosterUrl(url); |
|
|
}); |
|
|
return () => { mounted = false; }; |
|
|
}, [movieId]); |
|
|
|
|
|
return ( |
|
|
<div className="movie-card"> |
|
|
<img src={posterUrl} alt={`${title} poster`} /> |
|
|
<p className="movie-title">{title}</p> |
|
|
</div> |
|
|
); |
|
|
}; |
|
|
|
|
|
return ( |
|
|
<div className="App"> |
|
|
<header className="App-header"> |
|
|
<h1>PragyanAI - Super 30 Movie Recommender</h1> |
|
|
<p>Select a movie you like to get 10 similar recommendations.</p> |
|
|
</header> |
|
|
|
|
|
<div className="controls"> |
|
|
<select |
|
|
value={selectedMovie} |
|
|
onChange={e => { |
|
|
console.log("Selected movie changed to:", e.target.value); // Debug log |
|
|
setSelectedMovie(e.target.value); |
|
|
}} |
|
|
> |
|
|
{movies.map(movie => ( |
|
|
<option key={movie} value={movie}> |
|
|
{movie} |
|
|
</option> |
|
|
))} |
|
|
</select> |
|
|
|
|
|
<button onClick={handleRecommend} disabled={loading || !selectedMovie}> |
|
|
{loading ? 'Searching...' : 'Recommend'} |
|
|
</button> |
|
|
</div> |
|
|
|
|
|
{error && <p className="error">{error}</p>} |
|
|
|
|
|
<div className="recommendation-grid"> |
|
|
{recommendations.map(rec => ( |
|
|
<Poster key={rec.id} movieId={rec.id} title={rec.title} /> |
|
|
))} |
|
|
</div> |
|
|
</div> |
|
|
); |
|
|
} |
|
|
|
|
|
export default App; |
|
|
|
|
|
|