Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,9 @@ Second, you can call the calculate function by passing the following information
- `page`: The current page
- `size`: The amount of items shown per page
- `total`: The amount of total items in the list/collection
- `maxPages`: The maximum amount of pages that should be shown (default: 5)
- `config`: A configuration object containing the following possible configuration values:
- `firstPage`: The first page of the pagination (default: 1)
- `maxPages`: The maximum amount of pages that should be shown (default: 5)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Are you sure you want to have a default for maxPages? How would I say that I want all pages to be shown?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is the number of pages that should be shown blow. For example if you have hundreds of results, then we show only the next 2 pages. Otherwise, it breaks most of the times on mobile.

Do you know a sceznario, where you want to show all pages?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I like the feature, but I would just keep the possibility to also show all pages. I think a lib should support that.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would you than also stick to this config object? Because in our case with our designs we then always have to pass this parameter.


In return, you receive an object with all relevant information:

Expand Down
84 changes: 84 additions & 0 deletions src/__test__/pagination-with-first-page-0.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
import { calculatePagination } from '../index'

it('should return no pagination if not enough items are given', () => {
const page = 0
const size = 5
const total = 2
const pagination = calculatePagination(page, size, total, { firstPage: 0 })

expect(pagination).toBeNull()
})
it('should return only a few pages', () => {
const page = 1
const size = 5
const total = 15
const pagination = calculatePagination(page, size, total, { firstPage: 0 })

expect(pagination).not.toBeNull()
expect(pagination?.pages).toHaveLength(3)

expect(pagination?.pages[0].number).toBe(0)
expect(pagination?.pages[0].isCurrent).toBeFalsy()
expect(pagination?.pages[1].number).toBe(1)
expect(pagination?.pages[1].isCurrent).toBeTruthy()
expect(pagination?.pages[2].number).toBe(2)
expect(pagination?.pages[2].isCurrent).toBeFalsy()
})
it('should return the maximum number of pages', () => {
const page = 4
const size = 5
const total = 50
const maxPages = 5
const pagination = calculatePagination(page, size, total, {
firstPage: 0,
maxPages: maxPages,
})

expect(pagination).not.toBeNull()
expect(pagination?.pages).toHaveLength(5)

expect(pagination?.pages[0].number).toBe(2)
expect(pagination?.pages[0].isCurrent).toBeFalsy()
expect(pagination?.pages[1].number).toBe(3)
expect(pagination?.pages[1].isCurrent).toBeFalsy()
expect(pagination?.pages[2].number).toBe(4)
expect(pagination?.pages[2].isCurrent).toBeTruthy()
expect(pagination?.pages[3].number).toBe(5)
expect(pagination?.pages[3].isCurrent).toBeFalsy()
expect(pagination?.pages[4].number).toBe(6)
expect(pagination?.pages[4].isCurrent).toBeFalsy()
})
it('should disable the previous link', () => {
const page = 0
const size = 5
const total = 10
const pagination = calculatePagination(page, size, total, { firstPage: 0 })

expect(pagination).not.toBeNull()

expect(pagination?.previous.number).toBe(0)
expect(pagination?.previous.isDisabled).toBeTruthy()

expect(pagination?.next.number).toBe(1)
expect(pagination?.next.isDisabled).toBeFalsy()

expect(pagination?.pages[0].isCurrent).toBeTruthy()
expect(pagination?.pages[1].isCurrent).toBeFalsy()
})
it('should disable the next link', () => {
const page = 1
const size = 5
const total = 10
const pagination = calculatePagination(page, size, total, { firstPage: 0 })

expect(pagination).not.toBeNull()

expect(pagination?.previous.number).toBe(0)
expect(pagination?.previous.isDisabled).toBeFalsy()

expect(pagination?.next.number).toBe(1)
expect(pagination?.next.isDisabled).toBeTruthy()

expect(pagination?.pages[0].isCurrent).toBeFalsy()
expect(pagination?.pages[1].isCurrent).toBeTruthy()
})
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,9 @@ it('should return the maximum number of pages', () => {
const size = 5
const total = 50
const maxPages = 5
const pagination = calculatePagination(page, size, total, maxPages)
const pagination = calculatePagination(page, size, total, {
maxPages: maxPages,
})

expect(pagination).not.toBeNull()
expect(pagination?.pages).toHaveLength(5)
Expand Down
33 changes: 21 additions & 12 deletions src/index.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
const calculateVisiblePages = (
page: number,
total: number,
firstPage: number,
lastPage: number,
maxPages: number
): number[] => {
const range = Math.floor(maxPages / 2)
let lowerBound = 1
let lowerBound = firstPage
let lowerBoundRest = 0
let upperBound = total
let upperBound = lastPage
let upperBoundRest = 0

if (page - range >= 1) {
Expand All @@ -15,20 +16,22 @@ const calculateVisiblePages = (
lowerBoundRest = (page - range - 1) * -1
}

if (page + range <= total) {
if (page + range <= lastPage) {
upperBound = page + range
} else {
upperBoundRest = (total - range - page) * -1
upperBoundRest = (lastPage - range - page) * -1
}

if (upperBoundRest > 0) {
lowerBound =
lowerBound - upperBoundRest > 0 ? lowerBound - upperBoundRest : 1
lowerBound - upperBoundRest > 0 ? lowerBound - upperBoundRest : firstPage
}

if (lowerBoundRest > 0) {
upperBound =
upperBound + lowerBoundRest < total ? upperBound + lowerBoundRest : total
upperBound + lowerBoundRest < lastPage
? upperBound + lowerBoundRest
: lastPage
}

const pages = []
Expand All @@ -44,7 +47,10 @@ const calculatePagination = (
page: number,
size: number,
total: number,
maxPages = 5
config?: {
firstPage?: number
maxPages?: number
}
): {
previous: {
number: number
Expand All @@ -63,20 +69,23 @@ const calculatePagination = (
return null
}

const lastPage = Math.ceil(total / size)
const isCurrentTheFirstPage = page === 1
const firstPage = config?.firstPage ?? 1
const maxPages = config?.maxPages ?? 5

const lastPage = Math.ceil(total / size) + (firstPage - 1)
const isCurrentTheFirstPage = page === firstPage
const isCurrentTheLastPage = page === lastPage

return {
previous: {
number: isCurrentTheFirstPage ? 1 : page - 1,
number: isCurrentTheFirstPage ? firstPage : page - 1,
isDisabled: isCurrentTheFirstPage,
},
next: {
number: isCurrentTheLastPage ? lastPage : page + 1,
isDisabled: isCurrentTheLastPage,
},
pages: calculateVisiblePages(page, lastPage, maxPages).map(
pages: calculateVisiblePages(page, firstPage, lastPage, maxPages).map(
(visiblePage) => {
return {
number: visiblePage,
Expand Down