diff --git a/shared/index.tsx b/shared/index.tsx index 3eabf894..a7539582 100644 --- a/shared/index.tsx +++ b/shared/index.tsx @@ -140,6 +140,7 @@ export { loginWithEmail, loginWithToken, registerWithEmail, + modifyUserPassword, createTemporaryUser, claimTemporaryUser, searchUserWithUniqueName, diff --git a/shared/model/user.ts b/shared/model/user.ts index 4eb9f0e4..ef1b7d38 100644 --- a/shared/model/user.ts +++ b/shared/model/user.ts @@ -82,6 +82,16 @@ export async function registerWithEmail( return data; } +export async function modifyUserPassword( + oldPassword: string, + newPassword: string +): Promise { + await request.post('/api/user/modifyPassword', { + oldPassword, + newPassword, + }); +} + /** * 创建访客账号 * @param nickname 访客昵称 diff --git a/web/src/App.tsx b/web/src/App.tsx index 5fb7ada2..b0d1964f 100644 --- a/web/src/App.tsx +++ b/web/src/App.tsx @@ -41,6 +41,7 @@ const AppContainer: React.FC = React.memo((props) => {
void; + onSuccess?: () => void; } export const ClaimTemporaryUser: React.FC = React.memo( (props) => { @@ -63,7 +63,7 @@ export const ClaimTemporaryUser: React.FC = React.memo( typeof props.onSuccess === 'function' && props.onSuccess(); }, - [, userId, props.onSuccess] + [userId, props.onSuccess] ); return ( diff --git a/web/src/components/modals/ModifyPassword.tsx b/web/src/components/modals/ModifyPassword.tsx new file mode 100644 index 00000000..2b720edd --- /dev/null +++ b/web/src/components/modals/ModifyPassword.tsx @@ -0,0 +1,84 @@ +import React from 'react'; +import { + createFastFormSchema, + FastFormFieldMeta, + fieldSchema, + modifyUserPassword, + showToasts, + t, + useAsyncRequest, +} from 'tailchat-shared'; +import { ModalWrapper } from '../Modal'; +import { WebFastForm } from '../WebFastForm'; + +interface Values { + oldPassword: string; + newPassword: string; + newPasswordRepeat: string; +} + +const fields: FastFormFieldMeta[] = [ + { + type: 'password', + name: 'oldPassword', + label: t('旧密码'), + }, + { + type: 'password', + name: 'newPassword', + label: t('新密码'), + }, + { + type: 'password', + name: 'newPasswordRepeat', + label: t('重复密码'), + }, +]; + +const schema = createFastFormSchema({ + oldPassword: fieldSchema + .string() + .min(6, t('密码不能低于6位')) + .required(t('密码不能为空')), + newPassword: fieldSchema + .string() + .min(6, t('密码不能低于6位')) + .required(t('密码不能为空')), + newPasswordRepeat: fieldSchema + .string() + .min(6, t('密码不能低于6位')) + .required(t('密码不能为空')), +}); + +interface ModifyPasswordProps { + onSuccess?: () => void; +} +export const ModifyPassword: React.FC = React.memo( + (props) => { + const [{}, handleModifyPassword] = useAsyncRequest( + async (values: Values) => { + if (values.newPassword !== values.newPasswordRepeat) { + showToasts(t('新旧密码不匹配'), 'warning'); + return; + } + + await modifyUserPassword(values.oldPassword, values.newPassword); + showToasts(t('密码修改成功'), 'success'); + + typeof props.onSuccess === 'function' && props.onSuccess(); + }, + [props.onSuccess] + ); + + return ( + + + + ); + } +); +ModifyPassword.displayName = 'ModifyPassword'; diff --git a/web/src/components/modals/SettingsView/Account.tsx b/web/src/components/modals/SettingsView/Account.tsx index fe404cb1..260bc3c5 100644 --- a/web/src/components/modals/SettingsView/Account.tsx +++ b/web/src/components/modals/SettingsView/Account.tsx @@ -4,9 +4,11 @@ import { DefaultFullModalInputEditorRender, FullModalField, } from '@/components/FullModal/Field'; +import { openModal } from '@/components/Modal'; +import { closeModal } from '@/plugin/common'; import { getGlobalSocket } from '@/utils/global-state-helper'; import { setUserJWT } from '@/utils/jwt-helper'; -import { Button, Divider } from 'antd'; +import { Button, Divider, Typography } from 'antd'; import React, { useCallback } from 'react'; import { useHistory } from 'react-router'; import { @@ -19,6 +21,7 @@ import { userActions, useUserInfo, } from 'tailchat-shared'; +import { ModifyPassword } from '../ModifyPassword'; export const SettingsAccount: React.FC = React.memo(() => { const userInfo = useUserInfo(); @@ -53,6 +56,10 @@ export const SettingsAccount: React.FC = React.memo(() => { [] ); + const handleUpdatePassword = useCallback(() => { + const key = openModal( closeModal(key)} />); + }, []); + // 登出 const handleLogout = useCallback(async () => { await setUserJWT(null); @@ -86,6 +93,14 @@ export const SettingsAccount: React.FC = React.memo(() => { />
+ + + + {t('密码')} + +
diff --git a/web/src/styles/antd/theme.less b/web/src/styles/antd/theme.less index 9d9e8b86..af8ad67d 100644 --- a/web/src/styles/antd/theme.less +++ b/web/src/styles/antd/theme.less @@ -1,5 +1,5 @@ // antd 主题色支持 -#tailchat-app { +.tailchat-app { --tc-primary-color: rgb(24, 144, 255); .ant-btn-primary {