From 1812d59cd9e5a229025075a4bd7b969b34b9e007 Mon Sep 17 00:00:00 2001
From: "haitao(lj)" <haitao@sifou.com>
Date: Tue, 6 Dec 2022 10:35:06 +0800
Subject: [PATCH] feat(seo): add robots setting for seo

---
 i18n/en_US.yaml                        |  6 ++
 ui/src/common/constants.ts             |  1 +
 ui/src/common/interface.ts             |  4 ++
 ui/src/pages/Admin/Answers/index.tsx   |  2 -
 ui/src/pages/Admin/Flags/index.tsx     |  2 -
 ui/src/pages/Admin/General/index.tsx   |  2 -
 ui/src/pages/Admin/Legal/index.tsx     |  1 -
 ui/src/pages/Admin/Questions/index.tsx |  2 -
 ui/src/pages/Admin/Seo/index.tsx       | 86 ++++++++++++++++++++++++++
 ui/src/pages/Admin/Smtp/index.tsx      |  3 +-
 ui/src/pages/Admin/Users/index.tsx     |  2 -
 ui/src/pages/Admin/Write/index.tsx     |  7 +--
 ui/src/router/routes.ts                |  4 ++
 ui/src/services/admin/settings.ts      |  8 +++
 14 files changed, 112 insertions(+), 18 deletions(-)
 create mode 100644 ui/src/pages/Admin/Seo/index.tsx

diff --git a/i18n/en_US.yaml b/i18n/en_US.yaml
index 5dd61252..0f5e5e8b 100644
--- a/i18n/en_US.yaml
+++ b/i18n/en_US.yaml
@@ -955,6 +955,7 @@ ui:
     write: Write
     tos: Terms of Service
     privacy: Privacy
+    seo: SEO
   admin:
     admin_header:
       title: Admin
@@ -1204,6 +1205,11 @@ ui:
       reserved_tags:
         label: Reserved Tags
         text: "Reserved tags can only be added to a post by moderator."
+    seo:
+      page_title: SEO
+      robots:
+        label: robots.txt
+        text: This will permanently override any related site settings.
   form:
     empty: cannot be empty
     invalid: is invalid
diff --git a/ui/src/common/constants.ts b/ui/src/common/constants.ts
index ab06f5f9..90a07fd6 100644
--- a/ui/src/common/constants.ts
+++ b/ui/src/common/constants.ts
@@ -62,6 +62,7 @@ export const ADMIN_NAV_MENUS = [
       { name: 'smtp' },
       { name: 'legal' },
       { name: 'write' },
+      { name: 'seo' },
     ],
   },
 ];
diff --git a/ui/src/common/interface.ts b/ui/src/common/interface.ts
index ce37c548..1e9a6ba5 100644
--- a/ui/src/common/interface.ts
+++ b/ui/src/common/interface.ts
@@ -338,6 +338,10 @@ export interface AdminSettingsWrite {
   reserved_tags: string[];
 }
 
+export interface AdminSettingsSeo {
+  robots: string;
+}
+
 /**
  * @description interface for Activity
  */
diff --git a/ui/src/pages/Admin/Answers/index.tsx b/ui/src/pages/Admin/Answers/index.tsx
index 72a98990..f2a3f01a 100644
--- a/ui/src/pages/Admin/Answers/index.tsx
+++ b/ui/src/pages/Admin/Answers/index.tsx
@@ -21,8 +21,6 @@ import { useAnswerSearch, changeAnswerStatus } from '@/services';
 import { escapeRemove } from '@/utils';
 import { pathFactory } from '@/router/pathFactory';
 
