Skip to content

Commit 5ac760c

Browse files
Merge pull request #1 from FrancoisCoding/develop
Develop
2 parents 96ed1a3 + 93c9121 commit 5ac760c

File tree

18 files changed

+613
-23
lines changed

18 files changed

+613
-23
lines changed

src/components/App/App.js

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
import React from "react";
2+
import { BrowserRouter, Route, Switch } from "react-router-dom";
3+
import Header from "../elements/Header/Header";
4+
import Home from "../Home/Home";
5+
import Movie from "../Movie/Movie";
6+
import NotFound from "../elements/NotFound/NotFound";
7+
8+
export default function App() {
9+
return (
10+
<BrowserRouter>
11+
<React.Fragment>
12+
<Header />
13+
<Switch>
14+
<Route exact path="/" component={Home} />
15+
<Route exact path="/:movieId" component={Movie} />
16+
<Route component={NotFound} />
17+
</Switch>
18+
</React.Fragment>
19+
</BrowserRouter>
20+
);
21+
}

src/components/Home/Home.js

Lines changed: 150 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,150 @@
1+
import React, { Component } from "react";
2+
import {
3+
API_URL,
4+
API_KEY,
5+
IMAGE_BASE_URL,
6+
POSTER_SIZE,
7+
BACKDROP_SIZE
8+
} from "../../config";
9+
import HeroImage from "../elements/HeroImage/HeroImage";
10+
import SearchBar from "../elements/SearchBar/SearchBar";
11+
import FourColGrid from "../elements/FourColGrid/FourColGrid";
12+
import MovieThumb from "../elements/MovieThumb/MovieThumb";
13+
import LoadMoreBtn from "../elements/LoadMoreBtn/LoadMoreBtn";
14+
import Spinner from "../elements/Spinner/Spinner";
15+
import "./Home.css";
16+
17+
class Home extends Component {
18+
state = {
19+
movies: [],
20+
heroImage: null,
21+
loading: false,
22+
currentPage: 0,
23+
totalPages: 0,
24+
searchTerm: ""
25+
};
26+
27+
componentDidMount() {
28+
if (localStorage.getItem("HomeState")) {
29+
let state = JSON.parse(localStorage.getItem("HomeState"));
30+
this.setState({ ...state });
31+
} else {
32+
this.setState({ loading: true });
33+
const endpoint = `${API_URL}movie/popular?api_key=${API_KEY}&language=en-US&page=1`;
34+
this.fetchItems(endpoint);
35+
}
36+
}
37+
38+
searchItems = searchTerm => {
39+
let endpoint = "";
40+
this.setState({
41+
movies: [],
42+
loading: true,
43+
searchTerm
44+
});
45+
46+
if (searchTerm === "") {
47+
endpoint = `${API_URL}movie/popular?api_key=${API_KEY}&language=en-US&page=1`;
48+
} else {
49+
endpoint = `${API_URL}search/movie?api_key=${API_KEY}&language=en-US&query=${searchTerm}`;
50+
}
51+
this.fetchItems(endpoint);
52+
};
53+
54+
loadMoreItems = () => {
55+
// ES6 Destructuring the state
56+
const { searchTerm, currentPage } = this.state;
57+
58+
let endpoint = "";
59+
this.setState({ loading: true });
60+
61+
if (searchTerm === "") {
62+
endpoint = `${API_URL}movie/popular?api_key=${API_KEY}&language=en-US&page=${currentPage +
63+
1}`;
64+
} else {
65+
endpoint = `${API_URL}search/movie?api_key=${API_KEY}&language=en-US&query=${searchTerm}&page=${currentPage +
66+
1}`;
67+
}
68+
this.fetchItems(endpoint);
69+
};
70+
71+
fetchItems = endpoint => {
72+
// ES6 Destructuring the state
73+
const { movies, heroImage, searchTerm } = this.state;
74+
75+
fetch(endpoint)
76+
.then(result => result.json())
77+
.then(result => {
78+
this.setState(
79+
{
80+
movies: [...movies, ...result.results],
81+
heroImage: heroImage || result.results[0],
82+
loading: false,
83+
currentPage: result.page,
84+
totalPages: result.total_pages
85+
},
86+
() => {
87+
if (this.state.searchTerm === "") {
88+
localStorage.setItem("HomeState", JSON.stringify(this.state));
89+
}
90+
}
91+
);
92+
})
93+
.catch(error => console.error("Error:", error));
94+
};
95+
96+
render() {
97+
// ES6 Destructuring the state
98+
const {
99+
movies,
100+
heroImage,
101+
loading,
102+
currentPage,
103+
totalPages,
104+
searchTerm
105+
} = this.state;
106+
107+
return (
108+
<div className="rmdb-home">
109+
{heroImage ? (
110+
<div>
111+
<HeroImage
112+
image={`${IMAGE_BASE_URL}${BACKDROP_SIZE}${
113+
heroImage.backdrop_path
114+
}`}
115+
title={heroImage.original_title}
116+
text={heroImage.overview}
117+
/>
118+
<SearchBar callback={this.searchItems} />
119+
</div>
120+
) : null}
121+
<div className="rmdb-home-grid">
122+
<FourColGrid
123+
header={searchTerm ? "Search Result" : "Popular Movies"}
124+
loading={loading}
125+
>
126+
{movies.map((element, i) => (
127+
<MovieThumb
128+
key={i}
129+
clickable={true}
130+
image={
131+
element.poster_path
132+
? `${IMAGE_BASE_URL}${POSTER_SIZE}${element.poster_path}`
133+
: "./images/no_image.jpg"
134+
}
135+
movieId={element.id}
136+
movieName={element.original_title}
137+
/>
138+
))}
139+
</FourColGrid>
140+
{loading ? <Spinner /> : null}
141+
{currentPage <= totalPages && !loading ? (
142+
<LoadMoreBtn text="Load More" onClick={this.loadMoreItems} />
143+
) : null}
144+
</div>
145+
</div>
146+
);
147+
}
148+
}
149+
150+
export default Home;

