EditorNavbarBottom.tsx 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152
  1. import React, { useCallback, useState, useEffect } from 'react';
  2. import dynamic from 'next/dynamic';
  3. import { Collapse, Button } from 'reactstrap';
  4. import { useIsSlackConfigured } from '~/stores/context';
  5. import { useSWRxSlackChannels, useIsSlackEnabled } from '~/stores/editor';
  6. import { useCurrentPagePath } from '~/stores/page';
  7. import {
  8. EditorMode, useDrawerOpened, useEditorMode, useIsDeviceSmallerThanMd,
  9. } from '~/stores/ui';
  10. const SavePageControls = dynamic(() => import('~/components/SavePageControls').then(mod => mod.SavePageControls), { ssr: false });
  11. const SlackLogo = dynamic(() => import('~/components/SlackLogo').then(mod => mod.SlackLogo), { ssr: false });
  12. const SlackNotification = dynamic(() => import('~/components/SlackNotification').then(mod => mod.SlackNotification), { ssr: false });
  13. const OptionsSelector = dynamic(() => import('~/components/PageEditor/OptionsSelector').then(mod => mod.OptionsSelector), { ssr: false });
  14. const EditorNavbarBottom = (): JSX.Element => {
  15. const [isExpanded, setExpanded] = useState(false);
  16. const [isSlackExpanded, setSlackExpanded] = useState(false);
  17. const { data: editorMode } = useEditorMode();
  18. const { data: isSlackConfigured } = useIsSlackConfigured();
  19. const { mutate: mutateDrawerOpened } = useDrawerOpened();
  20. const { data: isDeviceSmallerThanMd } = useIsDeviceSmallerThanMd();
  21. const { data: currentPagePath } = useCurrentPagePath();
  22. const { data: slackChannelsData } = useSWRxSlackChannels(currentPagePath);
  23. const { data: isSlackEnabled, mutate: mutateIsSlackEnabled } = useIsSlackEnabled();
  24. const additionalClasses = ['grw-editor-navbar-bottom'];
  25. const [slackChannelsStr, setSlackChannelsStr] = useState<string>('');
  26. useEffect(() => {
  27. if (slackChannelsData != null) {
  28. setSlackChannelsStr(slackChannelsData.toString());
  29. mutateIsSlackEnabled(false);
  30. }
  31. }, [mutateIsSlackEnabled, slackChannelsData]);
  32. const isSlackEnabledToggleHandler = (bool: boolean) => {
  33. mutateIsSlackEnabled(bool, false);
  34. };
  35. const slackChannelsChangedHandler = useCallback((slackChannels: string) => {
  36. setSlackChannelsStr(slackChannels);
  37. }, []);
  38. const renderDrawerButton = () => (
  39. <button
  40. type="button"
  41. className="btn btn-outline-secondary border-0"
  42. onClick={() => mutateDrawerOpened(true)}
  43. >
  44. <i className="icon-menu"></i>
  45. </button>
  46. );
  47. const renderExpandButton = () => (
  48. <div className="d-md-none ml-2">
  49. <button
  50. type="button"
  51. className={`btn btn-outline-secondary btn-expand border-0 ${isExpanded ? 'expand' : ''}`}
  52. onClick={() => setExpanded(!isExpanded)}
  53. >
  54. <i className="icon-arrow-up"></i>
  55. </button>
  56. </div>
  57. );
  58. const isOptionsSelectorEnabled = editorMode !== EditorMode.HackMD;
  59. const isCollapsedOptionsSelectorEnabled = isOptionsSelectorEnabled && isDeviceSmallerThanMd;
  60. return (
  61. <div className={`${isCollapsedOptionsSelectorEnabled ? 'fixed-bottom' : ''} `}>
  62. {/* Collapsed SlackNotification */}
  63. {isSlackConfigured && (
  64. <Collapse isOpen={isSlackExpanded && isDeviceSmallerThanMd === true}>
  65. <nav className={`navbar navbar-expand-lg border-top ${additionalClasses.join(' ')}`}>
  66. {isSlackEnabled != null
  67. && (
  68. <SlackNotification
  69. isSlackEnabled={isSlackEnabled}
  70. slackChannels={slackChannelsStr}
  71. onEnabledFlagChange={isSlackEnabledToggleHandler}
  72. onChannelChange={slackChannelsChangedHandler}
  73. id="idForEditorNavbarBottomForMobile"
  74. />
  75. )
  76. }
  77. </nav>
  78. </Collapse>
  79. )
  80. }
  81. <div className={`navbar navbar-expand border-top px-2 px-md-3 ${additionalClasses.join(' ')}`}>
  82. <form className="form-inline">
  83. { isDeviceSmallerThanMd && renderDrawerButton() }
  84. { isOptionsSelectorEnabled && !isDeviceSmallerThanMd && <OptionsSelector /> }
  85. </form>
  86. <form className="form-inline flex-nowrap ml-auto">
  87. {/* Responsive Design for the SlackNotification */}
  88. {/* Button or the normal Slack banner */}
  89. {isSlackConfigured && (isDeviceSmallerThanMd ? (
  90. <Button
  91. className="grw-btn-slack border mr-2"
  92. onClick={() => (setSlackExpanded(!isSlackExpanded))}
  93. >
  94. <div className="grw-slack-logo">
  95. <SlackLogo />
  96. <span className="grw-btn-slack-triangle fa fa-caret-up ml-2"></span>
  97. </div>
  98. </Button>
  99. ) : (
  100. <div className="mr-2">
  101. {isSlackEnabled != null
  102. && (
  103. <SlackNotification
  104. isSlackEnabled={isSlackEnabled}
  105. slackChannels={slackChannelsStr}
  106. onEnabledFlagChange={isSlackEnabledToggleHandler}
  107. onChannelChange={slackChannelsChangedHandler}
  108. id="idForEditorNavbarBottom"
  109. />
  110. )}
  111. </div>
  112. ))}
  113. <SavePageControls />
  114. { isCollapsedOptionsSelectorEnabled && renderExpandButton() }
  115. </form>
  116. </div>
  117. {/* Collapsed OptionsSelector */}
  118. { isCollapsedOptionsSelectorEnabled && (
  119. <Collapse isOpen={isExpanded}>
  120. <div className="px-2"> {/* set padding for border-top */}
  121. <div className={`navbar navbar-expand border-top px-0 ${additionalClasses.join(' ')}`}>
  122. <form className="form-inline ml-auto">
  123. <OptionsSelector />
  124. </form>
  125. </div>
  126. </div>
  127. </Collapse>
  128. ) }
  129. </div>
  130. );
  131. };
  132. export default EditorNavbarBottom;