From 3c5144373a553cd98aa948d9f17c7726797a1569 Mon Sep 17 00:00:00 2001 From: Arthur Kalule Date: Wed, 19 Jun 2019 09:00:16 +0300 Subject: [PATCH] feat(pagination): add article pagination - add article pagination - Revise article like count prop validation from array to object since it has been modified in the back end [starts #165273536] --- .../ArticlePagination/ArticlePagination.scss | 6 ++ .../ArticlePagination.test.js | 49 ++++++++++++++ .../ArticlePagination.test.js.snap | 50 ++++++++++++++ src/components/ArticlePagination/index.js | 65 +++++++++++++++++++ src/components/Button/index.js | 9 ++- .../Login/__snapshots__/login.test.js.snap | 2 + .../__snapshots__/SignupForm.test.js.snap | 1 + src/pages/Landing/Landing.test.js | 15 +++++ src/pages/Landing/index.js | 63 ++++++++++++++++-- src/store/actions/articleActions/index.js | 18 +++-- src/store/reducers/articles/index.js | 3 + 11 files changed, 270 insertions(+), 11 deletions(-) create mode 100644 src/components/ArticlePagination/ArticlePagination.scss create mode 100644 src/components/ArticlePagination/ArticlePagination.test.js create mode 100644 src/components/ArticlePagination/__snapshots__/ArticlePagination.test.js.snap create mode 100644 src/components/ArticlePagination/index.js diff --git a/src/components/ArticlePagination/ArticlePagination.scss b/src/components/ArticlePagination/ArticlePagination.scss new file mode 100644 index 0000000..1879443 --- /dev/null +++ b/src/components/ArticlePagination/ArticlePagination.scss @@ -0,0 +1,6 @@ +.article-pagination { + display: flex; + flex-direction: row; + justify-content: space-around; + margin: 1rem; +} diff --git a/src/components/ArticlePagination/ArticlePagination.test.js b/src/components/ArticlePagination/ArticlePagination.test.js new file mode 100644 index 0000000..b37b751 --- /dev/null +++ b/src/components/ArticlePagination/ArticlePagination.test.js @@ -0,0 +1,49 @@ +import React from 'react'; + +import { mount } from 'enzyme'; + +import ArticlePagination from 'components/ArticlePagination'; +import Button from 'components/Button'; + +describe('ArticlePagination', () => { + const props = { + previous: null, + next: 'next', + paginate: jest.fn(), + count: 20, + }; + let wrapper = mount(); + + it('should render without crushing', () => { + expect(wrapper).toMatchSnapshot(); + }); + + const previousButton = wrapper.find(Button).at(0); + const nextButton = wrapper.find(Button).at(1); + + it('should disable buttons if null', () => { + expect(previousButton.props().disabled).toBe(true); + expect(nextButton.props().disabled).toBe(false); + }); + + + it('should call the paginate function on button click', () => { + const event = { + target: { + type: 'button', + name: '', + }, + preventDefault: jest.fn(), + }; + + nextButton.simulate('click', event); + expect(props.paginate).toBeCalled(); + previousButton.simulate('click', event); + + + props.previous = 'previous'; + wrapper = mount(); + wrapper.find(Button).at(0).simulate('click', event); + expect(props.paginate).toBeCalled(); + }); +}); diff --git a/src/components/ArticlePagination/__snapshots__/ArticlePagination.test.js.snap b/src/components/ArticlePagination/__snapshots__/ArticlePagination.test.js.snap new file mode 100644 index 0000000..ce32fd1 --- /dev/null +++ b/src/components/ArticlePagination/__snapshots__/ArticlePagination.test.js.snap @@ -0,0 +1,50 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`ArticlePagination should render without crushing 1`] = ` + +
+ + + 1 + + / + + 2 + + pages + + +
+
+`; diff --git a/src/components/ArticlePagination/index.js b/src/components/ArticlePagination/index.js new file mode 100644 index 0000000..53abab0 --- /dev/null +++ b/src/components/ArticlePagination/index.js @@ -0,0 +1,65 @@ +// react +import React from 'react'; + +// Proptypes for validation +import PropTypes from 'prop-types'; + +// stylesheets +import './ArticlePagination.scss'; + +// Button component +import Button from 'components/Button'; + +const ArticlePagination = ({ + previous, next, paginate, count, page +}) => { + const pages = Math.ceil(count / 10); + return ( + +
+
+ ); +}; + +ArticlePagination.defaultProps = { + next: null, + previous: null, +}; + +ArticlePagination.propTypes = { + next: PropTypes.string, + page: PropTypes.number.isRequired, + count: PropTypes.number.isRequired, + previous: PropTypes.string, + paginate: PropTypes.func.isRequired, +}; + + +export default ArticlePagination; diff --git a/src/components/Button/index.js b/src/components/Button/index.js index 793d309..cedf59b 100644 --- a/src/components/Button/index.js +++ b/src/components/Button/index.js @@ -7,7 +7,7 @@ import PropTypes from 'prop-types'; const Button = (props) => { // Destructure props const { - btnClass, btnName, btnEvent, + btnClass, btnName, btnEvent, disabled } = props; return ( @@ -16,14 +16,21 @@ const Button = (props) => { className={btnClass} type="button" onClick={btnEvent} + disabled={disabled} > {btnName} ); }; +// Default proptypes +Button.defaultProps = { + disabled: false, +}; + // Props validation Button.propTypes = { + disabled: PropTypes.bool, btnName: PropTypes.string.isRequired, btnClass: PropTypes.string.isRequired, btnEvent: PropTypes.func.isRequired, diff --git a/src/components/Login/__snapshots__/login.test.js.snap b/src/components/Login/__snapshots__/login.test.js.snap index 955e959..754930b 100644 --- a/src/components/Login/__snapshots__/login.test.js.snap +++ b/src/components/Login/__snapshots__/login.test.js.snap @@ -47,6 +47,7 @@ exports[`login component matches the snapshot 1`] = ` btnClass="login__button" btnEvent={[Function]} btnName="Login" + disabled={false} /> diff --git a/src/pages/Landing/Landing.test.js b/src/pages/Landing/Landing.test.js index 6fe8632..414a606 100644 --- a/src/pages/Landing/Landing.test.js +++ b/src/pages/Landing/Landing.test.js @@ -40,4 +40,19 @@ describe('Article Column', () => { const component = shallow(); expect(component.exists()).toBe(true); }); + + it('should call the get articles function', () => { + const getArticlesFn = jest.fn(); + const props = { + next: 'nexturl', + previous: 'previousurl', + count: 10, + articles: [], + getArticles: getArticlesFn, + + }; + const wrapper = shallow(); + wrapper.instance().paginate(); + expect(getArticlesFn).toBeCalled(); + }); }); diff --git a/src/pages/Landing/index.js b/src/pages/Landing/index.js index e083b33..231c7e4 100644 --- a/src/pages/Landing/index.js +++ b/src/pages/Landing/index.js @@ -3,7 +3,6 @@ import React, { Component } from 'react'; // third-party libraries import { ToastContainer } from 'react-toastify'; -import { bindActionCreators } from 'redux'; import { connect } from 'react-redux'; import PropTypes from 'prop-types'; @@ -15,10 +14,18 @@ import Navbar from 'components/NavBar'; import Footer from 'components/Footer'; import Loader from 'components/Loader'; import { getAllArticles } from 'store/actions/articleActions'; +import ArticlePagination from 'components/ArticlePagination'; import ArticleColumn from './ArticleColumn'; export class LandingPage extends Component { + constructor(props) { + super(props); + this.state = { + page: 1, + }; + } + componentDidMount() { const { getArticles } = this.props; @@ -26,8 +33,25 @@ export class LandingPage extends Component { getArticles(); } + + paginate = (apiCallUrl, Increment) => { + const { getArticles } = this.props; + const { page } = this.state; + this.setState({ + page: page + Increment + }); + + getArticles(apiCallUrl); + }; + + render() { - const { articles, isFetching } = this.props; + const { + articles, isFetching, previous, count, next + } = this.props; + const { page } = this.state; + + return ( // Navbar @@ -65,7 +89,18 @@ export class LandingPage extends Component { + +
+ +
+