diff --git a/package-lock.json b/package-lock.json index 79f52b34f..cdd05bc6b 100644 --- a/package-lock.json +++ b/package-lock.json @@ -434,6 +434,15 @@ "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.7.0.tgz", "integrity": "sha512-32NDda82rhwD9/JBCCkB+MRYDp0oSvlo2IL6rQWA10PQi7tDUM3eqMSltXmY+Oyl/7N3P3qNtAlv7X0d9bI28w==" }, + "axios": { + "version": "0.18.0", + "resolved": "https://registry.npmjs.org/axios/-/axios-0.18.0.tgz", + "integrity": "sha1-MtU+SFHv3AoRmTts0AB4nXDAUQI=", + "requires": { + "follow-redirects": "1.5.0", + "is-buffer": "1.1.6" + } + }, "axobject-query": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/axobject-query/-/axobject-query-0.1.0.tgz", @@ -4657,6 +4666,28 @@ "resolved": "https://registry.npmjs.org/he/-/he-1.1.1.tgz", "integrity": "sha1-k0EP0hsAlzUVH4howvJx80J+I/0=" }, + "history": { + "version": "4.7.2", + "resolved": "https://registry.npmjs.org/history/-/history-4.7.2.tgz", + "integrity": "sha512-1zkBRWW6XweO0NBcjiphtVJVsIQ+SXF29z9DVkceeaSLVMFXHool+fdCZD4spDCfZJCILPILc3bm7Bc+HRi0nA==", + "requires": { + "invariant": "2.2.4", + "loose-envify": "1.3.1", + "resolve-pathname": "2.2.0", + "value-equal": "0.4.0", + "warning": "3.0.0" + }, + "dependencies": { + "warning": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/warning/-/warning-3.0.0.tgz", + "integrity": "sha1-MuU3fLVy3kqwR1O9+IIcAe1gW3w=", + "requires": { + "loose-envify": "1.3.1" + } + } + } + }, "hmac-drbg": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/hmac-drbg/-/hmac-drbg-1.0.1.tgz", @@ -4667,6 +4698,11 @@ "minimalistic-crypto-utils": "1.0.1" } }, + "hoist-non-react-statics": { + "version": "2.5.5", + "resolved": "https://registry.npmjs.org/hoist-non-react-statics/-/hoist-non-react-statics-2.5.5.tgz", + "integrity": "sha512-rqcy4pJo55FTTLWt+bU8ukscqHeE/e9KWvsOW2b/a3afxQZhwkQdT1rPPCJ0rYXdj4vNcasY8zHTH+jF/qStxw==" + }, "home-or-tmp": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/home-or-tmp/-/home-or-tmp-2.0.0.tgz", @@ -8809,6 +8845,33 @@ "resolved": "https://registry.npmjs.org/react-error-overlay/-/react-error-overlay-4.0.0.tgz", "integrity": "sha512-FlsPxavEyMuR6TjVbSSywovXSEyOg6ZDj5+Z8nbsRl9EkOzAhEIcS+GLoQDC5fz/t9suhUXWmUrOBrgeUvrMxw==" }, + "react-router": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/react-router/-/react-router-4.3.1.tgz", + "integrity": "sha512-yrvL8AogDh2X42Dt9iknk4wF4V8bWREPirFfS9gLU1huk6qK41sg7Z/1S81jjTrGHxa3B8R3J6xIkDAA6CVarg==", + "requires": { + "history": "4.7.2", + "hoist-non-react-statics": "2.5.5", + "invariant": "2.2.4", + "loose-envify": "1.3.1", + "path-to-regexp": "1.7.0", + "prop-types": "15.6.1", + "warning": "4.0.1" + } + }, + "react-router-dom": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-4.3.1.tgz", + "integrity": "sha512-c/MlywfxDdCp7EnB7YfPMOfMD3tOtIjrQlj/CKfNMBxdmpJP8xcz5P/UAFn3JbnQCNUxsHyVVqllF9LhgVyFCA==", + "requires": { + "history": "4.7.2", + "invariant": "2.2.4", + "loose-envify": "1.3.1", + "prop-types": "15.6.1", + "react-router": "4.3.1", + "warning": "4.0.1" + } + }, "react-scripts": { "version": "1.1.4", "resolved": "https://registry.npmjs.org/react-scripts/-/react-scripts-1.1.4.tgz", @@ -9231,6 +9294,11 @@ "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-1.0.1.tgz", "integrity": "sha1-Jsv+k10a7uq7Kbw/5a6wHpPUQiY=" }, + "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", @@ -10564,6 +10632,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", @@ -10600,6 +10673,14 @@ "makeerror": "1.0.11" } }, + "warning": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/warning/-/warning-4.0.1.tgz", + "integrity": "sha512-rAVtTNZw+cQPjvGp1ox0XC5Q2IBFyqoqh+QII4J/oguyu83Bax1apbo2eqB8bHRS+fqYUBagys6lqUoVwKSmXQ==", + "requires": { + "loose-envify": "1.3.1" + } + }, "watch": { "version": "0.10.0", "resolved": "https://registry.npmjs.org/watch/-/watch-0.10.0.tgz", diff --git a/package.json b/package.json index 951a38e2f..a7160dab9 100644 --- a/package.json +++ b/package.json @@ -3,8 +3,11 @@ "version": "0.1.0", "private": true, "dependencies": { + "axios": "^0.18.0", "react": "^16.4.1", "react-dom": "^16.4.1", + "react-router": "^4.3.1", + "react-router-dom": "^4.3.1", "react-scripts": "1.1.4" }, "scripts": { @@ -13,4 +16,4 @@ "test": "react-scripts test --env=jsdom", "eject": "react-scripts eject" } -} \ No newline at end of file +} diff --git a/src/App.css b/src/App.css index c5c6e8a68..a777d2e08 100644 --- a/src/App.css +++ b/src/App.css @@ -1,5 +1,7 @@ .App { text-align: center; + background-color: #00064d; + color: #bbbbbb; } .App-logo { @@ -15,7 +17,9 @@ } .App-title { - font-size: 1.5em; + font-size: 2em; + margin-top: 1em; + } .App-intro { @@ -26,3 +30,22 @@ from { transform: rotate(0deg); } to { transform: rotate(360deg); } } + +table { + border: 2px solid black; + padding: 10px; + margin: 20px; + background-color: lightyellow; + width: 95%; + text-align: left; +} + +.ul { + display: flex; + justify-content: space-around; + list-style-type: none; + border: 1px ; + margin-top: 5em; + + +} diff --git a/src/App.js b/src/App.js index 203067e4d..7986d570d 100644 --- a/src/App.js +++ b/src/App.js @@ -1,19 +1,100 @@ import React, { Component } from 'react'; -import logo from './logo.svg'; import './App.css'; +import FormPage from './components/FormPage'; +import Home from './components/Home'; +import Search from './components/Search'; +import Status from './components/Status'; +import { BrowserRouter as Router, Route, Link } from "react-router-dom"; + + class App extends Component { + + constructor() { + super(); + + this.state = { + + movieTitle: '', + customerId: '', + customerName: '', + + status: { + message: 'loaded the page', + type: 'success' + } + } + } + + updateStatus = (message, type) => { + this.setState({ + status: { + message: message, + type: type + } + }) + } + + custHandler = (customerInfo) => { + console.log('in custHandler'); + console.log(customerInfo); + this.setState({ + customerId: customerInfo.id, + customerName: customerInfo.name + }); + } + + movHandler = (movieTitle) => { + console.log('in movHandler'); + console.log(movieTitle); + this.setState({ + movieTitle: movieTitle + }); + } + render() { return ( -
-
- logo -

