diff --git a/src/components/Navbar.js b/src/components/Navbar.js index 3482315..46eaa27 100644 --- a/src/components/Navbar.js +++ b/src/components/Navbar.js @@ -1,4 +1,4 @@ -import React, { useState, useEffect } from 'react' +import React, { useState, useEffect, useRef } from 'react' import { NavLink } from 'react-router-dom' import { withRouter } from 'react-router-dom' @@ -10,6 +10,7 @@ import DropdownArrow from '../static/images/drop-down-arrow.svg' import DropdownContent from '../components/DropdownContent' const Navbar = ({ history }) => { + const searchInput = React.useRef(null) const [userInput, setUserInput] = useState('') const [scrollDimensions] = useScroll() const { scrollY } = scrollDimensions @@ -19,10 +20,14 @@ const Navbar = ({ history }) => { } useEffect(() => { - userInput.length <= 0 - ? history.push('/') - : history.push(`/search?q=${userInput}`) - }, [userInput]) + if ( + document.activeElement === searchInput.current && + userInput.length === 0 + ) { + history.push('/browse') + } + if (userInput.length > 0) history.push(`/search?q=${userInput}`) + }, [userInput, searchInput]) const onLogoClick = () => { setUserInput('') @@ -50,6 +55,7 @@ const Navbar = ({ history }) => {
onChange(event)} className='navigation__container--left__input' diff --git a/src/components/UI/Modal.js b/src/components/UI/Modal.js index f3a95e8..64d7e0f 100644 --- a/src/components/UI/Modal.js +++ b/src/components/UI/Modal.js @@ -6,8 +6,10 @@ const Modal = ({ show, modalClosed, children, + movie, movie: { backdrop_path, poster_path }, }) => { + console.log('Modal.movie', movie) const backgroundStyle = { backgroundSize: 'cover', backgroundImage: `url(https://image.tmdb.org/t/p/original/${ diff --git a/src/pages/Search.js b/src/pages/Search.js index 1449354..9ea9699 100644 --- a/src/pages/Search.js +++ b/src/pages/Search.js @@ -3,10 +3,10 @@ import { useLocation } from 'react-router-dom' import { useDispatch, useSelector } from 'react-redux' import { useDebounce } from '../hooks/useDebounce' +import * as movieActions from '../store/actions' import Modal from '../components/UI/Modal' import MovieDetails from '../components/Movie/MovieDetails' import Movie from '../components/Movie/Movie' -import axios from '../axios-movies' // A custom hook that builds on useLocation to parse // the query string for you. @@ -14,171 +14,80 @@ const useQuery = () => { return new URLSearchParams(useLocation().search) } -const Search = ({ history }) => { +const Search = () => { let query = useQuery() const debouncedSearchTerm = useDebounce(query.get('q'), 500) const [isToggleModal, setIsToggleModal] = useState(false) - const searchResults = useSelector((state) => state.searchMovie) + const { searchResults, isLoading } = useSelector((state) => state.searchMovie) + const { movieDetails } = useSelector((state) => state.movieDetails) const dispatch = useDispatch() - // constructor(props) { - // super(props) - // this.state = { - // movies: [], - // toggleModal: false, - // /** Holds the movie information for a single movie. */ - // movieOverview: {}, - // } - // } useEffect(() => { if (debouncedSearchTerm) { - console.log('maing api call....') + dispatch(movieActions.fetchSearchMovie(debouncedSearchTerm)) } }, [debouncedSearchTerm]) - console.log('location', query.get('q')) - - // componentDidMount = async () => { - - // console.log('movie roww', movieRows) - // const { movieRows } = this.props.history.location; - // if (movieRows) { - // await this.setState({ movies: movieRows }); - - // } - // } - - // useEffect(() => { - // if (!userInput) { - // console.log('Search.useEffect()') - // history.push('/') - // } - // }, [userInput]) - - // useEffect(() => { - // console.log('searchResults', searchResults) - // }, [searchResults]) - - // componentDidUpdate = async (prevProps) => { - // console.log('hiiiiiii') - // if ( - // prevProps.location.movieRows.length !== - // this.props.location.movieRows.length - // ) { - // await this.setState({ movies: this.props.location.movieRows }); - // } - // } - - const closeModal = () => { + const onCloseModalHandler = () => { setIsToggleModal(false) } - // /* Get the appropriate details for a specific movie that was clicked */ - // selectMovieHandler = (movie) => { - // this.setState({ toggleModal: true }); + const onSelectMovieHandler = (movie) => { + dispatch(movieActions.fetchMovieDetails(movie.media_type, movie.id)) + setIsToggleModal(true) + } - // let url; - // /** Make the appropriate API call to get the details for a single movie or tv show. */ - // if (movie.media_type === "movie") { - // const movieId = movie.id; - // url = `https://api.themoviedb.org/3/movie/${movieId}?api_key=${process.env.API_KEY}`; + const renderSearchResults = () => { + return searchResults.length > 0 ? ( + <> +
+ {searchResults.map((movie) => { + let movieRows = [] + let movieImageUrl + if (movie.poster_path !== null && movie.media_type !== 'person') { + movieImageUrl = + 'https://image.tmdb.org/t/p/w500' + movie.poster_path + const movieComponent = ( + onSelectMovieHandler(movie)} + key={movie.id} + movieImage={movieImageUrl} + movie={movie} + /> + ) + movieRows.push(movieComponent) + } + return movieRows + })} +
+ + + + + ) : ( +
+
+

+ Your search for "{debouncedSearchTerm}" did not have any matches. +

+

Suggestions:

+
    +
  • Try different keywords
  • +
  • Looking for a movie or TV show?
  • +
  • Try using a movie, TV show title, an actor or director
  • +
  • Try a genre, like comedy, romance, sports, or drama
  • +
+
+
+ ) + } - // } else if (movie.media_type === "tv") { - // const tvId = movie.id - // url = `https://api.themoviedb.org/3/tv/${tvId}?api_key=${process.env.API_KEY}`; - // } - - // axios.get(url) - // .then(res => { - // const movieData = res.data; - // this.setState({ movieOverview: movieData }); - // }).catch(error => { - // console.log(error); - // }); - // } - - // const { movies } = this.state - // const { userInput } = this.props.location - // console.log('search().render()', this.props.history.location) - - return

