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); +};