Skip to content

Commit

Permalink
fix(bug fix): hot fix (#28)
Browse files Browse the repository at this point in the history
- adds descriptive messages when user tries to like and dislike an article.
- sets cookies life time.
- Adds login ang logout button.

 [Delivers #163817461]
  • Loading branch information
verenceLola authored and dotNesh committed Feb 8, 2019
1 parent 3c67e19 commit 362d67b
Show file tree
Hide file tree
Showing 23 changed files with 213 additions and 99 deletions.
8 changes: 4 additions & 4 deletions src/actions/__tests__/dislikeActions.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -35,19 +35,19 @@ describe('dislikeActions', () => {
});

it('should create a undislike failed action', () => {
const failed = 'You have undisliked this article';
const error = 'Please Log in to Continue.';
const expectedAction = {
type: types.DISLIKE_FAILED,
failed,
error,
};
expect(dislikeActions.DislikeFailed(failed)).toEqual(expectedAction);
expect(dislikeActions.DislikeFailed(error)).toEqual(expectedAction);
});
});
});

describe('async login actions', () => {
afterEach(
() => mock.restore()
() => mock.restore(),
);

it('should create an async action make dislike request', () => {
Expand Down
8 changes: 4 additions & 4 deletions src/actions/__tests__/likeAction.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -35,19 +35,19 @@ describe('likeActions', () => {
});

it('should create a like failed action', () => {
const unsuccessfull = 'You have unliked this article';
const error = 'Please Log in to Continue.';
const expectedAction = {
type: types.LIKE_UNSUCCESSFUL,
unsuccessfull,
error,
};
expect(likeActions.LikeActionRejected(unsuccessfull)).toEqual(expectedAction);
expect(likeActions.LikeActionRejected(error)).toEqual(expectedAction);
});
});
});

