PageAccessoriesModal.jsx 5.7 KB

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