hello

- // searchResults === undefined ? ( - // - // ) : ( - //
- // {searchResults.map((movie) => { - // let movieRows = [] - // let movieImageUrl - // if (movie.poster_path !== null && movie.media_type !== 'person') { - // movieImageUrl = 'https://image.tmdb.org/t/p/w500' + movie.poster_path - - // /** Set the movie object to our Movie component */ - // const movieComponent = ( - // this.selectMovieHandler(movie)} - // key={movie.id} - // movieImage={movieImageUrl} - // movie={movie} - // /> - // ) - - // /** Push our movie component to our movieRows array */ - // movieRows.push(movieComponent) - // } - // return movieRows - // })} - //
- // ) - - // <> - // {searchResults && searchResults.data.length > 0 ? ( - //
- // {searchResults.map((movie) => { - // let movieRows = [] - // let movieImageUrl - // if (movie.poster_path !== null && movie.media_type !== 'person') { - // movieImageUrl = - // 'https://image.tmdb.org/t/p/w500' + movie.poster_path - - // /** Set the movie object to our Movie component */ - // const movieComponent = ( - // this.selectMovieHandler(movie)} - // key={movie.id} - // movieImage={movieImageUrl} - // movie={movie} - // /> - // ) - - // /** Push our movie component to our movieRows array */ - // movieRows.push(movieComponent) - // } - // return movieRows - // })} - //
- // ) : ( - //
- //
- //

Your search for "{userInput}" did not have any matches.

- //

Suggestions:

- //
    - //
  • Try different keywords
  • - //
  • Looking for a movie or TV show?
  • - //
  • Try using a movie, TV show title, an actor or director
  • - //
  • Try a genre, like comedy, romance, sports, or drama
  • - //
- //
- //
- // )} - /* */ - /* */ - /* */ - // + return !isLoading ? renderSearchResults() :

