Skip to content

Commit fc710fb

Browse files
committed
fix(pagination): removed 'paging-algorithm', added function to calc pages range
1 parent 0977cbb commit fc710fb

File tree

9 files changed

+569
-201
lines changed

9 files changed

+569
-201
lines changed

index.d.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,11 @@ export interface RouteParams {
1818

1919
export interface PaginationInfo {
2020
itemCount: number;
21-
currentPage: number;
2221
perPage: number;
22+
pageCount: number;
23+
currentPage: number;
24+
hasNextPage: boolean;
25+
hasPreviousPage: boolean;
2326
}
2427

2528
export interface PaginationProps {

index.js.flow

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,11 @@ export interface RouteParams {
1818

1919
export interface PaginationInfo {
2020
itemCount: number;
21-
currentPage: number;
2221
perPage: number;
22+
pageCount: number;
23+
currentPage: number;
24+
hasNextPage: boolean;
25+
hasPreviousPage: boolean;
2326
}
2427

2528
export interface PaginationProps {

package.json

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,6 @@
4545
"classnames": "^2.2.6",
4646
"lodash": "^4.17.15",
4747
"mkdirp": "^0.5.1",
48-
"paging-algorithm": "^1.0.1",
4948
"path-to-regexp": "^3.0.0"
5049
},
5150
"devDependencies": {

src/components/Pagination/Pagination.fragment

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,10 @@ import { graphql } from "gatsby"
33
export const pagination = graphql`
44
fragment Pagination on PageInfo {
55
perPage
6+
pageCount
67
itemCount
78
currentPage
9+
hasNextPage
10+
hasPreviousPage
811
}
912
`

src/components/Pagination/Pagination.js

Lines changed: 48 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
import React from 'react'
22
import { shape, number, string, object, bool, element, oneOf, oneOfType } from 'prop-types'
33
import classNames from 'classnames'
4-
import { getPageInfo } from 'paging-algorithm'
54
import Link from '../Link'
65

76
export default class Pagination extends React.Component {
@@ -13,8 +12,11 @@ export default class Pagination extends React.Component {
1312
className: string,
1413
pageInfo: shape({
1514
itemCount: number.isRequired,
15+
perPage: number.isRequired,
16+
pageCount: number.isRequired,
1617
currentPage: number.isRequired,
17-
perPage: number.isRequired
18+
hasNextPage: bool.isRequired,
19+
hasPreviousPage: bool.isRequired
1820
}).isRequired,
1921
labels: shape({
2022
prev: oneOfType([string, element]),
@@ -41,8 +43,8 @@ export default class Pagination extends React.Component {
4143
range: 6,
4244
labels: {
4345
first: '« First',
44-
prev: ' Previous',
45-
next: 'Next ',
46+
prev: ' Previous',
47+
next: 'Next ',
4648
last: 'Last »'
4749
},
4850
theme: {
@@ -59,39 +61,19 @@ export default class Pagination extends React.Component {
5961
renderDisabled: true
6062
}
6163

62-
constructor (props) {
63-
super(props)
64-
65-
this.state = getPageInfo({
66-
limit: props.pageInfo.perPage,
67-
pageCount: props.range,
68-
total: props.pageInfo.itemCount,
69-
page: props.pageInfo.currentPage
70-
})
71-
}
72-
7364
render () {
7465
const {
75-
totalPages,
76-
hasPreviousPage,
77-
hasNextPage,
78-
previousPage,
79-
nextPage,
80-
firstPage,
81-
lastPage,
82-
currentPage
83-
} = this.state
84-
85-
if (!totalPages || !/^\d+$/.test(totalPages)) {
86-
if (process.env.NODE_ENV !== `production`) {
87-
console.error(
88-
'Warning: Invalid pageInfo prop supplied to `Pagination`' +
89-
' component: ' + JSON.stringify(this.props.pageInfo))
66+
ui,
67+
pageInfo: {
68+
perPage,
69+
pageCount,
70+
itemCount,
71+
currentPage,
72+
hasNextPage,
73+
hasPreviousPage
9074
}
91-
return <div className={this.props.className}>Pagination not available</div>
92-
}
75+
} = this.props
9376

94-
const { ui } = this.props
9577
const labels = Object.assign({}, Pagination.defaultProps.labels, this.props.labels)
9678
const theme = Object.assign({}, Pagination.defaultProps.theme, this.props.theme)
9779
const pages = []
@@ -108,14 +90,15 @@ export default class Pagination extends React.Component {
10890

10991
pages.push({
11092
key: 'prev',
111-
number: previousPage,
93+
number: currentPage - 1,
11294
type: 'prev',
11395
label: labels.prev,
11496
disabled: !hasPreviousPage
11597
})
11698

11799
if (ui !== 'mini') {
118-
for (let i = firstPage; i <= lastPage; i++) {
100+
const [fp, lp] = this.calcRange()
101+
for (let i = fp; i <= lp; i++) {
119102
pages.push({
120103
key: i,
121104
number: i,
@@ -128,7 +111,7 @@ export default class Pagination extends React.Component {
128111

129112
pages.push({
130113
key: 'next',
131-
number: nextPage,
114+
number: currentPage + 1,
132115
type: 'next',
133116
label: labels.next,
134117
disabled: !hasNextPage
@@ -137,7 +120,7 @@ export default class Pagination extends React.Component {
137120
if (ui === 'full') {
138121
pages.push({
139122
key: 'last',
140-
number: totalPages,
123+
number: pageCount,
141124
type: 'last',
142125
label: labels.last,
143126
disabled: !hasNextPage
@@ -192,4 +175,32 @@ export default class Pagination extends React.Component {
192175
</nav>
193176
)
194177
}
178+
179+
calcRange () {
180+
const { range, pageInfo: { currentPage, pageCount } } = this.props
181+
182+
let fp = Math.max(1, currentPage - Math.floor(range / 2));
183+
let lp = Math.min(pageCount, currentPage + Math.floor(range / 2));
184+
185+
if (lp - fp + 1 < range) {
186+
if (currentPage < pageCount / 2) {
187+
lp = Math.min(
188+
pageCount,
189+
lp + (range - (lp - fp))
190+
);
191+
} else {
192+
fp = Math.max(1, fp - (range - (lp - fp)));
193+
}
194+
}
195+
196+
if (lp - fp + 1 > range) {
197+
if (currentPage > pageCount / 2) {
198+
fp = fp + 1;
199+
} else {
200+
lp = lp - 1;
201+
}
202+
}
203+
204+
return [fp, lp]
205+
}
195206
}

src/components/Pagination/__tests__/Pagination.js

Lines changed: 16 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -2,17 +2,11 @@ import React from 'react'
22
import ShallowRenderer from 'react-test-renderer/shallow'
33
import { mapValues, merge } from 'lodash'
44
import Pagination from '../Pagination'
5+
import testCases, { defaultTestCase } from '../../../../test/__fixtures__/pagination'
56

67
describe(`<Pagination />`, () => {
78
const render = (props = {}) => {
8-
props = merge({
9-
route: 'blog',
10-
pageInfo: {
11-
perPage: 10,
12-
itemCount: 90,
13-
currentPage: 4
14-
}
15-
}, props)
9+
props = merge({}, defaultTestCase, props)
1610
return ShallowRenderer.createRenderer().render(
1711
<Pagination {...props} />
1812
)
@@ -55,26 +49,29 @@ describe(`<Pagination />`, () => {
5549

5650
it(`shouldn't render disabled nav items when renderDisabled is false`, () => {
5751
expect(render({
58-
pageInfo: { currentPage: 1 },
52+
pageInfo: { currentPage: 1, hasPreviousPage: false },
5953
renderDisabled: false
6054
})).toMatchSnapshot()
6155
expect(render({
62-
pageInfo: { currentPage: 9 },
56+
pageInfo: { currentPage: defaultTestCase.pageInfo.pageCount, hasNextPage: false },
6357
renderDisabled: false
6458
})).toMatchSnapshot()
6559
expect(render({
66-
pageInfo: { itemCount: 5, currentPage: 1 },
60+
pageInfo: {
61+
itemCount: 1,
62+
perPage: 10,
63+
pageCount: 1,
64+
currentPage: 1,
65+
hasNextPage: false,
66+
hasPreviousPage: false
67+
},
6768
renderDisabled: false
6869
})).toMatchSnapshot()
6970
})
7071

71-
it(`should log console error when called with invalid pageInfo prop`, () => {
72-
const spy = jest.spyOn(console, 'error').mockImplementation()
73-
render({ pageInfo: { perPage: 0, itemCount: 10 } })
74-
expect(spy.mock.calls).toMatchSnapshot()
75-
spy.mockClear()
76-
render({ pageInfo: { perPage: 0, itemCount: 0 } })
77-
expect(spy.mock.calls).toMatchSnapshot()
78-
spy.mockRestore()
72+
it(`should be able to handle different pageInfos`, () => {
73+
for (const testCase of testCases) {
74+
expect(render(testCase)).toMatchSnapshot()
75+
}
7976
})
8077
})

0 commit comments

Comments
 (0)