From c7f274278bc3b7611507f28484a870894845aef0 Mon Sep 17 00:00:00 2001 From: Deepak Bhagat Date: Fri, 17 Apr 2026 01:42:40 +0530 Subject: [PATCH 1/2] fix: remove trailing space in tooltip text when formatter has no shortcut The template literal unconditionally included a space before the shortcut expression, so formatters without a keyboard shortcut (strike, code, multiline) rendered their tooltip as e.g. 'strike ' instead of 'strike'. Replace with a ternary so the space and parentheses are only added when a shortcut is present. --- .../src/views/ChatInput/ChatInputFormattingToolbar.js | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/packages/react/src/views/ChatInput/ChatInputFormattingToolbar.js b/packages/react/src/views/ChatInput/ChatInputFormattingToolbar.js index a68dc340f..bed47dada 100644 --- a/packages/react/src/views/ChatInput/ChatInputFormattingToolbar.js +++ b/packages/react/src/views/ChatInput/ChatInputFormattingToolbar.js @@ -216,7 +216,7 @@ const ChatInputFormattingToolbar = ({ ) : ( @@ -296,9 +296,11 @@ const ChatInputFormattingToolbar = ({ if (itemInFormatter) { return ( From b701cdc304318dd8ebc9648e08a1cd0e7eebd48c Mon Sep 17 00:00:00 2001 From: Deepak Bhagat Date: Fri, 17 Apr 2026 01:45:16 +0530 Subject: [PATCH 2/2] fix: apply prettier formatting to MessageAIBadges useState initializer --- .../src/views/Message/MessageAIBadges.js | 100 ++++++++++++++++++ 1 file changed, 100 insertions(+) create mode 100644 packages/react/src/views/Message/MessageAIBadges.js diff --git a/packages/react/src/views/Message/MessageAIBadges.js b/packages/react/src/views/Message/MessageAIBadges.js new file mode 100644 index 000000000..e3f7c7952 --- /dev/null +++ b/packages/react/src/views/Message/MessageAIBadges.js @@ -0,0 +1,100 @@ +import React, { useEffect, useState, useContext } from 'react'; +import PropTypes from 'prop-types'; +import { css } from '@emotion/react'; +import { Box } from '@embeddedchat/ui-elements'; +import RCContext from '../../context/RCInstance'; + +const CATEGORY_COLORS = { + question: '#6366f1', + greeting: '#22c55e', + request: '#f59e0b', + statement: '#64748b', + other: '#94a3b8', +}; + +const SENTIMENT_COLORS = { + positive: '#22c55e', + negative: '#ef4444', + neutral: '#94a3b8', +}; + +const badgeStyle = (bg) => css` + font-size: 0.6rem; + font-weight: 600; + padding: 0.1rem 0.4rem; + border-radius: 4px; + background: ${bg}; + color: #fff; + text-transform: uppercase; + letter-spacing: 0.03em; + white-space: nowrap; +`; + +// Simple in-memory cache so we don't re-call the API for the same message +const badgeCache = new Map(); + +// Only process messages sent in the last 60 seconds to avoid hammering the API +const isRecent = (ts) => { + const msgTime = new Date(ts).getTime(); + return Date.now() - msgTime < 60000; +}; + +const MessageAIBadges = ({ message }) => { + const { ECOptions } = useContext(RCContext); + const adapter = ECOptions?.aiAdapter ?? null; + const [badges, setBadges] = useState( + () => badgeCache.get(message._id) || null + ); + + useEffect(() => { + if (!adapter || !message.msg || message.t) return; + // Skip old messages — only classify recent ones + if (!isRecent(message.ts)) return; + // Already cached + if (badgeCache.has(message._id)) { + setBadges(badgeCache.get(message._id)); + return; + } + + let cancelled = false; + + adapter + .processMessage(message.msg) + .then((result) => { + if (!cancelled) { + badgeCache.set(message._id, result); + setBadges(result); + } + }) + .catch(() => {}); + + return () => { + cancelled = true; + }; + }, [adapter, message._id, message.msg, message.t, message.ts]); + + if (!badges) return null; + + return ( + + + {badges.category} + + + {badges.sentiment} + + + ); +}; + +MessageAIBadges.propTypes = { + message: PropTypes.object.isRequired, +}; + +export default MessageAIBadges;