PaginationWrapper.jsx 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175
  1. import React, { useCallback, useMemo } from 'react';
  2. import PropTypes from 'prop-types';
  3. import { Pagination, PaginationItem, PaginationLink } from 'reactstrap';
  4. /**
  5. *
  6. * @author Mikitaka Itizawa <itizawa@weseek.co.jp>
  7. *
  8. * @export
  9. * @class PaginationWrapper
  10. * @extends {React.Component}
  11. */
  12. const PaginationWrapper = React.memo((props) => {
  13. const {
  14. activePage, changePage, totalItemsCount, pagingLimit, align,
  15. } = props;
  16. /**
  17. * various numbers used to generate pagination dom
  18. */
  19. const paginationNumbers = useMemo(() => {
  20. // avoid using null
  21. const limit = pagingLimit || Infinity;
  22. // calc totalPageNumber
  23. const totalPage = Math.floor(totalItemsCount / limit) + (totalItemsCount % limit === 0 ? 0 : 1);
  24. let paginationStart = activePage - 2;
  25. let maxViewPageNum = activePage + 2;
  26. // if pagiNation Number area size = 5 , pageNumber is calculated here
  27. // activePage Position calculate ex. 4 5 [6] 7 8 (Page8 over is Max), 3 4 5 [6] 7 (Page7 is Max)
  28. if (paginationStart < 1) {
  29. const diff = 1 - paginationStart;
  30. paginationStart += diff;
  31. maxViewPageNum = Math.min(totalPage, maxViewPageNum + diff);
  32. }
  33. if (maxViewPageNum > totalPage) {
  34. const diff = maxViewPageNum - totalPage;
  35. maxViewPageNum -= diff;
  36. paginationStart = Math.max(1, paginationStart - diff);
  37. }
  38. return {
  39. totalPage,
  40. paginationStart,
  41. maxViewPageNum,
  42. };
  43. }, [activePage, totalItemsCount, pagingLimit]);
  44. const { paginationStart } = paginationNumbers;
  45. const { maxViewPageNum } = paginationNumbers;
  46. const { totalPage } = paginationNumbers;
  47. /**
  48. * generate Elements of Pagination First Prev
  49. * ex. << < 1 2 3 > >>
  50. * this function set << & <
  51. */
  52. const generateFirstPrev = useCallback(() => {
  53. const paginationItems = [];
  54. if (activePage !== 1) {
  55. paginationItems.push(
  56. <PaginationItem key="painationItemFirst">
  57. <PaginationLink first onClick={() => { return changePage(1) }} />
  58. </PaginationItem>,
  59. <PaginationItem key="painationItemPrevious">
  60. <PaginationLink previous onClick={() => { return changePage(activePage - 1) }} />
  61. </PaginationItem>,
  62. );
  63. }
  64. else {
  65. paginationItems.push(
  66. <PaginationItem key="painationItemFirst" disabled>
  67. <PaginationLink first />
  68. </PaginationItem>,
  69. <PaginationItem key="painationItemPrevious" disabled>
  70. <PaginationLink previous />
  71. </PaginationItem>,
  72. );
  73. }
  74. return paginationItems;
  75. }, [activePage, changePage]);
  76. /**
  77. * generate Elements of Pagination First Prev
  78. * ex. << < 4 5 6 7 8 > >>, << < 1 2 3 4 > >>
  79. * this function set numbers
  80. */
  81. const generatePaginations = useCallback(() => {
  82. const paginationItems = [];
  83. for (let number = paginationStart; number <= maxViewPageNum; number++) {
  84. paginationItems.push(
  85. <PaginationItem key={`paginationItem-${number}`} active={number === activePage}>
  86. <PaginationLink onClick={() => { return changePage(number) }}>
  87. {number}
  88. </PaginationLink>
  89. </PaginationItem>,
  90. );
  91. }
  92. return paginationItems;
  93. }, [activePage, changePage, paginationStart, maxViewPageNum]);
  94. /**
  95. * generate Elements of Pagination First Prev
  96. * ex. << < 1 2 3 > >>
  97. * this function set > & >>
  98. */
  99. const generateNextLast = useCallback(() => {
  100. const paginationItems = [];
  101. if (totalPage !== activePage) {
  102. paginationItems.push(
  103. <PaginationItem key="painationItemNext">
  104. <PaginationLink next onClick={() => { return changePage(activePage + 1) }} />
  105. </PaginationItem>,
  106. <PaginationItem key="painationItemLast">
  107. <PaginationLink last onClick={() => { return changePage(totalPage) }} />
  108. </PaginationItem>,
  109. );
  110. }
  111. else {
  112. paginationItems.push(
  113. <PaginationItem key="painationItemNext" disabled>
  114. <PaginationLink next />
  115. </PaginationItem>,
  116. <PaginationItem key="painationItemLast" disabled>
  117. <PaginationLink last />
  118. </PaginationItem>,
  119. );
  120. }
  121. return paginationItems;
  122. }, [activePage, changePage, totalPage]);
  123. const getListClassName = useMemo(() => {
  124. const listClassNames = [];
  125. if (align === 'center') {
  126. listClassNames.push('justify-content-center');
  127. }
  128. if (align === 'right') {
  129. listClassNames.push('justify-content-end');
  130. }
  131. return listClassNames.join(' ');
  132. }, [align]);
  133. return (
  134. <React.Fragment>
  135. <Pagination size={props.size} listClassName={getListClassName}>
  136. {generateFirstPrev()}
  137. {generatePaginations()}
  138. {generateNextLast()}
  139. </Pagination>
  140. </React.Fragment>
  141. );
  142. });
  143. PaginationWrapper.propTypes = {
  144. activePage: PropTypes.number.isRequired,
  145. changePage: PropTypes.func.isRequired,
  146. totalItemsCount: PropTypes.number.isRequired,
  147. pagingLimit: PropTypes.number,
  148. align: PropTypes.string,
  149. size: PropTypes.string,
  150. };
  151. PaginationWrapper.defaultProps = {
  152. align: 'left',
  153. size: 'md',
  154. pagingLimit: Infinity,
  155. };
  156. export default PaginationWrapper;