describe('async like actions', () => {
afterEach(
() => mock.restore()
() => mock.restore(),
);

it('should create an async action make like request', () => {
Expand Down
3 changes: 3 additions & 0 deletions src/actions/actionTypes.js
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,8 @@ export const LIKE_SUCCESSFUL = 'LIKE_SUCCESSFUL';
export const LIKE_UNSUCCESSFUL = 'LIKE_UNSUCCESSFUL';
export const LIKE_COUNT = 'LIKE_COUNTS';
export const LIKE_COUNTFAIL = 'LIKE_COUNTFAIL';
export const LIKE_RESET = 'LIKE_RESET';
export const DISLIKE_RESET = 'DISLIKE_RESET';
export const DISLIKE_SUCCESSFUL = 'DISLIKE_SUCCESSFUL';
export const DISLIKE_FAILED = 'DISLIKE_FAILED';
export const DISLIKE_ACTION = 'DISLIKE_ACTION';
Expand All @@ -59,3 +61,4 @@ export const RATE_ARTICLE = 'RATE_ARTICLE';
export const RATE_ARTICLE_SUCCESS = 'RATE_ARTICLE_SUCCESS';
export const RATE_ARTICLE_FAIL = 'RATE_ARTICLE_FAIL';
export const RATE_ARTICLE_RESET = 'RATE_ARTICLE_RESET';
export const LOGOUT_SUCCESSFUL = 'LOGOUT SUCCESSFUL';
34 changes: 20 additions & 14 deletions src/actions/dislikeActions.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import axios from 'axios';
import Cookies from 'js-cookie';
import * as types from './actionTypes';
import { fetchArticle } from './viewArticleActions';
import { LikeActionRejected, LikeActionReset } from './likeActions';

// creates request action
export const DislikeAction = request => (
Expand All @@ -20,28 +20,34 @@ export const DislikeSuccessful = success => (
);

// creates undisliking action
export const DislikeFailed = failed => (
export const DislikeFailed = error => (
{
type: types.DISLIKE_FAILED,
failed,
error,
}
);

const token = Cookies.get('access_token');

export const DisLikeActionReset = () => (
{
type: types.DISLIKE_RESET,
}
);


const url = 'https://ah-technocrats.herokuapp.com/api/articles';
const headers = {
headers: {
'Content-Type': 'application/json',
Authorization: `Token ${token}`,
},
};
export const dislikeArticle = slug => (dispatch) => {
export const dislikeArticle = (slug, token) => (dispatch) => {
dispatch(DislikeAction(slug));
return axios.put(`${url}/${slug}/dislike/`, slug,
headers)
return axios.put(`${url}/${slug}/dislike/`, slug, {
headers: {
'Content-Type': 'application/json',
Authorization: `Token ${token}`,
},
})
.then(res => dispatch(DislikeSuccessful(res.data.article),
dispatch(fetchArticle(slug))))
.catch((error) => {
dispatch(DislikeFailed(error));
dispatch(LikeActionRejected(error));
dispatch(LikeActionReset());
});
};
16 changes: 11 additions & 5 deletions src/actions/likeActions.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import axios from 'axios';
import Cookies from 'js-cookie';
import * as types from './actionTypes';
import { fetchArticle } from './viewArticleActions';

Expand All @@ -19,16 +18,22 @@ export const LikeAction = successfulLike => (
}
);

export const LikeActionRejected = unsuccessfull => (
export const LikeActionRejected = error => (
{
type: types.LIKE_UNSUCCESSFUL,
unsuccessfull,
error,
}
);

export const LikeActionReset = () => (
{
type: types.LIKE_RESET,
}
);


const url = 'https://ah-technocrats.herokuapp.com/api/articles';
const token = Cookies.get('access_token');
export const likeAction = slug => (dispatch) => {
export const likeAction = (slug, token) => (dispatch) => {
dispatch(Action(slug));
return axios.put(`${url}/${slug}/like/`, slug, {
headers: {
Expand All @@ -40,5 +45,6 @@ export const likeAction = slug => (dispatch) => {
dispatch(fetchArticle(slug))))
.catch((error) => {
dispatch(LikeActionRejected(error));
dispatch(LikeActionReset());
});
};
24 changes: 22 additions & 2 deletions src/actions/loginActions.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import axios from 'axios';
import Cookies from 'js-cookie';
import * as types from './actionTypes';

// creates request action
Expand All @@ -17,6 +18,13 @@ export const LoginSuccessful = successfulMessage => (
}
);

export const LogoutSuccess = successfulMessage => (
{
type: types.LOGOUT_SUCCESSFUL,
successfulMessage,
}
);

// creates login reject action
export const LoginRejected = error => (
{
Expand All @@ -31,11 +39,23 @@ export function loginUser(credentials) {
try {
const response = await axios.post('https://ah-technocrats.herokuapp.com/api/users/login/', credentials);
const { token, username } = response.data.user;
document.cookie = `access_token=${token}`;
document.cookie = `username=${username}`;
Cookies.set('username', username, {
expires: 1 / 24,
});
Cookies.set('access_token', token, {
expires: 1 / 24,
});
dispatch(LoginSuccessful(response.data));
} catch (error) {
dispatch(LoginRejected(error.response.data.errors));
}
};
}

export const logout = () => (
(dispatch) => {
Cookies.remove('username');
Cookies.remove('access_token');
dispatch(LogoutSuccess('Logout SuccessFul.'));
}
);
6 changes: 6 additions & 0 deletions src/actions/profileActions.js
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,12 @@ export const updateProfileDetails = (details, token) => (
}
);

/**
* @function getFollowers
* @param {string} username The name of the user
* @param {string} token
*/

export const getFollowers = (username, token) => (
dispatch => (
getData(dispatch, 'followers', username, token)
Expand Down
8 changes: 6 additions & 2 deletions src/components/Article/LikeDislikeContainer.jsx
Original file line number Diff line number Diff line change
@@ -1,13 +1,17 @@
import React from 'react';
import LikeDislikeArticleComponent from './LikeDislikeErrorComponent';


const renderActionButtons = (article,
likeArticle, dislikeArticle, renderActionButton, renderLink) => (
likeArticle, dislikeArticle, renderActionButton, renderLink, likeFailing, dislikeFailing) => (
<div className="ui right floated column inline" style={{ display: 'contents' }}>
<LikeDislikeArticleComponent likeFailing={likeFailing} dislikeFailing={dislikeFailing} />
{renderActionButton(
'ui tiny toggle circular green button',
'like',
`Like ${article.article.like.likeCount}`,
'thumbs up icon', likeArticle,
'thumbs up icon',
likeArticle,
)}
{renderActionButton(
'ui tiny toggle circular red button',
Expand Down
16 changes: 16 additions & 0 deletions src/components/Article/LikeDislikeErrorComponent.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import React from 'react';
import { toast } from 'react-semantic-toasts';

const LikeDislikeArticleComponent = likeFailing => (
<div className="right float same-line">
{ likeFailing.likeFailing ? toast({
type: 'warning',
icon: 'sign-in',
title: 'Session has Expired.',
description: 'Please Log in to Continue.',
time: 3000,
}) : null }
</div>
);

export default LikeDislikeArticleComponent;
38 changes: 24 additions & 14 deletions src/components/Article/ViewSingleArticleComponent.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import renderActionButtons from './LikeDislikeContainer';
import { rateArticle } from '../../actions/ratingActions';
import rateArticleComponent from './ratingArticleComponent';


class ViewSingleArticleComponent extends Component {
constructor() {
super();
Expand Down Expand Up @@ -66,12 +67,14 @@ class ViewSingleArticleComponent extends Component {

likeArticle = () => {
const { like, match } = this.props;
like(match.params.slug);
const token = Cookies.get('access_token');
like(match.params.slug, token);
}

dislikeArticle = () => {
const { match, dislike } = this.props;
dislike(match.params.slug);
const token = Cookies.get('access_token');
dislike(match.params.slug, token);
}

renderComment = article => (
Expand Down Expand Up @@ -128,7 +131,7 @@ class ViewSingleArticleComponent extends Component {
</Link>
);

renderUiGrid(article) {
renderUiGrid(article, likeFailing, dislikeFailing) {
return (
<div className="ui grid">
<div className="ui four column row">
Expand All @@ -148,7 +151,8 @@ class ViewSingleArticleComponent extends Component {
</div>
</div>
{renderActionButtons(article,
this.likeArticle, this.dislikeArticle, this.renderActionButton, this.renderLink)}
this.likeArticle, this.dislikeArticle, this.renderActionButton, this.renderLink,
likeFailing, dislikeFailing)}
</div>
<div>
<br />
Expand Down Expand Up @@ -235,20 +239,20 @@ ${window.location.href}`,
renderArticleCover = article => (
<img
src={
article.article.image === '' ? 'https://i1.wp.com/thefrontline.org.uk/'
+ 'wp-content/uploads/2018/10/placeholder.jpg?ssl=1' : article.article.image}
article.article.image === '' ? 'https://i1.wp.com/thefrontline.org.uk/'
+ 'wp-content/uploads/2018/10/placeholder.jpg?ssl=1' : article.article.image}
alt=""
className="ui space centered fluid image cover"
/>
);

renderFollow(article) {
return this.renderLink('follow',

<div className="ui label space-bottom">
<i className="users icon" />
31 Followers
</div>, `/${article.article.author.username}/followers`);
{' '}
Follow
</div>, `/profiles/${article.article.author.username}`);
}

renderReadTime = article => (
Expand All @@ -270,6 +274,7 @@ ${window.location.href}`,
const { rating } = this.state;
const { history, failing } = this.props;

const { likeFailing, dislikeFailing } = this.props;
return (
<div className="ui container">
<div className="ui space borderless">
Expand All @@ -280,7 +285,7 @@ ${window.location.href}`,
{rateArticleComponent(this.onStarClick, rating, history, failing)}
{this.renderArticleCover(article)}
{this.renderCenteredGrid(article)}
{this.renderUiGrid(article)}
{this.renderUiGrid(article, likeFailing, dislikeFailing)}
{this.renderTagSpace()}
{this.renderComments(article)}
{this.setInitialState(article)}
Expand Down Expand Up @@ -345,16 +350,20 @@ ViewSingleArticleComponent.defaultProps = {

const matchDispatchToProps = dispatch => (
{
like: slug => (
dispatch(likingActions.likeAction(slug))
like: (slug, token) => (
dispatch(likingActions.likeAction(slug, token))
),
dislike: slug => (
dispatch(dislikeActions.dislikeArticle(slug))
dislike: (slug, token) => (
dispatch(dislikeActions.dislikeArticle(slug, token))
),

rateArticle: (articlesData, token) => (
dispatch(rateArticle(articlesData, token))
),
unlikeUpdated: unsuccessfull => (
dispatch(likingActions.LikeActionRejected(unsuccessfull))
),

}
);

Expand All @@ -363,6 +372,7 @@ function mapStateToProps(state) {
likeReducer: state.likeReducer,
dislikeReducer: state.dislikeReducer,
failing: state.ratingReducer.failing,
likeFailing: state.likeReducer.error,

};
}
Expand Down
4 changes: 3 additions & 1 deletion src/components/Article/__tests__/ratingComponent.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ import configureStore from 'redux-mock-store';
import thunk from 'redux-thunk';
import { Provider } from 'react-redux';
import { BrowserRouter } from 'react-router-dom';

import rateArticleComponent from '../ratingArticleComponent';
import ViewSingleArticleComponent from '../ViewSingleArticleComponent';

Expand All @@ -28,6 +27,9 @@ describe('Rating on ViewSingleArticle tests', () => {
ratingReducer: {
rating: 0,
},
likeReducer: {
error: {},
},
});
const article = {
message: 'Article found.',
Expand Down
Loading

0 comments on commit 362d67b

Please sign in to comment.