EditorNavbarBottom.jsx 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141
  1. import React, { 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. const EditorNavbarBottom = (props) => {
  15. const { data: editorMode } = useEditorMode();
  16. const [isExpanded, setExpanded] = useState(false);
  17. const [isSlackExpanded, setSlackExpanded] = useState(false);
  18. const isSlackConfigured = props.appContainer.getConfig().isSlackConfigured;
  19. const { mutate: mutateDrawerOpened } = useDrawerOpened();
  20. const { data: isDeviceSmallerThanMd } = useIsDeviceSmallerThanMd();
  21. const additionalClasses = ['grw-editor-navbar-bottom'];
  22. const renderDrawerButton = () => (
  23. <button
  24. type="button"
  25. className="btn btn-outline-secondary border-0"
  26. onClick={() => mutateDrawerOpened(true)}
  27. >
  28. <i className="icon-menu"></i>
  29. </button>
  30. );
  31. const slackEnabledFlagChangedHandler = (isSlackEnabled) => {
  32. props.editorContainer.setState({ isSlackEnabled });
  33. };
  34. const slackChannelsChangedHandler = (slackChannels) => {
  35. props.editorContainer.setState({ slackChannels });
  36. };
  37. // eslint-disable-next-line react/prop-types
  38. const renderExpandButton = () => (
  39. <div className="d-md-none ml-2">
  40. <button
  41. type="button"
  42. className={`btn btn-outline-secondary btn-expand border-0 ${isExpanded ? 'expand' : ''}`}
  43. onClick={() => setExpanded(!isExpanded)}
  44. >
  45. <i className="icon-arrow-up"></i>
  46. </button>
  47. </div>
  48. );
  49. const isOptionsSelectorEnabled = editorMode !== EditorMode.HackMD;
  50. const isCollapsedOptionsSelectorEnabled = isOptionsSelectorEnabled && isDeviceSmallerThanMd;
  51. return (
  52. <div className={`${isCollapsedOptionsSelectorEnabled ? 'fixed-bottom' : ''} `}>
  53. {/* Collapsed SlackNotification */}
  54. {isSlackConfigured && (
  55. <Collapse isOpen={isSlackExpanded && isDeviceSmallerThanMd}>
  56. <nav className={`navbar navbar-expand-lg border-top ${additionalClasses.join(' ')}`}>
  57. <SlackNotification
  58. isSlackEnabled={props.editorContainer.state.isSlackEnabled}
  59. slackChannels={props.editorContainer.state.slackChannels}
  60. onEnabledFlagChange={slackEnabledFlagChangedHandler}
  61. onChannelChange={slackChannelsChangedHandler}
  62. id="idForEditorNavbarBottomForMobile"
  63. popUp
  64. />
  65. </nav>
  66. </Collapse>
  67. )
  68. }
  69. <div className={`navbar navbar-expand border-top px-2 px-md-3 ${additionalClasses.join(' ')}`}>
  70. <form className="form-inline">
  71. { isDeviceSmallerThanMd && renderDrawerButton() }
  72. { isOptionsSelectorEnabled && !isDeviceSmallerThanMd && <OptionsSelector /> }
  73. </form>
  74. <form className="form-inline flex-nowrap ml-auto">
  75. {/* Responsive Design for the SlackNotification */}
  76. {/* Button or the normal Slack banner */}
  77. {isSlackConfigured && (isDeviceSmallerThanMd ? (
  78. <Button
  79. className="grw-btn-slack border mr-2"
  80. onClick={() => (setSlackExpanded(!isSlackExpanded))}
  81. >
  82. <div className="grw-slack-logo">
  83. <SlackLogo />
  84. <span className="grw-btn-slack-triangle fa fa-caret-up ml-2"></span>
  85. </div>
  86. </Button>
  87. ) : (
  88. <div className="mr-2">
  89. <SlackNotification
  90. isSlackEnabled={props.editorContainer.state.isSlackEnabled}
  91. slackChannels={props.editorContainer.state.slackChannels}
  92. onEnabledFlagChange={slackEnabledFlagChangedHandler}
  93. onChannelChange={slackChannelsChangedHandler}
  94. id="idForEditorNavbarBottom"
  95. popUp={false}
  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]);