From b67a37453db400e97867092a567c882b770522e7 Mon Sep 17 00:00:00 2001 From: Zeng1998 <1129142694@qq.com> Date: Mon, 28 Nov 2022 19:59:11 +0800 Subject: [PATCH] feat: member management enhancement (#617) * feat: member management enhancement * update * update * update * update --- .../components/ChangeMemberPasswordDialog.tsx | 125 ++++++++++++++++++ web/src/components/Settings/MemberSection.tsx | 42 +++++- web/src/less/common-dialog.less | 2 +- web/src/less/setting-dialog.less | 14 +- 4 files changed, 179 insertions(+), 4 deletions(-) create mode 100644 web/src/components/ChangeMemberPasswordDialog.tsx diff --git a/web/src/components/ChangeMemberPasswordDialog.tsx b/web/src/components/ChangeMemberPasswordDialog.tsx new file mode 100644 index 00000000..8777e79d --- /dev/null +++ b/web/src/components/ChangeMemberPasswordDialog.tsx @@ -0,0 +1,125 @@ +import { useEffect, useState } from "react"; +import { useTranslation } from "react-i18next"; +import { validate, ValidatorConfig } from "../helpers/validator"; +import { userService } from "../services"; +import Icon from "./Icon"; +import { generateDialog } from "./Dialog"; +import toastHelper from "./Toast"; + +const validateConfig: ValidatorConfig = { + minLength: 4, + maxLength: 320, + noSpace: true, + noChinese: true, +}; + +interface Props extends DialogProps { + user: User; +} + +const ChangeMemberPasswordDialog: React.FC = (props: Props) => { + const { user: propsUser, destroy } = props; + const { t } = useTranslation(); + const [newPassword, setNewPassword] = useState(""); + const [newPasswordAgain, setNewPasswordAgain] = useState(""); + + useEffect(() => { + // do nth + }, []); + + const handleCloseBtnClick = () => { + destroy(); + }; + + const handleNewPasswordChanged = (e: React.ChangeEvent) => { + const text = e.target.value as string; + setNewPassword(text); + }; + + const handleNewPasswordAgainChanged = (e: React.ChangeEvent) => { + const text = e.target.value as string; + setNewPasswordAgain(text); + }; + + const handleSaveBtnClick = async () => { + if (newPassword === "" || newPasswordAgain === "") { + toastHelper.error(t("message.fill-all")); + return; + } + + if (newPassword !== newPasswordAgain) { + toastHelper.error(t("message.new-password-not-match")); + setNewPasswordAgain(""); + return; + } + + const passwordValidResult = validate(newPassword, validateConfig); + if (!passwordValidResult.result) { + toastHelper.error(`${t("common.password")} ${passwordValidResult.reason}`); + return; + } + + try { + await userService.patchUser({ + id: propsUser.id, + password: newPassword, + }); + toastHelper.info(t("message.password-changed")); + handleCloseBtnClick(); + } catch (error: any) { + console.error(error); + toastHelper.error(error.response.data.message); + } + }; + + return ( + <> +
+

+ {t("setting.account-section.change-password")} ({propsUser.username}) +

+ +
+
+

{t("common.new-password")}

+ +

{t("common.repeat-new-password")}

+ +
+ + {t("common.cancel")} + + + {t("common.save")} + +
+
+ + ); +}; + +function showChangeMemberPasswordDialog(user: User) { + generateDialog( + { + className: "change-member-password-dialog", + }, + ChangeMemberPasswordDialog, + { user } + ); +} + +export default showChangeMemberPasswordDialog; diff --git a/web/src/components/Settings/MemberSection.tsx b/web/src/components/Settings/MemberSection.tsx index 38b5d1e9..52a04793 100644 --- a/web/src/components/Settings/MemberSection.tsx +++ b/web/src/components/Settings/MemberSection.tsx @@ -4,8 +4,10 @@ import { userService } from "../../services"; import { useAppSelector } from "../../store"; import * as api from "../../helpers/api"; import toastHelper from "../Toast"; +import Icon from "../Icon"; import Dropdown from "../common/Dropdown"; import { showCommonDialog } from "../Dialog/CommonDialog"; +import showChangeMemberPasswordDialog from "../ChangeMemberPasswordDialog"; import "../../less/settings/member-section.less"; interface State { @@ -22,8 +24,13 @@ const PreferencesSection = () => { createUserPassword: "", repeatUserPassword: "", }); + const [userNameQueryText, setUserNameQueryText] = useState(""); const [userList, setUserList] = useState([]); + const showUserList = userList.filter((user: User) => { + return user.username.toLowerCase().includes(userNameQueryText.toLowerCase()); + }); + useEffect(() => { fetchUserList(); }, []); @@ -83,6 +90,15 @@ const PreferencesSection = () => { }); }; + const handleUserNameQueryInput = (event: React.FormEvent) => { + const text = event.currentTarget.value; + setUserNameQueryText(text); + }; + + const handleChangePasswordClick = (user: User) => { + showChangeMemberPasswordDialog(user); + }; + const handleArchiveUserClick = (user: User) => { showCommonDialog({ title: `Archive Member`, @@ -145,13 +161,29 @@ const PreferencesSection = () => { -

{t("setting.member-list")}

+
+
{t("setting.member-list")}
+
+
+
+ + +
+
+
+
ID {t("common.username")}
- {userList.map((user) => ( + {showUserList.map((user) => (
{user.id} {user.username} @@ -163,6 +195,12 @@ const PreferencesSection = () => { actionsClassName="!w-24" actions={ <> + {user.rowStatus === "NORMAL" ? (