├── src ├── APIKey.js ├── components │ ├── layout │ │ ├── spinner.gif │ │ ├── Spinner.js │ │ ├── Footer.js │ │ └── Navbar.js │ └── home │ │ ├── Landing.js │ │ ├── MoviesContainer.js │ │ ├── MovieCard.js │ │ ├── SearchForm.js │ │ └── Movie.js ├── reducers │ ├── index.js │ └── searchReducer.js ├── actions │ ├── types.js │ └── searchActions.js ├── index.js ├── App.test.js ├── App.css ├── index.css ├── store.js ├── App.js └── serviceWorker.js ├── public ├── favicon.ico ├── manifest.json └── index.html ├── .gitignore ├── package.json └── README.md /src/APIKey.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | APIKey: 'c951ff1' 3 | }; 4 | -------------------------------------------------------------------------------- /public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yaser-alazm/movies-series-info/HEAD/public/favicon.ico -------------------------------------------------------------------------------- /src/components/layout/spinner.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yaser-alazm/movies-series-info/HEAD/src/components/layout/spinner.gif -------------------------------------------------------------------------------- /src/reducers/index.js: -------------------------------------------------------------------------------- 1 | import { combineReducers } from 'redux'; 2 | import searchReducer from './searchReducer'; 3 | 4 | export default combineReducers({ 5 | movies: searchReducer 6 | }); 7 | -------------------------------------------------------------------------------- /src/actions/types.js: -------------------------------------------------------------------------------- 1 | export const SEARCH_MOVIE = 'SEARCH_MOVIE'; 2 | export const FETCH_MOVIES = 'FETCH_MOVIES'; 3 | export const FETCH_MOVIE = 'FETCH_MOVIE'; 4 | export const LOADING = 'LOADING'; 5 | -------------------------------------------------------------------------------- /src/index.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import ReactDOM from 'react-dom'; 3 | import './index.css'; 4 | import App from './App'; 5 | import * as serviceWorker from './serviceWorker'; 6 | 7 | ReactDOM.render(, document.getElementById('root')); 8 | 9 | serviceWorker.unregister(); 10 | -------------------------------------------------------------------------------- /src/App.test.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import ReactDOM from 'react-dom'; 3 | import App from './App'; 4 | 5 | it('renders without crashing', () => { 6 | const div = document.createElement('div'); 7 | ReactDOM.render(, div); 8 | ReactDOM.unmountComponentAtNode(div); 9 | }); 10 | -------------------------------------------------------------------------------- /src/App.css: -------------------------------------------------------------------------------- 1 | #movies img, 2 | #movie img { 3 | width: 100%; 4 | } 5 | .brand-text { 6 | font-size: 2rem; 7 | } 8 | #react-logo { 9 | color: #00d8ff; 10 | } 11 | #imdb-logo { 12 | color: #f5de50; 13 | } 14 | @media (min-width: 960px) { 15 | #movies .col-md-3 .well { 16 | height: 390px; 17 | } 18 | 19 | #movies .col-md-3 img { 20 | height: 240px; 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/components/layout/Spinner.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import spinner from './spinner.gif' 3 | 4 | function Spinner() { 5 | return ( 6 |
7 | Loading... 12 |
13 | ) 14 | } 15 | 16 | export default Spinner 17 | -------------------------------------------------------------------------------- /public/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "short_name": "React App", 3 | "name": "Create React App Sample", 4 | "icons": [ 5 | { 6 | "src": "favicon.ico", 7 | "sizes": "64x64 32x32 24x24 16x16", 8 | "type": "image/x-icon" 9 | } 10 | ], 11 | "start_url": ".", 12 | "display": "standalone", 13 | "theme_color": "#000000", 14 | "background_color": "#ffffff" 15 | } 16 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files. 2 | 3 | # dependencies 4 | /node_modules 5 | /.pnp 6 | .pnp.js 7 | 8 | # testing 9 | /coverage 10 | 11 | # production 12 | /build 13 | 14 | # misc 15 | .DS_Store 16 | .env.local 17 | .env.development.local 18 | .env.test.local 19 | .env.production.local 20 | 21 | npm-debug.log* 22 | yarn-debug.log* 23 | yarn-error.log* 24 | -------------------------------------------------------------------------------- /src/index.css: -------------------------------------------------------------------------------- 1 | body { 2 | margin: 0; 3 | padding: 0; 4 | font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", "Roboto", "Oxygen", 5 | "Ubuntu", "Cantarell", "Fira Sans", "Droid Sans", "Helvetica Neue", 6 | sans-serif; 7 | -webkit-font-smoothing: antialiased; 8 | -moz-osx-font-smoothing: grayscale; 9 | } 10 | 11 | code { 12 | font-family: source-code-pro, Menlo, Monaco, Consolas, "Courier New", 13 | monospace; 14 | } 15 | -------------------------------------------------------------------------------- /src/store.js: -------------------------------------------------------------------------------- 1 | import { createStore, applyMiddleware } from 'redux'; 2 | import thunk from 'redux-thunk'; 3 | import { composeWithDevTools } from 'redux-devtools-extension/developmentOnly'; 4 | import rootReducer from './reducers'; 5 | 6 | const middleware = [thunk]; 7 | const initialState = {}; 8 | 9 | const store = createStore( 10 | rootReducer, 11 | initialState, 12 | composeWithDevTools(applyMiddleware(...middleware)) 13 | ); 14 | 15 | export default store; 16 | -------------------------------------------------------------------------------- /src/components/home/Landing.js: -------------------------------------------------------------------------------- 1 | import React, { Component } from 'react'; 2 | 3 | import { connect } from 'react-redux'; 4 | 5 | import SearchForm from './SearchForm'; 6 | import MoviesContainer from './MoviesContainer'; 7 | import Spinner from '../layout/Spinner'; 8 | 9 | export class Landing extends Component { 10 | render() { 11 | const { loading } = this.props; 12 | return ( 13 |
14 | 15 | {loading ? : } 16 |
17 | ); 18 | } 19 | } 20 | 21 | const mapStateToProps = state => ({ 22 | loading: state.movies.loading 23 | }); 24 | 25 | export default connect(mapStateToProps)(Landing); 26 | -------------------------------------------------------------------------------- /src/components/home/MoviesContainer.js: -------------------------------------------------------------------------------- 1 | import React, { Component } from 'react'; 2 | 3 | import { connect } from 'react-redux'; 4 | 5 | import MovieCard from './MovieCard'; 6 | 7 | export class MoviesContainer extends Component { 8 | render() { 9 | const { movies } = this.props; 10 | let content = ''; 11 | 12 | content = 13 | movies.Response === 'True' 14 | ? movies.Search.map((movie, index) => ( 15 | 16 | )) 17 | : null; 18 | return
{content}
; 19 | } 20 | } 21 | 22 | const mapStateToProps = state => ({ 23 | movies: state.movies.movies 24 | }); 25 | 26 | export default connect(mapStateToProps)(MoviesContainer); 27 | -------------------------------------------------------------------------------- /src/components/home/MovieCard.js: -------------------------------------------------------------------------------- 1 | import React, { Component } from 'react'; 2 | import { Link } from 'react-router-dom'; 3 | 4 | export class MovieCard extends Component { 5 | render() { 6 | const { movie } = this.props; 7 | return ( 8 |
9 |
10 | Movie Cover 11 |
12 | {movie.Title} - {movie.Year} 13 |
14 | 15 | Movie Details 16 | 17 | 18 |
19 |
20 | ); 21 | } 22 | } 23 | 24 | export default MovieCard; 25 | -------------------------------------------------------------------------------- /src/components/layout/Footer.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | 3 | function Footer() { 4 | return ( 5 |
6 |
7 |
8 |
9 | Developed By: 10 | 11 | Yaser AlAzem 12 | 13 | , Using React JS & Redux JS 14 | integrated with external movies data API 15 | 20 | OMDB 21 | 22 |
23 |
24 |
25 |
26 | ); 27 | } 28 | 29 | export default Footer; 30 | -------------------------------------------------------------------------------- /src/App.js: -------------------------------------------------------------------------------- 1 | import React, { Component } from 'react'; 2 | import { Provider } from 'react-redux'; 3 | import { HashRouter as Router, Route } from 'react-router-dom'; 4 | 5 | import './App.css'; 6 | 7 | import Navbar from './components/layout/Navbar'; 8 | import Footer from './components/layout/Footer'; 9 | 10 | import Landing from './components/home/Landing'; 11 | import Movie from './components/home/Movie'; 12 | 13 | import store from './store'; 14 | 15 | class App extends Component { 16 | render() { 17 | return ( 18 | 19 | 20 |
21 | 22 | 23 | 24 |
25 |
26 |
27 |
28 | ); 29 | } 30 | } 31 | 32 | export default App; 33 | -------------------------------------------------------------------------------- /src/reducers/searchReducer.js: -------------------------------------------------------------------------------- 1 | import { 2 | SEARCH_MOVIE, 3 | FETCH_MOVIES, 4 | FETCH_MOVIE, 5 | LOADING 6 | } from '../actions/types'; 7 | 8 | const initialState = { 9 | text: '', 10 | movies: [], 11 | loading: false, 12 | movie: [] 13 | }; 14 | 15 | export default function(state = initialState, action) { 16 | switch (action.type) { 17 | case SEARCH_MOVIE: 18 | return { 19 | ...state, 20 | text: action.payload, 21 | loading: false 22 | }; 23 | case FETCH_MOVIES: 24 | return { 25 | ...state, 26 | movies: action.payload, 27 | loading: false 28 | }; 29 | case FETCH_MOVIE: 30 | return { 31 | ...state, 32 | movie: action.payload, 33 | loading: false 34 | }; 35 | case LOADING: 36 | return { 37 | ...state, 38 | loading: true 39 | }; 40 | default: 41 | return state; 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "movies-series-app", 3 | "version": "0.1.0", 4 | "private": true, 5 | "homepage": "https://yaser-alazm.github.io/movies-series-info", 6 | "dependencies": { 7 | "axios": "^1.7.7", 8 | "gh-pages": "^6.1.1", 9 | "react": "^16.7.0", 10 | "react-dom": "^16.7.0", 11 | "react-redux": "^6.0.0", 12 | "react-router-dom": "^4.3.1", 13 | "react-scripts": "^5.0.1", 14 | "redux": "^4.0.1", 15 | "redux-devtools-extension": "^2.13.8", 16 | "redux-thunk": "^2.3.0" 17 | }, 18 | "scripts": { 19 | "deploy": "npm run build&&gh-pages -d build", 20 | "start": "react-scripts start", 21 | "build": "react-scripts build", 22 | "test": "react-scripts test", 23 | "eject": "react-scripts eject" 24 | }, 25 | "eslintConfig": { 26 | "extends": "react-app" 27 | }, 28 | "browserslist": [ 29 | ">0.2%", 30 | "not dead", 31 | "not ie <= 11", 32 | "not op_mini all" 33 | ] 34 | } 35 | -------------------------------------------------------------------------------- /src/components/layout/Navbar.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { Link } from 'react-router-dom'; 3 | 4 | function Navbar() { 5 | return ( 6 |
7 |