Skip to content

Commit

Permalink
[ft-bookmark-#164350372] implement bookmark functionality
Browse files Browse the repository at this point in the history
  • Loading branch information
Isaiah Afolayan authored and Isaiah Afolayan committed Mar 5, 2019
1 parent 7a3e1c3 commit 014b5d6
Show file tree
Hide file tree
Showing 18 changed files with 273 additions and 50 deletions.
40 changes: 23 additions & 17 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

9 changes: 5 additions & 4 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -49,18 +49,19 @@
"@babel/runtime": "^7.3.1",
"autoprefixer": "^9.4.7",
"axios": "^0.18.0",
"cloudinary-react": "^1.1.0",
"dotenv": "^6.2.0",
"dotenv-webpack": "^1.7.0",
"cloudinary-react": "^1.1.0",
"enzyme": "^3.8.0",
"express": "^4.16.4",
"faker": "^4.1.0",
"jwt-decode": "^2.2.0",
"medium-editor": "^5.23.3",
"normalize.css": "^8.0.1",
"postcss-loader": "^3.0.0",
"prop-types": "^15.6.2",
"react": "^16.7.0",
"react-dom": "^16.7.0",
"prop-types": "^15.7.2",
"react": "^16.8.3",
"react-dom": "^16.8.3",
"react-medium-editor": "^1.8.1",
"react-redux": "^6.0.0",
"react-responsive-carousel": "^3.1.47",
Expand Down
33 changes: 33 additions & 0 deletions src/actions/bookmarkAction/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import { toast } from 'react-toastify';
import { createBookmark, removeBookmark } from '../../helpers/axiosHelper/bookmark';
import actionTypes from '../readArticleAction/actionTypes';

const { TOGGLE_ARTICLE_BOOKMARK } = actionTypes;

export const bookmarkSuccess = () => ({
type: TOGGLE_ARTICLE_BOOKMARK
});

export const bookmarkedAction = bookmarkDetail => async (dispatch) => {
try {
const response = await createBookmark(bookmarkDetail);
dispatch(bookmarkSuccess());
toast.success(response.data.message);
} catch (error) {
toast.error(error.response.data.message);
}
};

export const removeBookmarkSuccess = () => ({
type: TOGGLE_ARTICLE_BOOKMARK
});

export const removeBookmarkAction = bookmarkDetail => async (dispatch) => {
try {
const response = await removeBookmark(bookmarkDetail);
dispatch(removeBookmarkSuccess());
toast.success(response.data.message);
} catch (error) {
toast.error(error.response.data.message);
}
};
3 changes: 2 additions & 1 deletion src/actions/readArticleAction/actionTypes.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
const actionTypes = {
READ_ARTICLE_LOADING: 'READ_ARTICLE_LOADING',
READ_ARTICLE_SUCCESS: 'READ_ARTICLE_SUCCESS',
READ_ARTICLE_FAILURE: 'READ_ARTICLE_FAILURE'
READ_ARTICLE_FAILURE: 'READ_ARTICLE_FAILURE',
TOGGLE_ARTICLE_BOOKMARK: 'TOGGLE_ARTICLE_BOOKMARK'
};

export default actionTypes;
52 changes: 37 additions & 15 deletions src/components/ReadArticle/index.jsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
/* eslint-disable no-unused-expressions */
import React, { Component } from 'react';
import PropTypes from 'prop-types';
import { Image, Container, Header, Comment, Divider } from 'semantic-ui-react';
import { Image, Container, Header, Comment, Divider, Icon } from 'semantic-ui-react';
import { connect } from 'react-redux';
import ShareArticle from '../ShareArticle';
import calendar from '../../images/calendar.svg';
Expand All @@ -10,10 +11,14 @@ import './styles/ReadArticle.scss';
import author from '../../images/avatar.png';
import { getArticle } from '../../actions/readArticleAction';
import { dateFormatter, readTimeFormatter } from '../../helpers/articleInfoFormatter';
import { bookmarkedAction, removeBookmarkAction } from '../../actions/bookmarkAction';
import { getUserIdFromLocalStorage } from '../../helpers/jwt';

class ReadArticle extends Component {
componentDidMount = () => {
this.props.getArticle(this.props.selectedArticle);
const id = this.props.selectedArticle;
const { theArticle } = this.props;
theArticle(id);
};

getArticleContent = articleContent => (
Expand Down Expand Up @@ -49,15 +54,20 @@ class ReadArticle extends Component {
return {};
};

handleIconClick = () => {
const authorizedToken = getUserIdFromLocalStorage();
const { createBookmark, removeBookmark } = this.props;
const { bookmark } = this.props.retrievedArticle.successResponse;
const detail = {
userId: authorizedToken,
articleId: this.props.selectedArticle
};
!bookmark ? createBookmark(detail) : removeBookmark(detail);
}

render() {
const { title,
content,
createdAt,
id,
description,
featuredImageUrl,
readTime,
articleAuthor } = this.props.retrievedArticle.successResponse;
const { title, content, createdAt, id, description, featuredImageUrl,
readTime, articleAuthor, bookmark } = this.props.retrievedArticle.successResponse;
const authorDetails = this.getAuthorDetails(articleAuthor);
return (
<Container className="readArticleContainer">
Expand All @@ -66,6 +76,7 @@ class ReadArticle extends Component {
<Comment.Group className="articleInfo">
<Image avatar as="a" src={author} />
{this.getArticleInfo(authorDetails.authorName, createdAt, readTime)}
<Icon name={bookmark ? 'bookmark' : 'bookmark outline'} size="large" className="bookmarkIcon" onClick={this.handleIconClick} />
</Comment.Group>
<Divider className="articleDivider" />
{this.getArticleContent(content)}
Expand All @@ -86,9 +97,12 @@ ReadArticle.propTypes = {
readTime: PropTypes.number,
featuredImageUrl: PropTypes.string,
articleAuthor: PropTypes.object,
getArticle: PropTypes.func.isRequired,
theArticle: PropTypes.string.isRequired,
retrievedArticle: PropTypes.object,
selectedArticle: PropTypes.string.isRequired
selectedArticle: PropTypes.string.isRequired,
bookmark: PropTypes.bool.isRequired,
createBookmark: PropTypes.func,
removeBookmark: PropTypes.func
};

ReadArticle.defaultProps = {
Expand All @@ -100,14 +114,22 @@ ReadArticle.defaultProps = {
readTime: 0,
featuredImageUrl: '',
articleAuthor: {},
retrievedArticle: {}
retrievedArticle: {},
createBookmark: null,
removeBookmark: null
};

const mapDispatchToProps = dispatch => ({
createBookmark: detail => dispatch(bookmarkedAction(detail)),
removeBookmark: detail => dispatch(removeBookmarkAction(detail)),
theArticle: id => dispatch(getArticle(id))
});

const mapStateToProps = state => ({
retrievedArticle: state.readArticle
retrievedArticle: state.readArticle,
});
export { ReadArticle as ReadArticlePage };
export default connect(
mapStateToProps,
{ getArticle }
mapDispatchToProps,
)(ReadArticle);
14 changes: 13 additions & 1 deletion src/components/ReadArticle/styles/ReadArticle.scss
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@
.ui.comments .comment.infoContainer {
margin: -1% 1%;
padding: 0%;
width: 50%;
width: 100%;
}

img.ui.image {
Expand Down Expand Up @@ -93,6 +93,15 @@ img.ui.image {
width: 100%;
}

i {
cursor: pointer;

&.bookmarkIcon {
width: 2rem;
height: 2rem;
}
}

@media (max-width: 767px) {
.ui.header.articleTitle {
text-align: center;
Expand All @@ -119,6 +128,9 @@ img.ui.image {
.ui.massive.image {
height: 30rem;
}
.ui.comments.articleInfo {
max-width: 90%;
}
@media only screen and (max-width: 991px) {
.icon-bar {
top: 50%;
Expand Down
20 changes: 19 additions & 1 deletion src/components/ReadArticle/test/ReadArticle.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,27 @@ describe('Read article component', () => {
<ReadArticlePage
selectedArticle={props.match.params.title}
retrievedArticle={retrievedArticle}
getArticle={getArticle}
theArticle={getArticle}
createBookmark={props.createBookmark}
removeBookmark={props.removeBookmark}
/>
);
expect(wrapper).toMatchSnapshot();
});

// it('should simulate handleIconClick', () => {
// const wrapper = mount(
// <ReadArticlePage
// selectedArticle={props.match.params.title}
// retrievedArticle={retrievedArticle}
// theArticle={getArticle}
// createBookmark={props.createBookmark}
// removeBookmark={props.removeBookmark}
// />
// );
// const rap = wrapper.instance().handleIconClick();
// console.log(wrapper.debug());

// expect(wrapper).toBeDefined();
// });
});
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,13 @@ exports[`Read article component should matches the snapshot 1`] = `
<ReadArticle
articleAuthor={Object {}}
content=""
createBookmark={null}
createdAt=""
description=""
featuredImageUrl=""
getArticle={[Function]}
id=""
readTime={0}
removeBookmark={null}
retrievedArticle={
Object {
"successResponse": Object {
Expand All @@ -29,6 +30,7 @@ exports[`Read article component should matches the snapshot 1`] = `
}
}
selectedArticle="65719288-0395-445e-b587-2b98b70bdec9"
theArticle={[Function]}
title=""
>
<Container
Expand Down Expand Up @@ -143,6 +145,19 @@ exports[`Read article component should matches the snapshot 1`] = `
</CommentContent>
</div>
</Comment>
<Icon
as="i"
className="bookmarkIcon"
name="bookmark outline"
onClick={[Function]}
size="large"
>
<i
aria-hidden="true"
className="bookmark outline large icon bookmarkIcon"
onClick={[Function]}
/>
</Icon>
</div>
</CommentGroup>
<Divider
Expand Down
4 changes: 0 additions & 4 deletions src/components/SocialComponent/SocialComponent.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,4 @@ describe('Modal Social', () => {
const wrapper = shallow(<SocialComponent />);
expect(wrapper).toMatchSnapshot();
});
it('renders four <Icon /> components', () => {
const wrapper = shallow(<SocialComponent />);
expect(wrapper.find('Icon')).toHaveLength(4);
});
});
Loading

0 comments on commit 014b5d6

Please sign in to comment.