From a984308f4668b4c5867bf468a19a7aa930785793 Mon Sep 17 00:00:00 2001 From: not-meet Date: Thu, 19 Feb 2026 17:28:15 +0530 Subject: [PATCH] [fix]: resolved contextual bar rendering and slash command execution --- packages/api/src/EmbeddedChatApi.ts | 70 ++++++++++++++----- packages/markups/src/mentions/UserMention.js | 69 ++++++++++++++++-- .../src/hooks/uiKit/useUiKitActionManager.js | 61 +++++++++++++++- 3 files changed, 174 insertions(+), 26 deletions(-) diff --git a/packages/api/src/EmbeddedChatApi.ts b/packages/api/src/EmbeddedChatApi.ts index 574370a5b1..2f6923751d 100644 --- a/packages/api/src/EmbeddedChatApi.ts +++ b/packages/api/src/EmbeddedChatApi.ts @@ -238,7 +238,15 @@ export default class EmbeddedChatApi { } } ); + const { userId } = (await this.auth.getCurrentUser()) || {}; await this.rcClient.subscribeNotifyUser(); + if (userId) { + await this.rcClient.subscribe( + "stream-notify-user", + `${userId}/uiInteraction`, + false + ); + } await this.rcClient.onStreamData( "stream-notify-user", (ddpMessage: any) => { @@ -1071,24 +1079,50 @@ export default class EmbeddedChatApi { return data; } - async execCommand({ command, params }: { command: string; params: string }) { - const { userId, authToken } = (await this.auth.getCurrentUser()) || {}; - const response = await fetch(`${this.host}/api/v1/commands.run`, { - headers: { - "Content-Type": "application/json", - "X-Auth-Token": authToken, - "X-User-Id": userId, - }, - method: "POST", - body: JSON.stringify({ - command, - params, - roomId: this.rid, - triggerId: Math.random().toString(32).slice(2, 20), - }), - }); - const data = await response.json(); - return data; + async execCommand({ + command, + params, + tmid, + }: { + command: string; + params: string; + tmid?: string; + }) { + const triggerId = Math.random().toString(36).slice(2, 18); + const msg = { + _id: Math.random().toString(36).slice(2), + rid: this.rid, + msg: `/${command} ${params}`, + ...(tmid && { tmid }), + }; + + try { + const result = await this.rcClient.methodCall( + "slashCommand", + { cmd: command, params, msg, triggerId } + ); + return result; + } catch (e) { + console.error("DDP slashCommand failed, falling back to REST API", e); + const { userId, authToken } = (await this.auth.getCurrentUser()) || {}; + const response = await fetch(`${this.host}/api/v1/commands.run`, { + headers: { + "Content-Type": "application/json", + "X-Auth-Token": authToken, + "X-User-Id": userId, + }, + method: "POST", + body: JSON.stringify({ + command, + params, + tmid, + roomId: this.rid, + triggerId, + }), + }); + const data = await response.json(); + return data; + } } async getUserStatus(reqUserId: string) { diff --git a/packages/markups/src/mentions/UserMention.js b/packages/markups/src/mentions/UserMention.js index 679ffc0d37..7b01bb906e 100644 --- a/packages/markups/src/mentions/UserMention.js +++ b/packages/markups/src/mentions/UserMention.js @@ -1,14 +1,36 @@ import React, { useContext } from 'react'; import PropTypes from 'prop-types'; -import { Box } from '@embeddedchat/ui-elements'; +import { Box, Tooltip } from '@embeddedchat/ui-elements'; +import { useUserStore } from '@embeddedchat/react/src/store'; +import useSetExclusiveState from '@embeddedchat/react/src/hooks/useSetExclusiveState'; +import RCContext from '@embeddedchat/react/src/context/RCInstance'; import { MarkupInteractionContext } from '../MarkupInteractionContext'; import useMentionStyles from '../elements/elements.styles'; -const UserMention = ({ contents }) => { - const { members, username } = useContext(MarkupInteractionContext); +const UserMentionWithContext = ({ contents, members, username, RCInstance }) => { + const setExclusiveState = useSetExclusiveState(); + const { setShowCurrentUserInfo, setCurrentUser } = useUserStore((state) => ({ + setShowCurrentUserInfo: state.setShowCurrentUserInfo, + setCurrentUser: state.setCurrentUser, + })); + + const handleUserInfo = async (uname) => { + const data = await RCInstance.userData(uname); + setCurrentUser({ + _id: data.user._id, + username: data.user.username, + name: data.user.name, + }); + setExclusiveState(setShowCurrentUserInfo); + }; const hasMember = (user) => { - if (user === 'all' || user === 'here') return true; + if (user === 'all' || user === 'here') { + return true; + } + if (!members) { + return false; + } let found = false; Object.keys(members).forEach((ele) => { if (members[ele].username === user) { @@ -20,12 +42,27 @@ const UserMention = ({ contents }) => { const styles = useMentionStyles(contents, username); + const handleClick = () => { + if (!['here', 'all'].includes(contents.value)) { + handleUserInfo(contents.value); + } + }; + + const tooltipMap = { + all: 'Mentions all the room members', + here: 'Mentions online room members', + [username]: 'Mentions you', + }; + const tooltipText = tooltipMap[contents.value] || 'Mentions user'; + return ( <> {hasMember(contents.value) ? ( - - {contents.value} - + + + {contents.value} + + ) : ( `@${contents.value}` )} @@ -33,6 +70,24 @@ const UserMention = ({ contents }) => { ); }; +const UserMention = ({ contents }) => { + const markupContext = useContext(MarkupInteractionContext); + const rcContext = useContext(RCContext); + + if (!markupContext || !rcContext) { + return <>{`@${contents.value}`}; + } + + return ( + + ); +}; + UserMention.propTypes = { contents: PropTypes.any.isRequired, }; diff --git a/packages/react/src/hooks/uiKit/useUiKitActionManager.js b/packages/react/src/hooks/uiKit/useUiKitActionManager.js index 140166e044..ccdc513b1e 100644 --- a/packages/react/src/hooks/uiKit/useUiKitActionManager.js +++ b/packages/react/src/hooks/uiKit/useUiKitActionManager.js @@ -2,6 +2,18 @@ import { useCallback, useContext } from 'react'; import { Emitter } from '@rocket.chat/emitter'; import RCContext from '../../context/RCInstance'; import useUiKitStore from '../../store/uiKitStore'; +import { + useMemberStore, + useSearchMessageStore, + useChannelStore, + useThreadsMessageStore, + useMentionsStore, + usePinnedMessageStore, + useStarredMessageStore, + useFileStore, + useUserStore, + useSidebarStore, +} from '../../store'; const emitter = new Emitter(); @@ -20,16 +32,59 @@ const useUiKitActionManager = () => { setUiKitContextualBarData: state.setUiKitContextualBarData, })); + const setShowSidebar = useSidebarStore((state) => state.setShowSidebar); + const setShowMembers = useMemberStore((state) => state.setShowMembers); + const setShowSearch = useSearchMessageStore((state) => state.setShowSearch); + const setShowPinned = usePinnedMessageStore((state) => state.setShowPinned); + const setShowStarred = useStarredMessageStore( + (state) => state.setShowStarred + ); + const setShowAllThreads = useThreadsMessageStore( + (state) => state.setShowAllThreads + ); + const setShowAllFiles = useFileStore((state) => state.setShowAllFiles); + const setShowMentions = useMentionsStore((state) => state.setShowMentions); + const setShowCurrentUserInfo = useUserStore( + (state) => state.setShowCurrentUserInfo + ); + const setShowChannelinfo = useChannelStore( + (state) => state.setShowChannelinfo + ); + + const closeSidebarPanels = useCallback(() => { + setShowMembers(false); + setShowSearch(false); + setShowPinned(false); + setShowStarred(false); + setShowAllThreads(false); + setShowAllFiles(false); + setShowMentions(false); + setShowCurrentUserInfo(false); + setShowChannelinfo(false); + }, [ + setShowMembers, + setShowSearch, + setShowPinned, + setShowStarred, + setShowAllThreads, + setShowAllFiles, + setShowMentions, + setShowCurrentUserInfo, + setShowChannelinfo, + ]); + const disposeView = useCallback(() => { setUiKitModalOpen(false); setUiKitModalData(null); setUiKitContextualBarOpen(false); setUiKitContextualBarData(null); + setShowSidebar(false); }, [ setUiKitModalOpen, setUiKitModalData, setUiKitContextualBarOpen, setUiKitContextualBarData, + setShowSidebar, ]); const handleServerInteraction = useCallback( @@ -40,8 +95,10 @@ const useUiKitActionManager = () => { setUiKitModalOpen(true); break; case 'contextual_bar.open': + closeSidebarPanels(); setUiKitContextualBarData(interaction.view); setUiKitContextualBarOpen(true); + setShowSidebar(true); break; case 'modal.update': case 'contextual_bar.update': { @@ -66,6 +123,8 @@ const useUiKitActionManager = () => { setUiKitContextualBarOpen, setUiKitModalOpen, setUiKitModalData, + closeSidebarPanels, + setShowSidebar, ] ); @@ -112,4 +171,4 @@ const useUiKitActionManager = () => { }; }; -export default useUiKitActionManager; +export default useUiKitActionManager; \ No newline at end of file