mirror of https://gitee.com/answerdev/answer.git
Merge remote-tracking branch 'github/feat/1.1.2/ui' into feat/1.1.2/user-center
This commit is contained in:
commit
f50ccea7e5
|
@ -326,6 +326,16 @@ export interface AdminSettingsSmtp {
|
|||
test_email_recipient?: string;
|
||||
}
|
||||
|
||||
export interface AdminSettingsUsers {
|
||||
allow_update_avatar: boolean;
|
||||
allow_update_bio: boolean;
|
||||
allow_update_display_name: boolean;
|
||||
allow_update_location: boolean;
|
||||
allow_update_username: boolean;
|
||||
allow_update_website: boolean;
|
||||
default_avatar: string;
|
||||
}
|
||||
|
||||
export interface SiteSettings {
|
||||
branding: AdminSettingBranding;
|
||||
general: AdminSettingsGeneral;
|
||||
|
@ -334,6 +344,7 @@ export interface SiteSettings {
|
|||
custom_css_html: AdminSettingsCustom;
|
||||
theme: AdminSettingsTheme;
|
||||
site_seo: AdminSettingsSeo;
|
||||
site_users: AdminSettingsUsers;
|
||||
version: string;
|
||||
revision: string;
|
||||
}
|
||||
|
|
|
@ -0,0 +1,44 @@
|
|||
import React, { FC, useState } from 'react';
|
||||
import { Button } from 'react-bootstrap';
|
||||
|
||||
import { request } from '@/utils';
|
||||
import type * as Type from '@/common/interface';
|
||||
import type { UIAction } from '../index.d';
|
||||
|
||||
interface Props {
|
||||
fieldName: string;
|
||||
text: string;
|
||||
action: UIAction | undefined;
|
||||
formData: Type.FormDataType;
|
||||
readOnly: boolean;
|
||||
}
|
||||
const Index: FC<Props> = ({
|
||||
fieldName,
|
||||
action,
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
formData,
|
||||
readOnly = false,
|
||||
text = '',
|
||||
}) => {
|
||||
const [isLoading, setLoading] = useState(false);
|
||||
const handleAction = async () => {
|
||||
if (!action) {
|
||||
return;
|
||||
}
|
||||
setLoading(true);
|
||||
const method = action.method || 'get';
|
||||
await request[method](action.url);
|
||||
setLoading(false);
|
||||
};
|
||||
const disabled = isLoading || readOnly;
|
||||
return (
|
||||
<div className="d-flex">
|
||||
<Button name={fieldName} onClick={handleAction} disabled={disabled}>
|
||||
{text || fieldName}
|
||||
{isLoading ? '...' : ''}
|
||||
</Button>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default Index;
|
|
@ -9,6 +9,7 @@ interface Props {
|
|||
fieldName: string;
|
||||
onChange: (evt: React.ChangeEvent<HTMLInputElement>, ...rest) => void;
|
||||
formData: Type.FormDataType;
|
||||
readOnly: boolean;
|
||||
}
|
||||
const Index: FC<Props> = ({
|
||||
type = 'text',
|
||||
|
@ -16,6 +17,7 @@ const Index: FC<Props> = ({
|
|||
fieldName,
|
||||
onChange,
|
||||
formData,
|
||||
readOnly = false,
|
||||
}) => {
|
||||
const fieldObject = formData[fieldName];
|
||||
return (
|
||||
|
@ -25,8 +27,9 @@ const Index: FC<Props> = ({
|
|||
type={type}
|
||||
value={fieldObject?.value || ''}
|
||||
onChange={onChange}
|
||||
style={type === 'color' ? { width: '6rem' } : {}}
|
||||
readOnly={readOnly}
|
||||
isInvalid={fieldObject?.isInvalid}
|
||||
style={type === 'color' ? { width: '6rem' } : {}}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
|
|
@ -6,5 +6,16 @@ import Timezone from './Timezone';
|
|||
import Upload from './Upload';
|
||||
import Textarea from './Textarea';
|
||||
import Input from './Input';
|
||||
import Button from './Button';
|
||||
|
||||
export { Legend, Select, Check, Switch, Timezone, Upload, Textarea, Input };
|
||||
export {
|
||||
Legend,
|
||||
Select,
|
||||
Check,
|
||||
Switch,
|
||||
Timezone,
|
||||
Upload,
|
||||
Textarea,
|
||||
Input,
|
||||
Button,
|
||||
};
|
||||
|
|
|
@ -0,0 +1,6 @@
|
|||
export interface UIAction {
|
||||
url: string;
|
||||
method?: 'get' | 'post' | 'put' | 'delete';
|
||||
event?: 'click' | 'change';
|
||||
handler?: ({evt, formData, request}) => Promise<void>
|
||||
}
|
|
@ -11,6 +11,7 @@ import classnames from 'classnames';
|
|||
|
||||
import type * as Type from '@/common/interface';
|
||||
|
||||
import type { UIAction } from './index.d';
|
||||
import {
|
||||
Legend,
|
||||
Select,
|
||||
|
@ -20,6 +21,7 @@ import {
|
|||
Upload,
|
||||
Textarea,
|
||||
Input,
|
||||
Button as CtrlButton,
|
||||
} from './components';
|
||||
|
||||
export interface JSONSchema {
|
||||
|
@ -45,12 +47,14 @@ export interface BaseUIOptions {
|
|||
// The className that will be attached to a form field container
|
||||
fieldClassName?: classnames.Argument;
|
||||
// Make a form component render into simplified mode
|
||||
readOnly?: boolean;
|
||||
simplify?: boolean;
|
||||
validator?: (
|
||||
value,
|
||||
formData?,
|
||||
) => Promise<string | true | void> | true | string;
|
||||
}
|
||||
|
||||
export interface InputOptions extends BaseUIOptions {
|
||||
placeholder?: string;
|
||||
inputType?:
|
||||
|
@ -92,6 +96,12 @@ export interface TextareaOptions extends BaseUIOptions {
|
|||
rows?: number;
|
||||
}
|
||||
|
||||
export interface ButtonOptions extends BaseUIOptions {
|
||||
text: string;
|
||||
icon?: string;
|
||||
action?: UIAction;
|
||||
}
|
||||
|
||||
export type UIOptions =
|
||||
| InputOptions
|
||||
| SelectOptions
|
||||
|
@ -100,7 +110,8 @@ export type UIOptions =
|
|||
| TimezoneOptions
|
||||
| CheckboxOptions
|
||||
| RadioOptions
|
||||
| TextareaOptions;
|
||||
| TextareaOptions
|
||||
| ButtonOptions;
|
||||
|
||||
export type UIWidget =
|
||||
| 'textarea'
|
||||
|
@ -111,7 +122,8 @@ export type UIWidget =
|
|||
| 'upload'
|
||||
| 'timezone'
|
||||
| 'switch'
|
||||
| 'legend';
|
||||
| 'legend'
|
||||
| 'button';
|
||||
export interface UISchema {
|
||||
[key: string]: {
|
||||
'ui:widget'?: UIWidget;
|
||||
|
@ -134,9 +146,13 @@ interface IRef {
|
|||
|
||||
/**
|
||||
* TODO:
|
||||
* * Normalize and document `formData[key].hidden && 'd-none'`
|
||||
* * `handleXXChange` methods are placed in the concrete component
|
||||
* * Improving field hints for `formData`
|
||||
* - Normalize and document `formData[key].hidden && 'd-none'`
|
||||
* - Normalize and document `hiddenSubmit`
|
||||
* - `handleXXChange` methods are placed in the concrete component
|
||||
* - Improving field hints for `formData`
|
||||
* - Optimise form data updates
|
||||
* * Automatic field type conversion
|
||||
* * Dynamic field generation
|
||||
*/
|
||||
|
||||
/**
|
||||
|
@ -378,7 +394,7 @@ const SchemaForm: ForwardRefRenderFunction<IRef, IProps> = (
|
|||
} = properties[key];
|
||||
const { 'ui:widget': widget = 'input', 'ui:options': uiOpt } =
|
||||
uiSchema[key] || {};
|
||||
const fieldData = formData[key];
|
||||
const fieldState = formData[key];
|
||||
const uiSimplify = widget === 'legend' || uiOpt?.simplify;
|
||||
let groupClassName: BaseUIOptions['fieldClassName'] = uiOpt?.simplify
|
||||
? 'mb-2'
|
||||
|
@ -389,7 +405,7 @@ const SchemaForm: ForwardRefRenderFunction<IRef, IProps> = (
|
|||
if (uiOpt?.fieldClassName) {
|
||||
groupClassName = uiOpt.fieldClassName;
|
||||
}
|
||||
|
||||
const readOnly = uiOpt?.readOnly || false;
|
||||
return (
|
||||
<Form.Group
|
||||
key={title}
|
||||
|
@ -472,11 +488,21 @@ const SchemaForm: ForwardRefRenderFunction<IRef, IProps> = (
|
|||
fieldName={key}
|
||||
onChange={handleInputChange}
|
||||
formData={formData}
|
||||
readOnly={readOnly}
|
||||
/>
|
||||
) : null}
|
||||
{widget === 'button' ? (
|
||||
<CtrlButton
|
||||
fieldName={key}
|
||||
text={uiOpt && 'text' in uiOpt ? uiOpt.text : ''}
|
||||
action={uiOpt && 'action' in uiOpt ? uiOpt.action : undefined}
|
||||
formData={formData}
|
||||
readOnly={readOnly}
|
||||
/>
|
||||
) : null}
|
||||
{/* Unified handling of `Feedback` and `Text` */}
|
||||
<Form.Control.Feedback type="invalid">
|
||||
{fieldData?.errorMsg}
|
||||
{fieldState?.errorMsg}
|
||||
</Form.Control.Feedback>
|
||||
{description ? (
|
||||
<Form.Text className="text-muted">{description}</Form.Text>
|
||||
|
|
|
@ -9,6 +9,7 @@ interface IProps {
|
|||
className?: string;
|
||||
children?: React.ReactNode;
|
||||
acceptType?: string;
|
||||
disabled?: boolean;
|
||||
uploadCallback: (img: string) => void;
|
||||
}
|
||||
|
||||
|
@ -18,6 +19,7 @@ const Index: React.FC<IProps> = ({
|
|||
children,
|
||||
acceptType = '',
|
||||
className,
|
||||
disabled = false,
|
||||
}) => {
|
||||
const { t } = useTranslation();
|
||||
const [status, setStatus] = useState(false);
|
||||
|
@ -52,6 +54,7 @@ const Index: React.FC<IProps> = ({
|
|||
<input
|
||||
type="file"
|
||||
className="d-none"
|
||||
disabled={disabled}
|
||||
accept={`image/jpeg,image/jpg,image/png,image/webp${acceptType}`}
|
||||
onChange={onChange}
|
||||
/>
|
||||
|
|
|
@ -10,7 +10,6 @@ import {
|
|||
AdminSettingsPrivilege,
|
||||
} from '@/services';
|
||||
import { handleFormError } from '@/utils';
|
||||
import * as Type from '@/common/interface';
|
||||
|
||||
const Index: FC = () => {
|
||||
const { t } = useTranslation('translation', {
|
||||
|
@ -18,27 +17,66 @@ const Index: FC = () => {
|
|||
});
|
||||
const Toast = useToast();
|
||||
const [privilege, setPrivilege] = useState<AdminSettingsPrivilege>();
|
||||
|
||||
const schema: JSONSchema = {
|
||||
const [schema, setSchema] = useState<JSONSchema>({
|
||||
title: t('title'),
|
||||
properties: {
|
||||
properties: {},
|
||||
});
|
||||
const [uiSchema, setUiSchema] = useState<UISchema>({
|
||||
level: {
|
||||
'ui:widget': 'select',
|
||||
},
|
||||
});
|
||||
const [formData, setFormData] = useState<FormDataType>(initFormData(schema));
|
||||
|
||||
const setFormConfig = (selectedLevel: number = 1) => {
|
||||
selectedLevel = Number(selectedLevel);
|
||||
const levelOptions = privilege?.options;
|
||||
const curLevel = levelOptions?.find((li) => {
|
||||
return li.level === selectedLevel;
|
||||
});
|
||||
if (!levelOptions || !curLevel) {
|
||||
return;
|
||||
}
|
||||
const uiState = {
|
||||
level: uiSchema.level,
|
||||
};
|
||||
const props: JSONSchema['properties'] = {
|
||||
level: {
|
||||
type: 'number',
|
||||
title: t('level.label'),
|
||||
description: t('level.text'),
|
||||
enum: privilege?.options.map((_) => _.level),
|
||||
enumNames: privilege?.options.map((_) => _.level_desc),
|
||||
default: 1,
|
||||
enum: levelOptions.map((_) => _.level),
|
||||
enumNames: levelOptions.map((_) => _.level_desc),
|
||||
default: selectedLevel,
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
const [formData, setFormData] = useState<FormDataType>(initFormData(schema));
|
||||
|
||||
const uiSchema: UISchema = {
|
||||
level: {
|
||||
'ui:widget': 'select',
|
||||
},
|
||||
};
|
||||
curLevel.privileges.forEach((li) => {
|
||||
props[li.key] = {
|
||||
type: 'number',
|
||||
title: li.label,
|
||||
default: li.value,
|
||||
};
|
||||
uiState[li.key] = {
|
||||
'ui:options': {
|
||||
readOnly: true,
|
||||
},
|
||||
};
|
||||
});
|
||||
const schemaState = {
|
||||
...schema,
|
||||
properties: props,
|
||||
};
|
||||
const formState = initFormData(schemaState);
|
||||
curLevel.privileges.forEach((li) => {
|
||||
formState[li.key] = {
|
||||
value: li.value,
|
||||
isInvalid: false,
|
||||
errorMsg: '',
|
||||
};
|
||||
});
|
||||
setSchema(schemaState);
|
||||
setUiSchema(uiState);
|
||||
setFormData(formState);
|
||||
};
|
||||
|
||||
const onSubmit = (evt: FormEvent) => {
|
||||
|
@ -60,21 +98,19 @@ const Index: FC = () => {
|
|||
});
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
if (!privilege) {
|
||||
return;
|
||||
}
|
||||
setFormConfig(privilege.selected_level);
|
||||
}, [privilege]);
|
||||
useEffect(() => {
|
||||
getPrivilegeSetting().then((resp) => {
|
||||
setPrivilege(resp);
|
||||
const formMeta: Type.FormDataType = {};
|
||||
formMeta.level = {
|
||||
value: resp.selected_level,
|
||||
errorMsg: '',
|
||||
isInvalid: false,
|
||||
};
|
||||
setFormData({ ...formData, ...formMeta });
|
||||
});
|
||||
}, []);
|
||||
|
||||
const handleOnChange = (data) => {
|
||||
setFormData(data);
|
||||
const handleOnChange = (state) => {
|
||||
setFormConfig(state.level.value);
|
||||
};
|
||||
|
||||
return (
|
||||
|
|
|
@ -12,13 +12,14 @@ import {
|
|||
} from '@/services';
|
||||
import { handleFormError } from '@/utils';
|
||||
import * as Type from '@/common/interface';
|
||||
import { siteInfoStore } from '@/stores';
|
||||
|
||||
const Index: FC = () => {
|
||||
const { t } = useTranslation('translation', {
|
||||
keyPrefix: 'admin.settings_users',
|
||||
});
|
||||
const Toast = useToast();
|
||||
|
||||
const { updateUsers: updateUsersStore } = siteInfoStore();
|
||||
const schema: JSONSchema = {
|
||||
title: t('title'),
|
||||
properties: {
|
||||
|
@ -129,6 +130,7 @@ const Index: FC = () => {
|
|||
};
|
||||
putUsersSetting(reqParams)
|
||||
.then(() => {
|
||||
updateUsersStore(reqParams);
|
||||
Toast.onShow({
|
||||
msg: t('update', { keyPrefix: 'toast' }),
|
||||
variant: 'success',
|
||||
|
|
|
@ -2,7 +2,7 @@ import React, { useEffect, useState } from 'react';
|
|||
import { useTranslation } from 'react-i18next';
|
||||
|
||||
import { userCenterStore } from '@/stores';
|
||||
import { getUcSettings } from '@/services';
|
||||
import { getUcSettings, UcSettingAgent } from '@/services';
|
||||
|
||||
import { ModifyEmail, ModifyPassword, MyLogins } from './components';
|
||||
|
||||
|
@ -11,17 +11,12 @@ const Index = () => {
|
|||
keyPrefix: 'settings.account',
|
||||
});
|
||||
const { agent: ucAgent } = userCenterStore();
|
||||
const [accountAgent, setAccountAgent] = useState('');
|
||||
const [accountAgent, setAccountAgent] = useState<UcSettingAgent>();
|
||||
|
||||
const initData = () => {
|
||||
if (ucAgent?.enabled) {
|
||||
getUcSettings().then((resp) => {
|
||||
if (
|
||||
resp.account_setting_agent?.enabled &&
|
||||
resp.account_setting_agent?.redirect_url
|
||||
) {
|
||||
setAccountAgent(resp.account_setting_agent.redirect_url);
|
||||
}
|
||||
setAccountAgent(resp.account_setting_agent);
|
||||
});
|
||||
}
|
||||
};
|
||||
|
@ -31,10 +26,12 @@ const Index = () => {
|
|||
return (
|
||||
<>
|
||||
<h3 className="mb-4">{t('heading')}</h3>
|
||||
{accountAgent ? (
|
||||
<a href={accountAgent}>{t('goto_modify', { keyPrefix: 'settings' })}</a>
|
||||
{accountAgent?.enabled && accountAgent?.redirect_url ? (
|
||||
<a href={accountAgent.redirect_url}>
|
||||
{t('goto_modify', { keyPrefix: 'settings' })}
|
||||
</a>
|
||||
) : null}
|
||||
{!ucAgent?.enabled ? (
|
||||
{!ucAgent?.enabled || accountAgent?.enabled === false ? (
|
||||
<>
|
||||
<ModifyEmail />
|
||||
<ModifyPassword />
|
||||
|
|
|
@ -6,9 +6,14 @@ import MD5 from 'md5';
|
|||
|
||||
import type { FormDataType } from '@/common/interface';
|
||||
import { UploadImg, Avatar, Icon } from '@/components';
|
||||
import { loggedUserInfoStore, userCenterStore } from '@/stores';
|
||||
import { loggedUserInfoStore, userCenterStore, siteInfoStore } from '@/stores';
|
||||
import { useToast } from '@/hooks';
|
||||
import { modifyUserInfo, getLoggedUserInfo, getUcSettings } from '@/services';
|
||||
import {
|
||||
modifyUserInfo,
|
||||
getLoggedUserInfo,
|
||||
getUcSettings,
|
||||
UcSettingAgent,
|
||||
} from '@/services';
|
||||
import { handleFormError } from '@/utils';
|
||||
|
||||
const Index: React.FC = () => {
|
||||
|
@ -18,9 +23,10 @@ const Index: React.FC = () => {
|
|||
const toast = useToast();
|
||||
const { user, update } = loggedUserInfoStore();
|
||||
const { agent: ucAgent } = userCenterStore();
|
||||
const { users: usersSetting } = siteInfoStore();
|
||||
const [mailHash, setMailHash] = useState('');
|
||||
const [count] = useState(0);
|
||||
const [profileAgent, setProfileAgent] = useState('');
|
||||
const [profileAgent, setProfileAgent] = useState<UcSettingAgent>();
|
||||
|
||||
const [formData, setFormData] = useState<FormDataType>({
|
||||
display_name: {
|
||||
|
@ -248,11 +254,9 @@ const Index: React.FC = () => {
|
|||
const initData = () => {
|
||||
if (ucAgent?.enabled) {
|
||||
getUcSettings().then((resp) => {
|
||||
if (
|
||||
resp.profile_setting_agent?.enabled &&
|
||||
resp.profile_setting_agent?.redirect_url
|
||||
) {
|
||||
setProfileAgent(resp.profile_setting_agent.redirect_url);
|
||||
setProfileAgent(resp.profile_setting_agent);
|
||||
if (resp.profile_setting_agent?.enabled === false) {
|
||||
getProfile();
|
||||
}
|
||||
});
|
||||
} else {
|
||||
|
@ -266,16 +270,19 @@ const Index: React.FC = () => {
|
|||
return (
|
||||
<>
|
||||
<h3 className="mb-4">{t('heading')}</h3>
|
||||
{profileAgent ? (
|
||||
<a href={profileAgent}>{t('goto_modify', { keyPrefix: 'settings' })}</a>
|
||||
{profileAgent?.enabled && profileAgent?.redirect_url ? (
|
||||
<a href={profileAgent.redirect_url}>
|
||||
{t('goto_modify', { keyPrefix: 'settings' })}
|
||||
</a>
|
||||
) : null}
|
||||
{!ucAgent?.enabled ? (
|
||||
{!ucAgent?.enabled || profileAgent?.enabled === false ? (
|
||||
<Form noValidate onSubmit={handleSubmit}>
|
||||
<Form.Group controlId="displayName" className="mb-3">
|
||||
<Form.Label>{t('display_name.label')}</Form.Label>
|
||||
<Form.Control
|
||||
required
|
||||
type="text"
|
||||
readOnly={!usersSetting.allow_update_display_name}
|
||||
value={formData.display_name.value}
|
||||
isInvalid={formData.display_name.isInvalid}
|
||||
onChange={(e) =>
|
||||
|
@ -298,6 +305,7 @@ const Index: React.FC = () => {
|
|||
<Form.Control
|
||||
required
|
||||
type="text"
|
||||
readOnly={!usersSetting.allow_update_username}
|
||||
value={formData.username.value}
|
||||
isInvalid={formData.username.isInvalid}
|
||||
onChange={(e) =>
|
||||
|
@ -321,6 +329,7 @@ const Index: React.FC = () => {
|
|||
<div className="mb-3">
|
||||
<Form.Select
|
||||
name="avatar.type"
|
||||
disabled={!usersSetting.allow_update_avatar}
|
||||
value={formData.avatar.type}
|
||||
onChange={handleAvatarChange}>
|
||||
<option value="gravatar" key="gravatar">
|
||||
|
@ -369,11 +378,15 @@ const Index: React.FC = () => {
|
|||
className="me-2 bg-gray-300 "
|
||||
/>
|
||||
<ButtonGroup vertical className="fit-content">
|
||||
<UploadImg type="avatar" uploadCallback={avatarUpload}>
|
||||
<UploadImg
|
||||
type="avatar"
|
||||
disabled={!usersSetting.allow_update_avatar}
|
||||
uploadCallback={avatarUpload}>
|
||||
<Icon name="cloud-upload" />
|
||||
</UploadImg>
|
||||
<Button
|
||||
variant="outline-secondary"
|
||||
disabled={!usersSetting.allow_update_avatar}
|
||||
onClick={removeCustomAvatar}>
|
||||
<Icon name="trash" />
|
||||
</Button>
|
||||
|
@ -410,6 +423,7 @@ const Index: React.FC = () => {
|
|||
required
|
||||
as="textarea"
|
||||
rows={5}
|
||||
readOnly={!usersSetting.allow_update_bio}
|
||||
value={formData.bio.value}
|
||||
isInvalid={formData.bio.isInvalid}
|
||||
onChange={(e) =>
|
||||
|
@ -435,6 +449,7 @@ const Index: React.FC = () => {
|
|||
required
|
||||
type="url"
|
||||
placeholder={t('website.placeholder')}
|
||||
readOnly={!usersSetting.allow_update_website}
|
||||
value={formData.website.value}
|
||||
isInvalid={formData.website.isInvalid}
|
||||
onChange={(e) =>
|
||||
|
@ -460,6 +475,7 @@ const Index: React.FC = () => {
|
|||
required
|
||||
type="text"
|
||||
placeholder={t('location.placeholder')}
|
||||
readOnly={!usersSetting.allow_update_location}
|
||||
value={formData.location.value}
|
||||
isInvalid={formData.location.isInvalid}
|
||||
onChange={(e) =>
|
||||
|
|
|
@ -19,6 +19,7 @@ interface PrivilegeLevel {
|
|||
privileges: {
|
||||
label: string;
|
||||
value: number;
|
||||
key: string;
|
||||
}[];
|
||||
}
|
||||
export interface AdminSettingsPrivilege {
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import create from 'zustand';
|
||||
|
||||
import { AdminSettingsGeneral } from '@/common/interface';
|
||||
import { AdminSettingsGeneral, AdminSettingsUsers } from '@/common/interface';
|
||||
import { DEFAULT_SITE_NAME } from '@/common/constants';
|
||||
|
||||
interface SiteInfoType {
|
||||
|
@ -9,6 +9,8 @@ interface SiteInfoType {
|
|||
revision: string;
|
||||
update: (params: AdminSettingsGeneral) => void;
|
||||
updateVersion: (ver: string, revision: string) => void;
|
||||
users: AdminSettingsUsers;
|
||||
updateUsers: (users: SiteInfoType['users']) => void;
|
||||
}
|
||||
|
||||
const siteInfo = create<SiteInfoType>((set) => ({
|
||||
|
@ -20,6 +22,15 @@ const siteInfo = create<SiteInfoType>((set) => ({
|
|||
contact_email: '',
|
||||
permalink: 1,
|
||||
},
|
||||
users: {
|
||||
allow_update_avatar: false,
|
||||
allow_update_bio: false,
|
||||
allow_update_display_name: false,
|
||||
allow_update_location: false,
|
||||
allow_update_username: false,
|
||||
allow_update_website: false,
|
||||
default_avatar: 'system',
|
||||
},
|
||||
version: '',
|
||||
revision: '',
|
||||
update: (params) =>
|
||||
|
@ -37,6 +48,11 @@ const siteInfo = create<SiteInfoType>((set) => ({
|
|||
return { version: ver, revision };
|
||||
});
|
||||
},
|
||||
updateUsers: (users) => {
|
||||
set(() => {
|
||||
return { users };
|
||||
});
|
||||
},
|
||||
}));
|
||||
|
||||
export default siteInfo;
|
||||
|
|
|
@ -371,6 +371,7 @@ export const initAppSettingsStore = async () => {
|
|||
siteInfoStore
|
||||
.getState()
|
||||
.updateVersion(appSettings.version, appSettings.revision);
|
||||
siteInfoStore.getState().updateUsers(appSettings.site_users);
|
||||
interfaceStore.getState().update(appSettings.interface);
|
||||
brandingStore.getState().update(appSettings.branding);
|
||||
loginSettingStore.getState().update(appSettings.login);
|
||||
|
|
Loading…
Reference in New Issue