Welcome to React

+
+ +
+ +
+ +
+

blockbuster

+ + +
+
    +
  • + Home +
  • +
  • + Search +
  • +
  • + Library +
  • +
  • + Customers +
  • +
+ +
+ + + + + + } /> + + } /> +
+
+
-

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

-
+ + ); } } diff --git a/src/components/AddToLibraryForm.js b/src/components/AddToLibraryForm.js new file mode 100644 index 000000000..1d5c00fdf --- /dev/null +++ b/src/components/AddToLibraryForm.js @@ -0,0 +1,50 @@ +import React, { Component } from 'react'; +import PropTypes from 'prop-types'; +import axios from 'axios'; + +class AddToLibraryForm extends Component { + + static propTypes = { + title: PropTypes.string.isRequired + } + + constructor(props) { + super(); + + this.state = { + title: props.title, + overview: props.overview, + release_date: props.release_date, + image_url: props.image_url, + }; + + } + + onFormSubmit = (event) => { + let URL = `http://localhost:3000/movies?title=${this.state.title}&overview=${this.state.overview}&release_date=${this.state.release_date}&image_url=${this.state.image_url}` + event.preventDefault(); + axios.post(URL) + .then((response)=> { + }) + .catch((error) => { + // this.props.updateStatusCallback(error.message, 'error'); + + }); + } + + render(){ + + return( +
+ + + + + + +
+ ) + } +} + +export default AddToLibraryForm; diff --git a/src/components/Customer.js b/src/components/Customer.js new file mode 100644 index 000000000..99f48fed2 --- /dev/null +++ b/src/components/Customer.js @@ -0,0 +1,48 @@ +import React, { Component } from 'react'; +import PropTypes from 'prop-types'; + +class Customer extends Component { + + static propTypes = { + customerId: PropTypes.string, + name: PropTypes.string, + phone: PropTypes.string, + checkedOut: PropTypes.number, + rentMovie: PropTypes.func + } + + onClickHandler = (event) => { + let customerInfo = event.target; + this.props.rentMovie(customerInfo); + } + + render() { + + let customerInfo = {}; + customerInfo["customerId"] = this.props.customerId; + customerInfo["name"] = this.props.name; + + return( +
+ +
+ {this.props.name} +
+ +
+ {this.props.phone} +
+ +
+ {this.props.checkedOut} +
+
+ +
+
+
+ ) + } +} + +export default Customer; diff --git a/src/components/Customers.js b/src/components/Customers.js new file mode 100644 index 000000000..33c6f60ea --- /dev/null +++ b/src/components/Customers.js @@ -0,0 +1,68 @@ +import React, { Component } from 'react'; +import axios from 'axios'; +import Customer from './Customer'; +import RentalForm from './RentalForm'; +import PropTypes from 'prop-types'; + +class Customers extends Component { + + static propTypes = { + rentalCallback: PropTypes.func, + } + + constructor() { + super(); + + this.state = { + customers: [], + }; + } + + componentDidMount() { + const CUSTOMERS_URL = 'http://localhost:3000/customers' + + axios.get(CUSTOMERS_URL) + .then((response) => { + + this.setState({customers: response.data}); + }) + .catch((error) => { + + // this.props.updateStatusCallback(error.message, 'error'); + }); + } + + rentalCallback = (customerInfo) => { + this.props.rentalCallback(customerInfo); + } + + render() { + + const customers = this.state.customers.map((customer, index) => { + + return( + +
+ +
+ < Customer key={index} + customerId={customer.id} + name={customer.name} + phone={customer.phone} + rentMovie={this.rentalCallback} + /> +
+
+ ) + }); + + return( + +
+ {customers} +
+ ) + } +} + +export default Customers; diff --git a/src/components/FormPage.js b/src/components/FormPage.js new file mode 100644 index 000000000..90758adfb --- /dev/null +++ b/src/components/FormPage.js @@ -0,0 +1,29 @@ +import React, { Component } from 'react'; +import PropTypes from 'prop-types'; +import RentalForm from './RentalForm'; + +class CustomersPage extends Component { + + static propTypes = { + movieTitle: PropTypes.string, + customerId: PropTypes.string, + customerName: PropTypes.string, + selectedMovHandler: PropTypes.func, + selectedCustHandler: PropTypes.func, + hideCustomers: PropTypes.bool, + hideMovies: PropTypes.bool + } + + render() { + return( +
+

CUSTOMERS PAGE

+ +
+ ) + } +} + + + +export default CustomersPage; diff --git a/src/components/Home.js b/src/components/Home.js new file mode 100644 index 000000000..1190e8b7e --- /dev/null +++ b/src/components/Home.js @@ -0,0 +1,15 @@ +import React, { Component } from 'react'; +import PropTypes from 'prop-types'; + +class Home extends Component { + + render() { + return( +

Click the links above to navigate the site.

+ ) + } +} + + + +export default Home; diff --git a/src/components/Movie.js b/src/components/Movie.js new file mode 100644 index 000000000..c92fe750c --- /dev/null +++ b/src/components/Movie.js @@ -0,0 +1,79 @@ +import React, { Component } from 'react'; +import PropTypes from 'prop-types'; +import AddToLibraryForm from './AddToLibraryForm'; + + +class Movie extends Component { + static propTypes = { + title: PropTypes.string.isRequired, + overview: PropTypes.string, + release_date: PropTypes.string, + image_url: PropTypes.string.isRequired, + inLibrary: PropTypes.bool, + rentMovie: PropTypes.func + } + + onClickHandler = (event) => { + console.log('made it to movie clickhandler'); + console.log(this.props.rentMovie); + let movieTitle = event.target.name; + console.log(movieTitle); + this.props.rentMovie(movieTitle); + } + + + render() { + + const displayButton = () => { + if (this.props.inLibrary) { + return () + }else{ + + return( + + ) + + }; + } + + const display = displayButton(); + + return( +
+ + + + + + + + + + + + + + + + + + + + + + + + {display} + +
{this.props.title}
+ {this.props.title} +
Release: {this.props.release_date}
Overview: {this.props.overview}
+ +
+ ) + + } + +} + +export default Movie; diff --git a/src/components/MovieLibrary.css b/src/components/MovieLibrary.css new file mode 100644 index 000000000..7231dcd9b --- /dev/null +++ b/src/components/MovieLibrary.css @@ -0,0 +1,3 @@ +.ul { + list-style: "none;" +} diff --git a/src/components/MovieLibrary.js b/src/components/MovieLibrary.js new file mode 100644 index 000000000..bd0c1ac5b --- /dev/null +++ b/src/components/MovieLibrary.js @@ -0,0 +1,73 @@ +import React, { Component } from 'react'; +import Movie from './Movie'; +import axios from 'axios'; +import PropTypes from 'prop-types' +import './MovieLibrary.js'; +import '../App.css'; + +class MovieLibrary extends Component { + + static propTypes = { + rentalCallback: PropTypes.isRequired + } + + constructor() { + super(); + + this.state = { + movies: [], + + }; + } + + componentDidMount() { + const MOVIE_URL = 'http://localhost:3000/movies' + + axios.get(MOVIE_URL) + .then((response) => { + + this.setState({movies: response.data}); + }) + .catch((error) => { + + // this.props.updateStatusCallback(error.message, 'error'); + }); + } + + movieCallback = (movieTitle) => { + console.log('made it to the Library'); + console.log(movieTitle); + console.log(this.props.rentalCallback(movieTitle)); + + this.props.rentalCallback(movieTitle); + } + + + render() { + + const movies = this.state.movies.map((movie, index) => { + + return( +
+ < Movie key={index} + title={movie.title} + overview={movie.overview} + release_date={movie.release_date} + image_url={movie.image_url} + inLibrary={false} + rentMovie={this.movieCallback}/> +
+ ) + }); + + return( +
+ {movies} +
+ ) + + } + +} + +export default MovieLibrary; diff --git a/src/components/MovieLibraryPage.js b/src/components/MovieLibraryPage.js new file mode 100644 index 000000000..e86132d44 --- /dev/null +++ b/src/components/MovieLibraryPage.js @@ -0,0 +1,26 @@ +import React, { Component } from 'react'; +import PropTypes from 'prop-types'; +import RentalForm from './RentalForm'; + +class MovieLibraryPage extends Component { + + static propTypes = { + movieTitle: PropTypes.string, + customerId: PropTypes.string, + customerName: PropTypes.string, + selectedMovHandler: PropTypes.func, + selectedCustHandler: PropTypes.func + } + + render() { + return( +
+

MOV LIBRARY PAGE

+ +
+ ) + } +} + + +export default MovieLibraryPage; diff --git a/src/components/RentalForm.js b/src/components/RentalForm.js new file mode 100644 index 000000000..319068ed5 --- /dev/null +++ b/src/components/RentalForm.js @@ -0,0 +1,90 @@ +import React, { Component } from 'react'; +import PropTypes from 'prop-types'; +import axios from 'axios'; +import Customers from './Customers'; +import MovieLibrary from './MovieLibrary'; + +class RentalForm extends Component { + + static propTypes = { + movieTitle: PropTypes.string, + customerId: PropTypes.string, + customerName: PropTypes.string, + hideCustomers: PropTypes.bool, + hideMovies: PropTypes.bool, + selectedMovHandler: PropTypes.func, + selectedCustHandler: PropTypes.func + } + + constructor(props) { + super(); + + this.state = { + movieTitle: props.movieTitle, + customerId: props.customerId, + customerName: props.customerName, + hideCustomers: props.hideCustomers, + hideMovies: props.hideMovies + }; + + } + + selectedCustomer = (customerInfo) => { + this.props.selectedCustHandler(customerInfo); + } + + selectedMovie = (movieTitle) => { + this.props.selectedMovHandler(movieTitle); + } + + onFormSubmit = (event) => { + event.preventDefault(); + console.log('in onFormSubmit'); + console.log(event.target); + + let movieTitle = this.state.movieTitle; + let customerId = this.state.customerId; + + let date = new Date(); + date.setDate(date.getDate() + 7); + + const RENTAL_URL = `http://localhost:3000/rentals/${movieTitle}/check-out` + + axios.post(RENTAL_URL, { + title: movieTitle, + customer_id: customerId, + due_date: date + }) + .then((response) => { + + console.log(response); + }) + .catch((error) => { + + // this.props.updateStatusCallback(error.message, 'error'); + }); + } + + render(){ + + return( +
+
+ + + + + + + + {!this.state.hideCustomers && } + + {!this.state.hideMovies && } + + +
+ ) + } +} + +export default RentalForm; diff --git a/src/components/Search.js b/src/components/Search.js new file mode 100644 index 000000000..925e2168d --- /dev/null +++ b/src/components/Search.js @@ -0,0 +1,65 @@ +import React, { Component } from 'react'; +import axios from 'axios'; +import SearchForm from './SearchForm'; +import RentalForm from './RentalForm'; +import Movie from './Movie'; + +class Search extends Component { + + constructor() { + super(); + + this.state = { + searchResults: [], + }; + + } + + processSearchTerm = (search) => { + const MOVIE_URL = 'http://localhost:3000/movies' + + let customURL = `${MOVIE_URL}?query=${search.searchTerm}` + + axios.get(customURL) + .then((response) => { + console.log(response); + + this.setState({searchResults: response.data}); + }) + .catch((error) => { + // this.props.updateStatusCallback(error.message, 'error'); + }); + } + + render() { + + const searchResults = this.state.searchResults.map((movie, index) => { + + return ( + < Movie key={index} + title={movie.title} + overview={movie.overview} + release_date={movie.release_date} + image_url={movie.image_url} + inLibrary={true}/> + ) + }); + + return( + +
+
+

SEARCH JS

+ +
+ +
+ + {searchResults} +
+
+ ) + } +} + +export default Search; diff --git a/src/components/SearchForm.js b/src/components/SearchForm.js new file mode 100644 index 000000000..e2e078721 --- /dev/null +++ b/src/components/SearchForm.js @@ -0,0 +1,51 @@ +import React, { Component } from 'react'; +import PropTypes from 'prop-types'; + +class SearchForm extends Component { + + static propTypes = { + searchCallback: PropTypes.func.isRequired + } + + constructor() { + super(); + + this.state = { + searchTerm: '', + }; + + } + + onInputChange = (event) => { + let enteredTerm = {}; + enteredTerm[event.target.name] = event.target.value; + this.setState(enteredTerm); + + console.log('term'); + console.log(event.target); + } + + onFormSubmit = (event) => { + event.preventDefault(); + this.props.searchCallback(this.state); + + this.setState({ + searchTerm: '', + }); + } + + render() { + + return( + +
+
+ + +
+
+ ) + } +} + +export default SearchForm; diff --git a/src/components/Status.js b/src/components/Status.js new file mode 100644 index 000000000..c879db132 --- /dev/null +++ b/src/components/Status.js @@ -0,0 +1,21 @@ +import React from 'react'; +import PropTypes from 'prop-types'; + +class Status extends React.Component { + + static propTypes ={ + message: PropTypes.string, + type: PropTypes.string + } + + render() { + return ( +
+ {this.props.message} +
+ ); + } + +} + +export default Status; diff --git a/src/index.css b/src/index.css index b4cc7250b..4fe70f8e9 100644 --- a/src/index.css +++ b/src/index.css @@ -3,3 +3,7 @@ body { padding: 0; font-family: sans-serif; } + +ul { + list-style: "none;" +}