diff --git a/.talismanrc b/.talismanrc
index 384bfc36..0962f0a9 100644
--- a/.talismanrc
+++ b/.talismanrc
@@ -1,11 +1,13 @@
fileignoreconfig:
-- filename: .github/workflows/secrets-scan.yml
- ignore_detectors:
- - filecontent
-- filename: README.md
- checksum: 568289bbe7c088967493db246dbf29e465382648ac574c1b1236be57d5662a38
-- filename: CHANGELOG.md
- checksum: 677807c38f5135fac7ca0377e92953fb09097150ddd3c4f68667fe0368f916ee
-- filename: src/visualBuilder/components/__test__/fieldToolbar.test.tsx
- checksum: 3badd6a142456b6a361569e6fc546349a38ac6b366bef7fd5255d1e93220444e
-version: "1.0"
\ No newline at end of file
+ - filename: .github/workflows/secrets-scan.yml
+ ignore_detectors:
+ - filecontent
+ - filename: README.md
+ checksum: 568289bbe7c088967493db246dbf29e465382648ac574c1b1236be57d5662a38
+ - filename: CHANGELOG.md
+ checksum: 677807c38f5135fac7ca0377e92953fb09097150ddd3c4f68667fe0368f916ee
+ - filename: src/visualBuilder/components/__test__/fieldToolbar.test.tsx
+ checksum: 3badd6a142456b6a361569e6fc546349a38ac6b366bef7fd5255d1e93220444e
+ - filename: src/visualBuilder/components/Collab/ThreadPopup/__test__/CommentTextArea.test.tsx
+ checksum: d0ef271ee5381d9feab06bda6e7e89bd0a882fee87495627bd811c1f0a5459c7
+version: "1.0"
diff --git a/src/visualBuilder/components/Collab/ThreadPopup/CommentTextArea.tsx b/src/visualBuilder/components/Collab/ThreadPopup/CommentTextArea.tsx
index 203842dc..01275762 100644
--- a/src/visualBuilder/components/Collab/ThreadPopup/CommentTextArea.tsx
+++ b/src/visualBuilder/components/Collab/ThreadPopup/CommentTextArea.tsx
@@ -102,12 +102,22 @@ const MentionSuggestionsList: React.FC<{
tabIndex={-1}
aria-selected={index === selectedIndex}
>
- {(user.display?.length || 0) > 20 ? (
-
- {(user.display || "").substring(0, 18) + "..."}
-
+ {user.display == user.email ? (
+ user.display.length > 20 ? (
+
+ {(user.display || "").substring(0, 18) + "..."}
+
+ ) : (
+ user.display
+ )
) : (
- user.display || ""
+
+ {user.display.length > 20
+ ? (user.display || "").substring(0, 18) + "..."
+ : user.display}
+
)}
))}
diff --git a/src/visualBuilder/components/Collab/ThreadPopup/__test__/CommentTextArea.test.tsx b/src/visualBuilder/components/Collab/ThreadPopup/__test__/CommentTextArea.test.tsx
new file mode 100644
index 00000000..74cead4c
--- /dev/null
+++ b/src/visualBuilder/components/Collab/ThreadPopup/__test__/CommentTextArea.test.tsx
@@ -0,0 +1,367 @@
+/** @jsxImportSource preact */
+import { render, screen, fireEvent } from "@testing-library/preact";
+import CommentTextArea from "../CommentTextArea";
+import { useCommentTextArea } from "../../../../hooks/useCommentTextArea";
+import { Mock } from "vitest";
+import React from "preact/compat";
+import classNames from "classnames";
+
+// Mock dependencies
+vi.mock("../../../../hooks/useCommentTextArea");
+vi.mock("../Tooltip/Tooltip", () => ({
+ default: ({ children, content }) => (
+
{children}
+ ),
+}));
+vi.mock("../../../../collab.style", () => ({
+ collabStyles: () => ({
+ "collab-thread-input-indicator--error": "mocked-error-class",
+ "collab-thread-input-indicator--count": "mocked-count-class",
+ "collab-thread-body--input--wrapper": "mocked-wrapper-class",
+ "collab-thread-body--input": "mocked-input-class",
+ "collab-thread-body--input--textarea--wrapper":
+ "mocked-textarea-wrapper-class",
+ "collab-thread-body--input--textarea": "mocked-textarea-class",
+ "collab-thread-body--input--textarea--suggestionsList":
+ "mocked-suggestions-list-class",
+ "collab-thread-body--input--textarea--suggestionsList--item":
+ "mocked-suggestion-item-class",
+ "collab-thread-body--input--textarea--suggestionsList--item-selected":
+ "mocked-selected-item-class",
+ "collab-thread-input-indicator--wrapper":
+ "mocked-indicator-wrapper-class",
+ }),
+ flexAlignCenter: "flex-align-center-class",
+}));
+
+const mockUserState = {
+ userMap: {
+ user1: {
+ uid: "user1",
+ email: "john.doe@example.com",
+ },
+ },
+ currentUser: {
+ uid: "user1",
+ email: "john.doe@example.com",
+ },
+ mentionsList: [
+ {
+ uid: "user1",
+ email: "john.doe@example.com",
+ display: "John Doe",
+ },
+ {
+ uid: "user2",
+ email: "jane.smith@example.com",
+ display: "Jane Smith",
+ },
+ ],
+};
+
+const mockComment = {
+ _id: "comment1",
+ threadUid: "thread-1",
+ message: "This is a comment",
+ author: "john.doe@example.com",
+ toUsers: [],
+ images: [],
+ createdAt: "2022-01-01T12:00:00Z",
+ createdBy: "user1",
+};
+
+const mockHandleOnSaveRef = { current: vi.fn() };
+const mockOnClose = vi.fn();
+
+// Mock implementation of useCommentTextArea hook
+const setupMockHook = (overrides = {}) => {
+ const defaultMock = {
+ state: { message: "Test message" },
+ error: { message: "" },
+ showSuggestions: false,
+ cursorPosition: { top: 20, showAbove: false },
+ selectedIndex: 0,
+ filteredUsers: [],
+ inputRef: { current: null },
+ listRef: { current: null },
+ itemRefs: { current: [] },
+ handleInputChange: vi.fn(),
+ handleKeyDown: vi.fn(),
+ handleSubmit: vi.fn(),
+ insertMention: vi.fn(),
+ maxMessageLength: 1000,
+ };
+
+ const mockImplementation = { ...defaultMock, ...overrides };
+ (useCommentTextArea as Mock).mockReturnValue(mockImplementation);
+ return mockImplementation;
+};
+
+describe("CommentTextArea", () => {
+ beforeEach(() => {
+ setupMockHook();
+ });
+
+ afterEach(() => {
+ vi.clearAllMocks();
+ });
+
+ it("should render the textarea with correct placeholder", () => {
+ render(
+
+ );
+
+ // Use a more reliable query that doesn't depend on exact placeholder text
+ const textarea = screen.getByRole("textbox");
+ expect(textarea).toBeInTheDocument();
+
+ // Check if placeholder contains the expected text without worrying about exact quotes
+ const placeholder = textarea.getAttribute("placeholder");
+ expect(placeholder).toContain("Enter a comment or tag others using");
+ expect(placeholder).toContain("@");
+ });
+
+ it("should set handleOnSaveRef.current to handleSubmit from the hook", () => {
+ const mockHook = setupMockHook();
+ render(
+
+ );
+
+ expect(mockHandleOnSaveRef.current).toBe(mockHook.handleSubmit);
+ });
+
+ it("should call handleInputChange when typing in textarea", () => {
+ const mockHook = setupMockHook();
+ render(
+
+ );
+
+ const textarea = screen.getByRole("textbox");
+ fireEvent.change(textarea, { target: { value: "New text" } });
+
+ expect(mockHook.handleInputChange).toHaveBeenCalled();
+ });
+
+ it("should call handleKeyDown when pressing keys in textarea", () => {
+ const mockHook = setupMockHook();
+ render(
+
+ );
+
+ const textarea = screen.getByRole("textbox");
+ fireEvent.keyDown(textarea, { key: "Enter" });
+
+ expect(mockHook.handleKeyDown).toHaveBeenCalled();
+ });
+
+ it("should display error message when there is an error", () => {
+ setupMockHook({ error: { message: "Error message" } });
+ render(
+
+ );
+
+ expect(screen.getByText("Error message")).toBeInTheDocument();
+ });
+
+ it("should display character counter with correct values", () => {
+ setupMockHook({ state: { message: "Hello" }, maxMessageLength: 100 });
+ render(
+
+ );
+
+ expect(screen.getByText("5/100")).toBeInTheDocument();
+ });
+
+ it("should render MentionSuggestionsList when showSuggestions is true", () => {
+ setupMockHook({
+ showSuggestions: true,
+ filteredUsers: [
+ {
+ uid: "user1",
+ email: "john@example.com",
+ display: "John Doe",
+ },
+ {
+ uid: "user2",
+ email: "jane@example.com",
+ display: "Jane Smith",
+ },
+ ],
+ selectedIndex: 0,
+ });
+
+ render(
+
+ );
+
+ expect(screen.getByText("John Doe")).toBeInTheDocument();
+ expect(screen.getByText("Jane Smith")).toBeInTheDocument();
+ });
+
+ it("should not render MentionSuggestionsList when showSuggestions is false", () => {
+ setupMockHook({
+ showSuggestions: false,
+ filteredUsers: [
+ {
+ uid: "user1",
+ email: "john@example.com",
+ display: "John Doe",
+ },
+ {
+ uid: "user2",
+ email: "jane@example.com",
+ display: "Jane Smith",
+ },
+ ],
+ });
+
+ render(
+
+ );
+
+ expect(screen.queryByText("John Doe")).not.toBeInTheDocument();
+ expect(screen.queryByText("Jane Smith")).not.toBeInTheDocument();
+ });
+});
+
+// Test sub-components individually
+describe("ErrorIndicator", () => {
+ it("should render error message", () => {
+ // We can access the ErrorIndicator through the CommentTextArea component
+ setupMockHook({ error: { message: "Test error message" } });
+ render(
+
+ );
+
+ expect(screen.getByText("Test error message")).toBeInTheDocument();
+ });
+});
+
+describe("CharacterCounter", () => {
+ it("should display current and max length", () => {
+ setupMockHook({ state: { message: "Test" }, maxMessageLength: 50 });
+ render(
+
+ );
+
+ expect(screen.getByText("4/50")).toBeInTheDocument();
+ });
+});
+
+describe("MentionSuggestionsList", () => {
+ it("should display filtered users and highlight the selected one", () => {
+ setupMockHook({
+ showSuggestions: true,
+ filteredUsers: [
+ {
+ uid: "user1",
+ email: "john@example.com",
+ display: "John Doe",
+ },
+ {
+ uid: "user2",
+ email: "jane@example.com",
+ display: "Jane Smith",
+ },
+ ],
+ selectedIndex: 1,
+ });
+
+ render(
+
+ );
+
+ const selectedItem = screen.getByText("Jane Smith").closest("li");
+ expect(selectedItem).toHaveAttribute("aria-selected", "true");
+ });
+
+ it("should truncate long display names", () => {
+ setupMockHook({
+ showSuggestions: true,
+ filteredUsers: [
+ {
+ uid: "user3",
+ email: "very.long.email@example.com",
+ display: "Very Long Name That Should Be Truncated",
+ },
+ ],
+ selectedIndex: 0,
+ });
+
+ render(
+
+ );
+
+ // Use a more flexible approach to find truncated text
+ const truncatedTextElement = screen.getByText((content, element) => {
+ return (
+ content.includes("Very Long Name") &&
+ content.includes("...") &&
+ element.tagName.toLowerCase() !== "html" &&
+ element.tagName.toLowerCase() !== "body"
+ );
+ });
+
+ expect(truncatedTextElement).toBeInTheDocument();
+ });
+});
diff --git a/src/visualBuilder/eventManager/useCollab.ts b/src/visualBuilder/eventManager/useCollab.ts
index 825ecb69..7f05cc2b 100644
--- a/src/visualBuilder/eventManager/useCollab.ts
+++ b/src/visualBuilder/eventManager/useCollab.ts
@@ -43,6 +43,10 @@ export const useCollab = () => {
"collab.pauseFeedback",
data?.data?.collab?.pauseFeedback
);
+ Config.set(
+ "collab.isFeedbackMode",
+ data?.data?.collab?.isFeedbackMode
+ );
showAllCollabIcons();
return;
}
diff --git a/src/visualBuilder/generators/generateThread.tsx b/src/visualBuilder/generators/generateThread.tsx
index 850cac7e..8f54a506 100644
--- a/src/visualBuilder/generators/generateThread.tsx
+++ b/src/visualBuilder/generators/generateThread.tsx
@@ -376,6 +376,7 @@ export function hideAllCollabIcons(): void {
".visual-builder__collab-wrapper .collab-thread"
);
icons?.forEach((icon) => icon?.classList.add(hiddenClass));
+ toggleCollabPopup({ threadUid: "", action: "close" });
}
export function showAllCollabIcons(): void {