From 7645300bda8025345bd7973663b60a28075f2d33 Mon Sep 17 00:00:00 2001 From: moonrailgun Date: Thu, 26 Jan 2023 22:20:32 +0800 Subject: [PATCH] =?UTF-8?q?refactor:=20=E5=B0=86=E7=BE=A4=E7=BB=84?= =?UTF-8?q?=E7=94=A8=E6=88=B7=E6=93=8D=E4=BD=9C=E7=9B=B8=E5=85=B3=E7=9A=84?= =?UTF-8?q?=E9=80=BB=E8=BE=91=E5=8D=95=E7=8B=AC=E6=8A=BD=E8=B1=A1=E6=88=90?= =?UTF-8?q?=E4=B8=80=E4=B8=AAhooks=E6=96=B9=E4=BE=BF=E5=A4=8D=E7=94=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../components/Panel/group/MembersPanel.tsx | 101 +------------- .../components/modals/GroupDetail/index.tsx | 8 ++ client/web/src/hooks/useGroupMemberAction.ts | 127 ++++++++++++++++++ 3 files changed, 142 insertions(+), 94 deletions(-) create mode 100644 client/web/src/hooks/useGroupMemberAction.ts diff --git a/client/web/src/components/Panel/group/MembersPanel.tsx b/client/web/src/components/Panel/group/MembersPanel.tsx index 305605a8..24e8faa0 100644 --- a/client/web/src/components/Panel/group/MembersPanel.tsx +++ b/client/web/src/components/Panel/group/MembersPanel.tsx @@ -1,93 +1,26 @@ import { Icon } from 'tailchat-design'; -import { openReconfirmModalP } from '@/components/Modal'; import { GroupUserPopover } from '@/components/popover/GroupUserPopover'; import { UserListItem } from '@/components/UserListItem'; import { Divider, Dropdown, Input, MenuProps, Skeleton } from 'antd'; import React, { useMemo } from 'react'; import { - formatFullTime, getGroupConfigWithInfo, - GroupMember, - humanizeMsDuration, - model, PERMISSION, - showToasts, t, - useAsyncRequest, useCachedOnlineStatus, useGroupInfo, useHasGroupPermission, UserBaseInfo, - useSearch, useUserInfoList, } from 'tailchat-shared'; import _compact from 'lodash/compact'; import { Problem } from '@/components/Problem'; +import { useGroupMemberAction } from '@/hooks/useGroupMemberAction'; interface MembersPanelProps { groupId: string; } -function getMembersHasMute(members: GroupMember[], userId: string): boolean { - const member = members.find((m) => m.userId === userId); - - if (!member || !member.muteUntil) { - return false; - } - - const muteUntil = member.muteUntil; - - return new Date(muteUntil).valueOf() > new Date().valueOf(); -} - -/** - * 禁言相关 - */ -function useMemberMuteAction( - groupId: string, - userInfoList: model.user.UserBaseInfo[] -) { - /** - * 禁言 - */ - const [, handleMuteMember] = useAsyncRequest( - async (memberId: string, ms: number) => { - const memberInfo = userInfoList.find((m) => m._id === memberId); - - if (!memberInfo) { - throw new Error(t('没有找到用户')); - } - - if ( - await openReconfirmModalP({ - title: t('确定要禁言 {{name}} 么', { name: memberInfo.nickname }), - content: t('禁言 {{length}}, 预计到 {{until}} 为止', { - length: humanizeMsDuration(ms), - until: formatFullTime(new Date().valueOf() + ms), - }), - }) - ) { - await model.group.muteGroupMember(groupId, memberId, ms); - showToasts(t('操作成功'), 'success'); - } - }, - [groupId, userInfoList] - ); - - /** - * 解除禁言 - */ - const [, handleUnmuteMember] = useAsyncRequest( - async (memberId: string) => { - await model.group.muteGroupMember(groupId, memberId, -1); - showToasts(t('操作成功'), 'success'); - }, - [groupId] - ); - - return { handleMuteMember, handleUnmuteMember }; -} - /** * 用户面板 */ @@ -109,10 +42,11 @@ export const MembersPanel: React.FC = React.memo((props) => { setSearchText, isSearching, searchResult: filteredGroupMembers, - } = useSearch({ - dataSource: userInfoList, - filterFn: (item, searchText) => item.nickname.includes(searchText), - }); + getMemberHasMute, + handleMuteMember, + handleUnmuteMember, + handleRemoveGroupMember, + } = useGroupMemberAction(groupId); const groupedMembers = useMemo(() => { const online: UserBaseInfo[] = []; @@ -132,27 +66,6 @@ export const MembersPanel: React.FC = React.memo((props) => { }; }, [userInfoList, membersOnlineStatus]); - const { handleMuteMember, handleUnmuteMember } = useMemberMuteAction( - groupId, - userInfoList - ); - - /** - * 解除禁言 - */ - const [, handleRemoveGroupMember] = useAsyncRequest( - async (memberId: string) => { - const confirm = await openReconfirmModalP({ - title: t('确认要将该用户移出群组么'), - }); - if (confirm) { - await model.group.deleteGroupMember(groupId, memberId); - showToasts(t('操作成功'), 'success'); - } - }, - [groupId] - ); - if (!groupInfo) { return ; } @@ -162,7 +75,7 @@ export const MembersPanel: React.FC = React.memo((props) => { } const renderUser = (member: UserBaseInfo) => { - const hasMute = getMembersHasMute(members, member._id); + const hasMute = getMemberHasMute(member._id); if (allowManageUser) { const muteItems: MenuProps['items'] = hasMute diff --git a/client/web/src/components/modals/GroupDetail/index.tsx b/client/web/src/components/modals/GroupDetail/index.tsx index 3b106ca3..cc2b0e67 100644 --- a/client/web/src/components/modals/GroupDetail/index.tsx +++ b/client/web/src/components/modals/GroupDetail/index.tsx @@ -14,6 +14,7 @@ import { GroupRole } from './Role'; import { GroupSummary } from './Summary'; import _compact from 'lodash/compact'; import { GroupConfig } from './Config'; +import { GroupMember } from './Member'; interface SettingsViewProps { groupId: string; @@ -31,11 +32,13 @@ export const GroupDetail: React.FC = React.memo((props) => { ); const [ allowManageConfig, + allowManageUser, allowManagePanel, allowManageInvite, allowManageRoles, ] = useHasGroupPermission(groupId, [ PERMISSION.core.groupConfig, + PERMISSION.core.manageUser, PERMISSION.core.managePanel, PERMISSION.core.manageInvite, PERMISSION.core.manageRoles, @@ -58,6 +61,11 @@ export const GroupDetail: React.FC = React.memo((props) => { title: t('配置'), content: , }, + allowManageUser && { + type: 'item', + title: t('成员'), + content: , + }, allowManagePanel && { type: 'item', title: t('面板'), diff --git a/client/web/src/hooks/useGroupMemberAction.ts b/client/web/src/hooks/useGroupMemberAction.ts new file mode 100644 index 00000000..9a1c2da3 --- /dev/null +++ b/client/web/src/hooks/useGroupMemberAction.ts @@ -0,0 +1,127 @@ +import { openReconfirmModalP } from '@/components/Modal'; +import { useCallback } from 'react'; +import { + formatFullTime, + humanizeMsDuration, + model, + showSuccessToasts, + t, + useAsyncRequest, + useGroupInfo, + useGroupMemberInfos, + useMemoizedFn, + useSearch, +} from 'tailchat-shared'; + +/** + * 群组成员管理相关操作 + */ +export function useGroupMemberAction(groupId: string) { + const groupInfo = useGroupInfo(groupId); + const members = groupInfo?.members ?? []; + const userInfos = useGroupMemberInfos(groupId); + + const { handleMuteMember, handleUnmuteMember } = useMemberMuteAction( + groupId, + userInfos + ); + + const { searchText, setSearchText, isSearching, searchResult } = useSearch({ + dataSource: userInfos, + filterFn: (item, searchText) => item.nickname.includes(searchText), + }); + + /** + * 移除用户 + */ + const [, handleRemoveGroupMember] = useAsyncRequest( + async (memberId: string) => { + const confirm = await openReconfirmModalP({ + title: t('确认要将该用户移出群组么'), + }); + if (confirm) { + await model.group.deleteGroupMember(groupId, memberId); + showSuccessToasts(); + } + }, + [groupId] + ); + + const getMemberHasMute = useCallback( + (userId: string): boolean => { + const member = members.find((m) => m.userId === userId); + + if (!member || !member.muteUntil) { + return false; + } + + const muteUntil = member.muteUntil; + + return new Date(muteUntil).valueOf() > new Date().valueOf(); + }, + [members] + ); + + return { + // 搜索相关 + searchText, + setSearchText, + isSearching, + searchResult, + + getMemberHasMute, + + // 用户操作 + handleMuteMember, + handleUnmuteMember, + handleRemoveGroupMember, + }; +} + +/** + * 禁言相关 + */ +function useMemberMuteAction( + groupId: string, + userInfoList: model.user.UserBaseInfo[] +) { + /** + * 禁言 + */ + const [, handleMuteMember] = useAsyncRequest( + async (memberId: string, ms: number) => { + const memberInfo = userInfoList.find((m) => m._id === memberId); + + if (!memberInfo) { + throw new Error(t('没有找到用户')); + } + + if ( + await openReconfirmModalP({ + title: t('确定要禁言 {{name}} 么', { name: memberInfo.nickname }), + content: t('禁言 {{length}}, 预计到 {{until}} 为止', { + length: humanizeMsDuration(ms), + until: formatFullTime(new Date().valueOf() + ms), + }), + }) + ) { + await model.group.muteGroupMember(groupId, memberId, ms); + showSuccessToasts(); + } + }, + [groupId, userInfoList] + ); + + /** + * 解除禁言 + */ + const [, handleUnmuteMember] = useAsyncRequest( + async (memberId: string) => { + await model.group.muteGroupMember(groupId, memberId, -1); + showSuccessToasts(); + }, + [groupId] + ); + + return { handleMuteMember, handleUnmuteMember }; +}