PageAccessoriesModal.tsx 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162
  1. import React, { useEffect, useMemo, useState } from 'react';
  2. import { useTranslation } from 'next-i18next';
  3. import {
  4. Modal, ModalBody, ModalHeader,
  5. } from 'reactstrap';
  6. import {
  7. useDisableLinkSharing, useIsGuestUser, useIsSharedUser,
  8. } from '~/stores/context';
  9. import { usePageAccessoriesModal, PageAccessoriesModalContents } from '~/stores/modal';
  10. import { CustomNavTab } from './CustomNavigation/CustomNav';
  11. import CustomTabContent from './CustomNavigation/CustomTabContent';
  12. import ExpandOrContractButton from './ExpandOrContractButton';
  13. import AttachmentIcon from './Icons/AttachmentIcon';
  14. import HistoryIcon from './Icons/HistoryIcon';
  15. import ShareLinkIcon from './Icons/ShareLinkIcon';
  16. import PageAttachment from './PageAttachment';
  17. import { PageHistory, getQueryParam } from './PageHistory';
  18. import ShareLink from './ShareLink/ShareLink';
  19. import styles from './PageAccessoriesModal.module.scss';
  20. const PageAccessoriesModal = (): JSX.Element => {
  21. const { t } = useTranslation();
  22. const [activeTab, setActiveTab] = useState<PageAccessoriesModalContents>(PageAccessoriesModalContents.PageHistory);
  23. const [sourceRevisionId, setSourceRevisionId] = useState<string>();
  24. const [targetRevisionId, setTargetRevisionId] = useState<string>();
  25. const [isWindowExpanded, setIsWindowExpanded] = useState(false);
  26. const { data: isSharedUser } = useIsSharedUser();
  27. const { data: isGuestUser } = useIsGuestUser();
  28. const { data: isLinkSharingDisabled } = useDisableLinkSharing();
  29. const { data: status, mutate, close } = usePageAccessoriesModal();
  30. // add event handler when opened
  31. useEffect(() => {
  32. if (status == null || status.onOpened != null) {
  33. return;
  34. }
  35. mutate({
  36. ...status,
  37. onOpened: (activatedContents) => {
  38. setActiveTab(activatedContents);
  39. },
  40. }, false);
  41. }, [mutate, status]);
  42. // Set sourceRevisionId and targetRevisionId as state with valid object id string
  43. useEffect(() => {
  44. const queryParams = getQueryParam();
  45. // https://regex101.com/r/YHTDsr/1
  46. const regex = /^([0-9a-f]{24})...([0-9a-f]{24})$/i;
  47. if (queryParams == null || !regex.test(queryParams)) {
  48. return;
  49. }
  50. const matches = queryParams.match(regex);
  51. if (matches == null) {
  52. return;
  53. }
  54. const [, sourceRevisionId, targetRevisionId] = matches;
  55. setSourceRevisionId(sourceRevisionId);
  56. setTargetRevisionId(targetRevisionId);
  57. mutate({ isOpened: true });
  58. }, [mutate]);
  59. const navTabMapping = useMemo(() => {
  60. const isOpened = status == null ? false : status.isOpened;
  61. return {
  62. [PageAccessoriesModalContents.PageHistory]: {
  63. Icon: HistoryIcon,
  64. Content: () => {
  65. if (!isOpened) {
  66. return <></>;
  67. }
  68. return <PageHistory onClose={close} sourceRevisionId={sourceRevisionId} targetRevisionId={targetRevisionId}/>;
  69. },
  70. i18n: t('History'),
  71. index: 0,
  72. isLinkEnabled: () => !isGuestUser && !isSharedUser,
  73. },
  74. [PageAccessoriesModalContents.Attachment]: {
  75. Icon: AttachmentIcon,
  76. Content: () => {
  77. if (!isOpened) {
  78. return <></>;
  79. }
  80. return <PageAttachment />;
  81. },
  82. i18n: t('attachment_data'),
  83. index: 1,
  84. },
  85. [PageAccessoriesModalContents.ShareLink]: {
  86. Icon: ShareLinkIcon,
  87. Content: () => {
  88. if (!isOpened) {
  89. return <></>;
  90. }
  91. return <ShareLink />;
  92. },
  93. i18n: t('share_links.share_link_management'),
  94. index: 2,
  95. isLinkEnabled: () => !isGuestUser && !isSharedUser && !isLinkSharingDisabled,
  96. },
  97. };
  98. }, [status, t, close, sourceRevisionId, targetRevisionId, isGuestUser, isSharedUser, isLinkSharingDisabled]);
  99. const buttons = useMemo(() => (
  100. <div className="d-flex flex-nowrap">
  101. <ExpandOrContractButton
  102. isWindowExpanded={isWindowExpanded}
  103. expandWindow={() => setIsWindowExpanded(true)}
  104. contractWindow={() => setIsWindowExpanded(false)}
  105. />
  106. <button type="button" className="close" onClick={close} aria-label="Close">
  107. <span aria-hidden="true">&times;</span>
  108. </button>
  109. </div>
  110. ), [close, isWindowExpanded]);
  111. if (status == null) {
  112. return <></>;
  113. }
  114. const { isOpened } = status;
  115. return (
  116. <Modal
  117. size="xl"
  118. isOpen={isOpened}
  119. toggle={close}
  120. data-testid="page-accessories-modal"
  121. className={`grw-page-accessories-modal ${styles['grw-page-accessories-modal']} ${isWindowExpanded ? 'grw-modal-expanded' : ''} `}
  122. >
  123. <ModalHeader className="p-0" toggle={close} close={buttons}>
  124. <CustomNavTab
  125. activeTab={activeTab}
  126. navTabMapping={navTabMapping}
  127. breakpointToHideInactiveTabsDown="md"
  128. onNavSelected={(v) => {
  129. setActiveTab(v);
  130. }}
  131. hideBorderBottom
  132. />
  133. </ModalHeader>
  134. <ModalBody className="overflow-auto grw-modal-body-style">
  135. <CustomTabContent activeTab={activeTab} navTabMapping={navTabMapping} />
  136. </ModalBody>
  137. </Modal>
  138. );
  139. };
  140. export default PageAccessoriesModal;