From ec9e30c7df3a191abf77e4d1c64ae78be8393341 Mon Sep 17 00:00:00 2001
From: "M. Reza Qorib" <rezaqorib96@gmail.com>
Date: Sun, 7 May 2017 19:17:04 +0700
Subject: [PATCH] [#144502159] [Green] #37 create Pagination component

---
 assets/js/VacancyPage.jsx                     | 13 ++-
 .../__test__/components/Pagination-test.jsx   | 97 +++++++++++--------
 assets/js/components/Pagination.jsx           | 75 ++++++++++++++
 kape/settings.py                              |  6 +-
 4 files changed, 143 insertions(+), 48 deletions(-)
 create mode 100644 assets/js/components/Pagination.jsx

diff --git a/assets/js/VacancyPage.jsx b/assets/js/VacancyPage.jsx
index 438defe0..e7b1b8a6 100644
--- a/assets/js/VacancyPage.jsx
+++ b/assets/js/VacancyPage.jsx
@@ -2,6 +2,8 @@ import React from 'react';
 import Tabs from './components/Tabs';
 import Pane from './components/Pane';
 import VacancyList from './components/VacancyList';
+import Pagination from './components/Pagination';
+import { Menu, Icon } from 'semantic-ui-react';
 
 export default class VacancyPage extends React.Component {
 
@@ -34,10 +36,15 @@ export default class VacancyPage extends React.Component {
       return (
         <Tabs selected={0}>
           <Pane label="Semua Lowongan" >
-            <VacancyList
-              key={1}
-              userId={this.state.id}
+            <Pagination
               url="/vacancies/"
+              child={
+                <VacancyList
+                  key={1}
+                  userId={this.state.id}
+                  url="/vacancies/"
+                />
+              }
             />
           </Pane>
           <Pane label="Lamaran saya" >
diff --git a/assets/js/__test__/components/Pagination-test.jsx b/assets/js/__test__/components/Pagination-test.jsx
index 54804bfd..54dc9211 100644
--- a/assets/js/__test__/components/Pagination-test.jsx
+++ b/assets/js/__test__/components/Pagination-test.jsx
@@ -2,41 +2,44 @@
 import React from 'react';
 import ReactTestUtils from 'react-addons-test-utils';
 import fetchMock from 'fetch-mock';
-import List from '../../components/Pagination'
-import VacancyList from '../../components/VacancyList'
+import Pagination from '../../components/Pagination';
 
 describe('Pagination', () => {
-  const response = [{
-    close_time: '2019-03-28T05:55:42Z',
-    company: {
-      address: 'kebayoran baru',
-      id: 1,
-      logo: null,
-      name: 'tutup lapak',
-    },
-    created: '2017-03-28T07:05:47.128672Z',
-    description: 'Lorem ipsum dolbh.',
-    id: 1,
-    name: 'Software Engineer',
-    open_time: '2017-03-28T05:55:38Z',
-    updated: '2017-03-28T07:34:13.122093Z',
-    verified: true,
-  }, {
-    close_time: '2019-03-28T05:55:42Z',
-    company: {
-      address: 'kebayoran baru',
-      id: 2,
-      logo: null,
-      name: 'tutup lapak',
-    },
-    created: '2017-03-28T07:05:47.128672Z',
-    description: 'Lorem ipsum dolbh.',
-    id: 2,
-    name: 'Software Engineer',
-    open_time: '2017-03-28T05:55:38Z',
-    updated: '2017-03-28T07:34:13.122093Z',
-    verified: true,
-  }];
+  const response = {
+    items: [{
+            close_time: '2019-03-28T05:55:42Z',
+            company: {
+              address: 'kebayoran baru',
+              id: 1,
+              logo: null,
+              name: 'tutup lapak',
+            },
+            created: '2017-03-28T07:05:47.128672Z',
+            description: 'Lorem ipsum dolbh.',
+            id: 1,
+            name: 'Software Engineer',
+            open_time: '2017-03-28T05:55:38Z',
+            updated: '2017-03-28T07:34:13.122093Z',
+            verified: true,
+          }, {
+            close_time: '2019-03-28T05:55:42Z',
+            company: {
+              address: 'kebayoran baru',
+              id: 2,
+              logo: null,
+              name: 'tutup lapak',
+            },
+            created: '2017-03-28T07:05:47.128672Z',
+            description: 'Lorem ipsum dolbh.',
+            id: 2,
+            name: 'Software Engineer',
+            open_time: '2017-03-28T05:55:38Z',
+            updated: '2017-03-28T07:34:13.122093Z',
+            verified: true,
+          },
+          ],
+    next:'/next',
+  };
 
   const response2 = [{
     close_time: '2019-03-28T05:55:42Z',
@@ -67,26 +70,34 @@ describe('Pagination', () => {
     fetchMock.get('*', response);
     const pagination = ReactTestUtils.renderIntoDocument(
       <Pagination child={<div />} url="test" />);
-    pagination.getItemsData();
-    expect(pagination.state.items).to.equal(response);
+    pagination.getItemsData().then(() =>
+      expect(JSON.stringify(pagination.state.items)).to.equal(JSON.stringify(response.items)));
+    fetchMock.restore();
+  });
+
+  it('renders without problem when failed getting data', () => {
+    fetchMock.get('*', 400);
+    const pagination = ReactTestUtils.renderIntoDocument(
+      <Pagination child={<div />} url="test" />);
+    expect(pagination).to.exist;
     fetchMock.restore();
   });
 
-  it('generate child components without problem', () => {
+  it('can go prev without problem', () => {
     fetchMock.get('*', response);
-    const child = <VacancyList url="" userId=""/>
     const pagination = ReactTestUtils.renderIntoDocument(
-      <Pagination child={child} url="test" />);
-    const childRendered = ReactTestUtils.findRenderedDOMComponentWithTag(pagination, child);
-    expect(childRendered).to,exist;
+      <Pagination child={<div />} url="test" />);
+    const prev = ReactTestUtils.scryRenderedDOMComponentsWithTag(pagination, 'a')[0];
+    ReactTestUtils.Simulate.click(prev);
     fetchMock.restore();
   });
 
-  it('renders without problem when failed getting data', () => {
-    fetchMock.get('*', 400);
+  it('can go next without problem', () => {
+    fetchMock.get('*', response);
     const pagination = ReactTestUtils.renderIntoDocument(
       <Pagination child={<div />} url="test" />);
-    expect(pagination).to.exist;
+    const next = ReactTestUtils.scryRenderedDOMComponentsWithTag(pagination, 'a')[2];
+    ReactTestUtils.Simulate.click(next);
     fetchMock.restore();
   });
 });
diff --git a/assets/js/components/Pagination.jsx b/assets/js/components/Pagination.jsx
new file mode 100644
index 00000000..618706e9
--- /dev/null
+++ b/assets/js/components/Pagination.jsx
@@ -0,0 +1,75 @@
+import React from 'react';
+import { Menu, Container, Icon } from 'semantic-ui-react';
+import Server from '../lib/Server';
+import ModalAlert from '../components/ModalAlert';
+
+
+export default class Pagination extends React.Component {
+
+  static propTypes = {
+    url: React.PropTypes.string.isRequired,
+    child: React.PropTypes.node.isRequired,
+  };
+
+  constructor(props) {
+    super(props);
+    /* istanbul ignore next */
+    this.state = {
+      items: [],
+      current: 1,
+      next: '',
+      prev: '',
+      url: this.props.url,
+    };
+    this.getItemsData = this.getItemsData.bind(this);
+    this.handleMovement = this.handleMovement.bind(this);
+    this.handleNext = this.handleNext.bind(this);
+    this.handlePrev = this.handlePrev.bind(this);
+    this.refresh = this.refresh.bind(this);
+    this.getItemsData();
+  }
+
+  getItemsData = () => Server.get(this.state.url, false).then((data) => {
+      this.setState({ items: data.items, next: data.next, prev: data.prev });
+    }, error => error.then((r) => {
+      this.modalAlert.open('Gagal Mengambil Data', r.error);
+    }));
+
+  refresh() {
+    this.forceUpdate();
+  }
+
+  handleMovement(dir) {
+    const newUrl = this.state[dir];
+    this.setState({ url: newUrl });
+    this.getItemsData();
+  }
+
+  handlePrev() {
+    this.handleMovement('prev');
+  }
+
+  handleNext() {
+    this.handleMovement('next');
+  }
+
+  render = () => (
+    <div>
+      <ModalAlert ref={(modal) => { this.modalAlert = modal; }} />
+      {this.props.child}
+      <Container textAlign="right">
+        <Menu pagination icon="labeled" className="vacancyList">
+          <Menu.Item name="prev" disabled={this.state.current !== 1} onClick={this.handlePrev}>
+            <span><Icon disabled={this.state.current !== 1} name="angle left" /></span>
+          </Menu.Item>
+          <Menu.Item name="current" active onClick={this.refresh}>
+            {this.state.current}
+          </Menu.Item>
+          <Menu.Item name="next" onClick={this.handleNext}>
+            <span><Icon name="angle right" /></span>
+          </Menu.Item>
+        </Menu>
+      </Container>
+    </div>
+  );
+}
diff --git a/kape/settings.py b/kape/settings.py
index 8fd0c2f2..7869e068 100755
--- a/kape/settings.py
+++ b/kape/settings.py
@@ -145,7 +145,9 @@ REST_FRAMEWORK = {
     # or allow read-only access for unauthenticated users.
     'DEFAULT_PERMISSION_CLASSES': [
         'rest_framework.permissions.DjangoModelPermissionsOrAnonReadOnly'
-    ]
+    ],
+    'DEFAULT_PAGINATION_CLASS': 'rest_framework.pagination.PageNumberPagination',
+    'PAGE_SIZE': 10
 }
 
 GZIP_CONTENT_TYPES = (
@@ -159,5 +161,5 @@ SESSION_COOKIE_HTTPONLY = False
 
 RUNNING_DEVSERVER = (len(sys.argv) > 1 and sys.argv[1] == 'runserver')
 
-API_CS_CREDENTIALS = {'user': 'lalala', 'password': 'lalala'}
+API_CS_CREDENTIALS = {'user': 'kape', 'password': 'yukcarikape'}
 
-- 
GitLab