diff --git a/client/src/components/DataTable.js b/client/src/components/DataTable.js index edff89154..7c26f36dd 100644 --- a/client/src/components/DataTable.js +++ b/client/src/components/DataTable.js @@ -16,7 +16,7 @@ import { ScrollSync, ScrollSyncPane } from 'react-scroll-sync'; import { ConditionalWrapper } from 'utils'; import { useUpdateEffect } from 'hooks'; -import { If } from 'components'; +import { If, Pagination } from 'components'; const IndeterminateCheckbox = React.forwardRef( ({ indeterminate, ...rest }, ref) => { @@ -46,6 +46,11 @@ export default function DataTable({ expandToggleColumn = 2, noInitialFetch = false, spinnerProps = { size: 40 }, + + pagination = false, + pagesCount: controlledPageCount, + initialPageIndex, + initialPageSize, }) { const { getTableProps, @@ -59,18 +64,28 @@ export default function DataTable({ isAllRowsExpanded, totalColumnsWidth, + // page, + pageCount, + canPreviousPage, + canNextPage, + gotoPage, + previousPage, + nextPage, + setPageSize, + // Get the state from the instance state: { pageIndex, pageSize, sortBy, selectedRowIds }, } = useTable( { columns, data: data, - initialState: { pageIndex: 0, expanded }, // Pass our hoisted table state - manualPagination: true, // Tell the usePagination - // hook that we'll handle our own data fetching - // This means we'll also have to provide our own - // pageCount. - // pageCount: controlledPageCount, + initialState: { + pageIndex: initialPageIndex, + pageSize: initialPageSize, + expanded, + }, // Pass our hoisted table state + manualPagination: true, + pageCount: controlledPageCount, getSubRows: (row) => row.children, manualSortBy, expandSubRows, @@ -80,10 +95,10 @@ export default function DataTable({ useSortBy, useExpanded, useRowSelect, - usePagination, useResizeColumns, useFlexLayout, useSticky, + usePagination, (hooks) => { hooks.visibleColumns.push((columns) => [ // Let's make a column for selection @@ -197,6 +212,7 @@ export default function DataTable({ {...cell.getCellProps({ className: classnames(cell.column.className || '', 'td'), })} + onContextMenu={handleRowContextMenu(cell, row)} > {RenderCell({ cell, row, index })} @@ -337,6 +353,21 @@ export default function DataTable({ + + + { + gotoPage(currentPage - 1); + }} + onPageSizeChange={(pageSize, currentPage) => { + gotoPage(currentPage - 1); + setPageSize(pageSize); + }} + /> + ); } diff --git a/client/src/components/Pagination.js b/client/src/components/Pagination.js new file mode 100644 index 000000000..29eb475de --- /dev/null +++ b/client/src/components/Pagination.js @@ -0,0 +1,218 @@ +import React, { useReducer, useEffect } from 'react'; +import classNames from 'classnames'; +import { Button, ButtonGroup, Intent, HTMLSelect, } from '@blueprintjs/core'; +import { FormattedMessage as T } from 'react-intl'; +import PropTypes from 'prop-types'; +import { range } from 'lodash'; +import { Icon } from 'components'; + +const getState = ({ currentPage, size, total }) => { + const totalPages = Math.ceil(total / size); + const visibleItems = 5; + const halfVisibleItems = Math.ceil(visibleItems / 2); + + // create an array of pages to ng-repeat in the pager control + let startPage, endPage; + if (totalPages <= visibleItems) { + // less than {visibleItems} total pages so show + startPage = 1; + endPage = totalPages; + } else { + // more than {visibleItems} total pages so calculate start and end pages + if (currentPage <= halfVisibleItems) { + startPage = 1; + endPage = visibleItems; + } else if (currentPage + (halfVisibleItems - 1) >= totalPages) { + startPage = totalPages - (visibleItems - 1); + endPage = totalPages; + } else { + startPage = currentPage - halfVisibleItems; + endPage = currentPage + halfVisibleItems - 1; + } + } + const pages = [...Array(endPage + 1 - startPage).keys()].map( + (i) => startPage + i, + ); + + // Too large or small currentPage + let correctCurrentpage = currentPage; + if (currentPage > totalPages) correctCurrentpage = totalPages; + if (currentPage <= 0) correctCurrentpage = 1; + + return { + currentPage: correctCurrentpage, + size, + total, + pages, + totalPages, + }; +}; + +const TYPE = { + PAGE_CHANGE: 'PAGE_CHANGE', + PAGE_SIZE_CHANGE: 'PAGE_SIZE_CHANGE', + INITIALIZE: 'INITIALIZE', +}; +const reducer = (state, action) => { + switch (action.type) { + case TYPE.PAGE_CHANGE: + return getState({ + currentPage: action.page, + size: state.size, + total: state.total, + }); + case TYPE.PAGE_SIZE_CHANGE: + return getState({ + currentPage: state.currentPage, + size: action.size, + total: state.total, + }); + case TYPE.INITIALIZE: + return getState({ + currentPage: state.currentPage, + size: action.size, + total: action.total, + }); + default: + throw new Error(); + } +}; + +const Pagination = ({ + initialPage, + total, + size, + pageSizesOptions = [5, 12, 20, 30, 50, 75, 100, 150], + onPageChange, + onPageSizeChange, +}) => { + const [state, dispatch] = useReducer( + reducer, + { currentPage: initialPage, total, size }, + getState, + ); + + useEffect(() => { + dispatch({ + type: 'INITIALIZE', + total, + size, + }); + }, [total, size]); + + return ( + + ); +}; + +Pagination.propTypes = { + initialPage: PropTypes.number.isRequired, + size: PropTypes.number.isRequired, + total: PropTypes.number.isRequired, + onPageChange: PropTypes.func, + onPageSizeChange: PropTypes.func, +}; + +Pagination.defaultProps = { + initialPage: 1, + size: 25, +}; + +export default Pagination; diff --git a/client/src/components/index.js b/client/src/components/index.js index df0a8242a..12fa1df92 100644 --- a/client/src/components/index.js +++ b/client/src/components/index.js @@ -10,6 +10,7 @@ import ErrorMessage from './ErrorMessage'; import MODIFIER from './modifiers'; import FieldHint from './FieldHint'; import MenuItemLabel from './MenuItemLabel'; +import Pagination from './Pagination'; const Hint = FieldHint; @@ -27,5 +28,6 @@ export { FieldHint, Hint, MenuItemLabel, + Pagination, // For, }; \ No newline at end of file diff --git a/client/src/containers/Accounting/ManualJournalsDataTable.js b/client/src/containers/Accounting/ManualJournalsDataTable.js index 40a0ca25c..ef41f1a16 100644 --- a/client/src/containers/Accounting/ManualJournalsDataTable.js +++ b/client/src/containers/Accounting/ManualJournalsDataTable.js @@ -11,7 +11,7 @@ import { Position, Tag, } from '@blueprintjs/core'; -import { useParams } from 'react-router-dom'; +import { withRouter, useParams } from 'react-router-dom'; import { FormattedMessage as T, useIntl } from 'react-intl'; import moment from 'moment'; @@ -29,18 +29,21 @@ import withViewDetails from 'containers/Views/withViewDetails'; import withManualJournals from 'containers/Accounting/withManualJournals'; import withManualJournalsActions from 'containers/Accounting/withManualJournalsActions'; - function ManualJournalsDataTable({ loading, - manualJournals, + // #withManualJournals + manualJournalsCurrentPage, manualJournalsLoading, + manualJournalsPagination, + manualJournalsTableQuery, // #withDashboardActions changeCurrentView, changePageSubtitle, setTopbarEditView, + // #withViewDetails viewId, viewMeta, @@ -96,27 +99,6 @@ function ManualJournalsDataTable({ [onDeleteJournal], ); - // const actionMenuList = (journal) => ( - // - // } /> - // - // {!journal.status && ( - // } - // onClick={handlePublishJournal(journal)} - // /> - // )} - // } - // onClick={handleEditJournal(journal)} - // /> - // } - // intent={Intent.DANGER} - // onClick={handleDeleteJournal(journal)} - // /> - // - // ); const actionMenuList = useCallback( (journal) => ( @@ -171,13 +153,9 @@ function ManualJournalsDataTable({ Header: formatMessage({ id: 'status' }), accessor: (r) => { return r.status ? ( - - - + ) : ( - - - + ); }, disableResizing: true, @@ -227,7 +205,7 @@ function ManualJournalsDataTable({ content={actionMenuList(cell.row.original)} position={Position.RIGHT_BOTTOM} > -