PageAccessoriesModal.jsx 4.9 KB

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