diff --git a/package-lock.json b/package-lock.json index 2207e63b9..4081138c2 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1902,6 +1902,38 @@ "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.8.0.tgz", "integrity": "sha512-ReZxvNHIOv88FlT7rxcXIIC0fPt4KZqZbOlivyWtXLt8ESx84zd3kMC6iK5jVeS2qt+g7ftS7ye4fi06X5rtRQ==" }, + "axios": { + "version": "0.19.0", + "resolved": "https://registry.npmjs.org/axios/-/axios-0.19.0.tgz", + "integrity": "sha512-1uvKqKQta3KBxIz14F2v06AEHZ/dIoeKfbTRkK1E5oqjDnuEerLmYTgJB5AiQZHJcljpg1TuRzdjDR06qNk0DQ==", + "requires": { + "follow-redirects": "1.5.10", + "is-buffer": "^2.0.2" + }, + "dependencies": { + "debug": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", + "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", + "requires": { + "ms": "2.0.0" + } + }, + "follow-redirects": { + "version": "1.5.10", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.5.10.tgz", + "integrity": "sha512-0V5l4Cizzvqt5D44aTXbFZz+FtyXV1vrDN6qrelxtfYQKW0KO0W2T/hkE8xvGa/540LkZlkaUjO4ailYTFtHVQ==", + "requires": { + "debug": "=3.1.0" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" + } + } + }, "axobject-query": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/axobject-query/-/axobject-query-2.0.2.tgz", @@ -2396,6 +2428,11 @@ "resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz", "integrity": "sha1-aN/1++YMUes3cl6p4+0xDcwed24=" }, + "bootstrap": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/bootstrap/-/bootstrap-4.3.1.tgz", + "integrity": "sha512-rXqOmH1VilAt2DyPzluTi2blhk17bO7ef+zLLPlWvG494pDxcM234pJ8wTc/6R40UWizAIIMgxjvxZg5kmsbag==" + }, "brace-expansion": { "version": "1.1.11", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", @@ -5603,6 +5640,11 @@ "resolved": "https://registry.npmjs.org/growly/-/growly-1.3.0.tgz", "integrity": "sha1-8QdIy+dq+WS3yWyTxrzCivEgwIE=" }, + "gud": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/gud/-/gud-1.0.0.tgz", + "integrity": "sha512-zGEOVKFM5sVPPrYs7J5/hYEw2Pof8KCyOwyhG8sAF26mCAeUFAcYPu1mwB7hhpIP29zOIBaDqwuHdLp0jvZXjw==" + }, "gzip-size": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/gzip-size/-/gzip-size-5.0.0.tgz", @@ -5777,6 +5819,19 @@ "resolved": "https://registry.npmjs.org/hex-color-regex/-/hex-color-regex-1.1.0.tgz", "integrity": "sha512-l9sfDFsuqtOqKDsQdqrMRk0U85RZc0RtOR9yPI7mRVOa4FsR/BVnZ0shmQRM96Ji99kYZP/7hn1cedc1+ApsTQ==" }, + "history": { + "version": "4.9.0", + "resolved": "https://registry.npmjs.org/history/-/history-4.9.0.tgz", + "integrity": "sha512-H2DkjCjXf0Op9OAr6nJ56fcRkTSNrUiv41vNJ6IswJjif6wlpZK0BTfFbi7qK9dXLSYZxkq5lBsj3vUjlYBYZA==", + "requires": { + "@babel/runtime": "^7.1.2", + "loose-envify": "^1.2.0", + "resolve-pathname": "^2.2.0", + "tiny-invariant": "^1.0.2", + "tiny-warning": "^1.0.0", + "value-equal": "^0.4.0" + } + }, "hmac-drbg": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/hmac-drbg/-/hmac-drbg-1.0.1.tgz", @@ -5787,6 +5842,14 @@ "minimalistic-crypto-utils": "^1.0.1" } }, + "hoist-non-react-statics": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/hoist-non-react-statics/-/hoist-non-react-statics-3.3.0.tgz", + "integrity": "sha512-0XsbTXxgiaCDYDIWFcwkmerZPSwywfUqYmwT4jzewKTQSWoE6FCMoUVOeBJWK3E/CrWbxRG3m5GzY4lnIwGRBA==", + "requires": { + "react-is": "^16.7.0" + } + }, "hosted-git-info": { "version": "2.7.1", "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.7.1.tgz", @@ -8134,6 +8197,16 @@ "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-1.2.0.tgz", "integrity": "sha512-jf84uxzwiuiIVKiOLpfYk7N46TSy8ubTonmneY9vrpHNAnp0QBt2BxWV9dO3/j+BoVAb+a5G6YDPW3M5HOdMWQ==" }, + "mini-create-react-context": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/mini-create-react-context/-/mini-create-react-context-0.3.2.tgz", + "integrity": "sha512-2v+OeetEyliMt5VHMXsBhABoJ0/M4RCe7fatd/fBy6SMiKazUSEt3gxxypfnk2SHMkdBYvorHRoQxuGoiwbzAw==", + "requires": { + "@babel/runtime": "^7.4.0", + "gud": "^1.0.0", + "tiny-warning": "^1.0.2" + } + }, "mini-css-extract-plugin": { "version": "0.5.0", "resolved": "https://registry.npmjs.org/mini-css-extract-plugin/-/mini-css-extract-plugin-0.5.0.tgz", @@ -10194,6 +10267,52 @@ "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.8.6.tgz", "integrity": "sha512-aUk3bHfZ2bRSVFFbbeVS4i+lNPZr3/WM5jT2J5omUVV1zzcs1nAaf3l51ctA5FFvCRbhrH0bdAsRRQddFJZPtA==" }, + "react-router": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/react-router/-/react-router-5.0.1.tgz", + "integrity": "sha512-EM7suCPNKb1NxcTZ2LEOWFtQBQRQXecLxVpdsP4DW4PbbqYWeRiLyV/Tt1SdCrvT2jcyXAXmVTmzvSzrPR63Bg==", + "requires": { + "@babel/runtime": "^7.1.2", + "history": "^4.9.0", + "hoist-non-react-statics": "^3.1.0", + "loose-envify": "^1.3.1", + "mini-create-react-context": "^0.3.0", + "path-to-regexp": "^1.7.0", + "prop-types": "^15.6.2", + "react-is": "^16.6.0", + "tiny-invariant": "^1.0.2", + "tiny-warning": "^1.0.0" + }, + "dependencies": { + "isarray": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", + "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=" + }, + "path-to-regexp": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-1.7.0.tgz", + "integrity": "sha1-Wf3g9DW62suhA6hOnTvGTpa5k30=", + "requires": { + "isarray": "0.0.1" + } + } + } + }, + "react-router-dom": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-5.0.1.tgz", + "integrity": "sha512-zaVHSy7NN0G91/Bz9GD4owex5+eop+KvgbxXsP/O+iW1/Ln+BrJ8QiIR5a6xNPtrdTvLkxqlDClx13QO1uB8CA==", + "requires": { + "@babel/runtime": "^7.1.2", + "history": "^4.9.0", + "loose-envify": "^1.3.1", + "prop-types": "^15.6.2", + "react-router": "5.0.1", + "tiny-invariant": "^1.0.2", + "tiny-warning": "^1.0.0" + } + }, "react-scripts": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/react-scripts/-/react-scripts-3.0.1.tgz", @@ -10575,6 +10694,11 @@ "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-3.0.0.tgz", "integrity": "sha1-six699nWiBvItuZTM17rywoYh0g=" }, + "resolve-pathname": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/resolve-pathname/-/resolve-pathname-2.2.0.tgz", + "integrity": "sha512-bAFz9ld18RzJfddgrO2e/0S2O81710++chRMUxHjXOYKF6jTAMrUNZrEZ1PvV0zlhfjidm08iRPdTLPno1FuRg==" + }, "resolve-url": { "version": "0.2.1", "resolved": "https://registry.npmjs.org/resolve-url/-/resolve-url-0.2.1.tgz", @@ -11685,6 +11809,16 @@ "resolved": "https://registry.npmjs.org/timsort/-/timsort-0.3.0.tgz", "integrity": "sha1-QFQRqOfmM5/mTbmiNN4R3DHgK9Q=" }, + "tiny-invariant": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/tiny-invariant/-/tiny-invariant-1.0.4.tgz", + "integrity": "sha512-lMhRd/djQJ3MoaHEBrw8e2/uM4rs9YMNk0iOr8rHQ0QdbM7D4l0gFl3szKdeixrlyfm9Zqi4dxHCM2qVG8ND5g==" + }, + "tiny-warning": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/tiny-warning/-/tiny-warning-1.0.2.tgz", + "integrity": "sha512-rru86D9CpQRLvsFG5XFdy0KdLAvjdQDyZCsRcuu60WtzFylDM3eAWSxEVz5kzL2Gp544XiUvPbVKtOA/txLi9Q==" + }, "tmp": { "version": "0.0.33", "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz", @@ -12122,6 +12256,11 @@ "spdx-expression-parse": "^3.0.0" } }, + "value-equal": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/value-equal/-/value-equal-0.4.0.tgz", + "integrity": "sha512-x+cYdNnaA3CxvMaTX0INdTCN8m8aF2uY9BvEqmxuYp8bL09cs/kWVQPVGcA35fMktdOsP69IgU7wFj/61dJHEw==" + }, "vary": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", diff --git a/package.json b/package.json index e7e4a7c62..42e177ba0 100644 --- a/package.json +++ b/package.json @@ -3,8 +3,11 @@ "version": "0.1.0", "private": true, "dependencies": { + "axios": "^0.19.0", + "bootstrap": "^4.3.1", "react": "^16.8.6", "react-dom": "^16.8.6", + "react-router-dom": "^5.0.1", "react-scripts": "3.0.1" }, "scripts": { @@ -12,5 +15,17 @@ "build": "react-scripts build", "test": "react-scripts test --env=jsdom", "eject": "react-scripts eject" + }, + "browserslist": { + "production": [ + ">0.2%", + "not dead", + "not op_mini all" + ], + "development": [ + "last 1 chrome version", + "last 1 firefox version", + "last 1 safari version" + ] } } diff --git a/src/App.css b/src/App.css index c5c6e8a68..323ac380b 100644 --- a/src/App.css +++ b/src/App.css @@ -1,28 +1,7 @@ -.App { - text-align: center; +.table-container { + padding: 25px; } -.App-logo { - animation: App-logo-spin infinite 20s linear; - height: 80px; -} - -.App-header { - background-color: #222; - height: 150px; - padding: 20px; - color: white; -} - -.App-title { - font-size: 1.5em; -} - -.App-intro { - font-size: large; -} - -@keyframes App-logo-spin { - from { transform: rotate(0deg); } - to { transform: rotate(360deg); } -} +.checkoutSection { + margin: 20px; +} \ No newline at end of file diff --git a/src/App.js b/src/App.js index 203067e4d..2c9364f66 100644 --- a/src/App.js +++ b/src/App.js @@ -1,19 +1,129 @@ import React, { Component } from 'react'; -import logo from './logo.svg'; +import { Route, Link, Switch } from "react-router-dom"; +import axios from 'axios' +import 'bootstrap/dist/css/bootstrap.css'; import './App.css'; +import HomePage from './components/HomePage'; +import RentalLibraryPage from './components/RentalLibraryPage'; +import CustomerListPage from './components/CustomerListPage'; +import MovieSearchPage from './components/MovieSearchPage'; class App extends Component { + constructor(props){ + super(props); + this.state = { + selectedMovie: null, + selectedCustomer: null, + error: null, + success:null, + show: true + }; + } + handleHide = () => { + this.setState({ show: false }); + } + onSelectCustomer = (customerID) => { + this.setState({selectedCustomer: customerID}); + } + onSelectMovie = (movieTitle) => { + this.setState({selectedMovie: movieTitle}); + } + onClose() { + this.setState({hidden:true}) + } + onCheckOutClick = () => { + let d=new Date(new Date().getTime() + (7 * 24 * 60 * 60 * 1000)); + let dueDate = d.toJSON().slice(0,10) + + const rentalInfo = { + customer_id: this.state.selectedCustomer, + due_date: dueDate + } + + const url = "http://localhost:3001/rentals/"+this.state.selectedMovie+"/check-out" + + axios.post(url, rentalInfo) + .then((response) => { + this.setState({ + selectedMovie: null, + selectedCustomer: null, + success: response.status, + show: true + }) + }) + .catch((error) => { + this.setState({ + error: error.message, + show: true + }); + }); + } + + render() { + const movieSection = (this.state.selectedMovie) ? + (
+ Selected Movie: {this.state.selectedMovie} +
) : null; + + const customerSection = (this.state.selectedCustomer) ? + (
+ Selected Customer ID: {this.state.selectedCustomer} +
) : null; + + const checkOut = (this.state.selectedCustomer && this.state.selectedMovie) ? + (
+ +
) : null; + + const errorSection = (this.state.error && this.state.show) ? + (
+ Error: {this.state.error} + +
) : null; + + const successSection = (this.state.success && this.state.show) ? + (
+ Movie was successfully checked out to the customer! + +
) : null; + return ( -
-
- logo -

Welcome to React

-
-

- To get started, edit src/App.js and save to reload. -

-
+
+
+ +
+ + {successSection } + {errorSection} + {movieSection} + {customerSection} + {checkOut} + + + + } /> + + } /> + +
); } } diff --git a/src/components/Customer.js b/src/components/Customer.js new file mode 100644 index 000000000..6a73853ec --- /dev/null +++ b/src/components/Customer.js @@ -0,0 +1,51 @@ +import React from 'react'; +import 'bootstrap/dist/css/bootstrap.css'; +import PropTypes from 'prop-types'; + +const Customer = (props) => { + const {id, name, registered_at, address, + city, state, postal_code, + phone, account_credit, movies_checked_out_count, + onSelectHandler} = props; + + const onCustomerClick = () => { + onSelectHandler(id); + } + + return ( + + + {id} + {name} + {registered_at} + {address} + {city} + {state} + {postal_code} + {phone} + {account_credit} + {movies_checked_out_count} + + + + + + ); +}; + +Customer.propTypes = { + id: PropTypes.number.isRequired, + name: PropTypes.string, + registered_at: PropTypes.string, + address: PropTypes.string, + city: PropTypes.string, + state: PropTypes.string, + postal_code: PropTypes.string, + phone: PropTypes.string, + account_credit: PropTypes.number, + movies_checked_out_count: PropTypes.number +}; + +export default Customer; \ No newline at end of file diff --git a/src/components/CustomerListPage.js b/src/components/CustomerListPage.js new file mode 100644 index 000000000..8c12f4ca9 --- /dev/null +++ b/src/components/CustomerListPage.js @@ -0,0 +1,80 @@ +import React, { Component } from 'react'; +import axios from 'axios' +import Customer from './Customer' +import 'bootstrap/dist/css/bootstrap.css'; +import PropTypes from 'prop-types'; + +class CustomerListPage extends Component { + constructor(props) { + super(props); + this.state = { + customers:[], + error: null + }; + } + + componentDidMount() { + const URL = "http://localhost:3001/customers" + axios.get(URL) + .then((response) => { + this.setState({ customers: response.data }); + }) + .catch((error) => { + this.setState({ error: error.message }); + }); + } + + render() { + const { customers } = this.state; + const customerList = customers.map((customers) => { + const {id, name, registered_at, address, + city, state, postal_code, phone, + account_credit, movies_checked_out_count} = customers; + return ( ) + }); + + const errorSection = (this.state.error) ? + (
+ Error: {this.state.error} +
) : null; + + return ( +
+ {errorSection} +
+ + + + + + + + + + + + + + + + + + {customerList} + +
#NameRegisted AtAddressCityStatePostal CodePhoneAccount CreditMovies Checked Out Count
+
+
+ ); + } +}; + +CustomerListPage.propTypes = { + onSelectCustomerCallback: PropTypes.func, +}; + +export default CustomerListPage; \ No newline at end of file diff --git a/src/components/HomePage.css b/src/components/HomePage.css new file mode 100644 index 000000000..58b265163 --- /dev/null +++ b/src/components/HomePage.css @@ -0,0 +1,3 @@ +.homepage { + padding: 20px; +} \ No newline at end of file diff --git a/src/components/HomePage.js b/src/components/HomePage.js new file mode 100644 index 000000000..8b434ff20 --- /dev/null +++ b/src/components/HomePage.js @@ -0,0 +1,17 @@ +import React, { Component } from 'react'; +import { Link } from "react-router-dom"; +import './HomePage.css'; + +class HomePage extends Component { + render() { + return ( +
+
Movie Rental Library
+
Search for a Movie
+
Customers
+
+ ); + } +} + +export default HomePage; \ No newline at end of file diff --git a/src/components/Movie.js b/src/components/Movie.js new file mode 100644 index 000000000..ddd8a9ebe --- /dev/null +++ b/src/components/Movie.js @@ -0,0 +1,38 @@ +import React from 'react'; +import 'bootstrap/dist/css/bootstrap.css'; +import PropTypes from 'prop-types'; + +const Movie = (props) => { + const {id, title, overview, release_date, image_url, + onSelectHandler} = props; + + const onMovieClick = () => { + onSelectHandler(props.title); + } + return ( + + {`movie + {id} + {title} + {overview} + {release_date} + + + + + ); +} + +Movie.propTypes = { + title: PropTypes.string.isRequired, + overview: PropTypes.string, + release_date: PropTypes.string, + image_url: PropTypes.string, + external_id: PropTypes.number, + onSelectHandler: PropTypes.func, +}; + + +export default Movie; \ No newline at end of file diff --git a/src/components/MovieSearchBar.css b/src/components/MovieSearchBar.css new file mode 100644 index 000000000..c0a4b160c --- /dev/null +++ b/src/components/MovieSearchBar.css @@ -0,0 +1,7 @@ +h5 { + padding: 30px 25px 10px 25px; +} + +.input-group { + padding: 15px 25px 10px 25px; +} \ No newline at end of file diff --git a/src/components/MovieSearchBar.js b/src/components/MovieSearchBar.js new file mode 100644 index 000000000..c90b6bb34 --- /dev/null +++ b/src/components/MovieSearchBar.js @@ -0,0 +1,51 @@ +import React, { Component } from 'react'; +import 'bootstrap/dist/css/bootstrap.css'; +import PropTypes from 'prop-types'; + +class MovieSearchBar extends Component { + + constructor (props) { + super(props); + this.state = { + query: "", + clickHandler: this.props.searchCallback, + } + } + + onInputChange = (event) => { + const updatedState = this.state; + + const field = event.target.name; + const value = event.target.value; + + updatedState[field] = value; + this.setState(updatedState); + }; + + submitSearchResults = () => { + this.state.clickHandler(this.state.query); + }; + + + + render() { + + return ( +
+
Search for a movie with a title
+
+ +
+ +
+
+
+ ); + } +}; + +MovieSearchBar.propTypes = { + searchCallback: PropTypes.func, +}; + +export default MovieSearchBar; \ No newline at end of file diff --git a/src/components/MovieSearchPage.js b/src/components/MovieSearchPage.js new file mode 100644 index 000000000..8e3c207c3 --- /dev/null +++ b/src/components/MovieSearchPage.js @@ -0,0 +1,116 @@ +import React, { Component } from 'react'; +import MovieSearchBar from './MovieSearchBar'; +import SearchResult from './SearchResult'; +import Axios from 'axios'; +import 'bootstrap/dist/css/bootstrap.css'; +import './MovieSearchBar.css'; +import { Link } from "react-router-dom"; + + +const baseURL = `http://localhost:3001`; +class MovieSearchPage extends Component { + constructor () { + super(); + this.state = { + searchResults: [], + rentalAddedMessage: false, + rentalToAdd: {}, + addRentalsLink: false, + } + }; + + submitSearchQuery = (searchTerm) => { + + const formattedTerm = searchTerm.replace(' ', '%20') ; + Axios.get(`${baseURL}/movies?query=${formattedTerm}`) + .then((response) => { + const results = response.data; + this.setState({ + searchResults: results, + success: `Found ${response.data.length} movies matching "${searchTerm}"`, + addRentalsLink: false, }) + }) + .catch((error) => { + this.setState({ error: error.message }); + }); + }; + + addRental = (movieData) => { + const rental = { + title: movieData.title, + overview: movieData.overview, + release_date: movieData.release_date, + image_url: movieData.image_url, + external_id: movieData.external_id + }; + + Axios.post(`${baseURL}/movies`, rental) + .then((response) => { + this.setState({ + success: `Successfully added ${rental.title} to the library.`, + addRentalsLink: true, + }) + }) + } + + render() { + const {searchResults} = this.state; + const resultList = searchResults.map((result) => { + const {external_id, title, overview, release_date, image_url} = result; + return ( ) + }); + + const errorSection = (this.state.error) ? + (
+ Error: {this.state.error} +
) : null; + + const successSection = (this.state.success) ? + (
+

+ {this.state.success} +

+
) + : null; + + const libraryLink = (this.state.addRentalsLink) ? + (
+ Go to rental library +
) : null; + + return ( +
+ {errorSection} + {successSection} + {libraryLink} +
+ +
+
+ + + + + + + + + + + {resultList} + +
TitleOverviewRelease Date
+
+
+ ); + } +} + +export default MovieSearchPage; \ No newline at end of file diff --git a/src/components/RentalLibraryPage.js b/src/components/RentalLibraryPage.js new file mode 100644 index 000000000..76d193bdf --- /dev/null +++ b/src/components/RentalLibraryPage.js @@ -0,0 +1,68 @@ +import React, { Component } from 'react'; +import 'bootstrap/dist/css/bootstrap.css'; +import axios from 'axios'; +import Movie from "./Movie"; +import PropTypes from 'prop-types'; + +class RentalLibraryPage extends Component { + constructor(props){ + super(props); + this.state = { + movies: [], + error: null + }; + } + componentDidMount() { + const URL = "http://localhost:3001/movies" + axios.get(URL) + .then((response) => { + this.setState({ movies: response.data }); + }) + .catch((error) => { + this.setState({ error: error.message }); + }); + } + + render() { + const {movies} = this.state; + const movieList = movies.map((movie) => { + const {id, title, overview, release_date, image_url} = movie; + return ( ) + }); + + const errorSection = (this.state.error) ? + (
+ Error: {this.state.error} +
) : null; + + return ( +
+ {errorSection} +
+ + + + + + + + + + + + {movieList} + +
Poster#TitleOverviewRelease Date
+
+
+ ); + } +} + +RentalLibraryPage.propTypes = { + onSelectMovieCallback: PropTypes.func, +}; + +export default RentalLibraryPage; \ No newline at end of file diff --git a/src/components/SearchResult.js b/src/components/SearchResult.js new file mode 100644 index 000000000..3be9745dd --- /dev/null +++ b/src/components/SearchResult.js @@ -0,0 +1,37 @@ +import React from 'react'; +import 'bootstrap/dist/css/bootstrap.css'; +import PropTypes from 'prop-types'; + +const SearchResult = (props) => { + const {id, title, overview, release_date, external_id, + image_url, onSelectHandler} = props; + + const onMovieClick = () => { + onSelectHandler(props); + } + return ( + + {`movie + {title} + {overview} + {release_date} + + + + + ); +}; + +SearchResult.propTypes = { + title: PropTypes.string.isRequired, + overview: PropTypes.string, + release_date: PropTypes.string, + image_url: PropTypes.string, + external_id: PropTypes.number, + onSelectHandler: PropTypes.func, +}; + + +export default SearchResult; \ No newline at end of file diff --git a/src/index.js b/src/index.js index fae3e3500..d12f2e35a 100644 --- a/src/index.js +++ b/src/index.js @@ -1,8 +1,14 @@ import React from 'react'; import ReactDOM from 'react-dom'; +import { BrowserRouter } from 'react-router-dom' + import './index.css'; import App from './App'; import registerServiceWorker from './registerServiceWorker'; -ReactDOM.render(, document.getElementById('root')); +ReactDOM.render( + + + , + document.getElementById('root')); registerServiceWorker();