| | |
| |
|
| | 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 => { |
| | setMovies(data.movies); |
| | if (data.movies.length > 0) { |
| | setSelectedMovie(data.movies[0]); |
| | } |
| | }) |
| | .catch(err => console.error("Failed to fetch movies:", err)); |
| | }, []); |
| |
|
| | 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 = "YOUR_TMDB_API_KEY_HERE"; |
| | const url = `https://api.themoviedb.org/3/movie/${movieId}?api_key=${apiKey}`; |
| | try { |
| | const response = await fetch(url); |
| | 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:", movieId); |
| | } |
| | return "https://via.placeholder.com/500x750.png?text=No+Poster"; |
| | }; |
| | |
| | |
| | const Poster = ({ movieId, title }) => { |
| | const [posterUrl, setPosterUrl] = useState(''); |
| |
|
| | useEffect(() => { |
| | fetchPosterUrl(movieId).then(setPosterUrl); |
| | }, [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>🎬 Movie Recommender</h1> |
| | <p>Select a movie you like to get 10 similar recommendations.</p> |
| | </header> |
| | <div className="controls"> |
| | <select value={selectedMovie} onChange={e => setSelectedMovie(e.target.value)}> |
| | {movies.map(movie => <option key={movie} value={movie}>{movie}</option>)} |
| | </select> |
| | <button onClick={handleRecommend} disabled={loading}> |
| | {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; |