From 55e13f7851d96e38a8fe28dd5051082faa9eee20 Mon Sep 17 00:00:00 2001 From: moonrailgun Date: Wed, 5 Jan 2022 17:58:48 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E5=A2=9E=E5=8A=A0=E5=8F=96=E6=B6=88rea?= =?UTF-8?q?ction=E7=9A=84=E6=93=8D=E4=BD=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- shared/index.tsx | 7 ++- shared/model/message.ts | 15 ++++++ shared/redux/setup.ts | 14 +++++ shared/redux/slices/chat.ts | 34 ++++++++++++ .../ChatBox/ChatMessageList/Item.tsx | 4 +- .../useChatMessageReaction.tsx | 4 +- .../ChatMessageList/useMessageReactions.tsx | 53 ++++++++++++------- 7 files changed, 107 insertions(+), 24 deletions(-) diff --git a/shared/index.tsx b/shared/index.tsx index 7336bd1d..aaa321dd 100644 --- a/shared/index.tsx +++ b/shared/index.tsx @@ -115,7 +115,12 @@ export { deleteGroupPanel, } from './model/group'; export type { GroupPanel, GroupInfo, GroupBasicInfo } from './model/group'; -export { recallMessage, deleteMessage, addReaction } from './model/message'; +export { + recallMessage, + deleteMessage, + addReaction, + removeReaction, +} from './model/message'; export type { ChatMessageReaction, ChatMessage } from './model/message'; export type { PluginManifest } from './model/plugin'; export type { UserBaseInfo, UserLoginInfo } from './model/user'; diff --git a/shared/model/message.ts b/shared/model/message.ts index 32fe1db2..e958e9dc 100644 --- a/shared/model/message.ts +++ b/shared/model/message.ts @@ -118,3 +118,18 @@ export async function addReaction( return data; } + +/** + * 移除表情行为 + */ +export async function removeReaction( + messageId: string, + emoji: string +): Promise { + const { data } = await request.post('/api/chat/message/removeReaction', { + messageId, + emoji, + }); + + return data; +} diff --git a/shared/redux/setup.ts b/shared/redux/setup.ts index dbeea6a6..c8c32aed 100644 --- a/shared/redux/setup.ts +++ b/shared/redux/setup.ts @@ -199,6 +199,20 @@ function listenNotify(socket: AppSocket, store: AppStore) { ); }); + socket.listen<{ + converseId: string; + messageId: string; + reaction: ChatMessageReaction; + }>('chat.message.removeReaction', ({ converseId, messageId, reaction }) => { + store.dispatch( + chatActions.removeMessageReaction({ + converseId, + messageId, + reaction, + }) + ); + }); + socket.listen( 'chat.converse.updateDMConverse', (converse) => { diff --git a/shared/redux/slices/chat.ts b/shared/redux/slices/chat.ts index 8e0efe9f..89d441eb 100644 --- a/shared/redux/slices/chat.ts +++ b/shared/redux/slices/chat.ts @@ -261,6 +261,40 @@ const chatSlice = createSlice({ message.reactions.push(reaction); }, + + /** + * 移除消息反应 + */ + removeMessageReaction( + state, + action: PayloadAction<{ + converseId: string; + messageId: string; + reaction: ChatMessageReaction; + }> + ) { + const { converseId, messageId, reaction } = action.payload; + const converse = state.converses[converseId]; + if (!converse) { + console.warn('Not found converse,', converseId); + return; + } + + const message = converse.messages.find((m) => m._id === messageId); + if (!message) { + console.warn('Not found message,', messageId); + return; + } + + if (!Array.isArray(message.reactions)) { + message.reactions = []; + } + + const reactionIndex = message.reactions.findIndex( + (r) => r.name === reaction.name && r.author === reaction.author + ); + message.reactions.splice(reactionIndex, 1); + }, }, }); diff --git a/web/src/components/ChatBox/ChatMessageList/Item.tsx b/web/src/components/ChatBox/ChatMessageList/Item.tsx index 277d8313..68d11e1c 100644 --- a/web/src/components/ChatBox/ChatMessageList/Item.tsx +++ b/web/src/components/ChatBox/ChatMessageList/Item.tsx @@ -19,7 +19,7 @@ import { Divider, Dropdown } from 'antd'; import { UserName } from '@/components/UserName'; import clsx from 'clsx'; import { useChatMessageItemAction } from './useChatMessageItemAction'; -import { useChatMessageReaction } from './useChatMessageReaction'; +import { useChatMessageReactionAction } from './useChatMessageReaction'; import { DevContainer } from '@/components/DevContainer'; import { TcPopover } from '@/components/TcPopover'; import { useMessageReactions } from './useMessageReactions'; @@ -65,7 +65,7 @@ const NormalMessage: React.FC = React.memo((props) => { const reactions = useMessageReactions(payload); - const emojiAction = useChatMessageReaction(payload); + const emojiAction = useChatMessageReactionAction(payload); const moreActions = useChatMessageItemAction(payload, { onClick: () => { setIsActionBtnActive(false); diff --git a/web/src/components/ChatBox/ChatMessageList/useChatMessageReaction.tsx b/web/src/components/ChatBox/ChatMessageList/useChatMessageReaction.tsx index 92d11a43..02fe3220 100644 --- a/web/src/components/ChatBox/ChatMessageList/useChatMessageReaction.tsx +++ b/web/src/components/ChatBox/ChatMessageList/useChatMessageReaction.tsx @@ -12,7 +12,9 @@ import { /** * 消息的反应信息操作 */ -export function useChatMessageReaction(payload: ChatMessage): RenderFunction { +export function useChatMessageReactionAction( + payload: ChatMessage +): RenderFunction { const payloadRef = useUpdateRef(payload); const Component = useMemo( () => diff --git a/web/src/components/ChatBox/ChatMessageList/useMessageReactions.tsx b/web/src/components/ChatBox/ChatMessageList/useMessageReactions.tsx index 52481f15..95a771c2 100644 --- a/web/src/components/ChatBox/ChatMessageList/useMessageReactions.tsx +++ b/web/src/components/ChatBox/ChatMessageList/useMessageReactions.tsx @@ -1,7 +1,7 @@ -import { ChatMessage, useUsernames } from 'tailchat-shared'; +import { ChatMessage, removeReaction, useUsernames } from 'tailchat-shared'; import _groupBy from 'lodash/groupBy'; import _uniqBy from 'lodash/uniqBy'; -import { useMemo } from 'react'; +import { useCallback, useMemo } from 'react'; import { Emoji } from '@/components/Emoji'; import React from 'react'; import { Tooltip } from 'antd'; @@ -15,29 +15,31 @@ interface GroupedReaction { /** * 消息反应的用户名 */ -const ReactionItem: React.FC<{ reaction: GroupedReaction }> = React.memo( - (props) => { - const { reaction } = props; - - return ( -
- -
- - - {reaction.length > 1 && {reaction.length}} -
-
-
- ); - } -); +const ReactionItem: React.FC<{ + reaction: GroupedReaction; + onClick: () => void; +}> = React.memo((props) => { + const { reaction, onClick } = props; + + return ( +
+ +
+ + + {reaction.length > 1 && {reaction.length}} +
+
+
+ ); +}); ReactionItem.displayName = 'ReactionItem'; /** * 消息反应表情渲染 */ export function useMessageReactions(payload: ChatMessage) { + const messageId = payload._id; const reactions = payload.reactions ?? []; const groupedReactions: GroupedReaction[] = useMemo(() => { @@ -53,10 +55,21 @@ export function useMessageReactions(payload: ChatMessage) { }); }, [reactions]); + const handleClick = useCallback( + (reactionName: string) => { + removeReaction(messageId, reactionName); + }, + [messageId] + ); + return (
{groupedReactions.map((reaction) => ( - + handleClick(reaction.name)} + /> ))}
);