EditorNavbarBottom.tsx 5.6 KB

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