diff --git a/public/locales/en/member.json b/public/locales/en/member.json index cdf4402e..c937db75 100644 --- a/public/locales/en/member.json +++ b/public/locales/en/member.json @@ -17,18 +17,20 @@ "manage_tip": "Disabling your account means you can recover it at any time after taking this action.", "admin": "Admin", "user": "User", - "copy_email": "Copy Email", - "send_msg": "Send Message", + "copy_email": "Copy email", + "send_msg": "Send message", "call": "Call", - "remove": "Remove from Server", - "remove_from_contact": "Remove From Contact", - "remove_account": "Remove Account", + "remove": "Remove from server", + "remove_from_contact": "Remove from contact", + "remove_account": "Remove account", "remove_account_desc": "Are you sure remove this account?", - "remove_from_channel": "Remove From Channel", + "remove_from_channel": "Remove from channel", + "set_admin": "Set as admin", + "set_normal": "Set as normal user", "search_not_found": "Not found, or this user is not allowed to be searched.", "search_by_id": "Search by ID", "search_by_id_ph": "Input user ID", - "search_by_email": "Search by Email", + "search_by_email": "Search by email", "search_by_email_ph": "Input user email" } diff --git a/public/locales/zh/member.json b/public/locales/zh/member.json index fc8c0a10..7adc8960 100644 --- a/public/locales/zh/member.json +++ b/public/locales/zh/member.json @@ -24,6 +24,8 @@ "remove_account": "注销账号", "remove_account_desc": "确定永久注销该账号?", "remove_from_channel": "从频道移除", + "set_admin": "设置为管理员", + "set_normal": "设置为普通用户", "search_not_found": "用户不存在,或者不允许搜索", "search_by_id": "用户ID", diff --git a/src/components/Profile/index.tsx b/src/components/Profile/index.tsx index 382f5b98..01822cb9 100644 --- a/src/components/Profile/index.tsx +++ b/src/components/Profile/index.tsx @@ -29,7 +29,10 @@ const Profile: FC = ({ uid, type = "embed", cid }) => { removeFromChannel, canRemoveFromChannel, canRemove, - removeUser + removeUser, + isAdmin, + canUpdateRole, + updateRole } = useUserOperation({ uid, cid }); const { data } = useAppSelector((store) => { @@ -99,6 +102,11 @@ const Profile: FC = ({ uid, type = "embed", cid }) => { {t("copy_email")} )} + {canUpdateRole && ( +
  • + {isAdmin ? t("set_normal") : t("set_admin")} +
  • + )} {canRemoveFromChannel && (
  • {t("remove_from_channel")} diff --git a/src/components/User/ContextMenu.tsx b/src/components/User/ContextMenu.tsx index d444fe8e..fd554d7b 100644 --- a/src/components/User/ContextMenu.tsx +++ b/src/components/User/ContextMenu.tsx @@ -28,7 +28,10 @@ const UserContextMenu: FC = ({ enable = false, uid, cid, visible, hide, c canBlock, canRemoveFromChannel, removeFromChannel, - removeUser + removeUser, + isAdmin, + canUpdateRole, + updateRole } = useUserOperation({ uid, cid @@ -56,6 +59,10 @@ const UserContextMenu: FC = ({ enable = false, uid, cid, visible, hide, c title: t("copy_email"), handler: copyEmail }, + canUpdateRole && { + title: isAdmin ? t("set_normal") : t("set_admin"), + handler: updateRole + }, canRemoveFromChannel && { danger: true, title: t("remove_from_channel"), diff --git a/src/hooks/useUserOperation.ts b/src/hooks/useUserOperation.ts index 0f78a335..f77c1b99 100644 --- a/src/hooks/useUserOperation.ts +++ b/src/hooks/useUserOperation.ts @@ -7,7 +7,11 @@ import { useMatch, useNavigate } from "react-router-dom"; import { hideAll } from "tippy.js"; import { useRemoveMembersMutation } from "@/app/services/channel"; -import { useLazyDeleteUserQuery, useUpdateContactStatusMutation } from "@/app/services/user"; +import { + useLazyDeleteUserQuery, + useUpdateContactStatusMutation, + useUpdateUserMutation +} from "@/app/services/user"; import { updateDMVisibleAside } from "@/app/slices/footprint"; import { updateCallInfo } from "@/app/slices/voice"; import { useAppSelector } from "@/app/store"; @@ -30,6 +34,7 @@ const useUserOperation = ({ uid, cid }: IProps) => { const [passedUid, setPassedUid] = useState(undefined); const isUserDetailPath = useMatch(`/users/${uid}`); const [updateContactStatus] = useUpdateContactStatusMutation(); + const [updateUser, { isSuccess: updateUserSuccess }] = useUpdateUserMutation(); const [removeUser, { isSuccess: removeUserSuccess }] = useLazyDeleteUserQuery(); const [removeInChannel, { isSuccess: removeSuccess }] = useRemoveMembersMutation(); const navigateTo = useNavigate(); @@ -46,6 +51,12 @@ const useUserOperation = ({ uid, cid }: IProps) => { setPassedUid(uid ?? loginUser?.uid); }, [uid, loginUser]); + useEffect(() => { + if (updateUserSuccess) { + toast.success(ct("tip.update")); + } + }, [updateUserSuccess]); + useEffect(() => { if (removeSuccess || removeUserSuccess) { toast.success(ct("tip.delete")); @@ -99,6 +110,11 @@ const useUserOperation = ({ uid, cid }: IProps) => { const startChat = () => { navigateTo(`/chat/dm/${uid}`); }; + const updateRole = () => { + if (uid) { + updateUser({ id: uid, is_admin: !user?.is_admin }); + } + }; const removeFromContact = () => { if (uid) { updateContactStatus({ target_uid: uid, action: "remove" }); @@ -126,6 +142,9 @@ const useUserOperation = ({ uid, cid }: IProps) => { const canRemoveFromContact: boolean = loginUid != uid; const canInviteChannel = !!cid && (loginUser?.is_admin || channel?.owner == loginUser?.uid); return { + isAdmin: !!user?.is_admin, + updateRole, + canUpdateRole: isAdmin && loginUid != uid && uid != 1, removeFromContact, canBlock, canRemoveFromContact,