EditorNavbarBottom.tsx 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118
  1. import React, { useCallback, useState, useEffect } from 'react';
  2. import dynamic from 'next/dynamic';
  3. import { Collapse, Button } from 'reactstrap';
  4. import type { SavePageControlsProps } from '~/components/SavePageControls';
  5. import { useIsSlackConfigured } from '~/stores/context';
  6. import { useSWRxSlackChannels, useIsSlackEnabled } from '~/stores/editor';
  7. import { useCurrentPagePath } from '~/stores/page';
  8. import {
  9. useEditorMode, useIsDeviceLargerThanLg, useIsDeviceLargerThanMd,
  10. } from '~/stores/ui';
  11. import styles from './EditorNavbarBottom.module.scss';
  12. const moduleClass = styles['grw-editor-navbar-bottom'];
  13. const SavePageControls = dynamic<SavePageControlsProps>(() => import('~/components/SavePageControls').then(mod => mod.SavePageControls), { ssr: false });
  14. const SlackLogo = dynamic(() => import('~/components/SlackLogo').then(mod => mod.SlackLogo), { ssr: false });
  15. const SlackNotification = dynamic(() => import('~/components/SlackNotification').then(mod => mod.SlackNotification), { ssr: false });
  16. const OptionsSelector = dynamic(() => import('~/components/PageEditor/OptionsSelector').then(mod => mod.OptionsSelector), { ssr: false });
  17. const EditorNavbarBottom = (): JSX.Element => {
  18. const [isSlackExpanded, setSlackExpanded] = useState(false);
  19. const { data: editorMode } = useEditorMode();
  20. const { data: isSlackConfigured } = useIsSlackConfigured();
  21. const { data: isDeviceLargerThanMd } = useIsDeviceLargerThanMd();
  22. const { data: isDeviceLargerThanLg } = useIsDeviceLargerThanLg();
  23. const { data: currentPagePath } = useCurrentPagePath();
  24. const { data: slackChannelsData } = useSWRxSlackChannels(currentPagePath);
  25. const { data: isSlackEnabled, mutate: mutateIsSlackEnabled } = useIsSlackEnabled();
  26. const [slackChannelsStr, setSlackChannelsStr] = useState<string>('');
  27. // DO NOT dependent on slackChannelsData directly: https://github.com/weseek/growi/pull/7332
  28. const slackChannelsDataString = slackChannelsData?.toString();
  29. useEffect(() => {
  30. if (editorMode === 'editor') {
  31. setSlackChannelsStr(slackChannelsDataString ?? '');
  32. mutateIsSlackEnabled(false);
  33. }
  34. }, [editorMode, mutateIsSlackEnabled, slackChannelsDataString]);
  35. const isSlackEnabledToggleHandler = (bool: boolean) => {
  36. mutateIsSlackEnabled(bool, false);
  37. };
  38. const slackChannelsChangedHandler = useCallback((slackChannels: string) => {
  39. setSlackChannelsStr(slackChannels);
  40. }, []);
  41. return (
  42. <div className="border-top" data-testid="grw-editor-navbar-bottom">
  43. {/* Collapsed SlackNotification */}
  44. {isSlackConfigured && (
  45. <Collapse isOpen={isSlackExpanded && !isDeviceLargerThanLg}>
  46. <nav className={`navbar navbar-expand-lg border-top ${moduleClass}`}>
  47. {isSlackEnabled != null
  48. && (
  49. <SlackNotification
  50. isSlackEnabled={isSlackEnabled}
  51. slackChannels={slackChannelsStr}
  52. onEnabledFlagChange={isSlackEnabledToggleHandler}
  53. onChannelChange={slackChannelsChangedHandler}
  54. id="idForEditorNavbarBottomForMobile"
  55. />
  56. )
  57. }
  58. </nav>
  59. </Collapse>
  60. )
  61. }
  62. <div className={`flex-expand-horiz align-items-center px-2 py-1 py-md-2 px-md-3 ${moduleClass}`}>
  63. <form>
  64. <OptionsSelector collapsed={!isDeviceLargerThanMd} />
  65. </form>
  66. <form className="row row-cols-lg-auto g-3 align-items-center ms-auto">
  67. {/* Responsive Design for the SlackNotification */}
  68. {/* Button or the normal Slack banner */}
  69. {isSlackConfigured && (!isDeviceLargerThanMd ? (
  70. <Button
  71. className="grw-btn-slack border me-2"
  72. onClick={() => (setSlackExpanded(!isSlackExpanded))}
  73. >
  74. <div className="grw-slack-logo">
  75. <SlackLogo />
  76. <span className="grw-btn-slack-triangle material-symbols-outlined ms-2">arrow_drop_up</span>
  77. </div>
  78. </Button>
  79. ) : (
  80. <div className="me-2">
  81. {isSlackEnabled != null
  82. && (
  83. <SlackNotification
  84. isSlackEnabled={isSlackEnabled}
  85. slackChannels={slackChannelsStr}
  86. onEnabledFlagChange={isSlackEnabledToggleHandler}
  87. onChannelChange={slackChannelsChangedHandler}
  88. id="idForEditorNavbarBottom"
  89. />
  90. )}
  91. </div>
  92. ))}
  93. <SavePageControls slackChannels={slackChannelsStr} />
  94. </form>
  95. </div>
  96. </div>
  97. );
  98. };
  99. export default EditorNavbarBottom;