فهرست منبع

refs 114263: diable personal questionnaire settings ui when growi questionnaire settings is disabled

Futa Arai 3 سال پیش
والد
کامیت
d755f4442e

+ 12 - 12
packages/app/src/components/Admin/App/QuestionnaireSettings.tsx

@@ -19,9 +19,9 @@ const QuestionnaireSettings = (): JSX.Element => {
 
   const { data, error, mutate } = useSWRxAppSettings();
 
-  const [isEnableQuestionnaire, setIsEnableQuestionnaire] = useState(data?.isEnableQuestionnaire);
-  const onChangeIsEnableQuestionnaireHandler = useCallback(() => {
-    setIsEnableQuestionnaire(prev => !prev);
+  const [isQuestionnaireEnabled, setIsQuestionnaireEnabled] = useState(data?.isQuestionnaireEnabled);
+  const onChangeIsQuestionnaireEnabledHandler = useCallback(() => {
+    setIsQuestionnaireEnabled(prev => !prev);
   }, []);
 
   const [isAppSiteUrlHashed, setIsAppSiteUrlHashed] = useState(data?.isAppSiteUrlHashed);
@@ -32,7 +32,7 @@ const QuestionnaireSettings = (): JSX.Element => {
   const onSubmitHandler = useCallback(async() => {
     try {
       await apiv3Put('/app-settings/questionnaire-settings', {
-        isEnableQuestionnaire,
+        isQuestionnaireEnabled,
         isAppSiteUrlHashed,
       });
       toastSuccess(t('toaster.update_successed', { target: 'アンケート設定', ns: 'commons' }));
@@ -41,13 +41,13 @@ const QuestionnaireSettings = (): JSX.Element => {
       toastError(err);
     }
     mutate();
-  }, [isAppSiteUrlHashed, isEnableQuestionnaire, mutate, t]);
+  }, [isAppSiteUrlHashed, isQuestionnaireEnabled, mutate, t]);
 
   // Sync SWR value and state
   useEffect(() => {
-    setIsEnableQuestionnaire(data?.isEnableQuestionnaire);
+    setIsQuestionnaireEnabled(data?.isQuestionnaireEnabled);
     setIsAppSiteUrlHashed(data?.isAppSiteUrlHashed);
-  }, [data, data?.isAppSiteUrlHashed, data?.isEnableQuestionnaire]);
+  }, [data, data?.isAppSiteUrlHashed, data?.isQuestionnaireEnabled]);
 
   const isLoading = data === undefined && error === undefined;
 
@@ -75,11 +75,11 @@ const QuestionnaireSettings = (): JSX.Element => {
               <input
                 type="checkbox"
                 className="custom-control-input"
-                id="isEnableQuestionnaire"
-                checked={isEnableQuestionnaire}
-                onChange={onChangeIsEnableQuestionnaireHandler}
+                id="isQuestionnaireEnabled"
+                checked={isQuestionnaireEnabled}
+                onChange={onChangeIsQuestionnaireEnabledHandler}
               />
-              <label className="custom-control-label" htmlFor="isEnableQuestionnaire">
+              <label className="custom-control-label" htmlFor="isQuestionnaireEnabled">
                 アンケートを有効にする
               </label>
             </div>
@@ -93,7 +93,7 @@ const QuestionnaireSettings = (): JSX.Element => {
                 id="isAppSiteUrlHashed"
                 checked={isAppSiteUrlHashed}
                 onChange={onChangeisAppSiteUrlHashedHandler}
-                disabled={!isEnableQuestionnaire}
+                disabled={!isQuestionnaireEnabled}
               />
               <label className="custom-control-label" htmlFor="isAppSiteUrlHashed">
                 サイト URL を匿名化して送信する

+ 40 - 24
packages/app/src/components/Me/OtherSettings.tsx

@@ -3,37 +3,40 @@ import {
 } from 'react';
 
 import { useTranslation } from 'next-i18next';
+import { UncontrolledTooltip } from 'reactstrap';
 
 import { toastSuccess, toastError } from '~/client/util/apiNotification';
 import { apiv3Put } from '~/client/util/apiv3-client';
 import { useCurrentUser } from '~/stores/context';
+import { useSWRxIsQuestionnaireEnabled } from '~/stores/questionnaire';
 
 const OtherSettings = (): JSX.Element => {
   const { t } = useTranslation();
   const { data: currentUser, error: errorCurrentUser } = useCurrentUser();
+  const { data: growiIsQuestionnaireEnabled } = useSWRxIsQuestionnaireEnabled();
 
-  const [isEnableQuestionnaire, setIsEnableQuestionnaire] = useState(currentUser?.isEnableQuestionnaire);
+  const [isQuestionnaireEnabled, setIsQuestionnaireEnabled] = useState(currentUser?.isQuestionnaireEnabled);
 
-  const onChangeIsEnableQuestionnaireHandler = useCallback(async() => {
-    setIsEnableQuestionnaire(prev => !prev);
+  const onChangeIsQuestionnaireEnabledHandler = useCallback(async() => {
+    setIsQuestionnaireEnabled(prev => !prev);
   }, []);
 
-  const onClickUpdateIsEnableQuestionnaireHandler = useCallback(async() => {
+  const onClickUpdateIsQuestionnaireEnabledHandler = useCallback(async() => {
     try {
       await apiv3Put('/personal-setting/questionnaire-settings', {
-        isEnableQuestionnaire,
+        isQuestionnaireEnabled,
       });
       toastSuccess(t('toaster.update_successed', { target: 'アンケート設定', ns: 'commons' }));
     }
     catch (err) {
       toastError(err);
     }
-  }, [isEnableQuestionnaire, t]);
+  }, [isQuestionnaireEnabled, t]);
 
   // Sync currentUser and state
   useEffect(() => {
-    setIsEnableQuestionnaire(currentUser?.isEnableQuestionnaire);
-  }, [currentUser?.isEnableQuestionnaire]);
+    setIsQuestionnaireEnabled(currentUser?.isQuestionnaireEnabled);
+  }, [currentUser?.isQuestionnaireEnabled]);
 
   const isLoadingCurrentUser = currentUser === undefined && errorCurrentUser === undefined;
 
@@ -49,19 +52,25 @@ const OtherSettings = (): JSX.Element => {
         <div className="offset-md-3 col-md-6 text-left">
           {!isLoadingCurrentUser && (
             <div className="custom-control custom-switch custom-checkbox-primary">
-              <input
-                type="checkbox"
-                className="custom-control-input"
-                id="isEnableQuestionnaire"
-                checked={isEnableQuestionnaire}
-                onChange={onChangeIsEnableQuestionnaireHandler}
-              />
-              <label className="custom-control-label" htmlFor="isEnableQuestionnaire">
+              <span id="personal-questionnaire-settings-toggle">
+                <input
+                  type="checkbox"
+                  className="custom-control-input"
+                  id="isQuestionnaireEnabled"
+                  checked={growiIsQuestionnaireEnabled && isQuestionnaireEnabled}
+                  onChange={onChangeIsQuestionnaireEnabledHandler}
+                  disabled={!growiIsQuestionnaireEnabled}
+                />
+                <label className="custom-control-label" htmlFor="isQuestionnaireEnabled">
                 アンケートを有効にする
-              </label>
+                </label>
+              </span>
               <p className="form-text text-muted small">
                 GROWI 改善のためのアンケートが表示されるようになります。ご意見ご要望はユーザーアイコンのドロップダウンからお願いいたします。
               </p>
+              <UncontrolledTooltip placement="bottom" target="personal-questionnaire-settings-toggle">
+                管理者によってアンケートは無効化されています
+              </UncontrolledTooltip>
             </div>
           )}
         </div>
@@ -69,13 +78,20 @@ const OtherSettings = (): JSX.Element => {
 
       <div className="row my-3">
         <div className="offset-4 col-5">
-          <button
-            type="button"
-            className="btn btn-primary"
-            onClick={onClickUpdateIsEnableQuestionnaireHandler}
-          >
-            {t('Update')}
-          </button>
+          <span className="d-inline-block" id="personal-questionnaire-settings-btn">
+            <button
+              type="button"
+              className="btn btn-primary"
+              onClick={onClickUpdateIsQuestionnaireEnabledHandler}
+              disabled={!growiIsQuestionnaireEnabled}
+              style={growiIsQuestionnaireEnabled ? {} : { pointerEvents: 'none' }}
+            >
+              {t('Update')}
+            </button>
+          </span>
+          <UncontrolledTooltip placement="bottom" target="personal-questionnaire-settings-btn">
+            管理者によってアンケートは無効化されています
+          </UncontrolledTooltip>
         </div>
       </div>
     </>

+ 1 - 1
packages/app/src/interfaces/res/admin/app-settings.ts

@@ -41,7 +41,7 @@ export type IResAppSettings = {
 
   isEnabledPlugins: boolean,
 
-  isEnableQuestionnaire: boolean,
+  isQuestionnaireEnabled: boolean,
   isAppSiteUrlHashed: boolean,
 
   isMaintenanceMode: boolean,

+ 3 - 3
packages/app/src/server/models/user.js

@@ -69,7 +69,7 @@ module.exports = function(crowi) {
     lastLoginAt: { type: Date },
     admin: { type: Boolean, default: 0, index: true },
     isInvitationEmailSended: { type: Boolean, default: false },
-    isEnableQuestionnaire: { type: Boolean, default: true },
+    isQuestionnaireEnabled: { type: Boolean, default: true },
   }, {
     timestamps: true,
     toObject: {
@@ -731,8 +731,8 @@ module.exports = function(crowi) {
     return { users, totalCount };
   };
 
-  userSchema.methods.updateIsEnableQuestionnaire = async function(value) {
-    this.isEnableQuestionnaire = value;
+  userSchema.methods.updateIsQuestionnaireEnabled = async function(value) {
+    this.isQuestionnaireEnabled = value;
     return this.save();
   };
 

+ 5 - 5
packages/app/src/server/routes/apiv3/app-settings.js

@@ -199,7 +199,7 @@ module.exports = (crowi) => {
       body('s3ReferenceFileWithRelayMode').if(value => value != null).isBoolean(),
     ],
     questionnaireSettings: [
-      body('isEnableQuestionnaire').isBoolean(),
+      body('isQuestionnaireEnabled').isBoolean(),
       body('isAppSiteUrlHashed').isBoolean(),
     ],
     maintenanceMode: [
@@ -271,7 +271,7 @@ module.exports = (crowi) => {
 
       isEnabledPlugins: crowi.configManager.getConfig('crowi', 'plugin:isEnabledPlugins'),
 
-      isEnableQuestionnaire: crowi.configManager.getConfig('crowi', 'questionnaire:isEnableQuestionnaire'),
+      isQuestionnaireEnabled: crowi.configManager.getConfig('crowi', 'questionnaire:isQuestionnaireEnabled'),
       isAppSiteUrlHashed: crowi.configManager.getConfig('crowi', 'questionnaire:isAppSiteUrlHashed'),
 
       isMaintenanceMode: crowi.configManager.getConfig('crowi', 'app:isMaintenanceMode'),
@@ -680,10 +680,10 @@ module.exports = (crowi) => {
 
   // eslint-disable-next-line max-len
   router.put('/questionnaire-settings', loginRequiredStrictly, adminRequired, addActivity, validator.questionnaireSettings, apiV3FormValidator, async(req, res) => {
-    const { isEnableQuestionnaire, isAppSiteUrlHashed } = req.body;
+    const { isQuestionnaireEnabled, isAppSiteUrlHashed } = req.body;
 
     const requestParams = {
-      'questionnaire:isEnableQuestionnaire': isEnableQuestionnaire,
+      'questionnaire:isQuestionnaireEnabled': isQuestionnaireEnabled,
       'questionnaire:isAppSiteUrlHashed': isAppSiteUrlHashed,
     };
 
@@ -691,7 +691,7 @@ module.exports = (crowi) => {
       await crowi.configManager.updateConfigsInTheSameNamespace('crowi', requestParams, true);
 
       const responseParams = {
-        isEnableQuestionnaire: crowi.configManager.getConfig('crowi', 'questionnaire:isEnableQuestionnaire'),
+        isQuestionnaireEnabled: crowi.configManager.getConfig('crowi', 'questionnaire:isQuestionnaireEnabled'),
         isAppSiteUrlHashed: crowi.configManager.getConfig('crowi', 'questionnaire:isAppSiteUrlHashed'),
       };
 

+ 4 - 4
packages/app/src/server/routes/apiv3/personal-setting.js

@@ -128,7 +128,7 @@ module.exports = (crowi) => {
       body('defaultSubscribeRules.*.isEnabled').optional().isBoolean(),
     ],
     questionnaireSettings: [
-      body('isEnableQuestionnaire').isBoolean(),
+      body('isQuestionnaireEnabled').isBoolean(),
     ],
   };
 
@@ -686,12 +686,12 @@ module.exports = (crowi) => {
 
   // eslint-disable-next-line max-len
   router.put('/questionnaire-settings', accessTokenParser, loginRequiredStrictly, validator.questionnaireSettings, apiV3FormValidator, async(req, res) => {
-    const { isEnableQuestionnaire } = req.body;
+    const { isQuestionnaireEnabled } = req.body;
     const { user } = req;
     try {
-      await user.updateIsEnableQuestionnaire(isEnableQuestionnaire);
+      await user.updateIsQuestionnaireEnabled(isQuestionnaireEnabled);
 
-      return res.apiv3({ message: 'Successfully updated questionnaire settings.', isEnableQuestionnaire });
+      return res.apiv3({ message: 'Successfully updated questionnaire settings.', isQuestionnaireEnabled });
     }
     catch (err) {
       logger.error(err);

+ 5 - 0
packages/app/src/server/routes/apiv3/questionnaire.ts

@@ -67,6 +67,11 @@ module.exports = (crowi: Crowi): Router => {
     }
   });
 
+  router.get('/is-enabled', accessTokenParser, loginRequired, async(req: AuthorizedRequest, res: ApiV3Response) => {
+    const isEnabled = crowi.configManager!.getConfig('crowi', 'questionnaire:isQuestionnaireEnabled');
+    return res.apiv3({ isEnabled });
+  });
+
   router.post('/proactive/answer', accessTokenParser, loginRequired, validators.proactiveAnswer, async(req: AuthorizedRequest, res: ApiV3Response) => {
     const sendQuestionnaireAnswer = async() => {
       const growiQuestionnaireServerOrigin = crowi.configManager?.getConfig('crowi', 'app:growiQuestionnaireServerOrigin');

+ 1 - 1
packages/app/src/server/service/config-loader.ts

@@ -660,7 +660,7 @@ const ENV_VAR_NAME_TO_CONFIG_INFO = {
   },
   QUESTIONNAIRE_IS_ENABLE_QUESTIONNAIRE: {
     ns: 'crowi',
-    key: 'questionnaire:isEnableQuestionnaire',
+    key: 'questionnaire:isQuestionnaireEnabled',
     type: ValueType.BOOLEAN,
     default: true,
   },

+ 9 - 0
packages/app/src/stores/questionnaire.tsx

@@ -11,3 +11,12 @@ export const useSWRxQuestionnaireOrders = (): SWRResponse<IQuestionnaireOrderHas
     }),
   );
 };
+
+export const useSWRxIsQuestionnaireEnabled = (): SWRResponse<boolean, Error> => {
+  return useSWR(
+    '/questionnaire/is-enabled',
+    endpoint => apiv3Get(endpoint).then((response) => {
+      return !!response.data.isEnabled;
+    }),
+  );
+};

+ 1 - 1
packages/core/src/interfaces/user.ts

@@ -22,7 +22,7 @@ export type IUser = {
   lastLoginAt?: Date,
   introduction: string,
   status: IUserStatus,
-  isEnableQuestionnaire: boolean,
+  isQuestionnaireEnabled: boolean,
 }
 
 export type IUserGroupRelation = {