diff --git a/package-lock.json b/package-lock.json index 1458f57..e7a0691 100644 --- a/package-lock.json +++ b/package-lock.json @@ -13685,4 +13685,4 @@ } } } -} +} \ No newline at end of file diff --git a/src/MovieInfo/actions.js b/src/MovieInfo/actions.js new file mode 100644 index 0000000..0d7b7c1 --- /dev/null +++ b/src/MovieInfo/actions.js @@ -0,0 +1,25 @@ +import { + FETCH_MOVIE_LIST, + FETCH_MOVIE_LIST_SUCCESS, + FETCH_MOVIE_LIST_FAILURE, +} from './constants'; + +export function fetchMovieList() { + return { + type: FETCH_MOVIE_LIST, + }; +} + +export function fetchMovieListSuccess(movieList) { + return { + type: FETCH_MOVIE_LIST_SUCCESS, + payload: movieList, + }; +} + +export function fetchMovieListFailure(error) { + return { + type: FETCH_MOVIE_LIST_FAILURE, + payload: { error }, + }; +} diff --git a/src/MovieInfo/component.jsx b/src/MovieInfo/component.jsx new file mode 100644 index 0000000..e298bee --- /dev/null +++ b/src/MovieInfo/component.jsx @@ -0,0 +1,28 @@ +import React from 'react'; +import PropTypes from 'prop-types'; + +function MovieInfo({ movie }) { + const { poster_path: path, overview } = movie; + return ( +
+
+
+ movie-poster +
+
+

{overview}

+
+
+
+ ); +} + +MovieInfo.propTypes = { + movie: PropTypes.object, +}; + +export default MovieInfo; diff --git a/src/MovieInfo/constants.js b/src/MovieInfo/constants.js new file mode 100644 index 0000000..50b8be8 --- /dev/null +++ b/src/MovieInfo/constants.js @@ -0,0 +1,9 @@ +export const FETCH_MOVIE_LIST = '@movieInfo/FETCH_MOVIE_LIST'; + +export const FETCH_MOVIE_LIST_SUCCESS = '@movieInfo/FETCH_MOVIE_LIST_SUCCESS'; + +export const FETCH_MOVIE_LIST_FAILURE = '@movieInfo/FETCH_MOVIE_LIST_FAILURE'; + +export const POPULAR_MOVIES = 'Popular Movies'; + +export const ERROR_TEXT = 'Oops! Something went wrong. Please refresh'; diff --git a/src/MovieInfo/container.jsx b/src/MovieInfo/container.jsx new file mode 100644 index 0000000..d437052 --- /dev/null +++ b/src/MovieInfo/container.jsx @@ -0,0 +1,64 @@ +import React, { useEffect } from 'react'; +import PropTypes from 'prop-types'; +import { connect } from 'react-redux'; +import { bindActionCreators } from 'redux'; +import { + fetchMovieListSuccess, + fetchMovieListFailure, +} from './actions'; +import MovieInfo from './component'; +import { ERROR_TEXT } from './constants'; +import { getDataFromAPI } from '../HandleAPICalls/actions'; + +const URL = + 'https://api.themoviedb.org/3/movie/popular?api_key=1e2bbb1e97b4751a4945af538fa72a41'; + +function Movie({ + getDataFromAPI: getData, + fetchMovieListSuccess: fetchMovieSucces, + fetchMovieListFailure: fetchMovieFailure, + movies: { data, error }, +}) { + useEffect(() => { + getData(URL, 'GET', undefined, fetchMovieSucces, fetchMovieFailure); + }, [getData, fetchMovieFailure, fetchMovieFailure]); + return ( +
+ {!data.length &&
} + {error &&

{ERROR_TEXT}

} +
+ {data.map(movie => ( +
+ +
+ ))} +
+
+ ); +} + +function mapStateToProps(state) { + return { movies: state.movieList }; +} +function mapDispatchToProps(dispatch) { + return bindActionCreators( + { + getDataFromAPI, + fetchMovieListFailure, + fetchMovieListSuccess, + }, + dispatch, + ); +} + +export default connect( + mapStateToProps, + mapDispatchToProps, +)(Movie); + +Movie.propTypes = { + movies: PropTypes.object, + getDataFromAPI: PropTypes.func, + fetchMovieListSuccess: PropTypes.func, + fetchMovieListFailure: PropTypes.func +}; diff --git a/src/MovieInfo/reducer.js b/src/MovieInfo/reducer.js new file mode 100644 index 0000000..88e85e7 --- /dev/null +++ b/src/MovieInfo/reducer.js @@ -0,0 +1,32 @@ +import { + FETCH_MOVIE_LIST, + FETCH_MOVIE_LIST_SUCCESS, + FETCH_MOVIE_LIST_FAILURE, +} from './constants'; + +const movieListInitialState = { + data: [], + isFetching: false, + error: null, +}; + +export default function movieListReducer( + state = movieListInitialState, + action, +) { + switch (action.type) { + case FETCH_MOVIE_LIST: + return { ...state, isFetching: true }; + case FETCH_MOVIE_LIST_SUCCESS: + return { + ...state, + isFetching: false, + data: [...action.payload.results], + error: null, + }; + case FETCH_MOVIE_LIST_FAILURE: + return { ...state, error: action.payload }; + default: + return state; + } +} diff --git a/src/app/App.jsx b/src/app/App.jsx index 2a02b19..0e2572c 100644 --- a/src/app/App.jsx +++ b/src/app/App.jsx @@ -1,18 +1,13 @@ import React from 'react'; -import RandomQuote from '../RandomQuote/container'; -import TodoApp from './TodoApp/container'; +import Movie from '../MovieInfo/container'; +import { POPULAR_MOVIES } from '../MovieInfo/constants'; export default function App() { return (
-

Hello React with Hot Reload !

+

{POPULAR_MOVIES}

+
- -
-

Todos App - React hooks🔥

-
- -
); } diff --git a/src/index.css b/src/index.css index cf1defb..e5f4511 100644 --- a/src/index.css +++ b/src/index.css @@ -1,6 +1,7 @@ -@import url('https://fonts.googleapis.com/css?family=Dancing+Script'); +@import url("https://fonts.googleapis.com/css?family=Dancing+Script"); body { height: 100%; + width: 100%; } h1 { @@ -9,5 +10,117 @@ h1 { font-size: 5em; text-align: center; padding-top: 15vh; - font-family: 'Dancing Script', cursive; + font-family: "Dancing Script", cursive; +} + +h2 { + color: #4568de; + margin: 0 auto; + font-size: 6rem; + text-align: center; + font-family: "Dancing Script", cursive; +} + +/* show spinner - inspired from w3schools */ + +.movie-card { + background-color: transparent; + width: 15.625rem; + height: 18.75rem; + perspective: 1000px; +} + +.movie-card-inner { + position: relative; + width: 100%; + height: 100%; + text-align: center; + transition: transform 0.6s; + transform-style: preserve-3d; + box-shadow: 0 4px 8px 0 rgba(0, 0, 0, 0.2); +} + +.movie-card:hover .movie-card-inner { + transform: rotateY(180deg); +} + +.movie-card-front, +.movie-card-back { + position: absolute; + width: 100%; + height: 100%; + backface-visibility: hidden; +} + +.movie-card-front { + background-color: #bbb; + color: black; +} + +.movie-card-back { + background-color: #beebe7; + color: #000; + transform: rotateY(180deg); + overflow: hidden; +} + +.movie-container { + width: 100%; + display: flex; + flex-wrap: wrap; + justify-content: center; +} + +.items { + margin: 1rem; +} + +.image { + width: 15.625rem; + height: 18.75rem; +} + +.movie-description { + text-align: justify; + padding: 0.625rem; + line-height: 1.5; + font-weight: bold; + font-family: "Dancing Script"; +} + +.align-center { + text-align: center; +} + +.error-text { + color: red; + font-weight: bold; + font-family: "Dancing Script"; +} + +/* show spinner - inspired from pure css loader */ + +.lds-dual-ring { + display: inline-block; + width: 5rem; + height: 5rem; +} +.lds-dual-ring:after { + content: " "; + display: block; + width: 6rem; + height: 6rem; + margin: 0.1rem; + border-radius: 50%; + border: 5px solid green; + border-color: green transparent green transparent; + animation: lds-dual-ring 1.2s linear infinite; +} +@keyframes lds-dual-ring { + 0% { + transform: rotate(0deg); + } + 100% { + transform: rotate(360deg); + } } diff --git a/src/reducers/index.js b/src/reducers/index.js index 91cda8d..cf7a354 100644 --- a/src/reducers/index.js +++ b/src/reducers/index.js @@ -1,6 +1,8 @@ import { combineReducers } from 'redux'; +import movieListReducer from '../MovieInfo/reducer'; import randomQuoteReducer from '../RandomQuote/reducer'; export default combineReducers({ quote: randomQuoteReducer, + movieList: movieListReducer, });