feat: admin/privilege

This commit is contained in:
haitaoo 2023-04-17 17:54:51 +08:00
parent 9da53361a7
commit fbb29a0b74
5 changed files with 72 additions and 125 deletions

View File

@ -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)

View File

@ -161,9 +161,7 @@ const SchemaForm: ForwardRefRenderFunction<IRef, IProps> = (
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<IRef, IProps> = (
useEffect(() => {
setDefaultValueAsDomBehaviour();
}, [formData]);
const handleInputChange = (e: React.ChangeEvent<HTMLInputElement>) => {
const { name, value } = e.target;
const data = {
@ -367,7 +364,9 @@ const SchemaForm: ForwardRefRenderFunction<IRef, IProps> = (
useImperativeHandle(ref, () => ({
validator,
}));
if (!formData || !schema || !schema.properties) {
return null;
}
return (
<Form noValidate onSubmit={handleSubmit}>
{keys.map((key) => {
@ -379,7 +378,7 @@ const SchemaForm: ForwardRefRenderFunction<IRef, IProps> = (
} = 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<IRef, IProps> = (
if (uiOpt?.fieldClassName) {
groupClassName = uiOpt.fieldClassName;
}
return (
<Form.Group
key={title}
@ -476,7 +476,7 @@ const SchemaForm: ForwardRefRenderFunction<IRef, IProps> = (
) : null}
{/* Unified handling of `Feedback` and `Text` */}
<Form.Control.Feedback type="invalid">
{fieldObject?.errorMsg}
{fieldData?.errorMsg}
</Form.Control.Feedback>
{description ? (
<Form.Text className="text-muted">{description}</Form.Text>

View File

@ -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<LangsType[]>();
const { data: setting } = useInterfaceSetting();
const [privilege, setPrivilege] = useState<AdminSettingsPrivilege>();
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<FormDataType>({
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<FormDataType>(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 (
<>
<h3 className="mb-4">{t('page_title')}</h3>
<h3 className="mb-4">{t('title')}</h3>
<SchemaForm
schema={schema}
uiSchema={uiSchema}
@ -174,4 +91,4 @@ const Interface: FC = () => {
);
};
export default Interface;
export default Index;

View File

@ -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;

View File

@ -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<Type.AdminSettingsGeneral, Error>(
@ -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<AdminSettingsPrivilege>(
'/answer/admin/api/setting/privileges',
);
};
export const putPrivilegeSetting = (level: number) => {
return request.put('/answer/admin/api/setting/privileges', {
level,
});
};