EditorNavbarBottom.tsx 5.1 KB

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