From 6d5c1e8d6d6d8421765927afb29a80a8738982e2 Mon Sep 17 00:00:00 2001 From: KevinMidboe Date: Fri, 6 Oct 2017 11:55:20 +0200 Subject: [PATCH 01/15] File that holds functions for retriveing and saving cookie data. --- client/app/components/Cookie.jsx | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) create mode 100644 client/app/components/Cookie.jsx diff --git a/client/app/components/Cookie.jsx b/client/app/components/Cookie.jsx new file mode 100644 index 0000000..8aef20f --- /dev/null +++ b/client/app/components/Cookie.jsx @@ -0,0 +1,26 @@ + +import React from 'react'; + + +export function getCookie(cname) { + var name = cname + "="; + var decodedCookie = decodeURIComponent(document.cookie); + var ca = decodedCookie.split(';'); + for(var i = 0; i Date: Fri, 6 Oct 2017 11:56:22 +0200 Subject: [PATCH 02/15] Added 404 page when a request does not match any routes. --- client/app/components/NotFound.js | 10 ++++++++++ 1 file changed, 10 insertions(+) create mode 100644 client/app/components/NotFound.js diff --git a/client/app/components/NotFound.js b/client/app/components/NotFound.js new file mode 100644 index 0000000..5984e9b --- /dev/null +++ b/client/app/components/NotFound.js @@ -0,0 +1,10 @@ +// components/NotFound.js +import React from 'react'; + +const NotFound = () => +
+

404 page not found

+

We are sorry but the page you are looking for does not exist.

+
+ +export default NotFound; \ No newline at end of file -- 2.34.1 From 5b110b9d82e3003edc91d21886223ec3d47dad17 Mon Sep 17 00:00:00 2001 From: KevinMidboe Date: Fri, 6 Oct 2017 11:57:22 +0200 Subject: [PATCH 03/15] This is the main router for index page, routes to searchRequest and admin pages. --- client/app/components/Main.jsx | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) create mode 100644 client/app/components/Main.jsx diff --git a/client/app/components/Main.jsx b/client/app/components/Main.jsx new file mode 100644 index 0000000..118bb50 --- /dev/null +++ b/client/app/components/Main.jsx @@ -0,0 +1,21 @@ +import React from 'react'; +import { HashRouter as Router, Route, Switch} from 'react-router-dom'; +import { createBrowserHistory } from 'history'; + +import SearchRequest from './SearchRequest.jsx'; +import Admin from './Admin.jsx'; +import NotFound from './NotFound.js'; + +export const history = createBrowserHistory(); + +const Main = () => ( + + + + + + + +) + +export default Main -- 2.34.1 From 927352e9aef8dd6e3beb27ad54405919e348b950 Mon Sep 17 00:00:00 2001 From: KevinMidboe Date: Fri, 6 Oct 2017 11:59:16 +0200 Subject: [PATCH 04/15] Added react-redux, react-router and other redux packages. --- client/package.json | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/client/package.json b/client/package.json index e6fe23f..38c7c71 100644 --- a/client/package.json +++ b/client/package.json @@ -17,7 +17,13 @@ "react-dom": "^15.5.4", "react-infinite-scroller": "^1.0.15", "react-notify-toast": "^0.3.2", + "react-redux": "^5.0.6", "react-responsive": "^1.3.4", + "react-router": "^4.2.0", + "react-router-dom": "^4.2.2", + "redux": "^3.7.2", + "redux-logger": "^3.0.6", + "redux-thunk": "^2.2.0", "urijs": "^1.18.12", "webfontloader": "^1.6.28", "webpack": "^3.5.5", -- 2.34.1 From 0b79c8679d05cd3507b2b3bdee9b26520ec6ae00 Mon Sep 17 00:00:00 2001 From: KevinMidboe Date: Fri, 6 Oct 2017 12:00:51 +0200 Subject: [PATCH 05/15] This is the landing page for viewing all requested items. One must be authenticated through the admin page, and requests need the token variable in browser storage. The returned data can be filtered and sorted. --- client/app/components/FetchRequested.jsx | 165 +++++++++++++++++++++++ 1 file changed, 165 insertions(+) create mode 100644 client/app/components/FetchRequested.jsx diff --git a/client/app/components/FetchRequested.jsx b/client/app/components/FetchRequested.jsx new file mode 100644 index 0000000..568a526 --- /dev/null +++ b/client/app/components/FetchRequested.jsx @@ -0,0 +1,165 @@ +import React from 'react'; + +import requestElement from './styles/requestElementStyle.jsx' + +import { getCookie } from './Cookie.jsx'; + +class RequestElement extends React.Component { + constructor(props) { + super(props); + this.default_requestList = null; + } + + filterRequestList(requestList, filter) { + if (filter === 'all') + return requestList + + return requestList.filter(item => item.status === filter) + } + + sortRequestList(requestList, sort_type, reversed) { + requestList.sort(function(a,b) { + if(a[sort_type] < b[sort_type]) return -1; + if(a[sort_type] > b[sort_type]) return 1; + return 0; + }); + + if (reversed) + requestList.reverse(); + } + + createHTMLElement(data, index) { + var posterPath = 'https://image.tmdb.org/t/p/w300' + data.image_path; + + if (data.user_agent !== null) { + var user_agent = data.user_agent.split(" "); + var agent_shortened = user_agent[1].replace(/[\(\;]/g, '') + } + + return ( +
+ +
+ Name: {data.name} + Year: {data.year}

+ Status: {data.status}

+ Address: {data.ip}

+ Requested Data: {data.requested_date}

+ Requested By: {data.requested_by}

+ Agent: {agent_shortened}

+
+
+ ) + } + + render() { + const {requestedElementsList, requestedElementsFilter, requestedElementsSort, props} = this.props; + + var filteredRequestedList = this.filterRequestList(requestedElementsList, requestedElementsFilter) + + this.sortRequestList(filteredRequestedList, requestedElementsSort.value, requestedElementsSort.reversed) + + return ( +
+ {filteredRequestedList.map((requestItem, index) => this.createHTMLElement(requestItem, index))} +
+ ); + } +} + + +class FetchRequested extends React.Component { + constructor(props){ + super(props) + this.state = { + requested_objects: [], + filter: 'all', + sort: { + value: 'requested_date', + reversed: false + }, + } + } + + componentDidMount(){ + Promise.resolve() + fetch('https://apollo.kevinmidboe.com/api/v1/plex/requests/all', { + method: 'GET', + headers: { + 'Content-type': 'application/json', + 'authorization': getCookie('token') + } + }) + .then(response => { + if (response.status !== 200) { + console.log('error'); + } + + response.json() + .then(data => { + if (data.success === true) { + this.setState({ + requested_objects: data.requestedItems + }) + } + }) + }) + .catch(error => { + new Error(error); + }) + } + + changeFilter(filter) { + this.setState({ + filter: filter + }) + } + + updateSort(sort=null, reverse=false) { + if (sort) { + this.setState({ + sort: { value: sort, reversed: reverse } + }) + } + else { + this.setState({ + sort: { value: this.state.sort.value, reversed: reverse } + }) + } + } + + + + render(){ + return( +
+ + + + + + + + +
+ ) + } +} + +export default FetchRequested; \ No newline at end of file -- 2.34.1 From ed1d0f3c394c9a3f4d479cd7f3e8561ba1e795c4 Mon Sep 17 00:00:00 2001 From: KevinMidboe Date: Fri, 6 Oct 2017 12:01:30 +0200 Subject: [PATCH 06/15] App.jsx now loads the header and the main script that holds our routes. --- client/app/components/App.jsx | 35 ++++++++++------------------------- 1 file changed, 10 insertions(+), 25 deletions(-) diff --git a/client/app/components/App.jsx b/client/app/components/App.jsx index edc567c..6f87df6 100644 --- a/client/app/components/App.jsx +++ b/client/app/components/App.jsx @@ -1,27 +1,12 @@ -/* - ./app/components/App.jsx - - -*/ -import React from 'react'; -import FetchData from './FetchData.js'; -import ListStrays from './ListStrays.jsx' -import SearchRequest from './SearchRequest.jsx'; +import React, { Component } from "react"; +import Header from './Header.jsx'; +import Main from './Main.jsx'; -export default class App extends React.Component { +const App = () => ( +
+
+
+
+) - //
- //

Welcome to Seasoned

- //
- // - - // - render() { - return ( -
- - -
- ); - } -} \ No newline at end of file +export default App \ No newline at end of file -- 2.34.1 From bd74e1dee11bc63e278a799d6a2d3b65529d8967 Mon Sep 17 00:00:00 2001 From: KevinMidboe Date: Fri, 6 Oct 2017 12:03:16 +0200 Subject: [PATCH 07/15] The first thing the index does is to load the app file in a hashrouter object and send it to the element with id root. --- client/app/index.js | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/client/app/index.js b/client/app/index.js index ecc68f9..214f861 100644 --- a/client/app/index.js +++ b/client/app/index.js @@ -2,14 +2,19 @@ * @Author: KevinMidboe * @Date: 2017-06-01 21:08:55 * @Last Modified by: KevinMidboe -* @Last Modified time: 2017-06-01 21:34:32 +* @Last Modified time: 2017-10-05 13:47:37 ./client/index.js which is the webpack entry file */ import React from 'react'; -import ReactDOM from 'react-dom'; +import { render } from 'react-dom'; +import { HashRouter } from 'react-router-dom'; import App from './components/App.jsx'; -ReactDOM.render(, document.getElementById('root')); \ No newline at end of file +render(( + + + +), document.getElementById('root')); \ No newline at end of file -- 2.34.1 From 3bc8c5912bf727cc8631e64bc88cddb72a9393a4 Mon Sep 17 00:00:00 2001 From: KevinMidboe Date: Fri, 6 Oct 2017 12:04:35 +0200 Subject: [PATCH 08/15] Loader for what pages is to be displayed based on the state of cookie: logged_in. Either displays login page or fetchrequested. --- client/app/components/Admin.jsx | 35 +++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) create mode 100644 client/app/components/Admin.jsx diff --git a/client/app/components/Admin.jsx b/client/app/components/Admin.jsx new file mode 100644 index 0000000..96d36af --- /dev/null +++ b/client/app/components/Admin.jsx @@ -0,0 +1,35 @@ +/* + ./app/components/App.jsx + + +*/ +import React from 'react'; +import { Link } from 'react-router-dom' + +import FetchData from './FetchData.js'; +import ListStrays from './ListStrays.jsx'; + +import FetchRequested from './FetchRequested.jsx'; + +import LoginForm from './LoginForm/LoginForm.jsx'; +import { Provider } from 'react-redux'; +import store from './redux/store.jsx'; + +import { getCookie } from './Cookie.jsx'; + + +function getLoginStatus() { + const logged_in = getCookie('logged_in'); + if (logged_in) { + return + } + return +} + +const Admin = () => ( + + { getLoginStatus() } + +) + +export default Admin \ No newline at end of file -- 2.34.1 From 6dd45cf89e608202192c89a52baf895edd2da05e Mon Sep 17 00:00:00 2001 From: KevinMidboe Date: Fri, 6 Oct 2017 12:05:00 +0200 Subject: [PATCH 09/15] Empty header file. --- client/app/components/Header.jsx | 11 +++++++++++ 1 file changed, 11 insertions(+) create mode 100644 client/app/components/Header.jsx diff --git a/client/app/components/Header.jsx b/client/app/components/Header.jsx new file mode 100644 index 0000000..e068151 --- /dev/null +++ b/client/app/components/Header.jsx @@ -0,0 +1,11 @@ +import React from 'react' +import { Link } from 'react-router-dom' + +// The Header creates links that can be used to navigate +// between routes. +const Header = () => ( +
+
+) + +export default Header -- 2.34.1 From c03449b9e9ac3c0bda9c86f9aa5321b3790d23dc Mon Sep 17 00:00:00 2001 From: KevinMidboe Date: Fri, 6 Oct 2017 12:05:54 +0200 Subject: [PATCH 10/15] The login form for authentication a user. --- client/app/components/LoginForm/LoginForm.jsx | 66 +++++++++++++++++++ 1 file changed, 66 insertions(+) create mode 100644 client/app/components/LoginForm/LoginForm.jsx diff --git a/client/app/components/LoginForm/LoginForm.jsx b/client/app/components/LoginForm/LoginForm.jsx new file mode 100644 index 0000000..f25ab83 --- /dev/null +++ b/client/app/components/LoginForm/LoginForm.jsx @@ -0,0 +1,66 @@ +import React, { Component } from 'react'; +import { connect } from 'react-redux'; +import { login } from '../redux/reducer.jsx'; + +class LoginForm extends Component { + + constructor(props) { + super(props); + this.state = {}; + this.onSubmit = this.onSubmit.bind(this); + } + + render() { + let {email, password} = this.state; + let {isLoginPending, isLoginSuccess, loginError} = this.props; + return ( +
+
+
+ + this.setState({email: e.target.value})} value={email}/> +
+ +
+ + this.setState({password: e.target.value})} value={password}/> +
+
+ + + +
+ { isLoginPending &&
Please wait...
} + { isLoginSuccess &&
Success.
} + { loginError &&
{loginError.message}
} +
+
+ ) + } + + onSubmit(e) { + e.preventDefault(); + let { email, password } = this.state; + this.props.login(email, password); + this.setState({ + email: '', + password: '' + }); + } +} + +const mapStateToProps = (state) => { + return { + isLoginPending: state.isLoginPending, + isLoginSuccess: state.isLoginSuccess, + loginError: state.loginError + }; +} + +const mapDispatchToProps = (dispatch) => { + return { + login: (email, password) => dispatch(login(email, password)) + }; +} + +export default connect(mapStateToProps, mapDispatchToProps)(LoginForm); \ No newline at end of file -- 2.34.1 From dbb8eb4057685a7bdfac50dc2e706ca652c8b1d8 Mon Sep 17 00:00:00 2001 From: KevinMidboe Date: Fri, 6 Oct 2017 12:07:43 +0200 Subject: [PATCH 11/15] Added redux reducer and store for calling from the login page. --- client/app/components/redux/reducer.jsx | 108 ++++++++++++++++++++++++ client/app/components/redux/store.jsx | 7 ++ 2 files changed, 115 insertions(+) create mode 100644 client/app/components/redux/reducer.jsx create mode 100644 client/app/components/redux/store.jsx diff --git a/client/app/components/redux/reducer.jsx b/client/app/components/redux/reducer.jsx new file mode 100644 index 0000000..18317d7 --- /dev/null +++ b/client/app/components/redux/reducer.jsx @@ -0,0 +1,108 @@ + +import { setCookie } from '../Cookie.jsx'; + +const SET_LOGIN_PENDING = 'SET_LOGIN_PENDING'; +const SET_LOGIN_SUCCESS = 'SET_LOGIN_SUCCESS'; +const SET_LOGIN_ERROR = 'SET_LOGIN_ERROR'; + +export function login(email, password) { + return dispatch => { + dispatch(setLoginPending(true)); + dispatch(setLoginSuccess(false)); + dispatch(setLoginError(null)); + + callLoginApi(email, password, error => { + dispatch(setLoginPending(false)); + if (!error) { + dispatch(setLoginSuccess(true)); + } else { + dispatch(setLoginError(error)); + } + }); + } +} + +function setLoginPending(isLoginPending) { + return { + type: SET_LOGIN_PENDING, + isLoginPending + }; +} + +function setLoginSuccess(isLoginSuccess) { + return { + type: SET_LOGIN_SUCCESS, + isLoginSuccess + }; +} + +function setLoginError(loginError) { + return { + type: SET_LOGIN_ERROR, + loginError + } +} + + +function callLoginApi(email, password, callback) { + + Promise.resolve() + fetch('https://apollo.kevinmidboe.com/api/v1/user/login', { + method: 'POST', + headers: { + 'Content-type': 'application/json' + }, + body: JSON.stringify({ + username: email, + password: password, + }) + }) + .then(response => { + switch (response.status) { + case 200: + response.json() + .then((data) => { + if (data.success === true) { + let token = data.token; + setCookie('token', token, 10); + setCookie('logged_in', true, 10); + + window.location.reload(); + } + return callback(null); + }) + + case 401: + return callback(new Error(response.statusText)); + } + }) + .catch(error => { + return callback(new Error('Invalid email and password')); + }); +} + +export default function reducer(state = { + isLoginSuccess: false, + isLoginPending: false, + loginError: null +}, action) { + switch (action.type) { + case SET_LOGIN_PENDING: + return Object.assign({}, state, { + isLoginPending: action.isLoginPending + }); + + case SET_LOGIN_SUCCESS: + return Object.assign({}, state, { + isLoginSuccess: action.isLoginSuccess + }); + + case SET_LOGIN_ERROR: + return Object.assign({}, state, { + loginError: action.loginError + }); + + default: + return state; + } +} \ No newline at end of file diff --git a/client/app/components/redux/store.jsx b/client/app/components/redux/store.jsx new file mode 100644 index 0000000..6af9d92 --- /dev/null +++ b/client/app/components/redux/store.jsx @@ -0,0 +1,7 @@ +import { createStore, applyMiddleware } from 'redux'; +import thunk from 'redux-thunk'; +import logger from 'redux-logger'; +import reducer from './reducer.jsx'; + +const store = createStore(reducer, {}, applyMiddleware(thunk, logger)); +export default store; \ No newline at end of file -- 2.34.1 From c954bd48748db73dc2936bed9b02f40c331796d1 Mon Sep 17 00:00:00 2001 From: KevinMidboe Date: Fri, 6 Oct 2017 12:08:06 +0200 Subject: [PATCH 12/15] Added stylesheet for requestElement --- .../components/styles/requestElementStyle.jsx | 23 +++++++++++++++++++ 1 file changed, 23 insertions(+) create mode 100644 client/app/components/styles/requestElementStyle.jsx diff --git a/client/app/components/styles/requestElementStyle.jsx b/client/app/components/styles/requestElementStyle.jsx new file mode 100644 index 0000000..8fa0c15 --- /dev/null +++ b/client/app/components/styles/requestElementStyle.jsx @@ -0,0 +1,23 @@ + +export default { + bodyDiv: { + display: 'flex', + flexDirection: 'row', + flexWrap: 'wrap', + flexFlow: 'row wrap', + }, + + wrappingDiv: { + + }, + + requestPoster: { + height: '150px', + }, + + infoDiv: { + marginTop: 0, + marginLeft: '10px', + float: 'right', + }, +} \ No newline at end of file -- 2.34.1 From 7e27e19a0d73961a4815335405bbfb82362cb5f5 Mon Sep 17 00:00:00 2001 From: Kevin Midboe Date: Fri, 6 Oct 2017 12:12:21 +0200 Subject: [PATCH 13/15] Added more strict header allowence and was a error where endpoints for user was not using router, but app. --- seasoned_api/src/webserver/app.js | 32 ++++++++++++------- .../src/webserver/controllers/user/login.js | 1 + 2 files changed, 22 insertions(+), 11 deletions(-) diff --git a/seasoned_api/src/webserver/app.js b/seasoned_api/src/webserver/app.js index 3da15b0..b6fe7c4 100644 --- a/seasoned_api/src/webserver/app.js +++ b/seasoned_api/src/webserver/app.js @@ -8,25 +8,35 @@ const mustBeAuthenticated = require('./middleware/mustBeAuthenticated'); // this will let us get the data from a POST // configure app to use bodyParser() app.use(bodyParser.json()); +// router.use(bodyParser.urlencoded({ extended: true })); + + +/* Decode the Authorization header if provided */ +// router.use(tokenToUser); + +var port = 31459; // set our port +var router = express.Router(); +var allowedOrigins = ['129.241.229.146', 'https://kevinmidboe.com', 'http://localhost:8080'] + +// router.use(bodyParser.json()); app.use(bodyParser.urlencoded({ extended: true })); /* Decode the Authorization header if provided */ -app.use(tokenToUser); - -var port = 31459; // set our port -var router = express.Router(); -var allowedOrigins = ['https://kevinmidboe.com', 'http://localhost:8080'] - +router.use(tokenToUser); router.use(function(req, res, next) { // TODO add logging of all incoming console.log('Request: ', req.originalUrl); var origin = req.headers.origin; if (allowedOrigins.indexOf(origin) > -1) { - res.setHeader('Access-Control-Allow-Origin', origin); + console.log('allowed'); + res.setHeader('Access-Control-Allow-Origin', origin); } - next(); + res.header('Access-Control-Allow-Headers', 'Content-Type, Authorization'); + res.header('Access-Control-Allow-Methods', 'POST, GET', 'PUT'); + + next(); }); router.get('/', function(req, res) { @@ -36,9 +46,9 @@ router.get('/', function(req, res) { /** * User */ -app.post('/api/v1/user', require('./controllers/user/register.js')); -app.post('/api/v1/user/login', require('./controllers/user/login.js')); -app.get('/api/v1/user/history', mustBeAuthenticated, require('./controllers/user/history.js')); +router.post('/v1/user', require('./controllers/user/register.js')); +router.post('/v1/user/login', require('./controllers/user/login.js')); +router.get('/v1/user/history', mustBeAuthenticated, require('./controllers/user/history.js')); /** * Seasoned diff --git a/seasoned_api/src/webserver/controllers/user/login.js b/seasoned_api/src/webserver/controllers/user/login.js index 4fe7755..49be74a 100644 --- a/seasoned_api/src/webserver/controllers/user/login.js +++ b/seasoned_api/src/webserver/controllers/user/login.js @@ -14,6 +14,7 @@ const userSecurity = new UserSecurity(); function loginController(req, res) { const user = new User(req.body.username); const password = req.body.password; + // console.log('login: ', req.body) userSecurity.login(user, password) .then(() => { -- 2.34.1 From f8ff71bcff2ba0247555491bfe4b7392fc3a3f0c Mon Sep 17 00:00:00 2001 From: Kevin Midboe Date: Fri, 6 Oct 2017 12:14:05 +0200 Subject: [PATCH 14/15] Removed a no longer used ip address for allowed origins. --- seasoned_api/src/webserver/app.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/seasoned_api/src/webserver/app.js b/seasoned_api/src/webserver/app.js index b6fe7c4..be30da7 100644 --- a/seasoned_api/src/webserver/app.js +++ b/seasoned_api/src/webserver/app.js @@ -16,7 +16,7 @@ app.use(bodyParser.json()); var port = 31459; // set our port var router = express.Router(); -var allowedOrigins = ['129.241.229.146', 'https://kevinmidboe.com', 'http://localhost:8080'] +var allowedOrigins = ['https://kevinmidboe.com', 'http://localhost:8080'] // router.use(bodyParser.json()); app.use(bodyParser.urlencoded({ extended: true })); -- 2.34.1 From 42749c5b641c440d253601d8b6046df05d22eb7c Mon Sep 17 00:00:00 2001 From: KevinMidboe Date: Fri, 6 Oct 2017 12:20:51 +0200 Subject: [PATCH 15/15] Now searchRequest passes a index key to movieObject so that each div object can have a separate key. --- client/app/components/MovieObject.jsx | 4 ++-- client/app/components/SearchRequest.jsx | 12 ++++++------ 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/client/app/components/MovieObject.jsx b/client/app/components/MovieObject.jsx index 5b6f58a..e114900 100644 --- a/client/app/components/MovieObject.jsx +++ b/client/app/components/MovieObject.jsx @@ -34,7 +34,7 @@ class MovieObject { notify.show(this.title + ' requested!', 'success', 3000); } - getElement() { + getElement(index) { // TODO set the poster image async by updating the dom after this is returned if (this.poster == null || this.poster == undefined) { var posterPath = 'https://openclipart.org/image/2400px/svg_to_png/211479/Simple-Image-Not-Found-Icon.png' @@ -60,7 +60,7 @@ class MovieObject { return ( -
+
diff --git a/client/app/components/SearchRequest.jsx b/client/app/components/SearchRequest.jsx index 1f488dc..c9f64ca 100644 --- a/client/app/components/SearchRequest.jsx +++ b/client/app/components/SearchRequest.jsx @@ -156,11 +156,11 @@ class SearchRequest extends React.Component { .then(responseData => { if (this.state.page === 1) { this.setState({ - responseMovieList: responseData.results.map(searchResultItem => this.createMovieObjects(searchResultItem)), + responseMovieList: responseData.results.map((searchResultItem, index) => this.createMovieObjects(searchResultItem, index)), lastApiCallURI: uri // Save the value of the last sucessfull api call }) } else { - let responseMovieObjects = responseData.results.map(searchResultItem => this.createMovieObjects(searchResultItem)); + let responseMovieObjects = responseData.results.map((searchResultItem, index) => this.createMovieObjects(searchResultItem, index)); let growingReponseMovieObjectList = this.state.responseMovieList.concat(responseMovieObjects); this.setState({ responseMovieList: growingReponseMovieObjectList, @@ -202,11 +202,11 @@ class SearchRequest extends React.Component { .then(responseData => { if (this.state.page === 1) { this.setState({ - responseMovieList: responseData.results.map(searchResultItem => this.createMovieObjects(searchResultItem)), + responseMovieList: responseData.results.map((searchResultItem, index) => this.createMovieObjects(searchResultItem, index)), lastApiCallURI: uri // Save the value of the last sucessfull api call }) } else { - let responseMovieObjects = responseData.results.map(searchResultItem => this.createMovieObjects(searchResultItem)); + let responseMovieObjects = responseData.results.map((searchResultItem, index) => this.createMovieObjects(searchResultItem, index)); let growingReponseMovieObjectList = this.state.responseMovieList.concat(responseMovieObjects); this.setState({ responseMovieList: growingReponseMovieObjectList, @@ -288,9 +288,9 @@ class SearchRequest extends React.Component { // When called passes the variable to MovieObject and calls it's interal function for // generating the wanted HTML - createMovieObjects(item) { + createMovieObjects(item, index) { let movie = new MovieObject(item); - return movie.getElement(); + return movie.getElement(index); } toggleFilter(filterType) { -- 2.34.1