-import '../index.scss';
-
 const answerFilterItems: Type.AdminContentsFilterBy[] = ['normal', 'deleted'];
 
 const Answers: FC = () => {
diff --git a/ui/src/pages/Admin/Flags/index.tsx b/ui/src/pages/Admin/Flags/index.tsx
index 92c2dd24..79164715 100644
--- a/ui/src/pages/Admin/Flags/index.tsx
+++ b/ui/src/pages/Admin/Flags/index.tsx
@@ -16,8 +16,6 @@ import { useFlagSearch } from '@/services';
 import { escapeRemove } from '@/utils';
 import { pathFactory } from '@/router/pathFactory';
 
-import '../index.scss';
-
 const flagFilterKeys: Type.FlagStatus[] = ['pending', 'completed'];
 const flagTypeKeys: Type.FlagType[] = ['all', 'question', 'answer', 'comment'];
 
diff --git a/ui/src/pages/Admin/General/index.tsx b/ui/src/pages/Admin/General/index.tsx
index 1ab1f8b7..289ceb56 100644
--- a/ui/src/pages/Admin/General/index.tsx
+++ b/ui/src/pages/Admin/General/index.tsx
@@ -9,8 +9,6 @@ import { useGeneralSetting, updateGeneralSetting } from '@/services';
 import Pattern from '@/common/pattern';
 import { handleFormError } from '@/utils';
 
-import '../index.scss';
-
 const General: FC = () => {
   const { t } = useTranslation('translation', {
     keyPrefix: 'admin.general',
diff --git a/ui/src/pages/Admin/Legal/index.tsx b/ui/src/pages/Admin/Legal/index.tsx
index 1e6e4dd3..1438b20a 100644
--- a/ui/src/pages/Admin/Legal/index.tsx
+++ b/ui/src/pages/Admin/Legal/index.tsx
@@ -8,7 +8,6 @@ import { SchemaForm, JSONSchema, initFormData, UISchema } from '@/components';
 import { useToast } from '@/hooks';
 import { getLegalSetting, putLegalSetting } from '@/services';
 import { handleFormError } from '@/utils';
-import '../index.scss';
 
 const Legal: FC = () => {
   const { t } = useTranslation('translation', {
diff --git a/ui/src/pages/Admin/Questions/index.tsx b/ui/src/pages/Admin/Questions/index.tsx
index 7da830e5..c1694ce4 100644
--- a/ui/src/pages/Admin/Questions/index.tsx
+++ b/ui/src/pages/Admin/Questions/index.tsx
@@ -20,8 +20,6 @@ import * as Type from '@/common/interface';
 import { useQuestionSearch, changeQuestionStatus } from '@/services';
 import { pathFactory } from '@/router/pathFactory';
 
-import '../index.scss';
-
 const questionFilterItems: Type.AdminContentsFilterBy[] = [
   'normal',
   'closed',
diff --git a/ui/src/pages/Admin/Seo/index.tsx b/ui/src/pages/Admin/Seo/index.tsx
new file mode 100644
index 00000000..932d7d22
--- /dev/null
+++ b/ui/src/pages/Admin/Seo/index.tsx
@@ -0,0 +1,86 @@
+import { FC, useEffect, useState } from 'react';
+import { useTranslation } from 'react-i18next';
+
+import type * as Type from '@/common/interface';
+import { getSeoSetting, putSeoSetting } from '@/services';
+import { SchemaForm, JSONSchema, initFormData, UISchema } from '@/components';
+import { useToast } from '@/hooks';
+import { handleFormError } from '@/utils';
+
+const Index: FC = () => {
+  const { t } = useTranslation('translation', {
+    keyPrefix: 'admin.seo',
+  });
+  const Toast = useToast();
+  const schema: JSONSchema = {
+    title: t('page_title'),
+    properties: {
+      robots: {
+        type: 'string',
+        title: t('robots.label'),
+        description: t('robots.text'),
+      },
+    },
+  };
+  const uiSchema: UISchema = {
+    robots: {
+      'ui:widget': 'textarea',
+      'ui:options': {
+        rows: 10,
+      },
+    },
+  };
+  const [formData, setFormData] = useState(initFormData(schema));
+
+  const onSubmit = (evt) => {
+    evt.preventDefault();
+    evt.stopPropagation();
+
+    const reqParams: Type.AdminSettingsSeo = {
+      robots: formData.robots.value,
+    };
+
+    putSeoSetting(reqParams)
+      .then(() => {
+        Toast.onShow({
+          msg: t('update', { keyPrefix: 'toast' }),
+          variant: 'success',
+        });
+      })
+      .catch((err) => {
+        if (err.isError) {
+          const data = handleFormError(err, formData);
+          setFormData({ ...data });
+        }
+      });
+  };
+
+  useEffect(() => {
+    getSeoSetting().then((setting) => {
+      if (setting) {
+        const formMeta = { ...formData };
+        formMeta.robots.value = setting.robots;
+        setFormData(formMeta);
+      }
+    });
+  }, []);
+
+  const handleOnChange = (data) => {
+    setFormData(data);
+  };
+
+  return (
+    <>
+      <h3 className="mb-4">{t('page_title')}</h3>
+      <SchemaForm
+        schema={schema}
+        formData={formData}
+        onSubmit={onSubmit}
+        uiSchema={uiSchema}
+        onChange={handleOnChange}
+      />
+    </>
+  );
+};
+
+export default Index;
diff --git a/ui/src/pages/Admin/Smtp/index.tsx b/ui/src/pages/Admin/Smtp/index.tsx
index a60ed5c1..ba902aa4 100644
--- a/ui/src/pages/Admin/Smtp/index.tsx
+++ b/ui/src/pages/Admin/Smtp/index.tsx
@@ -5,8 +5,7 @@ import type * as Type from '@/common/interface';
 import { useToast } from '@/hooks';
 import { useSmtpSetting, updateSmtpSetting } from '@/services';
 import pattern from '@/common/pattern';
-import { SchemaForm, JSONSchema, UISchema } from '@/components';
-import { initFormData } from '../../../components/SchemaForm/index';
+import { SchemaForm, JSONSchema, UISchema, initFormData } from '@/components';
 import { handleFormError } from '@/utils';
 
 const Smtp: FC = () => {
diff --git a/ui/src/pages/Admin/Users/index.tsx b/ui/src/pages/Admin/Users/index.tsx
index 89b92bd4..4ad54bc4 100644
--- a/ui/src/pages/Admin/Users/index.tsx
+++ b/ui/src/pages/Admin/Users/index.tsx
@@ -18,8 +18,6 @@ import { useChangeModal, useChangeUserRoleModal, useToast } from '@/hooks';
 import { useQueryUsers } from '@/services';
 import { loggedUserInfoStore } from '@/stores';
 
-import '../index.scss';
-
 const UserFilterKeys: Type.UserFilterBy[] = [
   'all',
   'staff',
diff --git a/ui/src/pages/Admin/Write/index.tsx b/ui/src/pages/Admin/Write/index.tsx
index ce2c4335..1df9788f 100644
--- a/ui/src/pages/Admin/Write/index.tsx
+++ b/ui/src/pages/Admin/Write/index.tsx
@@ -10,14 +10,11 @@ import {
 } from '@/services';
 import { handleFormError } from '@/utils';
 
-import '../index.scss';
-
-const Legal: FC = () => {
+const Index: FC = () => {
   const { t } = useTranslation('translation', {
     keyPrefix: 'admin.write',
   });
   const Toast = useToast();
-  // const updateSiteInfo = siteInfoStore((state) => state.update);
 
   const schema: JSONSchema = {
     title: t('page_title'),
@@ -125,4 +122,4 @@ const Legal: FC = () => {
   );
 };
 
-export default Legal;
+export default Index;
diff --git a/ui/src/router/routes.ts b/ui/src/router/routes.ts
index 56bf46de..950d997b 100644
--- a/ui/src/router/routes.ts
+++ b/ui/src/router/routes.ts
@@ -276,6 +276,10 @@ const routes: RouteNode[] = [
             path: 'write',
             page: 'pages/Admin/Write',
           },
+          {
+            path: 'seo',
+            page: 'pages/Admin/Seo',
+          },
         ],
       },
       // for review
diff --git a/ui/src/services/admin/settings.ts b/ui/src/services/admin/settings.ts
index e24cf34f..6e0028c1 100644
--- a/ui/src/services/admin/settings.ts
+++ b/ui/src/services/admin/settings.ts
@@ -101,3 +101,11 @@ export const getLegalSetting = () => {
 export const putLegalSetting = (params: Type.AdminSettingsLegal) => {
   return request.put('/answer/admin/api/siteinfo/legal', params);
 };
+
+export const getSeoSetting = () => {
+  return request.get<Type.AdminSettingsSeo>('/answer/admin/api/siteinfo/seo');
+};
+
+export const putSeoSetting = (params: Type.AdminSettingsSeo) => {
+  return request.put('/answer/admin/api/siteinfo/seo', params);
+};