diff --git a/src/visits/SortableBarGraph.js b/src/visits/SortableBarGraph.js index a3efaf58..dc64e71f 100644 --- a/src/visits/SortableBarGraph.js +++ b/src/visits/SortableBarGraph.js @@ -1,4 +1,4 @@ -import React from 'react'; +import React, { useState } from 'react'; import PropTypes from 'prop-types'; import { fromPairs, head, keys, pipe, prop, reverse, sortBy, splitEvery, toLower, toPairs, type, zipObj } from 'ramda'; import SortingDropdown from '../utils/SortingDropdown'; @@ -8,73 +8,78 @@ import { roundTen } from '../utils/helpers/numbers'; import SimplePaginator from '../common/SimplePaginator'; import GraphCard from './GraphCard'; -const { max } = Math; +const propTypes = { + stats: PropTypes.object.isRequired, + highlightedStats: PropTypes.object, + highlightedLabel: PropTypes.string, + title: PropTypes.string.isRequired, + sortingItems: PropTypes.object.isRequired, + extraHeaderContent: PropTypes.func, + withPagination: PropTypes.bool, + onClick: PropTypes.func, +}; + const toLowerIfString = (value) => type(value) === 'String' ? toLower(value) : value; const pickKeyFromPair = ([ key ]) => key; const pickValueFromPair = ([ , value ]) => value; -export default class SortableBarGraph extends React.Component { - static propTypes = { - stats: PropTypes.object.isRequired, - highlightedStats: PropTypes.object, - highlightedLabel: PropTypes.string, - title: PropTypes.string.isRequired, - sortingItems: PropTypes.object.isRequired, - extraHeaderContent: PropTypes.func, - withPagination: PropTypes.bool, - onClick: PropTypes.func, - }; - - state = { +const SortableBarGraph = ({ + stats, + highlightedStats, + title, + sortingItems, + extraHeaderContent, + withPagination = true, + ...rest +}) => { + const [ order, setOrder ] = useState({ orderField: undefined, orderDir: undefined, - currentPage: 1, - itemsPerPage: 50, - }; + }); + const [ currentPage, setCurrentPage ] = useState(1); + const [ itemsPerPage, setItemsPerPage ] = useState(50); - getSortedPairsForStats(stats, sortingItems) { + const getSortedPairsForStats = (stats, sortingItems) => { const pairs = toPairs(stats); - const sortedPairs = !this.state.orderField ? pairs : sortBy( + const sortedPairs = !order.orderField ? pairs : sortBy( pipe( - prop(this.state.orderField === head(keys(sortingItems)) ? 0 : 1), + prop(order.orderField === head(keys(sortingItems)) ? 0 : 1), toLowerIfString ), pairs ); - return !this.state.orderDir || this.state.orderDir === 'ASC' ? sortedPairs : reverse(sortedPairs); - } - - determineStats(stats, highlightedStats, sortingItems) { - const sortedPairs = this.getSortedPairsForStats(stats, sortingItems); + return !order.orderDir || order.orderDir === 'ASC' ? sortedPairs : reverse(sortedPairs); + }; + const determineStats = (stats, highlightedStats, sortingItems) => { + const sortedPairs = getSortedPairsForStats(stats, sortingItems); const sortedKeys = sortedPairs.map(pickKeyFromPair); // The highlighted stats have to be ordered based on the regular stats, not on its own values const sortedHighlightedPairs = highlightedStats && toPairs( { ...zipObj(sortedKeys, sortedKeys.map(() => 0)), ...highlightedStats } ); - if (sortedPairs.length <= this.state.itemsPerPage) { + if (sortedPairs.length <= itemsPerPage) { return { currentPageStats: fromPairs(sortedPairs), currentPageHighlightedStats: sortedHighlightedPairs && fromPairs(sortedHighlightedPairs), }; } - const pages = splitEvery(this.state.itemsPerPage, sortedPairs); - const highlightedPages = sortedHighlightedPairs && splitEvery(this.state.itemsPerPage, sortedHighlightedPairs); + const pages = splitEvery(itemsPerPage, sortedPairs); + const highlightedPages = sortedHighlightedPairs && splitEvery(itemsPerPage, sortedHighlightedPairs); return { - currentPageStats: fromPairs(this.determineCurrentPagePairs(pages)), - currentPageHighlightedStats: highlightedPages && fromPairs(this.determineCurrentPagePairs(highlightedPages)), - pagination: this.renderPagination(pages.length), - max: roundTen(max(...sortedPairs.map(pickValueFromPair))), + currentPageStats: fromPairs(determineCurrentPagePairs(pages)), + currentPageHighlightedStats: highlightedPages && fromPairs(determineCurrentPagePairs(highlightedPages)), + pagination: renderPagination(pages.length), + max: roundTen(Math.max(...sortedPairs.map(pickValueFromPair))), }; - } + }; + const determineCurrentPagePairs = (pages) => { + const page = pages[currentPage - 1]; - determineCurrentPagePairs(pages) { - const page = pages[this.state.currentPage - 1]; - - if (this.state.currentPage < pages.length) { + if (currentPage < pages.length) { return page; } @@ -82,72 +87,60 @@ export default class SortableBarGraph extends React.Component { // Using the "hidden" key, the chart will just replace the label by an empty string return [ ...page, ...rangeOf(firstPageLength - page.length, (i) => [ `hidden_${i}`, 0 ]) ]; - } + }; + const renderPagination = (pagesCount) => + ; - renderPagination(pagesCount) { - const { currentPage } = this.state; - const setCurrentPage = (currentPage) => this.setState({ currentPage }); - - return ; - } - - render() { - const { - stats, - highlightedStats, - sortingItems, - title, - extraHeaderContent, - withPagination = true, - ...rest - } = this.props; - const { currentPageStats, currentPageHighlightedStats, pagination, max } = this.determineStats( - stats, - highlightedStats && keys(highlightedStats).length > 0 ? highlightedStats : undefined, - sortingItems - ); - const activeCities = keys(currentPageStats); - const computeTitle = () => ( - - {title} + const { currentPageStats, currentPageHighlightedStats, pagination, max } = determineStats( + stats, + highlightedStats && keys(highlightedStats).length > 0 ? highlightedStats : undefined, + sortingItems + ); + const activeCities = keys(currentPageStats); + const computeTitle = () => ( + + {title} +
+ setOrder({ orderField, orderDir }) || setCurrentPage(1)} + /> +
+ {withPagination && keys(stats).length > 50 && (
- this.setState({ orderField, orderDir, currentPage: 1 })} + setItemsPerPage(itemsPerPage) || setCurrentPage(1)} />
- {withPagination && keys(stats).length > 50 && ( -
- this.setState({ itemsPerPage, currentPage: 1 })} - /> -
- )} - {extraHeaderContent && ( -
- {extraHeaderContent(pagination ? activeCities : undefined)} -
- )} -
- ); + )} + {extraHeaderContent && ( +
+ {extraHeaderContent(pagination ? activeCities : undefined)} +
+ )} +
+ ); - return ( - - ); - } -} + return ( + + ); +}; + +SortableBarGraph.propTypes = propTypes; + +export default SortableBarGraph;