diff --git a/_test_/App.spec.js b/_test_/App.spec.js index f77c3d4..55eee89 100644 --- a/_test_/App.spec.js +++ b/_test_/App.spec.js @@ -26,6 +26,6 @@ describe('App', () => { expect(app.find('Switch').length).toBe(1); }); it('renders a Route component', () => { - expect(app.find('Route').length).toBe(17); + expect(app.find('Route').length).toBe(19); }); }); diff --git a/_test_/Navbar.spec.js b/_test_/Navbar.spec.js index 8ef2465..f55f1b6 100644 --- a/_test_/Navbar.spec.js +++ b/_test_/Navbar.spec.js @@ -1,6 +1,7 @@ import React from 'react'; import expect from 'expect'; -import Enzyme, { shallow } from 'enzyme'; +import Enzyme, { mount } from 'enzyme'; +import { BrowserRouter } from 'react-router-dom'; import Adapter from 'enzyme-adapter-react-16'; import Navbar, { Navbar as Nav } from '../src/components/NavigationBar'; @@ -25,8 +26,12 @@ describe('Navbar', () => { user: {}, }, }); - app = shallow(); - res = app.dive().dive(); + app = mount( + + + , + ); + res = app.find('Navbar'); }); it('renders successfully', () => { diff --git a/_test_/authReducer.spec.js b/_test_/authReducer.spec.js index a8d1122..6e8b960 100644 --- a/_test_/authReducer.spec.js +++ b/_test_/authReducer.spec.js @@ -22,7 +22,7 @@ describe('Login reducer', () => { ...initialState, isAuthenticated: false, user: {}, - loading: true, + loading: false, }); }); diff --git a/_test_/errorReducer.spec.js b/_test_/errorReducer.spec.js index c484220..01c1974 100644 --- a/_test_/errorReducer.spec.js +++ b/_test_/errorReducer.spec.js @@ -1,13 +1,13 @@ import errorReducer from '../src/reducers/errorReducer'; import { - GET_ERRORS, LOGIN_LOADING, + GET_ERRORS, AUTH_LOADING, } from '../src/actions/types'; describe('Error reducer', () => { it('should set loading to true before displaying error', () => { expect( errorReducer({}, { - type: LOGIN_LOADING, + type: AUTH_LOADING, loading: true, }), ).toEqual({ diff --git a/_test_/loginAction.spec.js b/_test_/loginAction.spec.js index 7bf874b..191453c 100644 --- a/_test_/loginAction.spec.js +++ b/_test_/loginAction.spec.js @@ -1,10 +1,9 @@ import moxios from 'moxios'; import thunk from 'redux-thunk'; import configureMockStore from 'redux-mock-store'; -import { SET_CURRENT_USER, GET_ERRORS, LOGIN_LOADING } from '../src/actions/types'; +import { SET_CURRENT_USER, GET_ERRORS, AUTH_LOADING } from '../src/actions/types'; import mockLoginData from '../src/utils/loginMockStore'; import { loginUser, socialLogin } from '../src/actions/authActions'; -import axios from '../src/config/axiosInstance'; const mockStore = configureMockStore([thunk]); let store = mockStore(); @@ -12,11 +11,11 @@ const { successResponse, errorResponse } = mockLoginData; describe('Login actions', () => { beforeEach(() => { - moxios.install(axios); + moxios.install(); store.clearActions(); }); - afterEach(() => moxios.uninstall(axios)); + afterEach(() => moxios.uninstall()); it('Returns failure if login was unsuccessful', (done) => { moxios.stubRequest('https://ah-nyati-backend-staging.herokuapp.com/api/v1/auth/login', { status: 400, @@ -24,7 +23,7 @@ describe('Login actions', () => { }); const expectedActions = [ { - type: LOGIN_LOADING, + type: AUTH_LOADING, }, { payload: errorResponse.message, @@ -45,7 +44,7 @@ describe('Login actions', () => { }); const expectedActions = [ { - type: LOGIN_LOADING, + type: AUTH_LOADING, }, { payload: successResponse.data[0], diff --git a/src/actions/authActions.js b/src/actions/authActions.js index a5df68d..fa6bde8 100644 --- a/src/actions/authActions.js +++ b/src/actions/authActions.js @@ -1,13 +1,14 @@ import { toast } from 'react-toastify'; -import axios from '../config/axiosInstance'; +import axios from '../api/axios'; import { - GET_ERRORS, SET_CURRENT_USER, LOGIN_LOADING, + GET_ERRORS, SET_CURRENT_USER, AUTH_LOADING, REMOVE_CURRENT_USER, } from './types'; import setAuthToken from '../utils/setAuthToken'; + // set logged in user export const setLoginLoading = () => ({ - type: LOGIN_LOADING, + type: AUTH_LOADING, }); // set logged in user @@ -16,9 +17,19 @@ export const setCurrentUser = decoded => ({ payload: decoded, }); +// remove logged in user +export const removeCurrentUser = () => ({ + type: REMOVE_CURRENT_USER, +}); + +export const logoutError = error => ({ + type: GET_ERRORS, + payload: error.message, +}); + export const loginUser = userData => (dispatch) => { dispatch(setLoginLoading()); - return axios + return axios() .post('/auth/login', userData) .then((res) => { // save token to local storage @@ -45,6 +56,19 @@ export const loginUser = userData => (dispatch) => { }); }); }; + +export const logoutUser = (history, user) => (dispatch) => { + return axios() + .post('/auth/logout', user) + .then(() => { + localStorage.removeItem('jwtToken'); + localStorage.removeItem('user'); + dispatch(removeCurrentUser()); + history.push('/'); + }) + .catch(error => dispatch(logoutError(error))); +}; + /** * @description - logs in a user his using social account details * @param {string} token - the request token diff --git a/src/actions/types.js b/src/actions/types.js index 36002b6..beda714 100644 --- a/src/actions/types.js +++ b/src/actions/types.js @@ -18,7 +18,7 @@ export const GET_CURRENT_USER = 'GET_CURRENT_USER'; export const CREATE_ARTICLE_START = 'CREATE_ARTICLE_START'; export const CREATE_ARTICLE_SUCCESS = 'CREATE_ARTICLE_SUCCESS'; export const CREATE_ARTICLE_FAILURE = 'CREATE_ARTICLE_FAILURE'; -export const LOGIN_LOADING = 'LOGGIN_LOADING'; +export const AUTH_LOADING = 'AUTH_LOADING'; export const SUCCESS = 'SUCCESS'; export const SIGNUP_LOADING = 'SIGNUP_LOADING'; export const VIEW_SINGLE_ARTICLE = 'VIEW_SINGLE_ARTICLE'; @@ -28,3 +28,4 @@ export const PROFILE_LOADING = 'PROFILE_LOADING'; export const PROFILE_NOT_FOUND = 'PROFILE_NOT_FOUND'; export const FETCH_PROFILE_ARTICLE = 'FETCH_ALL_ARTICLE'; export const PROFILE_ARTICLE_LOADING = 'PROFILE_ARTICLE_LOADING'; +export const REMOVE_CURRENT_USER = 'REMOVE_CURRENT_USER'; diff --git a/src/components/App.js b/src/components/App.js index 9792640..9e423a8 100644 --- a/src/components/App.js +++ b/src/components/App.js @@ -59,12 +59,14 @@ const App = () => ( - - + + + + diff --git a/src/components/NavigationBar/index.jsx b/src/components/NavigationBar/index.jsx index 8e4cabe..5f29444 100644 --- a/src/components/NavigationBar/index.jsx +++ b/src/components/NavigationBar/index.jsx @@ -1,8 +1,9 @@ import React from 'react'; -import { Link } from 'react-router-dom'; +import { Link, withRouter } from 'react-router-dom'; import { connect } from 'react-redux'; import PropTypes from 'prop-types'; import getUser from '../../actions/getUserAction'; +import { logoutUser } from '../../actions/authActions'; import '../../variables.scss'; import './index.scss'; @@ -25,14 +26,18 @@ export class Navbar extends React.Component { userName, }, } = user; - this.props.getUser(userName); } } + logOut = () => { + const { logoutUser, history } = this.props; + logoutUser(history); + } + componentDidUpdate(prevProps) { const { authUser: { userName } } = this.props; - if (prevProps.authUser.userName !== userName) { + if (userName && (prevProps.authUser.userName !== userName)) { this.props.getUser(userName); } } @@ -90,13 +95,7 @@ export class Navbar extends React.Component { notification, } = this.state; - const { - authUser, - loggedInUser: { - userName, - imageUrl, - }, - } = this.props; + const { authUser : {userName, imageUrl }, authUser } = this.props; const article = this.checkWidth(, 'Articles'); const notify = this.checkWidth(, 'Notifications'); @@ -206,7 +205,11 @@ export class Navbar extends React.Component {
  • Create Article
  • My Articles
  • Edit Profile
  • -
  • Log Out
  • +
  • + + Log Out + +
  • @@ -227,4 +230,4 @@ const mapStateToProps = state => ({ authUser: state.auth.user, }); -export default connect(mapStateToProps, { getUser })(Navbar); +export default withRouter(connect(mapStateToProps, { getUser, logoutUser })(Navbar)); diff --git a/src/reducers/authReducer.js b/src/reducers/authReducer.js index f817a65..c9cad80 100644 --- a/src/reducers/authReducer.js +++ b/src/reducers/authReducer.js @@ -1,6 +1,6 @@ import isEmpty from '../validations/isEmpty'; import { - SET_CURRENT_USER, LOGIN_LOADING, + SET_CURRENT_USER, AUTH_LOADING, REMOVE_CURRENT_USER, } from '../actions/types'; const initialState = { @@ -10,7 +10,7 @@ const initialState = { }; const reducer = (state = initialState, action) => { switch (action.type) { - case LOGIN_LOADING: + case AUTH_LOADING: return { ...state, loading: true, @@ -22,6 +22,11 @@ const reducer = (state = initialState, action) => { user: action.payload, loading: false, }; + case REMOVE_CURRENT_USER: + return { + ...initialState, + loading: false, + }; default: return state; } diff --git a/src/reducers/errorReducer.js b/src/reducers/errorReducer.js index ff85d92..55d2a13 100644 --- a/src/reducers/errorReducer.js +++ b/src/reducers/errorReducer.js @@ -1,4 +1,4 @@ -import { GET_ERRORS, LOGIN_LOADING } from '../actions/types'; +import { GET_ERRORS, AUTH_LOADING } from '../actions/types'; const initialState = { error: { @@ -10,7 +10,7 @@ const initialState = { export default function (state = initialState, action) { switch (action.type) { - case LOGIN_LOADING: + case AUTH_LOADING: return { ...state, loading: true, diff --git a/src/reducers/index.js b/src/reducers/index.js index e2cd3a7..f078ac1 100644 --- a/src/reducers/index.js +++ b/src/reducers/index.js @@ -29,6 +29,5 @@ export default combineReducers({ toastr: toastrReducer, fetchCategoryReducer, updateArticlesReducer, - profile: profileReducer, });