Loading...

} export default Search diff --git a/src/store/actions/index.js b/src/store/actions/index.js index 80811db..d769aa5 100644 --- a/src/store/actions/index.js +++ b/src/store/actions/index.js @@ -1,7 +1,6 @@ import axios from '../../axios-movies' export const FETCH_HEADER_MOVIE = 'FETCH_HEADER_MOVIE' -export const FETCH_SEARCH_MOVIE = 'FETCH_SEARCH_MOVIE' export const FETCH_TRENDING = 'FETCH_TRENDING' export const FETCH_NETFLIX_ORIGINALS = 'FETCH_NETFLIX_ORIGINALS' export const FETCH_TOP_RATED = 'FETCH_TOP_RATED' @@ -10,15 +9,49 @@ export const FETCH_COMEDY_MOVIES = 'FETCH_COMEDY_MOVIES' export const FETCH_HORROR_MOVIES = 'FETCH_HORROR_MOVIES' export const FETCH_ROMANCE_MOVIES = 'FETCH_ROMANCE_MOVIES' export const FETCH_DOCUMENTARIES = 'FETCH_DOCUMENTARIES' +// movie details +export const FETCH_MOVIE_DETAILS = 'FETCH_MOVIE_DETAILS' +export const FETCH_MOVIE_DETAILS_SUCCESS = 'FETCH_MOVIE_DETAILS_SUCCESS' +export const FETCH_MOVIE_DETAILS_FAIL = 'FETCH_MOVIE_DETAILS_FAIL' +// search +export const FETCH_SEARCH_MOVIE = 'FETCH_SEARCH_MOVIE' +export const FETCH_SEARCH_MOVIE_FAIL = 'FETCH_SEARCH_MOVIE_FAIL' +export const FETCH_SEARCH_MOVIE_SUCCESS = 'FETCH_SEARCH_MOVIE_SUCCESS' + +const media_type = { + tv: 'tv', + movie: 'movie', +} + +export const fetchMovieDetails = (mediaType, mediaId) => { + return async (dispatch) => { + try { + dispatch({ type: FETCH_MOVIE_DETAILS }) + let urlPath + if (mediaType === media_type.movie) + urlPath = `/movie/${mediaId}?api_key=${process.env.API_KEY}` + if (mediaType === media_type.tv) + urlPath = `/tv/${mediaId}?api_key=${process.env.API_KEY}` + + const request = await axios.get(urlPath) + dispatch({ type: FETCH_MOVIE_DETAILS_SUCCESS, payload: request }) + } catch (error) { + console.log('error', error) + dispatch({ type: FETCH_MOVIE_DETAILS_FAIL }) + } + } +} export const fetchSearchMovie = (searchTerm) => { return async (dispatch) => { try { + dispatch({ type: FETCH_SEARCH_MOVIE }) const request = await axios.get( `/search/multi?api_key=${process.env.API_KEY}&language=en-US&include_adult=false&query=${searchTerm}` ) - dispatch({ type: FETCH_SEARCH_MOVIE, payload: request }) + dispatch({ type: FETCH_SEARCH_MOVIE_SUCCESS, payload: request }) } catch (error) { + dispatch({ type: FETCH_SEARCH_MOVIE_FAIL }) console.log('error', error) } } diff --git a/src/store/reducers/index.js b/src/store/reducers/index.js index bf9a80a..b7f9edb 100644 --- a/src/store/reducers/index.js +++ b/src/store/reducers/index.js @@ -9,6 +9,7 @@ import RomanceMoviesReducer from './reducerRomanceMovies' import DocumentaryReducer from './reducerDocumentary' import HeaderMovieReducer from './reducerHeaderMovie' import SearchMovieReducer from './reducerSearchMovie' +import MovieDetailsReducer from './reducerMovieDetails' const rootReducer = combineReducers({ trending: TrendingReducer, @@ -21,6 +22,7 @@ const rootReducer = combineReducers({ documentary: DocumentaryReducer, headerMovie: HeaderMovieReducer, searchMovie: SearchMovieReducer, + movieDetails: MovieDetailsReducer, }) export default rootReducer diff --git a/src/store/reducers/reducerMovieDetails.js b/src/store/reducers/reducerMovieDetails.js new file mode 100644 index 0000000..d7067a8 --- /dev/null +++ b/src/store/reducers/reducerMovieDetails.js @@ -0,0 +1,24 @@ +import { + FETCH_MOVIE_DETAILS, + FETCH_MOVIE_DETAILS_SUCCESS, + FETCH_MOVIE_DETAILS_FAIL, +} from '../actions/index' + +const initialState = { + isLoading: false, + movieDetails: [], +} + +export default function (state = initialState, action) { + switch (action.type) { + case FETCH_MOVIE_DETAILS: + return { ...state, isLoading: true } + case FETCH_MOVIE_DETAILS_FAIL: + return { ...state, isLoading: false } + case FETCH_MOVIE_DETAILS_SUCCESS: + const movieDetails = action.payload.data + return { ...state, movieDetails, isLoading: false } + default: + return state + } +} diff --git a/src/store/reducers/reducerSearchMovie.js b/src/store/reducers/reducerSearchMovie.js index 48a199d..54713e5 100644 --- a/src/store/reducers/reducerSearchMovie.js +++ b/src/store/reducers/reducerSearchMovie.js @@ -1,10 +1,23 @@ -import { FETCH_SEARCH_MOVIE } from '../actions/index' +import { + FETCH_SEARCH_MOVIE, + FETCH_SEARCH_MOVIE_FAIL, + FETCH_SEARCH_MOVIE_SUCCESS, +} from '../actions/index' -export default function (state = {}, action) { +const initialState = { + isLoading: false, + searchResults: [], +} + +export default function (state = initialState, action) { switch (action.type) { case FETCH_SEARCH_MOVIE: - const data = action.payload.data.results - return { ...state, data } + return { ...state, isLoading: true } + case FETCH_SEARCH_MOVIE_FAIL: + return { ...state, isLoading: false } + case FETCH_SEARCH_MOVIE_SUCCESS: + const searchResults = action.payload.data.results + return { ...state, searchResults, isLoading: false } default: return state }