src/components/Movie/Movie.js

Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,103 @@
1+
import React, { Component } from "react";
2+
import { API_URL, API_KEY } from "../../config";
3+
import Navigation from "../elements/Navigation/Navigation";
4+
import MovieInfo from "../elements/MovieInfo/MovieInfo";
5+
import MovieInfoBar from "../elements/MovieInfoBar/MovieInfoBar";
6+
import FourColGrid from "../elements/FourColGrid/FourColGrid";
7+
import Actor from "../elements/Actor/Actor";
8+
import Spinner from "../elements/Spinner/Spinner";
9+
import "./Movie.css";
10+
11+
export default class Movie extends Component {
12+
state = {
13+
movie: null,
14+
actors: null,
15+
directors: [],
16+
loading: false
17+
};
18+
19+
componentDidMount() {
20+
if (localStorage.getItem(`${this.props.match.paramas.movieId}`)) {
21+
const state = JSON.parse(
22+
localStorage.getItem(`${this.props.match.paramas.movieId}`)
23+
);
24+
this.setState({ ...state });
25+
} else {
26+
this.setState({ loading: true });
27+
// Movie Data
28+
const endpoint = `${API_URL}movie/${
29+
this.props.match.params.movieId
30+
}?api_key=${API_KEY}&language=en-US`;
31+
this.fetchItems(endpoint);
32+
}
33+
}
34+
35+
fetchItems = endpoint => {
36+
fetch(endpoint)
37+
.then(res => res.json())
38+
.then(res => {
39+
console.log(res);
40+
if (res.status_code) {
41+
this.setState({ loading: false });
42+
} else {
43+
this.setState({ movie: res }, () => {
44+
// Actors Data In SetState Callback Function
45+
const endpoint = `${API_URL}movie/${
46+
this.props.match.params.movieId
47+
}/credits?api_key=${API_KEY}`;
48+
fetch(endpoint)
49+
.then(res => res.json())
50+
.then(res => {
51+
const directors = res.crew.filter(
52+
member => member.job === "Director"
53+
);
54+
this.setState(
55+
{ actors: res.cast, directors, loading: false },
56+
() => {
57+
localStorage.setItem(
58+
`${this.props.match.params.movieId}`,
59+
JSON.stringify(this.state)
60+
);
61+
}
62+
);
63+
});
64+
});
65+
}
66+
})
67+
.catch(err => console.error("Error:", err));
68+
};
69+
70+
render() {
71+
return (
72+
<div className="rmdb-movie">
73+
{this.state.movie ? (
74+
<div>
75+
<Navigation movie={this.props.location.movieName} />
76+
<MovieInfo
77+
movie={this.state.movie}
78+
directors={this.state.directors}
79+
/>
80+
<MovieInfoBar
81+
time={this.state.movie.runtime}
82+
budget={this.state.movie.budget}
83+
revenue={this.state.movie.revenue}
84+
/>
85+
</div>
86+
) : null}
87+
{this.state.actors ? (
88+
<div className="rmdb-movie-grid">
89+
<FourColGrid header={"Actors"}>
90+
{this.state.actors.map((element, i) => {
91+
return <Actor key={i} actor={element} />;
92+
})}
93+
</FourColGrid>
94+
</div>
95+
) : null}
96+
{!this.state.actors && !this.state.loading ? (
97+
<h1>No Movie Found</h1>
98+
) : null}
99+
{this.state.loading ? <Spinner /> : null}}
100+
</div>
101+
);
102+
}
103+
}
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
import React from "react";
2+
import { IMAGE_BASE_URL } from "../../../config";
3+
import "./Actor.css";
4+
5+
export default function Actor(props) {
6+
const POSTER_SIZE = "w154";
7+
return (
8+
<div className="rmdb-actor">
9+
<img
10+
src={
11+
props.actor.profile_path
12+
? `${IMAGE_BASE_URL}${POSTER_SIZE}${props.actor.profile_path}`
13+
: "./images/no_image.jpg}"
14+
}
15+
alt="Actor Thumbnail"
16+
/>
17+
<span className="rmdb-actor-name">{props.actor.name}</span>
18+
<span className="rmdb-actor-character">{props.actor.character}</span>
19+
</div>
20+
);
21+
}
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
import React from "react";
2+
import PropTypes from "prop-types";
3+
import "./FourColGrid.css";
4+
5+
function FourColGrid(props) {
6+
const renderElements = () => {
7+
const gridElements = props.children.map((element, i) => {
8+
return (
9+
<div key={i} className="rmdb-grid-element">
10+
{element}
11+
</div>
12+
);
13+
});
14+
return gridElements;
15+
};
16+
return (
17+
<div className="rmdb-grid">
18+
{props.header && !props.loading ? <h1>{props.header}</h1> : null}
19+
<div className="rmdb-grid-content">{renderElements()}</div>
20+
</div>
21+
);
22+
}
23+
24+
FourColGrid.propTypes = {
25+
header: PropTypes.string,
26+
loading: PropTypes.bool
27+
};
28+
29+
export default FourColGrid;
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
import React from "react";
2+
import { Link } from "react-router-dom";
3+
import "./Header.css";
4+
5+
export default function Header() {
6+
return (
7+
<div className="rmdb-header">
8+
<div className="rmdb-header-content">
9+
<Link to="/">
10+
<img
11+
src="./images/reactMovie_logo.png"
12+
alt="RMDB-Logo"
13+
className="rmdb-logo"
14+
/>
15+
</Link>
16+
<img
17+
src="./images/tmdb_logo.png"
18+
alt="TMDB-Logo"
19+
className="rmdb-tmdb-logo"
20+
/>
21+
</div>
22+
</div>
23+
);
24+
}

0 commit comments

Comments
 (0)