PaginationWrapper.jsx 5.0 KB

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