From a9bf936c45cb96f09ed89dc3492ddf8fe818e472 Mon Sep 17 00:00:00 2001 From: moonrailgun Date: Wed, 25 Aug 2021 19:57:22 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E9=80=80=E5=87=BA=E7=BE=A4=E7=BB=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- shared/index.tsx | 7 ++++++- shared/model/group.ts | 11 ++++++++++ shared/redux/hooks/useGroup.ts | 18 ++++++++++++++++ shared/redux/setup.ts | 4 ++++ shared/redux/slices/group.ts | 16 ++++++++++---- .../routes/Main/Content/Group/GroupHeader.tsx | 21 +++++++++++++------ .../Content/Group/useGroupHeaderAction.tsx | 19 ++++++++++++++++- 7 files changed, 84 insertions(+), 12 deletions(-) diff --git a/shared/index.tsx b/shared/index.tsx index 3f6082f8..ed116c01 100644 --- a/shared/index.tsx +++ b/shared/index.tsx @@ -64,6 +64,7 @@ export { createGroup, createGroupInviteCode, getGroupBasicInfo, + quitGroup, applyGroupInvite, modifyGroupField, createGroupPanel, @@ -85,7 +86,11 @@ export { export { useAppSelector, useAppDispatch } from './redux/hooks/useAppSelector'; export { useDMConverseList } from './redux/hooks/useConverse'; export { useConverseMessage } from './redux/hooks/useConverseMessage'; -export { useGroupInfo, useGroupPanel } from './redux/hooks/useGroup'; +export { + useGroupInfo, + useGroupPanel, + useIsGroupOwner, +} from './redux/hooks/useGroup'; export { useUserInfo, useUserId } from './redux/hooks/useUserInfo'; export { userActions } from './redux/slices'; export type { ChatConverseState } from './redux/slices/chat'; diff --git a/shared/model/group.ts b/shared/model/group.ts index 3ddbc18d..1eef8ecc 100644 --- a/shared/model/group.ts +++ b/shared/model/group.ts @@ -98,6 +98,17 @@ export async function modifyGroupField( }); } +/** + * 退出群组(群组拥有者是解散群组) + * 这里必须是一个socket请求因为后端需要进行房间的退出操作 + * @param groupId 群组ID + */ +export async function quitGroup(groupId: string) { + await request.post('/api/group/quitGroup', { + groupId, + }); +} + /** * 创建群组邀请码 * 邀请码默认 7天有效期 diff --git a/shared/redux/hooks/useGroup.ts b/shared/redux/hooks/useGroup.ts index 830fbe82..5d72da5e 100644 --- a/shared/redux/hooks/useGroup.ts +++ b/shared/redux/hooks/useGroup.ts @@ -1,6 +1,8 @@ import { useMemo } from 'react'; import type { GroupInfo, GroupPanel } from '../../model/group'; +import { isValidStr } from '../../utils/string-helper'; import { useAppSelector } from './useAppSelector'; +import { useUserId } from './useUserInfo'; /** * 获取群组信息 @@ -23,3 +25,19 @@ export function useGroupPanel( [groupInfo, panelId] ); } + +/** + * 检查是否为群组的所有者 + * @param userId 群组id 必填 + * @param userId 用户id 不传则为当前用户id + */ +export function useIsGroupOwner(groupId: string, userId?: string): boolean { + const groupInfo = useGroupInfo(groupId); + const selfUserId = useUserId(); + + if (isValidStr(userId)) { + return groupInfo?.owner === userId; + } else { + return typeof selfUserId === 'string' && groupInfo?.owner === selfUserId; + } +} diff --git a/shared/redux/setup.ts b/shared/redux/setup.ts index 13f6f5df..9a897fc9 100644 --- a/shared/redux/setup.ts +++ b/shared/redux/setup.ts @@ -81,4 +81,8 @@ function listenNotify(socket: AppSocket, store: AppStore) { socket.listen('group.updateInfo', (groupInfo) => { store.dispatch(groupActions.updateGroup(groupInfo)); }); + + socket.listen<{ groupId: string }>('group.remove', ({ groupId }) => { + store.dispatch(groupActions.removeGroup(groupId)); + }); } diff --git a/shared/redux/slices/group.ts b/shared/redux/slices/group.ts index 889f5abf..0c89a9eb 100644 --- a/shared/redux/slices/group.ts +++ b/shared/redux/slices/group.ts @@ -26,10 +26,18 @@ const groupSlice = createSlice({ updateGroup(state, action: PayloadAction) { const group = action.payload; const groupId = group._id; - state.groups[groupId] = { - ...state.groups[groupId], - ...group, - }; + + if (state.groups[groupId]) { + // NOTICE: updateGroup 只会去更新,不会去添加新的 + state.groups[groupId] = { + ...state.groups[groupId], + ...group, + }; + } + }, + removeGroup(state, action: PayloadAction) { + const groupId = action.payload; + delete state.groups[groupId]; }, }, }); diff --git a/web/src/routes/Main/Content/Group/GroupHeader.tsx b/web/src/routes/Main/Content/Group/GroupHeader.tsx index bc3816fc..4e046f25 100644 --- a/web/src/routes/Main/Content/Group/GroupHeader.tsx +++ b/web/src/routes/Main/Content/Group/GroupHeader.tsx @@ -14,7 +14,7 @@ export const GroupHeader: React.FC = React.memo((props) => { const groupInfo = useGroupInfo(groupId); const { t } = useTranslation(); - const { handleShowGroupDetail, handleInviteUser } = + const { isOwner, handleShowGroupDetail, handleInviteUser, handleQuitGroup } = useGroupHeaderAction(groupId); if (_isNil(groupInfo)) { @@ -23,11 +23,20 @@ export const GroupHeader: React.FC = React.memo((props) => { const menu = ( - - {t('查看详情')} - - - {t('邀请用户')} + {isOwner && ( + + {t('查看详情')} + + )} + + {isOwner && ( + + {t('邀请用户')} + + )} + + + {t('退出群组')} ); diff --git a/web/src/routes/Main/Content/Group/useGroupHeaderAction.tsx b/web/src/routes/Main/Content/Group/useGroupHeaderAction.tsx index 3d82b42d..332de083 100644 --- a/web/src/routes/Main/Content/Group/useGroupHeaderAction.tsx +++ b/web/src/routes/Main/Content/Group/useGroupHeaderAction.tsx @@ -3,11 +3,16 @@ import { GroupDetail } from '@/components/modals/GroupDetail'; import { GroupInvite } from '@/components/modals/GroupInvite'; import React from 'react'; import { useCallback } from 'react'; +import { useHistory } from 'react-router'; +import { quitGroup, showAlert, t, useIsGroupOwner } from 'tailchat-shared'; /** * 群组 Header 的操作 hooks */ export function useGroupHeaderAction(groupId: string) { + const isOwner = useIsGroupOwner(groupId); + const history = useHistory(); + const handleShowGroupDetail = useCallback(() => { const key = openModal( ); }, [groupId]); - return { handleShowGroupDetail, handleInviteUser }; + const handleQuitGroup = useCallback(() => { + showAlert({ + message: isOwner + ? t('您是群组管理者,退出群组会导致解散群组') + : t('确定要退出群组么?'), + async onConfirm() { + await quitGroup(groupId); + history.replace('/main'); // 返回到主页 + }, + }); + }, [groupId, isOwner]); + + return { isOwner, handleShowGroupDetail, handleInviteUser, handleQuitGroup }; }