PageAccessoriesModal.jsx 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169
  1. import React, {
  2. useRef, useEffect, useCallback,
  3. } from 'react';
  4. import PropTypes from 'prop-types';
  5. import {
  6. Modal, ModalBody, Nav, NavItem, NavLink, TabContent, TabPane,
  7. } from 'reactstrap';
  8. import { withTranslation } from 'react-i18next';
  9. import PageListIcon from './Icons/PageListIcon';
  10. import TimeLineIcon from './Icons/TimeLineIcon';
  11. import RecentChangesIcon from './Icons/RecentChangesIcon';
  12. import AttachmentIcon from './Icons/AttachmentIcon';
  13. import ShareLinkIcon from './Icons/ShareLinkIcon';
  14. import { withUnstatedContainers } from './UnstatedUtils';
  15. import PageAccessoriesContainer from '../services/PageAccessoriesContainer';
  16. import PageAttachment from './PageAttachment';
  17. import PageTimeline from './PageTimeline';
  18. import PageList from './PageList';
  19. import PageHistory from './PageHistory';
  20. import ShareLink from './ShareLink/ShareLink';
  21. const navTabMapping = [
  22. {
  23. icon: <PageListIcon />,
  24. id: 'pagelist',
  25. i18n: 'page_list',
  26. index: 0,
  27. },
  28. {
  29. icon: <TimeLineIcon />,
  30. id: 'timeline',
  31. i18n: 'Timeline View',
  32. index: 1,
  33. },
  34. {
  35. icon: <RecentChangesIcon />,
  36. id: 'page-history',
  37. i18n: 'History',
  38. index: 2,
  39. },
  40. {
  41. icon: <AttachmentIcon />,
  42. id: 'attachment',
  43. i18n: 'attachment_data',
  44. index: 3,
  45. },
  46. {
  47. icon: <ShareLinkIcon />,
  48. id: 'share-link',
  49. i18n: 'share_links.share_link_management',
  50. index: 4,
  51. },
  52. ];
  53. const PageAccessoriesModal = (props) => {
  54. const { t, pageAccessoriesContainer } = props;
  55. const { switchActiveTab } = pageAccessoriesContainer;
  56. const { activeTab } = pageAccessoriesContainer.state;
  57. const sliderEl = useRef(null);
  58. const navTitle = document.getElementById('nav-title');
  59. const navTabs = document.querySelectorAll('li.nav-link');
  60. function changeFlexibility(width, tempMarginLeft) {
  61. sliderEl.current.width = `${width}%`;
  62. sliderEl.current.style.marginLeft = `${tempMarginLeft}%`;
  63. }
  64. function closeModalHandler() {
  65. if (props.onClose == null) {
  66. return;
  67. }
  68. props.onClose();
  69. }
  70. // Might make this dynamic for px, %, pt, em
  71. function getPercentage(min, max) {
  72. return min / max * 100;
  73. }
  74. const fetchSize = useCallback(() => {
  75. return [].map.call(navTabs, (el) => {
  76. const width = getPercentage(el.offsetWidth, navTitle.offsetWidth);
  77. return width;
  78. });
  79. }, [navTabs, navTitle]);
  80. useEffect(() => {
  81. const array = fetchSize();
  82. if (activeTab === '') {
  83. return;
  84. }
  85. const result = navTabMapping.find(({ id }) => id === activeTab);
  86. const { index } = result;
  87. let marginLeft = 0;
  88. for (let i = 0; i < index; i++) {
  89. marginLeft += array[i];
  90. }
  91. changeFlexibility(array[index], marginLeft);
  92. // eslint-disable-next-line react-hooks/exhaustive-deps
  93. }, [activeTab]);
  94. return (
  95. <React.Fragment>
  96. <Modal size="xl" isOpen={props.isOpen} toggle={closeModalHandler} className="grw-page-accessories-modal">
  97. <ModalBody>
  98. <Nav className="nav-title" id="nav-title">
  99. {navTabMapping.map((tab, index) => {
  100. return (
  101. <NavItem key={tab.id} type="button" className={`nav-link ${activeTab === tab.id && 'active'}`}>
  102. <NavLink onClick={() => { switchActiveTab(tab.id) }}>
  103. {tab.icon}
  104. {t(tab.i18n)}
  105. </NavLink>
  106. </NavItem>
  107. );
  108. })}
  109. </Nav>
  110. <hr ref={sliderEl} id="grw-nav-slide-hr" className="my-0" />
  111. <TabContent activeTab={activeTab}>
  112. <TabPane tabId="pagelist">
  113. {pageAccessoriesContainer.state.activeComponents.has('pagelist') && <PageList />}
  114. </TabPane>
  115. <TabPane tabId="timeline" className="p-4">
  116. {pageAccessoriesContainer.state.activeComponents.has('timeline') && <PageTimeline /> }
  117. </TabPane>
  118. <TabPane tabId="page-history">
  119. <div className="overflow-auto">
  120. {pageAccessoriesContainer.state.activeComponents.has('page-history') && <PageHistory /> }
  121. </div>
  122. </TabPane>
  123. <TabPane tabId="attachment" className="p-4">
  124. {pageAccessoriesContainer.state.activeComponents.has('attachment') && <PageAttachment />}
  125. </TabPane>
  126. <TabPane tabId="share-link" className="p-4">
  127. {pageAccessoriesContainer.state.activeComponents.has('share-link') && <ShareLink />}
  128. </TabPane>
  129. </TabContent>
  130. </ModalBody>
  131. </Modal>
  132. </React.Fragment>
  133. );
  134. };
  135. /**
  136. * Wrapper component for using unstated
  137. */
  138. const PageAccessoriesModalWrapper = withUnstatedContainers(PageAccessoriesModal, [PageAccessoriesContainer]);
  139. PageAccessoriesModal.propTypes = {
  140. t: PropTypes.func.isRequired, // i18next
  141. // pageContainer: PropTypes.instanceOf(PageContainer).isRequired,
  142. pageAccessoriesContainer: PropTypes.instanceOf(PageAccessoriesContainer).isRequired,
  143. isOpen: PropTypes.bool.isRequired,
  144. onClose: PropTypes.func,
  145. };
  146. export default withTranslation()(PageAccessoriesModalWrapper);