diff --git a/package-lock.json b/package-lock.json
index 6f01c70..359041f 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1400,6 +1400,25 @@
"resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-1.1.3.tgz",
"integrity": "sha512-shAmDyaQC4H92APFoIaVDHCx5bStIocgvbwQyxPRrbUY20V1EYTbSDchWbuwlMG3V17cprZhA6+78JfB+3DTPw=="
},
+ "@popperjs/core": {
+ "version": "2.4.4",
+ "resolved": "https://registry.npmjs.org/@popperjs/core/-/core-2.4.4.tgz",
+ "integrity": "sha512-1oO6+dN5kdIA3sKPZhRGJTfGVP4SWV6KqlMOwry4J3HfyD68sl/3KmG7DeYUzvN+RbhXDnv/D8vNNB8168tAMg=="
+ },
+ "@restart/context": {
+ "version": "2.1.4",
+ "resolved": "https://registry.npmjs.org/@restart/context/-/context-2.1.4.tgz",
+ "integrity": "sha512-INJYZQJP7g+IoDUh/475NlGiTeMfwTXUEr3tmRneckHIxNolGOW9CTq83S8cxq0CgJwwcMzMJFchxvlwe7Rk8Q=="
+ },
+ "@restart/hooks": {
+ "version": "0.3.25",
+ "resolved": "https://registry.npmjs.org/@restart/hooks/-/hooks-0.3.25.tgz",
+ "integrity": "sha512-m2v3N5pxTsIiSH74/sb1yW8D9RxkJidGW+5Mfwn/lHb2QzhZNlaU1su7abSyT9EGf0xS/0waLjrf7/XxQHUk7w==",
+ "requires": {
+ "lodash": "^4.17.15",
+ "lodash-es": "^4.17.15"
+ }
+ },
"@sheerun/mutationobserver-shim": {
"version": "0.3.3",
"resolved": "https://registry.npmjs.org/@sheerun/mutationobserver-shim/-/mutationobserver-shim-0.3.3.tgz",
@@ -1681,6 +1700,11 @@
"@babel/types": "^7.3.0"
}
},
+ "@types/classnames": {
+ "version": "2.2.10",
+ "resolved": "https://registry.npmjs.org/@types/classnames/-/classnames-2.2.10.tgz",
+ "integrity": "sha512-1UzDldn9GfYYEsWWnn/P4wkTlkZDH7lDb0wBMGbtIQc9zXEQq7FlKBdZUn6OBqD8sKZZ2RQO2mAjGpXiDGoRmQ=="
+ },
"@types/color-name": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/@types/color-name/-/color-name-1.1.1.tgz",
@@ -1700,6 +1724,11 @@
"@types/node": "*"
}
},
+ "@types/invariant": {
+ "version": "2.2.34",
+ "resolved": "https://registry.npmjs.org/@types/invariant/-/invariant-2.2.34.tgz",
+ "integrity": "sha512-lYUtmJ9BqUN688fGY1U1HZoWT1/Jrmgigx2loq4ZcJpICECm/Om3V314BxdzypO0u5PORKGMM6x0OXaljV1YFg=="
+ },
"@types/istanbul-lib-coverage": {
"version": "2.0.3",
"resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.3.tgz",
@@ -1769,6 +1798,14 @@
"@types/react": "*"
}
},
+ "@types/react-transition-group": {
+ "version": "4.4.0",
+ "resolved": "https://registry.npmjs.org/@types/react-transition-group/-/react-transition-group-4.4.0.tgz",
+ "integrity": "sha512-/QfLHGpu+2fQOqQaXh8MG9q03bFENooTb/it4jr5kKaZlDQfWvjqWZg48AwzPVMBHlRuTRAY7hRHCEOXz5kV6w==",
+ "requires": {
+ "@types/react": "*"
+ }
+ },
"@types/stack-utils": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-1.0.1.tgz",
@@ -1868,6 +1905,11 @@
}
}
},
+ "@types/warning": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/@types/warning/-/warning-3.0.0.tgz",
+ "integrity": "sha1-DSUBJorY+ZYrdA04fEZU9fjiPlI="
+ },
"@types/yargs": {
"version": "13.0.10",
"resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-13.0.10.tgz",
@@ -2482,6 +2524,14 @@
"resolved": "https://registry.npmjs.org/aws4/-/aws4-1.10.1.tgz",
"integrity": "sha512-zg7Hz2k5lI8kb7U32998pRRFin7zJlkfezGJjUc2heaD4Pw2wObakCDVzkKztTm/Ln7eiVvYsjqak0Ed4LkMDA=="
},
+ "axios": {
+ "version": "0.20.0",
+ "resolved": "https://registry.npmjs.org/axios/-/axios-0.20.0.tgz",
+ "integrity": "sha512-ANA4rr2BDcmmAQLOKft2fufrtuvlqR+cXNNinUmvfeSNCOF98PZL+7M/v1zIdGo7OLjEA9J2gXJL+j4zGsl0bA==",
+ "requires": {
+ "follow-redirects": "^1.10.0"
+ }
+ },
"axobject-query": {
"version": "2.2.0",
"resolved": "https://registry.npmjs.org/axobject-query/-/axobject-query-2.2.0.tgz",
@@ -3501,6 +3551,11 @@
}
}
},
+ "classnames": {
+ "version": "2.2.6",
+ "resolved": "https://registry.npmjs.org/classnames/-/classnames-2.2.6.tgz",
+ "integrity": "sha512-JR/iSQOSt+LQIWwrwEzJ9uk0xfN3mTVYMwt1Ir5mUcSN6pU+V4zQFFaJsclJbPuAUQH+yfWef6tm7l1quW3C8Q=="
+ },
"clean-css": {
"version": "4.2.3",
"resolved": "https://registry.npmjs.org/clean-css/-/clean-css-4.2.3.tgz",
@@ -4536,6 +4591,15 @@
"utila": "~0.4"
}
},
+ "dom-helpers": {
+ "version": "5.2.0",
+ "resolved": "https://registry.npmjs.org/dom-helpers/-/dom-helpers-5.2.0.tgz",
+ "integrity": "sha512-Ru5o9+V8CpunKnz5LGgWXkmrH/20cGKwcHwS4m73zIvs54CN9epEmT/HLqFJW3kXpakAFkEdzgy1hzlJe3E4OQ==",
+ "requires": {
+ "@babel/runtime": "^7.8.7",
+ "csstype": "^3.0.2"
+ }
+ },
"dom-serializer": {
"version": "0.2.2",
"resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-0.2.2.tgz",
@@ -7627,6 +7691,11 @@
}
}
},
+ "jquery": {
+ "version": "3.5.1",
+ "resolved": "https://registry.npmjs.org/jquery/-/jquery-3.5.1.tgz",
+ "integrity": "sha512-XwIBPqcMn57FxfT+Go5pzySnm4KWkT1Tv7gjrpT1srtf8Weynl6R273VJ5GjkRb51IzMp5nbaPjJXMWeju2MKg=="
+ },
"js-tokens": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz",
@@ -7935,6 +8004,11 @@
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.20.tgz",
"integrity": "sha512-PlhdFcillOINfeV7Ni6oF1TAEayyZBoZ8bcshTHqOYJYlrqzRK5hagpagky5o4HfCzzd1TRkXPMFq6cKk9rGmA=="
},
+ "lodash-es": {
+ "version": "4.17.15",
+ "resolved": "https://registry.npmjs.org/lodash-es/-/lodash-es-4.17.15.tgz",
+ "integrity": "sha512-rlrc3yU3+JNOpZ9zj5pQtxnx2THmvRykwL4Xlxoa8I9lHBlVbbyPhgyPMioxVZ4NqyxaVVtaJnzsyOidQIhyyQ=="
+ },
"lodash._reinterpolate": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/lodash._reinterpolate/-/lodash._reinterpolate-3.0.0.tgz",
@@ -9156,6 +9230,11 @@
"ts-pnp": "^1.1.6"
}
},
+ "popper.js": {
+ "version": "1.16.1",
+ "resolved": "https://registry.npmjs.org/popper.js/-/popper.js-1.16.1.tgz",
+ "integrity": "sha512-Wb4p1J4zyFTbM+u6WuO4XstYx4Ky9Cewe4DWrel7B0w6VVICvPwdOpotjzcf6eD8TsckVnIMNONQyPIUFOUbCQ=="
+ },
"portfinder": {
"version": "1.0.28",
"resolved": "https://registry.npmjs.org/portfinder/-/portfinder-1.0.28.tgz",
@@ -10195,6 +10274,15 @@
"react-is": "^16.8.1"
}
},
+ "prop-types-extra": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/prop-types-extra/-/prop-types-extra-1.1.1.tgz",
+ "integrity": "sha512-59+AHNnHYCdiC+vMwY52WmvP5dM3QLeoumYuEyceQDi9aEhtwN9zIQ2ZNo25sMyXnbh32h+P1ezDsUpUH3JAew==",
+ "requires": {
+ "react-is": "^16.3.2",
+ "warning": "^4.0.0"
+ }
+ },
"proxy-addr": {
"version": "2.0.6",
"resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.6.tgz",
@@ -10374,6 +10462,31 @@
"whatwg-fetch": "^3.0.0"
}
},
+ "react-bootstrap": {
+ "version": "1.3.0",
+ "resolved": "https://registry.npmjs.org/react-bootstrap/-/react-bootstrap-1.3.0.tgz",
+ "integrity": "sha512-GYj0c6FO9mx7DaO8Xyz2zs0IcQ6CGCtM3O6/feIoCaG4N8B0+l4eqL7stlMcLpqO4d8NG2PoMO/AbUOD+MO7mg==",
+ "requires": {
+ "@babel/runtime": "^7.4.2",
+ "@restart/context": "^2.1.4",
+ "@restart/hooks": "^0.3.21",
+ "@types/classnames": "^2.2.10",
+ "@types/invariant": "^2.2.33",
+ "@types/prop-types": "^15.7.3",
+ "@types/react": "^16.9.35",
+ "@types/react-transition-group": "^4.4.0",
+ "@types/warning": "^3.0.0",
+ "classnames": "^2.2.6",
+ "dom-helpers": "^5.1.2",
+ "invariant": "^2.2.4",
+ "prop-types": "^15.7.2",
+ "prop-types-extra": "^1.1.0",
+ "react-overlays": "^4.1.0",
+ "react-transition-group": "^4.4.1",
+ "uncontrollable": "^7.0.0",
+ "warning": "^4.0.3"
+ }
+ },
"react-dev-utils": {
"version": "10.2.1",
"resolved": "https://registry.npmjs.org/react-dev-utils/-/react-dev-utils-10.2.1.tgz",
@@ -10596,6 +10709,26 @@
"resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz",
"integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ=="
},
+ "react-lifecycles-compat": {
+ "version": "3.0.4",
+ "resolved": "https://registry.npmjs.org/react-lifecycles-compat/-/react-lifecycles-compat-3.0.4.tgz",
+ "integrity": "sha512-fBASbA6LnOU9dOU2eW7aQ8xmYBSXUIWr+UmF9b1efZBazGNO+rcXT/icdKnYm2pTwcRylVUYwW7H1PHfLekVzA=="
+ },
+ "react-overlays": {
+ "version": "4.1.0",
+ "resolved": "https://registry.npmjs.org/react-overlays/-/react-overlays-4.1.0.tgz",
+ "integrity": "sha512-vdRpnKe0ckWOOD9uWdqykLUPHLPndIiUV7XfEKsi5008xiyHCfL8bxsx4LbMrfnxW1LzRthLyfy50XYRFNQqqw==",
+ "requires": {
+ "@babel/runtime": "^7.4.5",
+ "@popperjs/core": "^2.0.0",
+ "@restart/hooks": "^0.3.12",
+ "@types/warning": "^3.0.0",
+ "dom-helpers": "^5.1.0",
+ "prop-types": "^15.7.2",
+ "uncontrollable": "^7.0.0",
+ "warning": "^4.0.3"
+ }
+ },
"react-router": {
"version": "5.2.0",
"resolved": "https://registry.npmjs.org/react-router/-/react-router-5.2.0.tgz",
@@ -10702,6 +10835,27 @@
"workbox-webpack-plugin": "4.3.1"
}
},
+ "react-toastify": {
+ "version": "6.0.8",
+ "resolved": "https://registry.npmjs.org/react-toastify/-/react-toastify-6.0.8.tgz",
+ "integrity": "sha512-NSqCNwv+C4IfR+c92PFZiNyeBwOJvigrP2bcRi2f6Hg3WqcHhEHOknbSQOs9QDFuqUjmK3SOrdvScQ3z63ifXg==",
+ "requires": {
+ "classnames": "^2.2.6",
+ "prop-types": "^15.7.2",
+ "react-transition-group": "^4.4.1"
+ }
+ },
+ "react-transition-group": {
+ "version": "4.4.1",
+ "resolved": "https://registry.npmjs.org/react-transition-group/-/react-transition-group-4.4.1.tgz",
+ "integrity": "sha512-Djqr7OQ2aPUiYurhPalTrVy9ddmFCCzwhqQmtN+J3+3DzLO209Fdr70QrN8Z3DsglWql6iY1lDWAfpFiBtuKGw==",
+ "requires": {
+ "@babel/runtime": "^7.5.5",
+ "dom-helpers": "^5.0.1",
+ "loose-envify": "^1.4.0",
+ "prop-types": "^15.6.2"
+ }
+ },
"read-pkg": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-3.0.0.tgz",
@@ -12619,6 +12773,22 @@
"resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz",
"integrity": "sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c="
},
+ "typescript": {
+ "version": "4.0.2",
+ "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.0.2.tgz",
+ "integrity": "sha512-e4ERvRV2wb+rRZ/IQeb3jm2VxBsirQLpQhdxplZ2MEzGvDkkMmPglecnNDfSUBivMjP93vRbngYYDQqQ/78bcQ=="
+ },
+ "uncontrollable": {
+ "version": "7.1.1",
+ "resolved": "https://registry.npmjs.org/uncontrollable/-/uncontrollable-7.1.1.tgz",
+ "integrity": "sha512-EcPYhot3uWTS3w00R32R2+vS8Vr53tttrvMj/yA1uYRhf8hbTG2GyugGqWDY0qIskxn0uTTojVd6wPYW9ZEf8Q==",
+ "requires": {
+ "@babel/runtime": "^7.6.3",
+ "@types/react": "^16.9.11",
+ "invariant": "^2.2.4",
+ "react-lifecycles-compat": "^3.0.4"
+ }
+ },
"unicode-canonical-property-names-ecmascript": {
"version": "1.0.4",
"resolved": "https://registry.npmjs.org/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-1.0.4.tgz",
@@ -12910,6 +13080,14 @@
"makeerror": "1.0.x"
}
},
+ "warning": {
+ "version": "4.0.3",
+ "resolved": "https://registry.npmjs.org/warning/-/warning-4.0.3.tgz",
+ "integrity": "sha512-rpJyN222KWIvHJ/F53XSZv0Zl/accqHR8et1kpaMTD/fLCRxtV8iX8czMzY7sVZupTI3zcUTg8eycS2kNF9l6w==",
+ "requires": {
+ "loose-envify": "^1.0.0"
+ }
+ },
"watchpack": {
"version": "1.7.4",
"resolved": "https://registry.npmjs.org/watchpack/-/watchpack-1.7.4.tgz",
diff --git a/package.json b/package.json
index ebe369f..0bcf7e2 100644
--- a/package.json
+++ b/package.json
@@ -6,11 +6,17 @@
"@testing-library/jest-dom": "^4.2.4",
"@testing-library/react": "^9.5.0",
"@testing-library/user-event": "^7.2.1",
+ "axios": "^0.20.0",
"bootstrap": "^4.5.2",
+ "jquery": "^3.5.1",
+ "popper.js": "^1.16.1",
"react": "^16.13.1",
+ "react-bootstrap": "^1.3.0",
"react-dom": "^16.13.1",
"react-router-dom": "^5.2.0",
- "react-scripts": "3.4.3"
+ "react-scripts": "3.4.3",
+ "react-toastify": "^6.0.8",
+ "typescript": "^4.0.2"
},
"scripts": {
"start": "react-scripts start",
diff --git a/src/App.css b/src/App.css
index 959c307..3f46525 100644
--- a/src/App.css
+++ b/src/App.css
@@ -2,6 +2,9 @@
text-align: center;
}
-.container {
- margin-top: 5px;
+.header{
+ background-color: #337ab7;
+ color: white;
+ padding: 5px 0px;
+ margin: 0px 0px 20px 0px;
}
\ No newline at end of file
diff --git a/src/App.js b/src/App.js
index 13f4daa..c86d2d2 100644
--- a/src/App.js
+++ b/src/App.js
@@ -4,10 +4,16 @@ import './App.css';
import Movies from "./components/movies";
import MovieDetails from "./components/movieDetails";
import NotFound from "./components/notFound";
+import { ToastContainer} from "react-toastify";
+import 'react-toastify/dist/ReactToastify.css'
function App() {
return (
+
+
+ OMDB-API Search Movies
+
diff --git a/src/components/movieDetails.jsx b/src/components/movieDetails.jsx
index 0f366f0..4988d76 100644
--- a/src/components/movieDetails.jsx
+++ b/src/components/movieDetails.jsx
@@ -1,14 +1,112 @@
import React, { Component } from "react";
+import restService from '../services/restService';
+import config from "../config.json";
+import { Row, Col } from "react-bootstrap";
+import { Link } from "react-router-dom";
+
class MovieDetails extends Component {
constructor(props) {
super(props);
+ this.state = {
+ movie: null,
+ isLoading: false,
+ }
}
- render() {
+ async performSearch() {
+ try {
+ this.setState({ isLoading: true });
+ let url = config.endpointBase + '&plot=full&i=' + this.props.match.params.id;
+ const movie = await restService.get(url);
+ this.setState({ isLoading: false, movie: movie.data });
+ } catch (ex) {
+ this.setState({ isLoading: false });
+ if (ex.response && ex.response.status === 404) {
+ alert("not found")
+ }
+ }
+ }
+
+ async componentDidMount() {
+ this.performSearch();
+ }
+
+ displayColumn(content) {
+ return (
+
+ {content}
+
+ );
+ }
+
+ displayTitledData(title, content) {
return (
<>
+
+
+ {title}
+
+
+ {content}
+
+
+ >
+ )
+ }
+ displayTitledDataWithLine(title, content) {
+ return (
+ <>
+
+ {this.displayTitledData(title, content)}
+ >
+ )
+ }
+
+
+ render() {
+ const { movie, isLoading } = this.state;
+
+ if (!movie && !isLoading) return null;
+
+ if (isLoading) return (Loading Movie Details...
);
+ return (
+ <>
+ {movie.Title} {"(" + movie.Year + ")"}
+
+
+
+
+
+
+
+ {this.displayColumn(movie.Rated)}
+ {this.displayColumn(movie.Runtime)}
+ {this.displayColumn(movie.Genre)}
+
+
+
+
+ {movie.Plot}}
+
+
+ {this.displayTitledDataWithLine("Writer:", movie.Writer)}
+ {this.displayTitledData("Actors:", movie.Actors)}
+ {this.displayTitledData("Director:", movie.Director)}
+ {this.displayTitledData("Country:", movie.Country)}
+ {this.displayTitledDataWithLine("Awards:", movie.Awards)}
+ {this.displayTitledData("Metascore:", movie.Metascore)}
+ {this.displayTitledData("Imdb Rating:", movie.imdbRating)}
+ {this.displayTitledData("Imdb Votes:", movie.imdbVotes)}
+ {this.displayTitledDataWithLine("Box Office:", movie.BoxOffice)}
+ {this.displayTitledData("Production:", movie.Production)}
+
+
+
+
+ Back to Movies Search
+
>
);
}
diff --git a/src/components/movies.jsx b/src/components/movies.jsx
index 1857ea6..20dbfd9 100644
--- a/src/components/movies.jsx
+++ b/src/components/movies.jsx
@@ -1,19 +1,122 @@
import React, { Component } from "react";
+import MoviesTable from "./moviesTable";
+import restService from '../services/restService';
+import config from "../config.json";
+import { Form, Row, Col } from "react-bootstrap";
+import { toast } from 'react-toastify';
+
class Movies extends Component {
constructor(props) {
super(props);
+ this.state = {
+ movies: [],
+ totalMovies: 0,
+ isLoading: false,
+ didSearch: false,
+ movieSearchName: null,
+ movieYear: null,
+ lastPage: 1,
+ errors: {}
+ }
+ }
+
+ validate() {
+ const errors = {};
+ const { movieSearchName, movieYear } = this.state;
+
+ if (movieSearchName.trim() === '')
+ errors.movieSearchName = "Name of movie is required";
+ if (movieYear.trim().length > 0 && isNaN(parseInt(movieYear.trim()))) {
+ errors.movieYear = "Year is invalid";
+ }
+ return errors;
+ }
+
+ handleSubmit = event => {
+ event.preventDefault();
+ const errors = this.validate();
+ this.setState({ errors });
+ for (let key in errors) {
+ toast.error(errors[key]);
+ return; // return on first error
+ }
+
+ if (this.state.movieSearchName) {
+ this.performSearch(1)
+ }
+ }
+
+ getMoreMovies = event => {
+ this.performSearch(this.state.lastPage + 1);
+ }
+
+ getUrl(page) {
+ let url = config.endpointBase + '&s=' + this.state.movieSearchName;
+ if (this.state.movieYear)
+ url += "&y=" + this.state.movieYear;
+ if (page > 1)
+ url += "&page=" + page;
+ return url;
+ }
+
+
+ async performSearch(page) {
+ try {
+ this.setState({ isLoading: true });
+ const moviesRetrieved = await restService.get(this.getUrl(page));
+ if (page > 1)
+ this.setState({ movies: this.state.movies.concat(moviesRetrieved.data.Search), totalMovies: moviesRetrieved.data.totalResults });
+ else
+ this.setState({ movies: moviesRetrieved.data.Search, totalMovies: moviesRetrieved.data.totalResults });
+ this.setState({ isLoading: false, lastPage: page, didSearch: true });
+ } catch (ex) {
+ this.setState({ isLoading: false });
+ if (ex.response && ex.response.status === 404) {
+ alert("not found")
+ }
+ }
+ }
+
+ handleChange = event => {
+ const { id, value } = event.target;
+ this.setState(prevState => ({
+ ...prevState,
+ [id]: value
+ }));
+ }
+
+ showMovies() {
+ const { totalMovies, movies } = this.state;
+
+ return (
+
+
+ {totalMovies > 0 ?
Found {totalMovies} matching movies
: No matching movies found
}
+ {movies ? : null}
+
+
+ );
}
render() {
+ const { isLoading, movies, totalMovies, movieSearchName, movieYear } = this.state;
+ if (isLoading) return Loading...
+
return (
<>
- Movies
+
+ {this.state.didSearch ? this.showMovies() : null}
+ {movies && movies.length > 0 && movies.length < totalMovies ? : null}
>
);
}
-
}
export default Movies;
-
diff --git a/src/components/moviesTable.jsx b/src/components/moviesTable.jsx
new file mode 100644
index 0000000..a2ac92e
--- /dev/null
+++ b/src/components/moviesTable.jsx
@@ -0,0 +1,23 @@
+import React, { Component } from "react";
+import { Link } from "react-router-dom";
+
+class MoviesTable extends Component {
+ render() {
+ const { movies } = this.props;
+
+ return (
+
+ {movies.map(movie => (
+
+
+
+
{movie.Title} {"(" + movie.Year + ")"}
+
+
+ ))}
+
+ );
+ }
+}
+
+export default MoviesTable;
diff --git a/src/config.json b/src/config.json
new file mode 100644
index 0000000..def6e10
--- /dev/null
+++ b/src/config.json
@@ -0,0 +1,3 @@
+{
+ "endpointBase": "http://www.omdbapi.com?apikey=157f34ed&type=movie"
+}
\ No newline at end of file
diff --git a/src/index.css b/src/index.css
index ec2585e..55eab58 100644
--- a/src/index.css
+++ b/src/index.css
@@ -7,7 +7,80 @@ body {
-moz-osx-font-smoothing: grayscale;
}
-code {
- font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New',
- monospace;
+
+.btn-custom {
+ border-radius: 5px;
+ background-color: #337ab7;
+ color: white;
+ font-size: 18px;
+ font-weight: 700;
+ padding: 5px 10px;
+ border-color: #337ab7;
+}
+
+.btn-custom:hover{
+ background-color: #236aa7;
+ color: white;
+}
+
+
+.container {
+ margin-top: 5px;
+}
+
+.movieListEntry{
+ margin: 5px 0px;
+}
+
+.movieListImage{
+ width: 100%;
+ border-radius: 10px
+}
+
+.movieListTitle {
+ font-size: 18px;
+ font-weight: bold;
+}
+
+.searchControl{
+ margin-top: 5px;
+}
+
+.searchControlButton{
+ margin-top: 2px;
}
+
+.wideButton{
+ width: 100%
+}
+
+
+.margin-top-10{
+ margin-top: 10px;
+}
+
+.margin-top-20{
+ margin-top: 20px;
+}
+
+.margin-top-40{
+ margin-top: 40px;
+}
+
+.margin-bottom-40{
+ margin-bottom: 40px;
+}
+
+.description{
+ text-align: left;
+}
+
+.title{
+ font-weight: bold;
+ color: #337ab7;
+ text-align: left;
+}
+
+.content{
+ text-align: left
+}
\ No newline at end of file
diff --git a/src/services/loggerService.js b/src/services/loggerService.js
new file mode 100644
index 0000000..f3469a0
--- /dev/null
+++ b/src/services/loggerService.js
@@ -0,0 +1,17 @@
+// calls to console.log should be replaced with calls to a logging service such as loggly or sentry
+
+export function debug(message) {
+ console.log("DEBUG: " + message);
+}
+
+export function info(message) {
+ console.log("INFO: " + message);
+}
+
+export function error(message) {
+ console.log("ERROR: " + message);
+}
+
+export function warning(message) {
+ console.log("warn: " + message);
+}
\ No newline at end of file
diff --git a/src/services/restService.js b/src/services/restService.js
new file mode 100644
index 0000000..142a8ce
--- /dev/null
+++ b/src/services/restService.js
@@ -0,0 +1,14 @@
+import axios from 'axios';
+import { toast } from 'react-toastify';
+
+axios.interceptors.response.use(null, error => {
+ if (!error.response || error.response.status < 400 || error.response.status >= 500) {
+ console.log("Error getting movies from server - " + error);
+ toast.error("an unexpected error happened");
+ }
+ return Promise.reject(error);
+});
+
+export default {
+ get: axios.get
+}
\ No newline at end of file