feat(ui): add a pagination component with keyboard shortcuts

This commit is contained in:
Łukasz Mierzwa
2020-02-28 21:34:10 +00:00
parent d4b737833c
commit 26963b4d3b
6 changed files with 151 additions and 0 deletions

View File

@@ -0,0 +1,89 @@
import React, { Component } from "react";
import PropTypes from "prop-types";
import { HotKeys } from "react-hotkeys";
import Pagination from "react-js-pagination";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { faAngleLeft } from "@fortawesome/free-solid-svg-icons/faAngleLeft";
import { faAngleRight } from "@fortawesome/free-solid-svg-icons/faAngleRight";
import { faAngleDoubleLeft } from "@fortawesome/free-solid-svg-icons/faAngleDoubleLeft";
import { faAngleDoubleRight } from "@fortawesome/free-solid-svg-icons/faAngleDoubleRight";
class PageSelect extends Component {
static propTypes = {
totalPages: PropTypes.number.isRequired,
activePage: PropTypes.number.isRequired,
maxPerPage: PropTypes.number.isRequired,
totalItemsCount: PropTypes.number.isRequired,
setPageCallback: PropTypes.func.isRequired
};
constructor(props) {
super(props);
this.HotKeysRef = React.createRef();
}
onPageUp = () => {
const { setPageCallback, activePage, totalPages } = this.props;
setPageCallback(Math.min(activePage + 1, totalPages));
};
onPageDown = () => {
const { setPageCallback, activePage } = this.props;
setPageCallback(Math.max(activePage - 1, 1));
};
componentDidMount() {
this.HotKeysRef.current.focus();
}
render() {
const {
totalItemsCount,
maxPerPage,
activePage,
setPageCallback
} = this.props;
return (
<HotKeys
className="components-pagination"
innerRef={this.HotKeysRef}
keyMap={{
onArrowLeft: "ArrowLeft",
onArrowRight: "ArrowRight"
}}
handlers={{
onArrowLeft: this.onPageDown,
onArrowRight: this.onPageUp
}}
>
{totalItemsCount > maxPerPage ? (
<div className="mt-3">
<Pagination
activePage={activePage}
itemsCountPerPage={maxPerPage}
totalItemsCount={totalItemsCount}
pageRangeDisplayed={5}
onChange={setPageCallback}
hideFirstLastPages={totalItemsCount / maxPerPage < 20}
innerClass="pagination justify-content-center"
itemClass="page-item"
linkClass="page-link"
activeClass="active"
activeLinkClass="font-weight-bold"
prevPageText={<FontAwesomeIcon icon={faAngleLeft} />}
nextPageText={<FontAwesomeIcon icon={faAngleRight} />}
firstPageText={<FontAwesomeIcon icon={faAngleDoubleLeft} />}
lastPageText={<FontAwesomeIcon icon={faAngleDoubleRight} />}
/>
</div>
) : null}
</HotKeys>
);
}
}
export { PageSelect };

View File

@@ -0,0 +1,51 @@
import React from "react";
import { mount } from "enzyme";
import { PressKey } from "__mocks__/KeyPress";
import { PageSelect } from ".";
describe("<PageSelect />", () => {
it("calls setPageCallback on arrow key press", () => {
const setPageCallback = jest.fn();
const tree = mount(
<PageSelect
totalPages={4}
activePage={1}
maxPerPage={5}
totalItemsCount={17}
setPageCallback={setPageCallback}
/>
);
tree.simulate("focus");
setPageCallback.mockImplementation(val =>
tree.setProps({ activePage: val })
);
PressKey(tree, "ArrowRight", 39);
expect(setPageCallback).toHaveBeenLastCalledWith(2);
PressKey(tree, "ArrowRight", 39);
expect(setPageCallback).toHaveBeenLastCalledWith(3);
PressKey(tree, "ArrowRight", 39);
expect(setPageCallback).toHaveBeenLastCalledWith(4);
PressKey(tree, "ArrowRight", 39);
expect(setPageCallback).toHaveBeenLastCalledWith(4);
PressKey(tree, "ArrowLeft", 37);
expect(setPageCallback).toHaveBeenLastCalledWith(3);
PressKey(tree, "ArrowLeft", 37);
expect(setPageCallback).toHaveBeenLastCalledWith(2);
PressKey(tree, "ArrowLeft", 37);
expect(setPageCallback).toHaveBeenLastCalledWith(1);
PressKey(tree, "ArrowLeft", 37);
expect(setPageCallback).toHaveBeenLastCalledWith(1);
});
});

View File

@@ -0,0 +1,3 @@
.components-pagination:focus {
outline: none;
}

View File

@@ -122,6 +122,7 @@ $color-default: #708090;
@import "Styles/Components/MountFade";
@import "Styles/Components/NavBarSlide";
@import "Styles/Components/SilenceModal";
@import "Styles/Components/Pagination";
.badge,
.modal-content {

View File

@@ -105,6 +105,7 @@ $color-default: #708090;
@import "Styles/Components/MountFade";
@import "Styles/Components/NavBarSlide";
@import "Styles/Components/SilenceModal";
@import "Styles/Components/Pagination";
a {
color: $link-color;

View File

@@ -0,0 +1,6 @@
const PressKey = (tree, key, code) => {
tree.simulate("keyDown", { key: key, keyCode: code, which: code });
tree.simulate("keyUp", { key: key, keyCode: code, which: code });
};
export { PressKey };