|
|
@@ -1,15 +1,14 @@
|
|
|
-import React, { useEffect, useState } from 'react';
|
|
|
+import React, { useCallback, useMemo, useState } from 'react';
|
|
|
import PropTypes from 'prop-types';
|
|
|
|
|
|
import {
|
|
|
- Modal, ModalBody, ModalHeader, Nav, NavItem, NavLink, TabContent, TabPane,
|
|
|
+ Modal, ModalBody, ModalHeader, TabContent, TabPane,
|
|
|
} from 'reactstrap';
|
|
|
|
|
|
import { withTranslation } from 'react-i18next';
|
|
|
-
|
|
|
import PageListIcon from './Icons/PageListIcon';
|
|
|
import TimeLineIcon from './Icons/TimeLineIcon';
|
|
|
-import RecentChangesIcon from './Icons/RecentChangesIcon';
|
|
|
+import HistoryIcon from './Icons/HistoryIcon';
|
|
|
import AttachmentIcon from './Icons/AttachmentIcon';
|
|
|
import ShareLinkIcon from './Icons/ShareLinkIcon';
|
|
|
|
|
|
@@ -20,123 +19,106 @@ import PageTimeline from './PageTimeline';
|
|
|
import PageList from './PageList';
|
|
|
import PageHistory from './PageHistory';
|
|
|
import ShareLink from './ShareLink/ShareLink';
|
|
|
-
|
|
|
-
|
|
|
-const navTabMapping = {
|
|
|
- pagelist: {
|
|
|
- icon: <PageListIcon />,
|
|
|
- i18n: 'page_list',
|
|
|
- index: 0,
|
|
|
- },
|
|
|
- timeline: {
|
|
|
- icon: <TimeLineIcon />,
|
|
|
- i18n: 'Timeline View',
|
|
|
- index: 1,
|
|
|
- },
|
|
|
- pageHistory: {
|
|
|
- icon: <RecentChangesIcon />,
|
|
|
- i18n: 'History',
|
|
|
- index: 2,
|
|
|
- },
|
|
|
- attachment: {
|
|
|
- icon: <AttachmentIcon />,
|
|
|
- i18n: 'attachment_data',
|
|
|
- index: 3,
|
|
|
- },
|
|
|
- shareLink: {
|
|
|
- icon: <ShareLinkIcon />,
|
|
|
- i18n: 'share_links.share_link_management',
|
|
|
- index: 4,
|
|
|
- },
|
|
|
-};
|
|
|
+import { CustomNav } from './CustomNavigation';
|
|
|
+import ExpandOrContractButton from './ExpandOrContractButton';
|
|
|
|
|
|
const PageAccessoriesModal = (props) => {
|
|
|
- const { t, pageAccessoriesContainer } = props;
|
|
|
+ const {
|
|
|
+ t, pageAccessoriesContainer, onClose, isGuestUserMode,
|
|
|
+ } = props;
|
|
|
const { switchActiveTab } = pageAccessoriesContainer;
|
|
|
- const { activeTab } = pageAccessoriesContainer.state;
|
|
|
-
|
|
|
- const [sliderWidth, setSliderWidth] = useState(null);
|
|
|
- const [sliderMarginLeft, setSliderMarginLeft] = useState(null);
|
|
|
-
|
|
|
- function closeModalHandler() {
|
|
|
- if (props.onClose == null) {
|
|
|
- return;
|
|
|
- }
|
|
|
- props.onClose();
|
|
|
- }
|
|
|
-
|
|
|
- // Might make this dynamic for px, %, pt, em
|
|
|
- function getPercentage(min, max) {
|
|
|
- return min / max * 100;
|
|
|
- }
|
|
|
-
|
|
|
- useEffect(() => {
|
|
|
- if (activeTab === '') {
|
|
|
- return;
|
|
|
- }
|
|
|
-
|
|
|
- const navTitle = document.getElementById('nav-title');
|
|
|
- const navTabs = document.querySelectorAll('li.nav-link');
|
|
|
-
|
|
|
- if (navTitle == null || navTabs == null) {
|
|
|
+ const { activeTab, activeComponents } = pageAccessoriesContainer.state;
|
|
|
+ const [isWindowExpanded, setIsWindowExpanded] = useState(false);
|
|
|
+
|
|
|
+ const navTabMapping = useMemo(() => {
|
|
|
+ return {
|
|
|
+ pagelist: {
|
|
|
+ Icon: PageListIcon,
|
|
|
+ i18n: t('page_list'),
|
|
|
+ index: 0,
|
|
|
+ },
|
|
|
+ timeline: {
|
|
|
+ Icon: TimeLineIcon,
|
|
|
+ i18n: t('Timeline View'),
|
|
|
+ index: 1,
|
|
|
+ },
|
|
|
+ pageHistory: {
|
|
|
+ Icon: HistoryIcon,
|
|
|
+ i18n: t('History'),
|
|
|
+ index: 2,
|
|
|
+ },
|
|
|
+ attachment: {
|
|
|
+ Icon: AttachmentIcon,
|
|
|
+ i18n: t('attachment_data'),
|
|
|
+ index: 3,
|
|
|
+ },
|
|
|
+ shareLink: {
|
|
|
+ Icon: ShareLinkIcon,
|
|
|
+ i18n: t('share_links.share_link_management'),
|
|
|
+ index: 4,
|
|
|
+ isLinkEnabled: v => !isGuestUserMode,
|
|
|
+ },
|
|
|
+ };
|
|
|
+ }, [t, isGuestUserMode]);
|
|
|
+
|
|
|
+ const closeModalHandler = useCallback(() => {
|
|
|
+ if (onClose == null) {
|
|
|
return;
|
|
|
}
|
|
|
-
|
|
|
- let tempML = 0;
|
|
|
-
|
|
|
- const styles = [].map.call(navTabs, (el) => {
|
|
|
- const width = getPercentage(el.offsetWidth, navTitle.offsetWidth);
|
|
|
- const marginLeft = tempML;
|
|
|
- tempML += width;
|
|
|
- return { width, marginLeft };
|
|
|
- });
|
|
|
-
|
|
|
- const { width, marginLeft } = styles[navTabMapping[activeTab].index];
|
|
|
-
|
|
|
- setSliderWidth(width);
|
|
|
- setSliderMarginLeft(marginLeft);
|
|
|
-
|
|
|
- }, [activeTab]);
|
|
|
-
|
|
|
+ onClose();
|
|
|
+ }, [onClose]);
|
|
|
+
|
|
|
+ const expandWindow = () => {
|
|
|
+ setIsWindowExpanded(true);
|
|
|
+ };
|
|
|
+
|
|
|
+ const contractWindow = () => {
|
|
|
+ setIsWindowExpanded(false);
|
|
|
+ };
|
|
|
+
|
|
|
+ const buttons = (
|
|
|
+ <span>
|
|
|
+ {/* change order because of `float: right` by '.close' class */}
|
|
|
+ <button type="button" className="close" onClick={closeModalHandler} aria-label="Close">
|
|
|
+ <span aria-hidden="true">×</span>
|
|
|
+ </button>
|
|
|
+ <ExpandOrContractButton
|
|
|
+ isWindowExpanded={isWindowExpanded}
|
|
|
+ expandWindow={expandWindow}
|
|
|
+ contractWindow={contractWindow}
|
|
|
+ />
|
|
|
+ </span>
|
|
|
+ );
|
|
|
|
|
|
return (
|
|
|
<React.Fragment>
|
|
|
- <Modal size="xl" isOpen={props.isOpen} toggle={closeModalHandler} className="grw-page-accessories-modal">
|
|
|
- {/* [TODO: insert a modal header and move nav tabs there by gw-3890] */}
|
|
|
- <ModalHeader className="p-0" toggle={closeModalHandler}>
|
|
|
- <Nav className="nav-title" id="nav-title">
|
|
|
- {Object.entries(navTabMapping).map(([key, value]) => {
|
|
|
- return (
|
|
|
- <NavItem key={key} type="button" className={`p-0 nav-link ${activeTab === key && 'active'}`}>
|
|
|
- <NavLink onClick={() => { switchActiveTab(key) }}>
|
|
|
- {value.icon}
|
|
|
- {t(value.i18n)}
|
|
|
- </NavLink>
|
|
|
- </NavItem>
|
|
|
- );
|
|
|
- })}
|
|
|
- </Nav>
|
|
|
- <hr className="my-0 grw-nav-slide-hr border-none" style={{ width: `${sliderWidth}%`, marginLeft: `${sliderMarginLeft}%` }} />
|
|
|
+ <Modal size="xl" isOpen={props.isOpen} toggle={closeModalHandler} className={`grw-page-accessories-modal ${isWindowExpanded && 'grw-modal-expanded'} `}>
|
|
|
+ <ModalHeader className="p-0" toggle={closeModalHandler} close={buttons}>
|
|
|
+ <CustomNav activeTab={activeTab} navTabMapping={navTabMapping} onNavSelected={switchActiveTab} />
|
|
|
</ModalHeader>
|
|
|
<ModalBody className="overflow-auto grw-modal-body-style p-0">
|
|
|
+ {/* Do not use CustomTabContent because of performance problem:
|
|
|
+ the 'navTabMapping[tabId].Content' for PageAccessoriesModal depends on activeComponents */}
|
|
|
<TabContent activeTab={activeTab} className="p-5">
|
|
|
<TabPane tabId="pagelist">
|
|
|
- {pageAccessoriesContainer.state.activeComponents.has('pagelist') && <PageList />}
|
|
|
+ {activeComponents.has('pagelist') && <PageList />}
|
|
|
</TabPane>
|
|
|
<TabPane tabId="timeline">
|
|
|
- {pageAccessoriesContainer.state.activeComponents.has('timeline') && <PageTimeline /> }
|
|
|
+ {activeComponents.has('timeline') && <PageTimeline /> }
|
|
|
</TabPane>
|
|
|
<TabPane tabId="pageHistory">
|
|
|
<div className="overflow-auto">
|
|
|
- {pageAccessoriesContainer.state.activeComponents.has('pageHistory') && <PageHistory /> }
|
|
|
+ {activeComponents.has('pageHistory') && <PageHistory /> }
|
|
|
</div>
|
|
|
</TabPane>
|
|
|
<TabPane tabId="attachment">
|
|
|
- {pageAccessoriesContainer.state.activeComponents.has('attachment') && <PageAttachment />}
|
|
|
- </TabPane>
|
|
|
- <TabPane tabId="shareLink">
|
|
|
- {pageAccessoriesContainer.state.activeComponents.has('shareLink') && <ShareLink />}
|
|
|
+ {activeComponents.has('attachment') && <PageAttachment />}
|
|
|
</TabPane>
|
|
|
+ {!isGuestUserMode && (
|
|
|
+ <TabPane tabId="shareLink">
|
|
|
+ {activeComponents.has('shareLink') && <ShareLink />}
|
|
|
+ </TabPane>
|
|
|
+ )}
|
|
|
</TabContent>
|
|
|
</ModalBody>
|
|
|
</Modal>
|
|
|
@@ -151,8 +133,8 @@ const PageAccessoriesModalWrapper = withUnstatedContainers(PageAccessoriesModal,
|
|
|
|
|
|
PageAccessoriesModal.propTypes = {
|
|
|
t: PropTypes.func.isRequired, // i18next
|
|
|
- // pageContainer: PropTypes.instanceOf(PageContainer).isRequired,
|
|
|
pageAccessoriesContainer: PropTypes.instanceOf(PageAccessoriesContainer).isRequired,
|
|
|
+ isGuestUserMode: PropTypes.bool.isRequired,
|
|
|
isOpen: PropTypes.bool.isRequired,
|
|
|
onClose: PropTypes.func,
|
|
|
};
|