diff --git a/i18n/en_US.yaml b/i18n/en_US.yaml index 1cc723df..44a21977 100644 --- a/i18n/en_US.yaml +++ b/i18n/en_US.yaml @@ -1471,6 +1471,11 @@ ui: label: Allow users to change their website allow_update_location: label: Allow users to change their location + privilege: + title: Privileges + level: + label: Reputation required level + text: Choose the reputation required for the privileges form: optional: (optional) diff --git a/ui/src/components/SchemaForm/index.tsx b/ui/src/components/SchemaForm/index.tsx index a191f15c..bf8af1fc 100644 --- a/ui/src/components/SchemaForm/index.tsx +++ b/ui/src/components/SchemaForm/index.tsx @@ -161,9 +161,7 @@ const SchemaForm: ForwardRefRenderFunction = ( const { t } = useTranslation('translation', { keyPrefix: 'form', }); - - const { required = [], properties } = schema; - + const { required = [], properties = {} } = schema || {}; // check required field const excludes = required.filter((key) => !properties[key]); @@ -196,7 +194,6 @@ const SchemaForm: ForwardRefRenderFunction = ( useEffect(() => { setDefaultValueAsDomBehaviour(); }, [formData]); - const handleInputChange = (e: React.ChangeEvent) => { const { name, value } = e.target; const data = { @@ -367,7 +364,9 @@ const SchemaForm: ForwardRefRenderFunction = ( useImperativeHandle(ref, () => ({ validator, })); - + if (!formData || !schema || !schema.properties) { + return null; + } return (
{keys.map((key) => { @@ -379,7 +378,7 @@ const SchemaForm: ForwardRefRenderFunction = ( } = properties[key]; const { 'ui:widget': widget = 'input', 'ui:options': uiOpt } = uiSchema[key] || {}; - const fieldObject = formData[key]; + const fieldData = formData[key]; const uiSimplify = widget === 'legend' || uiOpt?.simplify; let groupClassName: BaseUIOptions['fieldClassName'] = uiOpt?.simplify ? 'mb-2' @@ -390,6 +389,7 @@ const SchemaForm: ForwardRefRenderFunction = ( if (uiOpt?.fieldClassName) { groupClassName = uiOpt.fieldClassName; } + return ( = ( ) : null} {/* Unified handling of `Feedback` and `Text` */} - {fieldObject?.errorMsg} + {fieldData?.errorMsg} {description ? ( {description} diff --git a/ui/src/pages/Admin/Privileges/index.tsx b/ui/src/pages/Admin/Privileges/index.tsx index 15ecddd7..e17e9b3c 100644 --- a/ui/src/pages/Admin/Privileges/index.tsx +++ b/ui/src/pages/Admin/Privileges/index.tsx @@ -2,132 +2,51 @@ import { FC, FormEvent, useEffect, useState } from 'react'; import { useTranslation } from 'react-i18next'; import { useToast } from '@/hooks'; +import { FormDataType } from '@/common/interface'; +import { JSONSchema, SchemaForm, UISchema, initFormData } from '@/components'; import { - LangsType, - FormDataType, - AdminSettingsInterface, -} from '@/common/interface'; -import { interfaceStore, loggedUserInfoStore } from '@/stores'; -import { JSONSchema, SchemaForm, UISchema } from '@/components'; -import { DEFAULT_TIMEZONE, SYSTEM_AVATAR_OPTIONS } from '@/common/constants'; -import { - updateInterfaceSetting, - useInterfaceSetting, - getLoggedUserInfo, + getPrivilegeSetting, + putPrivilegeSetting, + AdminSettingsPrivilege, } from '@/services'; -import { - setupAppLanguage, - loadLanguageOptions, - setupAppTimeZone, -} from '@/utils/localize'; import { handleFormError } from '@/utils'; +import * as Type from '@/common/interface'; -const Interface: FC = () => { +const Index: FC = () => { const { t } = useTranslation('translation', { - keyPrefix: 'admin.interface', + keyPrefix: 'admin.privilege', }); - const storeInterface = interfaceStore.getState().interface; const Toast = useToast(); - const [langs, setLangs] = useState(); - const { data: setting } = useInterfaceSetting(); + const [privilege, setPrivilege] = useState(); const schema: JSONSchema = { - title: t('page_title'), + title: t('title'), properties: { - language: { - type: 'string', - title: t('language.label'), - description: t('language.text'), - enum: langs?.map((lang) => lang.value), - enumNames: langs?.map((lang) => lang.label), - default: setting?.language || storeInterface.language, - }, - time_zone: { - type: 'string', - title: t('time_zone.label'), - description: t('time_zone.text'), - default: setting?.time_zone || DEFAULT_TIMEZONE, - }, - default_avatar: { - type: 'string', - title: t('avatar.label'), - description: t('avatar.text'), - enum: SYSTEM_AVATAR_OPTIONS?.map((v) => v.value), - enumNames: SYSTEM_AVATAR_OPTIONS?.map((v) => v.label), + level: { + type: 'number', + title: t('level.label'), + description: t('level.text'), + enum: privilege?.options.map((_) => _.level), + enumNames: privilege?.options.map((_) => _.level_desc), + default: 1, }, }, }; - const [formData, setFormData] = useState({ - language: { - value: setting?.language || storeInterface.language, - isInvalid: false, - errorMsg: '', - }, - time_zone: { - value: setting?.time_zone || DEFAULT_TIMEZONE, - isInvalid: false, - errorMsg: '', - }, - default_avatar: { - value: 'system', - isInvalid: false, - errorMsg: '', - }, - }); + const [formData, setFormData] = useState(initFormData(schema)); const uiSchema: UISchema = { - language: { + level: { 'ui:widget': 'select', }, - time_zone: { - 'ui:widget': 'timezone', - }, - default_avatar: { - 'ui:widget': 'select', - }, - }; - const getLangs = async () => { - const res: LangsType[] = await loadLanguageOptions(true); - setLangs(res); }; - const checkValidated = (): boolean => { - let ret = true; - const { language } = formData; - const formCheckData = { ...formData }; - if (!language.value) { - ret = false; - formCheckData.language = { - value: '', - isInvalid: true, - errorMsg: t('language.msg'), - }; - } - setFormData({ - ...formCheckData, - }); - return ret; - }; const onSubmit = (evt: FormEvent) => { evt.preventDefault(); evt.stopPropagation(); - if (checkValidated() === false) { - return; - } - const reqParams: AdminSettingsInterface = { - language: formData.language.value, - time_zone: formData.time_zone.value, - }; - - updateInterfaceSetting(reqParams) + const lv = Number(formData.level.value); + putPrivilegeSetting(lv) .then(() => { - interfaceStore.getState().update(reqParams); - setupAppLanguage(); - setupAppTimeZone(); - getLoggedUserInfo().then((info) => { - loggedUserInfoStore.getState().update(info); - }); Toast.onShow({ msg: t('update', { keyPrefix: 'toast' }), variant: 'success', @@ -142,27 +61,25 @@ const Interface: FC = () => { }; useEffect(() => { - if (setting) { - const formMeta = {}; - Object.keys(setting).forEach((k) => { - formMeta[k] = { ...formData[k], value: setting[k] }; - if (k === 'default_avatar') { - formMeta[k].value = setting[k] || 'system'; - } - }); + getPrivilegeSetting().then((resp) => { + setPrivilege(resp); + const formMeta: Type.FormDataType = {}; + formMeta.level = { + value: resp.selected_level, + errorMsg: '', + isInvalid: false, + }; setFormData({ ...formData, ...formMeta }); - } - }, [setting]); - useEffect(() => { - getLangs(); + }); }, []); const handleOnChange = (data) => { setFormData(data); }; + return ( <> -

{t('page_title')}

+

{t('title')}

{ ); }; -export default Interface; +export default Index; diff --git a/ui/src/pages/Admin/SettingsUsers/index.tsx b/ui/src/pages/Admin/SettingsUsers/index.tsx index 7595931d..0ab65c75 100644 --- a/ui/src/pages/Admin/SettingsUsers/index.tsx +++ b/ui/src/pages/Admin/SettingsUsers/index.tsx @@ -13,7 +13,7 @@ import { import { handleFormError } from '@/utils'; import * as Type from '@/common/interface'; -const Interface: FC = () => { +const Index: FC = () => { const { t } = useTranslation('translation', { keyPrefix: 'admin.settings_users', }); @@ -174,4 +174,4 @@ const Interface: FC = () => { ); }; -export default Interface; +export default Index; diff --git a/ui/src/services/admin/settings.ts b/ui/src/services/admin/settings.ts index 628ebd23..f9398bbe 100644 --- a/ui/src/services/admin/settings.ts +++ b/ui/src/services/admin/settings.ts @@ -13,6 +13,19 @@ export interface AdminSettingsUsers { default_avatar: string; } +interface PrivilegeLevel { + level: number; + level_desc: string; + privileges: { + label: string; + value: number; + }[]; +} +export interface AdminSettingsPrivilege { + selected_level: number; + options: PrivilegeLevel[]; +} + export const useGeneralSetting = () => { const apiUrl = `/answer/admin/api/siteinfo/general`; const { data, error } = useSWR( @@ -144,3 +157,15 @@ export const getUsersSetting = () => { export const putUsersSetting = (params: AdminSettingsUsers) => { return request.put('/answer/admin/api/siteinfo/users', params); }; + +export const getPrivilegeSetting = () => { + return request.get( + '/answer/admin/api/setting/privileges', + ); +}; + +export const putPrivilegeSetting = (level: number) => { + return request.put('/answer/admin/api/setting/privileges', { + level, + }); +};