diff --git a/__tests__/hooks/internal/useChatHistoryInternal.test.ts b/__tests__/hooks/internal/useChatHistoryInternal.test.ts index 3bf94b7e..4e1c6c4d 100644 --- a/__tests__/hooks/internal/useChatHistoryInternal.test.ts +++ b/__tests__/hooks/internal/useChatHistoryInternal.test.ts @@ -30,14 +30,14 @@ describe("useChatHistoryInternal Hook", () => { const initialChatHistory = [ { id: generateSecureUUID(), - sender: "user", + sender: "USER", content: "Hello", type: "string", timestamp: new Date().toUTCString() }, { id: generateSecureUUID(), - sender: "bot", + sender: "BOT", content: "Hi there!", type: "string", timestamp: new Date().toUTCString() diff --git a/__tests__/hooks/internal/useMessagesInternal.test.ts b/__tests__/hooks/internal/useMessagesInternal.test.ts index c233b25b..3f801878 100644 --- a/__tests__/hooks/internal/useMessagesInternal.test.ts +++ b/__tests__/hooks/internal/useMessagesInternal.test.ts @@ -66,7 +66,7 @@ describe("useMessagesInternal", () => { const { result } = renderHook(() => useMessagesInternal()); await act(async () => { - const messageId = await result.current.injectMessage("Test message", "bot"); + const messageId = await result.current.injectMessage("Test message", "BOT"); expect(messageId).toBeTruthy(); }); @@ -76,7 +76,7 @@ describe("useMessagesInternal", () => { it("should remove a message correctly", async () => { const mockMessageId = "test-id"; - const mockMessage: Message = { id: mockMessageId, content: "Test", sender: "bot", type: "text", + const mockMessage: Message = { id: mockMessageId, content: "Test", sender: "BOT", type: "text", timestamp: String(Date.now()) }; (useMessagesContext as jest.Mock).mockReturnValue({ messages: [mockMessage], @@ -98,25 +98,25 @@ describe("useMessagesInternal", () => { const { result } = renderHook(() => useMessagesInternal()); await act(async () => { - const messageId = await result.current.streamMessage("Test stream", "bot"); + const messageId = await result.current.streamMessage("Test stream", "BOT"); expect(messageId).toBeTruthy(); }); expect(mockSetMessages).toHaveBeenCalled(); expect(mockSetUnreadCount).toHaveBeenCalledWith(expect.any(Function)); - expect(mockStreamMessageMap.current.has("bot")).toBeTruthy(); + expect(mockStreamMessageMap.current.has("BOT")).toBeTruthy(); }); it("should end stream message correctly", async () => { - mockStreamMessageMap.current.set("bot", "test-id"); + mockStreamMessageMap.current.set("BOT", "test-id"); const { result } = renderHook(() => useMessagesInternal()); await act(async () => { - const success = await result.current.endStreamMessage("bot"); + const success = await result.current.endStreamMessage("BOT"); expect(success).toBeTruthy(); }); - expect(mockStreamMessageMap.current.has("bot")).toBeFalsy(); + expect(mockStreamMessageMap.current.has("BOT")).toBeFalsy(); }); }); \ No newline at end of file diff --git a/__tests__/services/AudioService.test.ts b/__tests__/services/AudioService.test.ts index 2b58add1..5f21c5d5 100644 --- a/__tests__/services/AudioService.test.ts +++ b/__tests__/services/AudioService.test.ts @@ -67,7 +67,7 @@ describe("AudioService.processAudio (Inline Mocks)", () => { // calls process audio const message: Message = { id: generateSecureUUID(), - sender: "user", + sender: "USER", content: "Hello, how can I assist you today?", type: "string", timestamp: Date.now().toString(), @@ -93,7 +93,7 @@ describe("AudioService.processAudio (Inline Mocks)", () => { // defines message to be from user const message: Message = { id: generateSecureUUID(), - sender: "user", + sender: "USER", content: "I need help with my account.", type: "string", timestamp: Date.now().toString(), @@ -121,7 +121,7 @@ describe("AudioService.processAudio (Inline Mocks)", () => { // defines message content as an object const message: Message = { id: generateSecureUUID(), - sender: "bot", + sender: "BOT", content: React.createElement("div"), type: "object", timestamp: Date.now().toString(), @@ -152,7 +152,7 @@ describe("AudioService.processAudio (Inline Mocks)", () => { // calls process audio const message: Message = { id: generateSecureUUID(), - sender: "bot", + sender: "BOT", content: "Welcome back! How can I help you today?", type: "string", timestamp: Date.now().toString(), @@ -178,7 +178,7 @@ describe("AudioService.processAudio (Inline Mocks)", () => { // calls process audio, but voice is toggled off const message: Message = { id: generateSecureUUID(), - sender: "bot", + sender: "BOT", content: "Let me know if you need any assistance.", type: "string", timestamp: Date.now().toString(), @@ -204,7 +204,7 @@ describe("AudioService.processAudio (Inline Mocks)", () => { // calls process audio const message: Message = { id: generateSecureUUID(), - sender: "bot", + sender: "BOT", content: "Hello! How can I assist you today?", type: "string", timestamp: Date.now().toString(), @@ -237,7 +237,7 @@ describe("AudioService.processAudio (Inline Mocks)", () => { // calls process audio const message: Message = { id: generateSecureUUID(), - sender: "bot", + sender: "BOT", content: "This is a test message without a specified voice.", type: "string", timestamp: Date.now().toString(), @@ -268,7 +268,7 @@ describe("AudioService.processAudio (Inline Mocks)", () => { const message: Message = { id: generateSecureUUID(), - sender: "bot", + sender: "BOT", content: "Hello! How can I assist you today?", type: "string", timestamp: Date.now().toString(), @@ -294,7 +294,7 @@ describe("AudioService.processAudio (Inline Mocks)", () => { const message: Message = { id: generateSecureUUID(), - sender: "bot", + sender: "BOT", content: "Hello! How can I assist you today?", type: "string", timestamp: Date.now().toString(), @@ -320,7 +320,7 @@ describe("AudioService.processAudio (Inline Mocks)", () => { const message: Message = { id: generateSecureUUID(), - sender: "bot", + sender: "BOT", content: "", type: "string", timestamp: Date.now().toString(), diff --git a/__tests__/services/ChatHistoryService.test.ts b/__tests__/services/ChatHistoryService.test.ts index 15bf8d0b..c5548d1b 100644 --- a/__tests__/services/ChatHistoryService.test.ts +++ b/__tests__/services/ChatHistoryService.test.ts @@ -15,7 +15,7 @@ describe("ChatHistoryService", () => { const mockMessage: Message = { id: "1", - sender: "user", + sender: "USER", content: "Hello good sir!", type: "text", timestamp: "2021-01-01T00:00:00Z", diff --git a/__tests__/utils/messageBuilder.test.ts b/__tests__/utils/messageBuilder.test.ts index ec805a94..04d025b2 100644 --- a/__tests__/utils/messageBuilder.test.ts +++ b/__tests__/utils/messageBuilder.test.ts @@ -21,7 +21,7 @@ describe("createMessage", () => { const mockId = "mocked-uuid"; mockedGenerateSecureUUID.mockReturnValue(mockId); const content = "This is a test message"; - const sender = "bot"; + const sender = "BOT"; // creates message const message = createMessage(content, sender); @@ -46,7 +46,7 @@ describe("createMessage", () => { const mockId = "mocked-uuid"; mockedGenerateSecureUUID.mockReturnValue(mockId); const content = React.createElement("div"); - const sender = "user"; + const sender = "USER"; // creates message const message = createMessage(content, sender); @@ -71,7 +71,7 @@ describe("createMessage", () => { const mockId = "mocked-uuid"; mockedGenerateSecureUUID.mockReturnValue(mockId); const content = ""; - const sender = "bot"; + const sender = "BOT"; // creates message const message = createMessage(content, sender); @@ -96,7 +96,7 @@ describe("createMessage", () => { const mockId = "mocked-uuid"; mockedGenerateSecureUUID.mockReturnValue(mockId); const content = 'Special characters! @#$%^&*()_+-=[]{}|;\':",.<>/?`~'; - const sender = "user"; + const sender = "USER"; // creates message const message = createMessage(content, sender); @@ -139,7 +139,7 @@ describe("createMessage", () => { React.createElement('li', null, 'Item 3') ) ); - const sender = "bot"; + const sender = "BOT"; // creates message const message = createMessage(content, sender); diff --git a/src/components/Buttons/FileAttachmentButton/FileAttachmentButton.tsx b/src/components/Buttons/FileAttachmentButton/FileAttachmentButton.tsx index 992f8d19..2792df86 100644 --- a/src/components/Buttons/FileAttachmentButton/FileAttachmentButton.tsx +++ b/src/components/Buttons/FileAttachmentButton/FileAttachmentButton.tsx @@ -119,7 +119,7 @@ const FileAttachmentButton = () => { // sends media display if file details are valid await injectMessage(, "user"); + fileUrl={fileDetails.fileUrl}/>, "USER"); } await handleSubmitText("📄 " + fileNames.join(", "), settings.fileAttachment?.sendFileName); await fileHandler({userInput: inputRef.current?.value as string, prevPath: getPrevPath(), diff --git a/src/components/Buttons/VoiceButton/VoiceButton.tsx b/src/components/Buttons/VoiceButton/VoiceButton.tsx index c4716e6b..c2144d16 100644 --- a/src/components/Buttons/VoiceButton/VoiceButton.tsx +++ b/src/components/Buttons/VoiceButton/VoiceButton.tsx @@ -98,7 +98,7 @@ const VoiceButton = () => { // sends media display if file details are valid await injectMessage(, "user"); + fileUrl={fileDetails.fileUrl}/>, "USER"); } /** diff --git a/src/components/ChatBotBody/ChatBotBody.tsx b/src/components/ChatBotBody/ChatBotBody.tsx index bc9cbf83..8681de21 100644 --- a/src/components/ChatBotBody/ChatBotBody.tsx +++ b/src/components/ChatBotBody/ChatBotBody.tsx @@ -212,13 +212,13 @@ const ChatBotBody = ({ onScroll={updateIsScrolling} > {messages.map((message, index) => { - if (message.sender === "system") { + if (message.sender.toUpperCase() === "SYSTEM") { return
{message.content}
} return (
- {message.sender === "user" + {message.sender.toUpperCase() === "USER" ? renderUserMessage(message, index) : renderBotMessage(message, index)}
diff --git a/src/hooks/internal/useMessagesInternal.ts b/src/hooks/internal/useMessagesInternal.ts index a8245fb8..3b7fce10 100644 --- a/src/hooks/internal/useMessagesInternal.ts +++ b/src/hooks/internal/useMessagesInternal.ts @@ -50,6 +50,9 @@ export const useMessagesInternal = () => { * @param useMarkup boolean indicating whether markup is used */ const simulateStream = useCallback(async (message: Message, streamSpeed: number, useMarkup: boolean) => { + // always convert to uppercase for checks + message.sender = message.sender.toUpperCase(); + // stop bot typing when simulating stream setIsBotTyping(false); @@ -113,7 +116,10 @@ export const useMessagesInternal = () => { * @param sender sender of the message, defaults to bot */ const injectMessage = useCallback(async (content: string | JSX.Element, - sender = "bot"): Promise => { + sender = "BOT"): Promise => { + + // always convert to uppercase for checks + sender = sender.toUpperCase(); let message = createMessage(content, sender); @@ -127,17 +133,17 @@ export const useMessagesInternal = () => { } let useMarkup = false; - if (sender === "bot") { + if (sender === "BOT") { useMarkup = settings.botBubble?.dangerouslySetInnerHtml as boolean; - } else if (sender === "user") { + } else if (sender === "USER") { useMarkup = settings.userBubble?.dangerouslySetInnerHtml as boolean; } processAudio(settings, audioToggledOn, isChatWindowOpen, message, useMarkup); const isBotStream = typeof message.content === "string" - && message.sender === "bot" && settings?.botBubble?.simStream; + && message.sender === "BOT" && settings?.botBubble?.simStream; const isUserStream = typeof message.content === "string" - && message.sender === "user" && settings?.userBubble?.simStream; + && message.sender === "USER" && settings?.userBubble?.simStream; // handles post-message inject event setUnreadCount(prev => prev + 1); @@ -197,7 +203,10 @@ export const useMessagesInternal = () => { * @param sender sender of the message, defaults to bot */ const streamMessage = useCallback(async (content: string | JSX.Element, - sender = "bot"): Promise => { + sender = "BOT"): Promise => { + + // always convert to uppercase for checks + sender = sender.toUpperCase(); if (!streamMessageMap.current.has(sender)) { const message = createMessage(content, sender); @@ -261,7 +270,10 @@ export const useMessagesInternal = () => { * be made mandatory. Another key implication of not using `endStreamMessage` in v2 is that the stop stream * message event will not be emitted, which may be problematic for logic (or plugins) that rely on this event. */ - const endStreamMessage = useCallback(async (sender = "bot"): Promise => { + const endStreamMessage = useCallback(async (sender = "BOT"): Promise => { + // always convert to uppercase for checks + sender = sender.toUpperCase(); + // nothing to end if not streaming if (!streamMessageMap.current.has(sender)) { return true; @@ -306,7 +318,7 @@ export const useMessagesInternal = () => { const lastMessage = updatedMessages[updatedMessages.length - 1]; // if message is sent by user or is bot typing or bot is embedded, return - if (!lastMessage || lastMessage.sender === "user") { + if (!lastMessage || lastMessage.sender === "USER") { shouldNotify = false; } diff --git a/src/hooks/internal/useSubmitInputInternal.ts b/src/hooks/internal/useSubmitInputInternal.ts index 411746df..f0a14f8f 100644 --- a/src/hooks/internal/useSubmitInputInternal.ts +++ b/src/hooks/internal/useSubmitInputInternal.ts @@ -78,12 +78,12 @@ export const useSubmitInputInternal = () => { if (settings?.sensitiveInput?.hideInUserBubble) { return; } else if (settings?.sensitiveInput?.maskInUserBubble) { - await injectMessage("*".repeat(settings.sensitiveInput?.asterisksCount as number ?? 10), "user"); + await injectMessage("*".repeat(settings.sensitiveInput?.asterisksCount as number ?? 10), "USER"); return; } } - await injectMessage(userInput, "user"); + await injectMessage(userInput, "USER"); }, [flowRef, getCurrPath, settings, injectMessage, textAreaSensitiveMode]); /** diff --git a/src/services/AudioService.ts b/src/services/AudioService.ts index 9ddda0fa..7d517553 100644 --- a/src/services/AudioService.ts +++ b/src/services/AudioService.ts @@ -57,7 +57,7 @@ export const processAudio = (settings: Settings, voiceToggledOn: boolean, isChatWindowOpen: boolean, message: Message, useMarkup: boolean) => { // Add check for empty message content - if (settings.audio?.disabled || message.sender === "user" || typeof message.content !== "string" + if (settings.audio?.disabled || message.sender.toUpperCase() === "USER" || typeof message.content !== "string" || (!isChatWindowOpen && !settings.general?.embedded) || !voiceToggledOn || message.content.trim() === "") { // Check for empty message content return; diff --git a/src/services/ChatHistoryService.tsx b/src/services/ChatHistoryService.tsx index fe64acd2..e78d7412 100644 --- a/src/services/ChatHistoryService.tsx +++ b/src/services/ChatHistoryService.tsx @@ -32,7 +32,7 @@ const saveChatHistory = async (messages: Message[]) => { for (let i = messages.length - 1; i >= offset; i--) { const message = messages[i]; - if (message.sender === "system") { + if (message.sender.toUpperCase() === "SYSTEM") { break; } @@ -127,7 +127,7 @@ const parseMessageToString = (message: Message) => { id: message.id, content: ReactDOMServer.renderToString(message.content), type: message.type, - sender: message.sender, + sender: message.sender.toUpperCase(), timestamp: message.timestamp }); return clonedMessage;