fix(ui): rewrite Pagination with hooks

This commit is contained in:
Łukasz Mierzwa
2020-06-10 13:14:50 +01:00
committed by Łukasz Mierzwa
parent 6fe85732b0
commit 1c4e8fc161
4 changed files with 104 additions and 91 deletions

View File

@@ -57,7 +57,6 @@ const LabelSetList = ({ alertStore, labelsList }) => {
</div>
<PageSelect
totalPages={Math.ceil(labelsList.length / maxPerPage)}
activePage={activePage}
maxPerPage={maxPerPage}
totalItemsCount={labelsList.length}
setPageCallback={setActivePage}

View File

@@ -1,4 +1,4 @@
import React, { Component } from "react";
import React, { useState, useCallback, useEffect } from "react";
import PropTypes from "prop-types";
import { HotKeys } from "react-hotkeys";
@@ -13,82 +13,90 @@ import { faAngleDoubleRight } from "@fortawesome/free-solid-svg-icons/faAngleDou
import { IsMobile } from "Common/Device";
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,
};
const PageSelect = ({
totalItemsCount,
totalPages,
maxPerPage,
initialPage,
setPageCallback,
}) => {
const [activePage, setActivePage] = useState(initialPage);
constructor(props) {
super(props);
this.HotKeysRef = React.createRef();
}
useEffect(() => {
if (activePage > totalPages) {
const page = Math.max(1, totalPages);
setActivePage(page);
setPageCallback(page);
}
}, [activePage, maxPerPage, totalPages, setPageCallback]);
onPageUp = () => {
const { setPageCallback, activePage, totalPages } = this.props;
setPageCallback(Math.min(activePage + 1, totalPages));
};
const onChange = useCallback(
(page) => {
setActivePage(page);
setPageCallback(page);
},
[setPageCallback]
);
onPageDown = () => {
const { setPageCallback, activePage } = this.props;
setPageCallback(Math.max(activePage - 1, 1));
};
const onPageUp = useCallback(() => {
const page = Math.min(activePage + 1, totalPages);
setActivePage(page);
setPageCallback(page);
}, [activePage, setPageCallback, totalPages]);
componentDidMount() {
this.HotKeysRef.current.focus();
}
const onPageDown = useCallback(() => {
const page = Math.max(activePage - 1, 1);
setActivePage(page);
setPageCallback(page);
}, [activePage, setPageCallback]);
render() {
const {
totalItemsCount,
totalPages,
maxPerPage,
activePage,
setPageCallback,
} = this.props;
const isMobile = IsMobile();
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={isMobile ? 3 : 5}
onChange={setPageCallback}
hideFirstLastPages={totalPages < 10}
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>
);
}
}
return (
<HotKeys
className="components-pagination"
innerRef={(r) => r && r.focus()}
keyMap={{
onArrowLeft: "ArrowLeft",
onArrowRight: "ArrowRight",
}}
handlers={{
onArrowLeft: onPageDown,
onArrowRight: onPageUp,
}}
allowChanges
>
{totalItemsCount > maxPerPage ? (
<div className="mt-3">
<Pagination
activePage={activePage}
itemsCountPerPage={maxPerPage}
totalItemsCount={totalItemsCount}
pageRangeDisplayed={IsMobile() ? 3 : 5}
onChange={onChange}
hideFirstLastPages={totalPages < 10}
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>
);
};
PageSelect.propTypes = {
totalPages: PropTypes.number.isRequired,
initialPage: PropTypes.number,
maxPerPage: PropTypes.number.isRequired,
totalItemsCount: PropTypes.number.isRequired,
setPageCallback: PropTypes.func.isRequired,
};
PageSelect.defaultProps = {
initialPage: 1,
};
export { PageSelect };

View File

@@ -26,7 +26,6 @@ describe("<PageSelect />", () => {
const tree = mount(
<PageSelect
totalPages={4}
activePage={1}
maxPerPage={5}
totalItemsCount={17}
setPageCallback={setPageCallback}
@@ -34,10 +33,6 @@ describe("<PageSelect />", () => {
);
tree.simulate("focus");
setPageCallback.mockImplementation((val) =>
tree.setProps({ activePage: val })
);
PressKey(tree, "ArrowRight", 39);
expect(setPageCallback).toHaveBeenLastCalledWith(2);
@@ -68,7 +63,6 @@ describe("<PageSelect />", () => {
const tree = mount(
<PageSelect
totalPages={7}
activePage={1}
maxPerPage={5}
totalItemsCount={35}
setPageCallback={jest.fn()}
@@ -82,7 +76,6 @@ describe("<PageSelect />", () => {
const tree = mount(
<PageSelect
totalPages={7}
activePage={1}
maxPerPage={5}
totalItemsCount={35}
setPageCallback={jest.fn()}
@@ -90,4 +83,27 @@ describe("<PageSelect />", () => {
);
expect(tree.find(".page-link")).toHaveLength(5);
});
it("resets page if activePage >= totalPages", () => {
const setPageCallback = jest.fn();
const tree = mount(
<PageSelect
initialPage={3}
totalPages={7}
maxPerPage={5}
totalItemsCount={35}
setPageCallback={setPageCallback}
/>
);
expect(tree.find(".page-item").at(3).hasClass("active")).toBe(true);
tree.setProps({ totalPages: 2 });
tree.update();
expect(tree.find(".page-item").at(2).hasClass("active")).toBe(true);
expect(setPageCallback).toHaveBeenLastCalledWith(2);
tree.setProps({ totalPages: 5 });
tree.update();
expect(tree.find(".page-item").at(2).hasClass("active")).toBe(true);
});
});

View File

@@ -77,15 +77,6 @@ const Browser = ({
{ deps: [currentTime] }
);
useEffect(() => {
if (response) {
const totalPages = Math.ceil(response.length / maxPerPage);
if (activePage > totalPages) {
setActivePage(Math.max(1, totalPages));
}
}
}, [activePage, maxPerPage, response]);
useEffect(() => {
const timer = setInterval(() => {
setCurrentTime(Math.floor(Date.now() / 1000));
@@ -168,7 +159,6 @@ const Browser = ({
))}
<PageSelect
totalPages={Math.ceil(response.length / maxPerPage)}
activePage={activePage}
maxPerPage={maxPerPage}
totalItemsCount={response.length}
setPageCallback={setActivePage}