diff --git a/package-lock.json b/package-lock.json
index 79f52b34f..140e58626 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,58 @@
"resolved": "https://registry.npmjs.org/react-error-overlay/-/react-error-overlay-4.0.0.tgz",
"integrity": "sha512-FlsPxavEyMuR6TjVbSSywovXSEyOg6ZDj5+Z8nbsRl9EkOzAhEIcS+GLoQDC5fz/t9suhUXWmUrOBrgeUvrMxw=="
},
+ "react-marquee": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/react-marquee/-/react-marquee-1.0.0.tgz",
+ "integrity": "sha512-AXHGGWdK+BBhKln/ysXD1CLV6pdv9LDm0beoyQ+RYI8FO2PzqwGqDYrS6ssH3TvYytiLCxY0pIxUGGXNn1f/gg==",
+ "requires": {
+ "prop-types": "15.6.1"
+ }
+ },
+ "react-marquee-double": {
+ "version": "0.1.8",
+ "resolved": "https://registry.npmjs.org/react-marquee-double/-/react-marquee-double-0.1.8.tgz",
+ "integrity": "sha512-qRdZ8q6EZg6y8GI50bshjcTTD5J7omvNnkxF6HwJK1CGkNBvNLchQUjA1MQ7c37GUv1Oh6ACwoDJ4o++rvBrsg==",
+ "requires": {
+ "prop-types": "15.6.1"
+ }
+ },
+ "react-meta-tags": {
+ "version": "0.4.1",
+ "resolved": "https://registry.npmjs.org/react-meta-tags/-/react-meta-tags-0.4.1.tgz",
+ "integrity": "sha512-bY5PcuFsoAc4HHYOMcMIOgQgPG7gXBg/5pDrPsPQozYQrFqOCpQId5UUTrq9BK2jvKWDgD30Du3AgWnSKa2jSA==",
+ "requires": {
+ "babel-runtime": "6.26.0",
+ "prop-types": "15.6.1"
+ }
+ },
+ "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",
@@ -8870,6 +8958,14 @@
}
}
},
+ "react-text-marquee": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/react-text-marquee/-/react-text-marquee-1.0.1.tgz",
+ "integrity": "sha1-b6wWpozu67iylAMIjkVBzdbtfhM=",
+ "requires": {
+ "prop-types": "15.6.1"
+ }
+ },
"read-pkg": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-1.1.0.tgz",
@@ -9231,6 +9327,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 +10665,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 +10706,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..22b56aa71 100644
--- a/package.json
+++ b/package.json
@@ -3,9 +3,15 @@
"version": "0.1.0",
"private": true,
"dependencies": {
+ "axios": "^0.18.0",
"react": "^16.4.1",
"react-dom": "^16.4.1",
- "react-scripts": "1.1.4"
+ "react-marquee": "^1.0.0",
+ "react-marquee-double": "^0.1.8",
+ "react-meta-tags": "^0.4.1",
+ "react-router-dom": "^4.3.1",
+ "react-scripts": "1.1.4",
+ "react-text-marquee": "^1.0.1"
},
"scripts": {
"start": "react-scripts start",
@@ -13,4 +19,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..d2112b91f 100644
--- a/src/App.css
+++ b/src/App.css
@@ -26,3 +26,7 @@
from { transform: rotate(0deg); }
to { transform: rotate(360deg); }
}
+
+body {
+ background-color: #2067B2;
+}
diff --git a/src/App.js b/src/App.js
index 203067e4d..06236fa97 100644
--- a/src/App.js
+++ b/src/App.js
@@ -1,19 +1,11 @@
import React, { Component } from 'react';
-import logo from './logo.svg';
import './App.css';
+import VideoStore from './components/VideoStore'
class App extends Component {
render() {
return (
-
-
-
- Welcome to React
-
-
- To get started, edit src/App.js
and save to reload.
-
-
+
);
}
}
diff --git a/src/components/Customer.css b/src/components/Customer.css
new file mode 100644
index 000000000..e69de29bb
diff --git a/src/components/Customer.js b/src/components/Customer.js
new file mode 100644
index 000000000..1c0b334d5
--- /dev/null
+++ b/src/components/Customer.js
@@ -0,0 +1,16 @@
+import React, { Component } from 'react';
+import './Customer.css';
+
+const Customer = (props) => {
+ // {"id":1,"name":"Shelley Rocha","registered_at":"2015-04-29T14:54:14.000Z","address":"Ap #292-5216 Ipsum Rd.","city":"Hillsboro","state":"OR","postal_code":"24309","phone":"(322) 510-8695","account_credit":13.15,"movies_checked_out_count":0}
+ return (
+
+
{props.customer.name} (Checked out: {props.customer.movies_checked_out_count})
+
{props.customer.address}
+
{props.customer.city} {props.customer.state} {props.customer.postal_code}
+
{props.customer.phone}
+
+ );
+}
+
+export default Customer;
diff --git a/src/components/CustomerList.css b/src/components/CustomerList.css
new file mode 100644
index 000000000..e69de29bb
diff --git a/src/components/CustomerList.js b/src/components/CustomerList.js
new file mode 100644
index 000000000..e89c15263
--- /dev/null
+++ b/src/components/CustomerList.js
@@ -0,0 +1,59 @@
+import React, { Component } from 'react';
+import PropTypes from 'prop-types';
+import axios from 'axios';
+
+import './CustomerList.css';
+import Customer from './Customer'
+
+class CustomerList extends Component {
+ constructor() {
+ super();
+ this.state = {
+ customers: [],
+ };
+ }
+
+ componentDidMount() {
+ this.props.setStatus('Loading customers...', 'pending');
+ axios.get(`${this.props.url}/customers`)
+ .then( (response) => {
+ console.log( response.data );
+ this.setState({
+ customers: response.data
+ });
+ this.props.setStatus(`Loaded ${response.data.length} customers`, 'success');
+ } )
+ .catch( (error) => {
+ this.props.setStatus(`Failed to load customers: ${error.message}`, 'error');
+ console.log("got to the error");
+ console.log(error);
+ } );
+ }
+
+ onClickSelect(e, customer) {
+ this.props.selectCustomerCallback(customer);
+ }
+
+ render () {
+ const customers = this.state.customers.map((customer, index) => {
+ return (
+
+
+ this.onClickSelect(e, customer) }>Select Customer
+
+ )
+ })
+ return (
+
+ {customers}
+
+ );
+ }
+}
+
+CustomerList.propTypes = {
+ url: PropTypes.string.isRequired,
+ selectCustomerCallback: PropTypes.func.isRequired,
+};
+
+export default CustomerList;
diff --git a/src/components/FeaturedFilms.css b/src/components/FeaturedFilms.css
new file mode 100644
index 000000000..cb75e5590
--- /dev/null
+++ b/src/components/FeaturedFilms.css
@@ -0,0 +1,19 @@
+h2 {
+ text-align: center;
+ margin-bottom: 50px;
+}
+
+.features-container {
+ display: grid;
+ /*grid-template-columns: 1fr 1fr 1fr;*/
+ /*grid-template-columns: repeat(auto-fill, minmax(186px, 1fr));*/
+ grid-template-columns: repeat(auto-fit, 186px);
+ grid-template-rows: auto;
+ justify-items: center;
+ justify-content: space-evenly;
+}
+
+.grid-item {
+ justify-self: center;
+ align-items: center;
+}
diff --git a/src/components/FeaturedFilms.js b/src/components/FeaturedFilms.js
new file mode 100644
index 000000000..a9d18d3a2
--- /dev/null
+++ b/src/components/FeaturedFilms.js
@@ -0,0 +1,61 @@
+import React, { Component } from 'react';
+import PropTypes from 'prop-types';
+import axios from 'axios';
+import './FeaturedFilms.css';
+import Movie from './Movie'
+
+
+class FeaturedFilms extends Component {
+ constructor() {
+ super();
+ this.state = {
+ movies: [],
+ };
+ }
+
+ componentDidMount() {
+ axios.get(`${this.props.url}/movies`)
+ .then( (response) => {
+ console.log( response.data );
+ this.setState({
+ movies: response.data
+ });
+ } )
+ .catch( (error) => {
+ this.props.setStatus(`Failed to load movies: ${error.message}`, 'success');
+ });
+ }
+
+ onClickSelect(e, movie) {
+ this.props.selectMovieCallback(movie);
+ e.preventDefault();
+ }
+
+ render () {
+ let movies = this.state.movies.map((movie, index) => {
+ return (
+
+
+ this.onClickSelect(e, movie) }>Select This Movie
+
+
+
+
+ )
+ })
+ movies = movies.sort(() => .5 - Math.random());
+ movies = movies.slice(0,3);
+ return (
+
+ {movies}
+
+ );
+ }
+}
+
+FeaturedFilms.propTypes = {
+ // url: PropTypes.string.isRequired,
+ // selectMovieCallback: PropTypes.func.isRequired,
+};
+
+export default FeaturedFilms;
diff --git a/src/components/Movie.css b/src/components/Movie.css
new file mode 100644
index 000000000..e69de29bb
diff --git a/src/components/Movie.js b/src/components/Movie.js
new file mode 100644
index 000000000..b97c322bb
--- /dev/null
+++ b/src/components/Movie.js
@@ -0,0 +1,17 @@
+import React, { Component } from 'react';
+import './Movie.css';
+
+const Movie = (props) => {
+ // {"id":1,"title":"Psycho","overview":"When larcenous real estate clerk Marion Crane goes on the lam with a wad of cash and hopes of starting a new life, she ends up at the notorious Bates Motel, where manager Norman Bates cares for his housebound mother. The place seems quirky, but fineā¦ until Marion decides to take a shower.","release_date":"1960-06-16","image_url":"https://image.tmdb.org/t/p/w185/81d8oyEFgj7FlxJqSDXWr8JH8kV.jpg","external_id":539}
+
+ return (
+
+
+
{props.movie.title}
+
{props.movie.overview}
+
{props.movie.release_date}
+
+ );
+}
+
+export default Movie;
diff --git a/src/components/RentalLibrary.css b/src/components/RentalLibrary.css
new file mode 100644
index 000000000..5b409abba
--- /dev/null
+++ b/src/components/RentalLibrary.css
@@ -0,0 +1,18 @@
+button {
+ padding: 5px;
+ margin: 5px;
+}
+
+.grid-container {
+ display: grid;
+ grid-template-columns: repeat(auto-fill, minmax(186px, 1fr));
+ /*grid-template-columns: 1fr 1fr 1fr (auto-fit, 186px);*/
+ /*grid-template-columns: repeat(auto-fit, 186px);*/
+ grid-column-gap: 25px;
+ grid-row-gap: 25px;
+}
+
+.grid-item {
+ justify-self: center;
+ align-items: center;
+}
diff --git a/src/components/RentalLibrary.js b/src/components/RentalLibrary.js
new file mode 100644
index 000000000..d905cdea6
--- /dev/null
+++ b/src/components/RentalLibrary.js
@@ -0,0 +1,63 @@
+import React, { Component } from 'react';
+import PropTypes from 'prop-types';
+import axios from 'axios';
+
+import './RentalLibrary.css';
+import Movie from './Movie'
+
+class RentalLibrary extends Component {
+ constructor() {
+ super();
+ this.state = {
+ movies: [],
+ };
+ }
+
+ componentDidMount() {
+ this.props.setStatus('Loading library...', 'pending');
+ axios.get(`${this.props.url}/movies`)
+ .then( (response) => {
+ this.props.setStatus(`Successfully loaded ${response.data.length} movies from the rental library`, 'success');
+ console.log( response.data );
+ this.setState({
+ movies: response.data
+ });
+ } )
+ .catch( (error) => {
+ this.props.setStatus(`Failed to load movies: ${error.message}`, 'success');
+ console.log("got to the error");
+ console.log(error);
+ });
+ }
+
+ onClickSelect(e, movie) {
+ this.props.selectMovieCallback(movie);
+ e.preventDefault();
+ }
+
+ render () {
+ let movies = this.state.movies.map((movie, index) => {
+ return (
+
+
+ this.onClickSelect(e, movie) }>Select This Movie
+
+
+
+
+ )
+ })
+ return (
+
+ );
+ }
+}
+
+RentalLibrary.propTypes = {
+ url: PropTypes.string.isRequired,
+ selectMovieCallback: PropTypes.func.isRequired,
+};
+
+export default RentalLibrary;
diff --git a/src/components/SearchForm.css b/src/components/SearchForm.css
new file mode 100644
index 000000000..e69de29bb
diff --git a/src/components/SearchForm.js b/src/components/SearchForm.js
new file mode 100644
index 000000000..c8d7f2dae
--- /dev/null
+++ b/src/components/SearchForm.js
@@ -0,0 +1,70 @@
+import React, { Component } from 'react';
+import PropTypes from 'prop-types';
+import axios from 'axios';
+import './SearchForm.css';
+import SearchResults from './SearchResults'
+
+
+class SearchForm extends Component {
+ constructor() {
+ super();
+ this.state = {
+ title: '',
+ results: [],
+ };
+ }
+
+ onFieldChange = (event) => {
+ const fieldName = event.target.name;
+ const fieldValue = event.target.value
+ const updateState = {};
+ updateState[fieldName] = fieldValue;
+ this.setState(updateState);
+ }
+
+ onFormSubmit = (event) => {
+ event.preventDefault();
+ this.props.setStatus(`Searching for "${this.state.title}"...`, 'pending');
+ console.log(`searching for ${this.state.title}`);
+ axios.get(`${this.props.url}/movies?query=${this.state.title}`)
+ .then((response) => {
+ this.props.setStatus(`Found ${response.data.length} results for ${this.state.title}`, 'success');
+ console.log(response.data);
+ this.setState({results: response.data});
+ })
+ .catch((error) => {
+ this.props.setStatus(`Could not search for "${this.state.title}": ${error.message}`, 'error');
+ });
+ }
+
+ render() {
+ return (
+
+ );
+ }
+}
+
+SearchForm.propTypes = {
+ url: PropTypes.string.isRequired,
+}
+
+export default SearchForm;
diff --git a/src/components/SearchResults.css b/src/components/SearchResults.css
new file mode 100644
index 000000000..e69de29bb
diff --git a/src/components/SearchResults.js b/src/components/SearchResults.js
new file mode 100644
index 000000000..ba4ca8904
--- /dev/null
+++ b/src/components/SearchResults.js
@@ -0,0 +1,53 @@
+import React, { Component } from 'react';
+import PropTypes from 'prop-types';
+import axios from 'axios';
+
+import './SearchResults.css';
+import Movie from './Movie'
+
+class SearchResults extends Component {
+
+ onClickSelect(e, movie) {
+ console.log(e);
+ console.log(movie);
+ this.props.setStatus(`Adding movie "${movie.title}" to library...`, 'pending');
+ axios.post(`${this.props.url}/movies`, movie)
+ .then((response) => {
+ console.log(response);
+ this.props.setStatus(`Successfully added "${movie.title}" to library`, 'success');
+ alert(`Successfully added ${movie.title} to Library`)
+ })
+ .catch((error) => {
+ this.props.setStatus(
+ `Could not add "${movie.title}" to library: ${error.message}`, 'error');
+ });
+ }
+
+ render () {
+ console.log(results);
+ const results = this.props.results.map((movie, index) => {
+ return (
+
+
+ this.onClickSelect(e, movie) } >
+ Add to Library
+
+
+ )
+ })
+ return (
+
+ {results}
+
+ );
+ }
+}
+
+SearchResults.propTypes = {
+ results: PropTypes.array.isRequired,
+};
+
+export default SearchResults;
diff --git a/src/components/Selections.css b/src/components/Selections.css
new file mode 100644
index 000000000..e69de29bb
diff --git a/src/components/Selections.js b/src/components/Selections.js
new file mode 100644
index 000000000..f7d1f7e86
--- /dev/null
+++ b/src/components/Selections.js
@@ -0,0 +1,16 @@
+import React, { Component } from 'react';
+import './Selections.css';
+
+
+const Selections = (props) => {
+ const customer = props.customer ? props.customer.name : "None";
+ const movie = props.movie ? props.movie.title : "None";
+ return (
+
+
Selected Customer: {customer} | Selected Movie: {movie}
+
+ );
+}
+
+
+export default Selections;
diff --git a/src/components/StatusBar.css b/src/components/StatusBar.css
new file mode 100644
index 000000000..b643ba02c
--- /dev/null
+++ b/src/components/StatusBar.css
@@ -0,0 +1,33 @@
+.status-bar {
+ border: 1px solid black;
+ display: -ms-flexbox;
+ display: flex;
+ -ms-flex-pack: justify;
+ justify-content: space-between;
+}
+
+.status-bar--hide {
+ display: none;
+}
+
+.status-bar--error {
+ background-color: rgb(245, 160, 160);
+}
+
+.status-bar--success {
+ background-color: rgb(123, 249, 108);
+}
+
+.status-bar--pending {
+ background-color: rgb(147, 255, 255)
+}
+
+.status-bar__text {
+ margin: .4em;
+}
+
+.status-bar__button {
+ background-color: inherit;
+ border: none;
+ cursor: pointer;
+}
diff --git a/src/components/StatusBar.js b/src/components/StatusBar.js
new file mode 100644
index 000000000..9352fb074
--- /dev/null
+++ b/src/components/StatusBar.js
@@ -0,0 +1,38 @@
+import PropTypes from 'prop-types';
+import React from 'react';
+
+import './StatusBar.css';
+
+class StatusBar extends React.Component {
+ static propTypes = {
+ message: PropTypes.string.isRequired,
+ type: PropTypes.oneOf(['error', 'success', 'pending']),
+ clearStatus: PropTypes.func.isRequired,
+ }
+
+
+
+ render() {
+ let className = "status-bar "
+ if (this.props.message.length === 0) {
+ className += "status-bar--hide"
+ } else {
+ className += `status-bar--${this.props.type}`;
+ }
+ return(
+
+
+ {this.props.message}
+
+
+ X
+
+
+ );
+ }
+}
+
+export default StatusBar;
diff --git a/src/components/VideoStore.css b/src/components/VideoStore.css
new file mode 100644
index 000000000..056a7a3b7
--- /dev/null
+++ b/src/components/VideoStore.css
@@ -0,0 +1,63 @@
+@import url('https://fonts.googleapis.com/css?family=Monoton');
+@import url('https://fonts.googleapis.com/css?family=Press+Start+2P');
+
+li {
+ display: flex;
+ flex-direction: row;
+ justify-content: center;
+ align-items: center;
+}
+
+.validation-errors-display {
+ text-align: center;
+ margin-bottom: 2em;
+}
+
+.validation-errors-display__list {
+ list-style-type: none;
+ padding: 0;
+}
+
+.grid-container {
+ display: grid;
+ /*grid-template-columns: repeat(auto-fill, minmax(186px, 1fr));*/
+ grid-template-columns: 1fr 1fr 1fr 1fr (auto-fit, 186px);
+ /*grid-template-columns: repeat(auto-fit, 186px);*/
+ grid-column-gap: 25px;
+ grid-row-gap: 25px;
+}
+
+.flex-container {
+ display: flex;
+ justify-content: space-between;
+}
+
+.flex-container h1 {
+ font-family: 'Monoton', cursive;
+ margin-bottom: 0;
+}
+
+.marquee {
+ font-family: 'Press Start 2P', cursive;
+}
+
+/*img, ul, li {
+ display: flex;
+}*/
+
+.nav-links {
+ color: #CBE9EB;
+ text-shadow: orange 0.1em 0.1em 0.2em;
+ font-weight: bold;
+}
+
+ul {
+ display: flex;
+ flex-direction: column;
+ padding-left: 0;
+}
+
+li {
+ padding: 5px;
+ justify-content: center;
+}
diff --git a/src/components/VideoStore.js b/src/components/VideoStore.js
new file mode 100644
index 000000000..3440abbf6
--- /dev/null
+++ b/src/components/VideoStore.js
@@ -0,0 +1,178 @@
+import React, { Component } from 'react';
+import PropTypes from 'prop-types';
+import { BrowserRouter as Router, Route, Link } from "react-router-dom";
+import CustomerList from './CustomerList';
+import Selections from './Selections';
+import RentalLibrary from './RentalLibrary';
+import './VideoStore.css';
+import SearchForm from './SearchForm';
+import StatusBar from './StatusBar';
+import FeaturedFilms from './FeaturedFilms';
+import axios from 'axios';
+import MarqueeDouble from 'react-marquee-double';
+
+
+class VideoStore extends Component {
+ constructor () {
+ super ();
+ this.state = {
+ selectedMovie: null,
+ selectedCustomer: null,
+ status: {
+ message: '',
+ }
+ }
+ }
+
+ selectCustomer = (customer) => {
+ console.log("selecting customer " + customer.name);
+ this.setState({
+ selectedCustomer: customer,
+ });
+ }
+
+ selectMovie = (movie) => {
+ console.log("selecting movie " + movie.title);
+ this.setState({
+ selectedMovie: movie,
+ });
+ }
+
+ setStatus = (message, type) => {
+ this.setState({
+ status: { message, type }
+ });
+ }
+
+ clearStatus = () => {
+ this.setState({ status: { message: '' }})
+ }
+
+ resetSelection = () => {
+ console.log("resetting select data");
+ this.setState({
+ selectedMovie: null,
+ selectedCustomer: null,
+ });
+ }
+
+ checkoutSelection = (e) => {
+ if ( this.state.selectedCustomer!=null && this.state.selectedMovie!=null ) {
+ let dueDate = new Date();
+ dueDate.setDate(dueDate.getDate() + 7);
+ axios.post(`${this.props.url}/rentals/${this.state.selectedMovie.title}/check-out?customer_id=${this.state.selectedCustomer.id}&due_date=${dueDate}`)
+ .then( (response) => {
+ this.setStatus(
+ `Successfully checked out ${this.state.selectedMovie.title} to ${this.state.selectedCustomer.name}`,
+ 'success');
+ })
+ .catch((error)=> {
+ this.setStatus(
+ `Could not check out ${this.state.selectedMovie.title} to ${this.state.selectedCustomer.name}: ${error.message}`,
+ 'error');
+ // console.log(error);
+ });
+ }
+ }
+
+ render() {
+ const Home = () => (
+
+ );
+
+ const Search = () => (
+
+
+
+ );
+
+ const Library = () => (
+
+
+
+ );
+
+ const Customers = () => (
+
+
+
+ );
+
+ return (
+
+
+
(
+
+ )} />
+
+
+
+
+
+
+
+ );
+ }
+ }
+
+ VideoStore.propTypes = {
+ url: PropTypes.string.isRequired,
+ }
+
+ export default VideoStore;