diff --git a/src/components/KeypressListener/__tests__/KeypressListener.test.js b/src/components/KeypressListener/__tests__/KeypressListener.test.js index 331e03973..dca225153 100644 --- a/src/components/KeypressListener/__tests__/KeypressListener.test.js +++ b/src/components/KeypressListener/__tests__/KeypressListener.test.js @@ -3,7 +3,7 @@ import { mount } from 'enzyme' import KeypressListener from '..' import Keys from '../../../constants/Keys' -const simulateKeyPress = (keyCode, modifier) => { +export const simulateKeyPress = (keyCode, modifier) => { const event = new Event('keyup') event.keyCode = keyCode if (modifier) { diff --git a/src/components/Pagination/Pagination.tsx b/src/components/Pagination/Pagination.tsx index 23b5df3e1..f3496ca52 100644 --- a/src/components/Pagination/Pagination.tsx +++ b/src/components/Pagination/Pagination.tsx @@ -6,6 +6,9 @@ import { namespaceComponent } from '../../utilities/component' import { noop } from '../../utilities/other' import { COMPONENT_KEY } from './Pagination.utils' import pluralize from '../../utilities/pluralize' +import KeypressListener from '../KeypressListener' +import Keys from '../../constants/Keys' +import { formatNumber } from '../../utilities/number' import { PaginationUI, @@ -20,6 +23,7 @@ import Icon from '../Icon' export interface Props { activePage: number className?: string + isLoading?: boolean innerRef: (node: HTMLElement) => void onChange: (nextPageNumber: number) => void rangePerPage: number @@ -33,6 +37,7 @@ export interface Props { export class Pagination extends React.PureComponent { static defaultProps = { activePage: 1, + isLoading: false, innerRef: noop, onChange: noop, rangePerPage: 50, @@ -120,7 +125,9 @@ export class Pagination extends React.PureComponent { renderRange() { const { separator, subject } = this.props const totalItems = this.getTotalItems() - const totalNode = {totalItems} + const totalNode = ( + {formatNumber(totalItems)} + ) if (!totalItems) { return subject ? totalNode : null @@ -128,9 +135,9 @@ export class Pagination extends React.PureComponent { return ( - {this.getStartRange()} + {formatNumber(this.getStartRange())} {` `}-{` `} - {this.getEndRange()} + {formatNumber(this.getEndRange())} {` `} {separator} {` `} @@ -140,18 +147,33 @@ export class Pagination extends React.PureComponent { } renderNavigation() { + const { isLoading } = this.props const currentPage = this.getCurrentPage() const isNotFirstPage = currentPage > 1 const isLastPage = currentPage >= this.getNumberOfPages() return ( + + {isNotFirstPage && [ , @@ -160,6 +182,8 @@ export class Pagination extends React.PureComponent { version={2} onClick={this.handlePrevClick} className="c-Pagination__prevButton" + disabled={isLoading} + title="Previous page (j)" > , @@ -167,17 +191,19 @@ export class Pagination extends React.PureComponent { diff --git a/src/components/Pagination/__tests__/Pagination.test.js b/src/components/Pagination/__tests__/Pagination.test.js index 3190bd86e..ae919c52f 100644 --- a/src/components/Pagination/__tests__/Pagination.test.js +++ b/src/components/Pagination/__tests__/Pagination.test.js @@ -3,7 +3,8 @@ import { mount } from 'enzyme' import { Pagination } from '../Pagination' import { NavigationUI } from '../Pagination.css' import { hasClass } from '../../../tests/helpers/enzyme' - +import { simulateKeyPress } from '../../KeypressListener/__tests__/KeypressListener.test' +import Keys from '../../../constants/Keys' describe('className', () => { test('Has a default className', () => { const wrapper = mount() @@ -155,6 +156,28 @@ describe('Navigation', () => { expect(last.props('disabled')).toBeTruthy() }) + test('Disables all buttons when loading', () => { + const wrapper = mount( + + ) + + const first = wrapper.find('Button.c-Pagination__firstButton').first() + const prev = wrapper.find('Button.c-Pagination__prevButton').first() + const next = wrapper.find('Button.c-Pagination__nextButton').first() + const last = wrapper.find('Button.c-Pagination__lastButton').first() + + expect(first.props('disabled')).toBeTruthy() + expect(prev.props('disabled')).toBeTruthy() + expect(next.props('disabled')).toBeTruthy() + expect(last.props('disabled')).toBeTruthy() + }) + test('Sets 1 as the minimum for currentPage', () => { const wrapper = mount( { expect(changeWatcher).not.toHaveBeenCalled() }) }) + +describe('Keyboard', () => { + test('Pressing j navigate to previous page', () => { + const totalItems = 17 + const rangePerPage = 5 + const changeWatcher = jest.fn() + + mount( + + ) + simulateKeyPress(Keys.KEY_J) + expect(changeWatcher).toHaveBeenCalledWith(1) + }) + + test('Pressing k navigate to next page', () => { + const totalItems = 17 + const rangePerPage = 5 + const changeWatcher = jest.fn() + + mount( + + ) + simulateKeyPress(Keys.KEY_K) + expect(changeWatcher).toHaveBeenCalledWith(2) + }) +}) diff --git a/src/utilities/__tests__/number.test.js b/src/utilities/__tests__/number.test.js index 716fef9b8..c9d7de49f 100644 --- a/src/utilities/__tests__/number.test.js +++ b/src/utilities/__tests__/number.test.js @@ -1,4 +1,4 @@ -import { isEven, isOdd, getMiddleIndex } from '../number' +import { isEven, isOdd, getMiddleIndex, formatNumber } from '../number' describe('isEven', () => { test('Should detect even numbers', () => { @@ -39,3 +39,16 @@ describe('getMiddleIndex', () => { expect(getMiddleIndex(100)).toBe(49) }) }) + +describe('formatNumber', () => { + test('Should format number', () => { + expect(formatNumber(4)).toBe('4') + expect(formatNumber(5000)).toBe('5,000') + expect(formatNumber(4500.23)).toBe('4,500.23') + expect(formatNumber(0)).toBe('0') + expect(formatNumber(null)).toBe(null) + expect(formatNumber(-10028.444)).toBe('-10,028.444') + expect(formatNumber(1032234234028.4)).toBe('1,032,234,234,028.4') + expect(formatNumber('test')).toBe('test') + }) +}) diff --git a/src/utilities/number.js b/src/utilities/number.js index 8cd88ebd3..9ac8cf774 100644 --- a/src/utilities/number.js +++ b/src/utilities/number.js @@ -1,3 +1,5 @@ +import { isDefined, isNumber } from './is' + export const isEven = (number: string): boolean => number % 2 === 0 export const isOdd = (number: string): boolean => !isEven(number) @@ -7,3 +9,10 @@ export const getMiddleIndex = (number: string): number => { return isOdd(number) ? middle : middle - 1 } + +export const formatNumber = num => { + if (!isDefined(num)) return num + if (!isNumber(num)) return num + + return num.toString().replace(/(\d)(?=(\d{3})+(?!\d))/g, '$1,') +} diff --git a/stories/Pagination.stories.js b/stories/Pagination.stories.js index bfd2f97ab..2e6dafaf0 100644 --- a/stories/Pagination.stories.js +++ b/stories/Pagination.stories.js @@ -94,6 +94,20 @@ stories.add('end of navigation', () => { ) }) +stories.add('isLoading', () => { + return ( + + ) +}) + class PaginationWrapper extends React.Component { state = { activePage: 1,