| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216 |
- import { useCallback, useEffect, useState } from 'react';
- import { SlackbotType } from '@growi/slack';
- import { useTranslation } from 'next-i18next';
- import PropTypes from 'prop-types';
- import { TabContent, TabPane } from 'reactstrap';
- import AdminNotificationContainer from '~/client/services/AdminNotificationContainer';
- import { toastError } from '~/client/util/toastr';
- import { toArrayIfNot } from '~/utils/array-utils';
- import loggerFactory from '~/utils/logger';
- import CustomNav from '../../CustomNavigation/CustomNav';
- import { withUnstatedContainers } from '../../UnstatedUtils';
- import GlobalNotification from './GlobalNotification';
- import UserTriggerNotification from './UserTriggerNotification';
- const logger = loggerFactory('growi:NotificationSetting');
- const SettingsIcon = () => (
- <span className="material-symbols-outlined">settings</span>
- );
- const navTabMapping = {
- user_trigger_notification: {
- Icon: SettingsIcon,
- i18n: 'User trigger notification',
- },
- global_notification: {
- Icon: SettingsIcon,
- i18n: 'Global notification',
- },
- };
- const Badge = ({ isEnabled }) => {
- const { t } = useTranslation('admin');
- return isEnabled ? (
- <span className="badge text-bg-success">
- {t('external_notification.enabled')}
- </span>
- ) : (
- <span className="badge text-bg-primary">
- {t('external_notification.disabled')}
- </span>
- );
- };
- const SkeletonListItem = () => (
- <li className="list-group-item">
- <h4 className="mb-2">
- <span className="badge text-bg-primary">――</span>
- <span className="ms-2">...</span>
- </h4>
- </li>
- );
- const SlackIntegrationListItem = ({ isEnabled, currentBotType }) => {
- const { t } = useTranslation('admin');
- const isCautionVisible =
- currentBotType === SlackbotType.OFFICIAL ||
- currentBotType === SlackbotType.CUSTOM_WITH_PROXY;
- return (
- <li
- data-testid="slack-integration-list-item"
- className="list-group-item bg-body-tertiary"
- >
- <h4>
- <Badge isEnabled={isEnabled} />
- <a href="/admin/slack-integration" className="ms-2">
- {t('slack_integration.slack_integration')}
- </a>
- </h4>
- {isCautionVisible && (
- <ul className="mt-2 ps-4">
- <li
- // biome-ignore lint/security/noDangerouslySetInnerHtml: trusted translation markup
- dangerouslySetInnerHTML={{
- __html: t('external_notification.caution_enabled'),
- }}
- />
- </ul>
- )}
- </li>
- );
- };
- const LegacySlackIntegrationListItem = ({ isEnabled }) => {
- const { t } = useTranslation('admin');
- return (
- <li className="list-group-item">
- <h4>
- <Badge isEnabled={isEnabled} />
- <a href="/admin/slack-integration-legacy" className="ms-2">
- {t('slack_integration_legacy.slack_integration_legacy')}
- </a>
- </h4>
- {isEnabled && (
- <ul className="mt-2 ps-4">
- <li>
- <span
- className="text-danger"
- // biome-ignore lint/security/noDangerouslySetInnerHtml: trusted translation markup
- dangerouslySetInnerHTML={{
- __html: t('slack_integration_legacy.alert_deplicated'),
- }}
- ></span>
- </li>
- </ul>
- )}
- </li>
- );
- };
- function NotificationSetting(props) {
- const { adminNotificationContainer } = props;
- const { t } = useTranslation('admin');
- const [isMounted, setMounted] = useState(false);
- const [activeTab, setActiveTab] = useState('user_trigger_notification');
- const [activeComponents, setActiveComponents] = useState(
- new Set(['user_trigger_notification']),
- );
- const switchActiveTab = (selectedTab) => {
- setActiveTab(selectedTab);
- setActiveComponents(activeComponents.add(selectedTab));
- };
- const fetchData = useCallback(async () => {
- try {
- await adminNotificationContainer.retrieveNotificationData();
- } catch (err) {
- const errs = toArrayIfNot(err);
- toastError(errs);
- logger.error(errs);
- retrieveErrors = errs;
- } finally {
- setMounted(true);
- }
- }, [adminNotificationContainer]);
- useEffect(() => {
- fetchData();
- }, [fetchData]);
- const { isSlackbotConfigured, isSlackLegacyConfigured, currentBotType } =
- adminNotificationContainer.state;
- const isSlackEnabled = isSlackbotConfigured;
- const isSlackLegacyEnabled = !isSlackbotConfigured && isSlackLegacyConfigured;
- return (
- <div data-testid="admin-notification">
- <h2 className="admin-setting-header">
- {t('external_notification.header_status')}
- </h2>
- <ul className="list-group">
- {!isMounted && <SkeletonListItem />}
- {isMounted && (
- <>
- <SlackIntegrationListItem
- isEnabled={isSlackEnabled}
- currentBotType={currentBotType}
- />
- {/* Legacy Slack Integration become visible only when new Slack Integration is disabled */}
- {!isSlackEnabled && (
- <LegacySlackIntegrationListItem
- isEnabled={isSlackLegacyEnabled}
- />
- )}
- </>
- )}
- </ul>
- <h2 className="admin-setting-header mt-5">
- {t('notification_settings.notification_settings')}
- </h2>
- <CustomNav
- activeTab={activeTab}
- navTabMapping={navTabMapping}
- onNavSelected={switchActiveTab}
- hideBorderBottom
- breakpointToSwitchDropdownDown="md"
- />
- <TabContent activeTab={activeTab} className="p-5">
- <TabPane tabId="user_trigger_notification">
- {activeComponents.has('user_trigger_notification') && (
- <UserTriggerNotification />
- )}
- </TabPane>
- <TabPane tabId="global_notification">
- {activeComponents.has('global_notification') && (
- <GlobalNotification />
- )}
- </TabPane>
- </TabContent>
- </div>
- );
- }
- const NotificationSettingWithUnstatedContainer = withUnstatedContainers(
- NotificationSetting,
- [AdminNotificationContainer],
- );
- NotificationSetting.propTypes = {
- adminNotificationContainer: PropTypes.instanceOf(AdminNotificationContainer)
- .isRequired,
- };
- export default NotificationSettingWithUnstatedContainer;
|