diff --git a/package.json b/package.json
index bb7d450..2b630ea 100644
--- a/package.json
+++ b/package.json
@@ -13,6 +13,7 @@
"babel-polyfill": "^6.16.0",
"bootstrap": "^3.3.6",
"font-awesome": "^4.7.0",
+ "history": "^4.4.0",
"jquery": "^2.2.4",
"jwt-decode": "^2.1.0",
"react": "^15.3.2",
@@ -23,7 +24,6 @@
"redux": "^3.6.0",
"redux-auth-wrapper": "^0.9.0",
"redux-logger": "^2.7.4",
- "redux-promise-middleware": "^4.1.0",
"redux-thunk": "^2.1.0"
},
"devDependencies": {
diff --git a/src/public/js/actions/actionCreators.js b/src/public/js/actions/actionCreators.js
index de9f1b1..92b0d2a 100644
--- a/src/public/js/actions/actionCreators.js
+++ b/src/public/js/actions/actionCreators.js
@@ -1,8 +1,7 @@
-export const ADD_MOVIES = 'ADD_MOVIES'
-export const SELECT_MOVIE = 'SELECT_MOVIE'
-export const IS_USER_LOGGED_IN = 'IS_USER_LOGGED_IN'
+import axios from 'axios'
// Select Movie
+export const SELECT_MOVIE = 'SELECT_MOVIE'
export function selectMovie(index) {
return {
type: SELECT_MOVIE,
@@ -10,6 +9,7 @@ export function selectMovie(index) {
}
}
+export const ADD_MOVIES = 'ADD_MOVIES'
export function addMovies(movies) {
return {
type: ADD_MOVIES,
@@ -17,8 +17,66 @@ export function addMovies(movies) {
}
}
+export const IS_USER_LOGGED_IN = 'IS_USER_LOGGED_IN'
export function isUserLoggedIn() {
return {
type: IS_USER_LOGGED_IN,
}
}
+
+export const ADD_ERROR = 'ADD_ERROR'
+export function addError(message) {
+ return {
+ type: ADD_ERROR,
+ payload: {
+ message,
+ }
+ }
+}
+
+export const DISMISS_ERROR = 'DISMISS_ERROR'
+export function dismissError() {
+ return {
+ type: DISMISS_ERROR,
+ }
+}
+
+export const USER_LOGOUT = 'USER_LOGOUT'
+export function userLogout() {
+ return {
+ type: USER_LOGOUT,
+ }
+}
+
+export const USER_LOGIN_FULFILLED = 'USER_LOGIN_FULFILLED',
+ USER_LOGIN_PENDING = 'USER_LOGIN_PENDING';
+export function loginUser(username, password) {
+ return function(dispatch) {
+ dispatch({
+ type: USER_LOGIN_PENDING,
+ })
+ axios.post(
+ '/users/login',
+ {
+ username: username,
+ password: password,
+ },
+ ).then(response => {
+ if (response.data && response.data.type && response.data.type === 'error')
+ {
+ dispatch({
+ type: ADD_ERROR,
+ payload: {
+ message: response.data.message,
+ }
+ })
+ }
+ dispatch({
+ type: USER_LOGIN_FULFILLED,
+ payload: response,
+ })
+ }).catch(error => {
+ console.log(error)
+ })
+ }
+}
diff --git a/src/public/js/app.js b/src/public/js/app.js
index 17d76b6..c4ba719 100644
--- a/src/public/js/app.js
+++ b/src/public/js/app.js
@@ -19,6 +19,7 @@ import store, { history } from './store'
import NavBar from './components/navbar.jsx'
import MovieList from './components/movie-list.jsx'
import UserLoginForm from './components/user-login.jsx'
+import Error from './components/errors.jsx'
class Main extends React.Component {
componentWillMount() {
@@ -30,6 +31,7 @@ class Main extends React.Component {
+
{React.cloneElement(this.props.children, this.props)}
@@ -44,6 +46,7 @@ function mapStateToProps(state) {
return {
movieStore: state.movieStore,
userStore: state.userStore,
+ errors: state.errors,
}
}
@@ -61,7 +64,6 @@ const UserIsAuthenticated = UserAuthWrapper({
predicate: user => user.isLogged,
failureRedirectPath: '/users/login',
})
-const Authenticated = UserIsAuthenticated((props) => props.children);
ReactDOM.render((
@@ -69,9 +71,7 @@ ReactDOM.render((
-
-
-
+
diff --git a/src/public/js/components/errors.jsx b/src/public/js/components/errors.jsx
new file mode 100644
index 0000000..6cd9f94
--- /dev/null
+++ b/src/public/js/components/errors.jsx
@@ -0,0 +1,19 @@
+import React from 'react'
+
+export default function Error(props) {
+ if (!props.errors.message) {
+ return null
+ }
+ return (
+
+
+
+
+
{props.errors.message}
+
+
+
+ )
+}
diff --git a/src/public/js/components/navbar.jsx b/src/public/js/components/navbar.jsx
index 8ddd4b2..07c0344 100644
--- a/src/public/js/components/navbar.jsx
+++ b/src/public/js/components/navbar.jsx
@@ -30,7 +30,7 @@ export default class NavBar extends React.Component {
Login
}
{isLoggedIn &&
-
Logout
+
Logout
}
diff --git a/src/public/js/components/user-login.jsx b/src/public/js/components/user-login.jsx
index 16eb337..5036199 100644
--- a/src/public/js/components/user-login.jsx
+++ b/src/public/js/components/user-login.jsx
@@ -1,6 +1,4 @@
import React from 'react'
-import axios from 'axios'
-import store from '../store'
export default class UserLoginForm extends React.Component {
constructor(props) {
@@ -14,16 +12,7 @@ export default class UserLoginForm extends React.Component {
}
const username = this.refs.username.value;
const password = this.refs.password.value;
- store.dispatch({
- type: "USER_LOGIN",
- payload: axios.post(
- '/users/login',
- {
- username: username,
- password: password,
- },
- )
- })
+ this.props.loginUser(username, password);
}
render() {
return (
diff --git a/src/public/js/reducers/errors.js b/src/public/js/reducers/errors.js
new file mode 100644
index 0000000..7853485
--- /dev/null
+++ b/src/public/js/reducers/errors.js
@@ -0,0 +1,14 @@
+import { ADD_ERROR, DISMISS_ERROR } from '../actions/actionCreators'
+
+export default function error(state = {}, action) {
+ switch (action.type) {
+ case ADD_ERROR:
+ return Object.assign({}, state, {
+ message: action.payload.message,
+ })
+ case DISMISS_ERROR:
+ return {};
+ default:
+ return state;
+ }
+}
diff --git a/src/public/js/reducers/index.js b/src/public/js/reducers/index.js
index 3595843..15d6dd4 100644
--- a/src/public/js/reducers/index.js
+++ b/src/public/js/reducers/index.js
@@ -3,11 +3,13 @@ import { routerReducer } from 'react-router-redux'
import movieStore from './movie-store'
import userStore from './users'
+import errors from './errors'
const rootReducer = combineReducers({
routing: routerReducer,
movieStore,
- userStore
+ userStore,
+ errors,
})
export default rootReducer;
diff --git a/src/public/js/reducers/users.js b/src/public/js/reducers/users.js
index d718533..5c046dc 100644
--- a/src/public/js/reducers/users.js
+++ b/src/public/js/reducers/users.js
@@ -1,4 +1,4 @@
-import { IS_USER_LOGGED_IN } from '../actions/actionCreators'
+import { IS_USER_LOGGED_IN, USER_LOGIN_PENDING, USER_LOGIN_FULFILLED, USER_LOGOUT } from '../actions/actionCreators'
import jwtDecode from 'jwt-decode'
const defaultState = {
@@ -8,25 +8,26 @@ const defaultState = {
isLogged: false,
};
-// This actions are generated from the promise middleware
-
export default function userStore(state = defaultState, action) {
switch (action.type) {
- case 'USER_LOGIN_PENDING':
+ case USER_LOGIN_PENDING:
return Object.assign({}, state, {
userLoading: true,
})
- case 'USER_LOGIN_FULFILLED':
- if (action.payload.data.type === "error") {
+ case USER_LOGIN_FULFILLED:
+ const data = action.payload.data;
+ if (data && data.type === "error") {
return logoutUser(state)
}
- return updateFromToken(state, action.payload.data.token)
+ return updateFromToken(state, data.token)
case IS_USER_LOGGED_IN:
let localToken = localStorage.getItem('token');
if (!localToken || localToken === "") {
return state;
}
return updateFromToken(state, localToken)
+ case USER_LOGOUT:
+ return logoutUser(state)
default:
return state;
}
diff --git a/src/public/js/store.js b/src/public/js/store.js
index 930f969..861331a 100644
--- a/src/public/js/store.js
+++ b/src/public/js/store.js
@@ -2,7 +2,6 @@ import { createStore, applyMiddleware, compose } from 'redux';
import { syncHistoryWithStore } from 'react-router-redux'
import { hashHistory } from 'react-router'
import thunk from 'redux-thunk'
-import promise from 'redux-promise-middleware'
import { routerMiddleware } from 'react-router-redux'
// Import the root reducer
@@ -10,7 +9,7 @@ import rootReducer from './reducers/index'
const routingMiddleware = routerMiddleware(hashHistory)
-const middlewares = [promise(), thunk, routingMiddleware];
+const middlewares = [thunk, routingMiddleware];
// Only use in development mode (set in webpack)
if (process.env.NODE_ENV === `development`) {
diff --git a/yarn.lock b/yarn.lock
index d2ddea0..297bd59 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -1568,6 +1568,16 @@ hawk@~3.1.3:
hoek "2.x.x"
sntp "1.x.x"
+history:
+ version "4.4.0"
+ resolved "https://registry.yarnpkg.com/history/-/history-4.4.0.tgz#b1369588cb9e5d80219d0b1f866b0ac62c14a7f8"
+ dependencies:
+ invariant "^2.2.1"
+ loose-envify "^1.2.0"
+ resolve-pathname "^2.0.0"
+ value-equal "^0.1.1"
+ warning "^3.0.0"
+
history@^3.0.0:
version "3.2.1"
resolved "https://registry.yarnpkg.com/history/-/history-3.2.1.tgz#71c7497f4e6090363d19a6713bb52a1bfcdd99aa"
@@ -2716,10 +2726,6 @@ redux-logger:
dependencies:
deep-diff "0.3.4"
-redux-promise-middleware:
- version "4.1.0"
- resolved "https://registry.yarnpkg.com/redux-promise-middleware/-/redux-promise-middleware-4.1.0.tgz#8477866fa09837c1f08f5869c473747577f5446a"
-
redux-thunk:
version "2.1.0"
resolved "https://registry.yarnpkg.com/redux-thunk/-/redux-thunk-2.1.0.tgz#c724bfee75dbe352da2e3ba9bc14302badd89a98"
@@ -2807,6 +2813,10 @@ resolve-dir@^0.1.0:
expand-tilde "^1.2.2"
global-modules "^0.2.3"
+resolve-pathname@^2.0.0:
+ version "2.0.2"
+ resolved "https://registry.yarnpkg.com/resolve-pathname/-/resolve-pathname-2.0.2.tgz#e55c016eb2e9df1de98e85002282bfb38c630436"
+
resolve@^1.1.6, resolve@^1.1.7:
version "1.1.7"
resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.1.7.tgz#203114d82ad2c5ed9e8e0411b3932875e889e97b"
@@ -3144,6 +3154,10 @@ validate-npm-package-license@^3.0.1:
spdx-correct "~1.0.0"
spdx-expression-parse "~1.0.0"
+value-equal@^0.1.1:
+ version "0.1.1"
+ resolved "https://registry.yarnpkg.com/value-equal/-/value-equal-0.1.1.tgz#b174df21f203c81e17f2e4d59d3a900024cbef7b"
+
verror@1.3.6:
version "1.3.6"
resolved "https://registry.yarnpkg.com/verror/-/verror-1.3.6.tgz#cff5df12946d297d2baaefaa2689e25be01c005c"