Skip to content

Comments

fix: hide message reactions when "Use Emojis" is disabled in user preferences#38863

Open
ishanmitra wants to merge 5 commits intoRocketChat:developfrom
ishanmitra:fix/disable-react-emojis
Open

fix: hide message reactions when "Use Emojis" is disabled in user preferences#38863
ishanmitra wants to merge 5 commits intoRocketChat:developfrom
ishanmitra:fix/disable-react-emojis

Conversation

@ishanmitra
Copy link

@ishanmitra ishanmitra commented Feb 20, 2026

Proposed changes (including videos or screenshots)

The screenshot reflects the before and after of disabling Use Emojis from the settings:
Use Emojis enabled:
image
Use Emojis disabled:
image

Note that the emoji rendering as shortcodes was already implemented. Only the quick reactions and reactions below the message gets hidden.

Issue(s)

A bug was identified where users were able to react to messages with emojis, even after disabling the "Use Emojis" option in their personal preferences. The expected behavior is that when this setting is turned off, users should no longer be able to add emoji reactions to any messages.

Steps to test or reproduce

Go to Admin > Accounts > Default User Preferences and turn off both "User Emojis" options.

  1. Go to a Workspace
  2. Create a room
  3. Attempt to add an emoji reaction to the most recent message in the chat.

Further comments

Added tests that assert the correct behavior.

Summary by CodeRabbit

  • Improvements
    • Emoji reactions and reaction toolbar now follow the user's "use emojis" preference — when disabled, emoji elements and reaction controls are hidden while message text remains visible.
  • Tests
    • Added tests verifying emoji rendering and reaction visibility toggle behavior based on the user preference.

@ishanmitra ishanmitra requested a review from a team as a code owner February 20, 2026 23:48
@dionisio-bot
Copy link
Contributor

dionisio-bot bot commented Feb 20, 2026

Looks like this PR is not ready to merge, because of the following issues:

  • This PR is missing the 'stat: QA assured' label
  • This PR is missing the required milestone or project

Please fix the issues and try again

If you have any trouble, please check the PR guidelines

@changeset-bot
Copy link

changeset-bot bot commented Feb 20, 2026

⚠️ No Changeset found

Latest commit: e4a6cd8

Merging this PR will not cause a version bump for any packages. If these changes should not result in a new version, you're good to go. If these changes should result in a version bump, you need to add a changeset.

This PR includes no changesets

When changesets are added to this PR, you'll see the packages that this PR includes changesets for and the associated semver types

Click here to learn what changesets are, and how to add one.

Click here if you're a maintainer who wants to add a changeset to this PR

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Feb 20, 2026

Walkthrough

Adds a user-preference guard (useUserPreference('useEmojis')) to conditionally render emoji reactions: the toolbar's reaction action and the message content's Reactions now only render when the preference is enabled; also adds tests covering both enabled and disabled states.

Changes

Cohort / File(s) Summary
Toolbar & Content: conditional emoji rendering
apps/meteor/client/components/message/toolbar/items/DefaultItems.tsx, apps/meteor/client/components/message/variants/room/RoomMessageContent.tsx
Import and use useUserPreference('useEmojis'); render ReactionMessageAction and Reactions only when the preference is truthy (and reactions exist for content).
Tests: emoji preference behavior
apps/meteor/client/components/message/variants/RoomMessageEmoji.spec.tsx
New test spec covering two scenarios: when useEmojis is enabled (emoji elements rendered, original text hidden, toolbar visible) and when disabled (no emoji elements, original text shown, toolbar hidden).

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Poem

🐰 A twitch of whiskers, a tiny delight,
Toggle the preference and emojis take flight,
Show the reactions or keep them away,
I nibble on changes—hooray for the day! 🥕✨

🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately describes the main change: hiding message reactions when the 'Use Emojis' preference is disabled, which is directly supported by the file changes showing conditional rendering of ReactionMessageAction and Reactions components based on the enableEmojis flag.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Contributor

@cubic-dev-ai cubic-dev-ai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No issues found across 3 files

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 4

🧹 Nitpick comments (1)
apps/meteor/client/components/message/variants/RoomMessageEmoji.spec.tsx (1)

73-73: tagName assertion is brittle.

expect(emoji.tagName).toBe('SPAN') couples the test to the internal DOM element choice. The role="img" query on line 72 already confirms the accessible semantic; the tagName check adds no meaningful contract and will fail if the emoji renderer ever switches to a different element.

♻️ Proposed simplification
 const emoji = screen.getByRole('img', { name: ':emoji:' });
-expect(emoji.tagName).toBe('SPAN');
 expect(emoji).toBeInTheDocument();
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/meteor/client/components/message/variants/RoomMessageEmoji.spec.tsx` at
line 73, The test's assertion on DOM internals is brittle: remove the tagName
check (expect(emoji.tagName).toBe('SPAN')) and rely on the existing accessible
query (getByRole('img') / the emoji variable) and any semantic/attribute checks
you need (e.g., aria-label, role, textContent) instead; update the test in
RoomMessageEmoji.spec.tsx to delete the tagName assertion so it only asserts
accessible behavior such as that the element with role="img" exists and has the
expected aria-label or content.
📜 Review details

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 7d23911 and 94e46d1.

📒 Files selected for processing (3)
  • apps/meteor/client/components/message/toolbar/items/DefaultItems.tsx
  • apps/meteor/client/components/message/variants/RoomMessageEmoji.spec.tsx
  • apps/meteor/client/components/message/variants/room/RoomMessageContent.tsx
🧰 Additional context used
📓 Path-based instructions (1)
**/*.{ts,tsx,js}

📄 CodeRabbit inference engine (.cursor/rules/playwright.mdc)

**/*.{ts,tsx,js}: Write concise, technical TypeScript/JavaScript with accurate typing in Playwright tests
Avoid code comments in the implementation

Files:

  • apps/meteor/client/components/message/variants/room/RoomMessageContent.tsx
  • apps/meteor/client/components/message/variants/RoomMessageEmoji.spec.tsx
  • apps/meteor/client/components/message/toolbar/items/DefaultItems.tsx
🧠 Learnings (8)
📚 Learning: 2025-11-19T18:20:07.720Z
Learnt from: gabriellsh
Repo: RocketChat/Rocket.Chat PR: 37419
File: packages/i18n/src/locales/en.i18n.json:918-921
Timestamp: 2025-11-19T18:20:07.720Z
Learning: Repo: RocketChat/Rocket.Chat — i18n/formatting
Learning: This repository uses a custom message formatting parser in UI blocks/messages; do not assume standard Markdown rules. For keys like Call_ended_bold, Call_not_answered_bold, Call_failed_bold, and Call_transferred_bold in packages/i18n/src/locales/en.i18n.json, retain the existing single-asterisk emphasis unless maintainers request otherwise.

Applied to files:

  • apps/meteor/client/components/message/variants/room/RoomMessageContent.tsx
  • apps/meteor/client/components/message/toolbar/items/DefaultItems.tsx
📚 Learning: 2025-12-10T21:00:54.909Z
Learnt from: KevLehman
Repo: RocketChat/Rocket.Chat PR: 37091
File: ee/packages/abac/jest.config.ts:4-7
Timestamp: 2025-12-10T21:00:54.909Z
Learning: Rocket.Chat monorepo: Jest testMatch pattern '<rootDir>/src/**/*.spec.(ts|js|mjs)' is valid in this repo and used across multiple packages (e.g., packages/tools, ee/packages/omnichannel-services). Do not flag it as invalid in future reviews.

Applied to files:

  • apps/meteor/client/components/message/variants/RoomMessageEmoji.spec.tsx
📚 Learning: 2025-11-24T17:08:17.065Z
Learnt from: CR
Repo: RocketChat/Rocket.Chat PR: 0
File: .cursor/rules/playwright.mdc:0-0
Timestamp: 2025-11-24T17:08:17.065Z
Learning: Applies to apps/meteor/tests/e2e/**/*.spec.ts : Utilize Playwright fixtures (`test`, `page`, `expect`) for consistency in test files

Applied to files:

  • apps/meteor/client/components/message/variants/RoomMessageEmoji.spec.tsx
📚 Learning: 2025-11-24T17:08:17.065Z
Learnt from: CR
Repo: RocketChat/Rocket.Chat PR: 0
File: .cursor/rules/playwright.mdc:0-0
Timestamp: 2025-11-24T17:08:17.065Z
Learning: Applies to apps/meteor/tests/e2e/**/*.spec.ts : Prefer web-first assertions (`toBeVisible`, `toHaveText`, etc.) in Playwright tests

Applied to files:

  • apps/meteor/client/components/message/variants/RoomMessageEmoji.spec.tsx
📚 Learning: 2025-11-24T17:08:17.065Z
Learnt from: CR
Repo: RocketChat/Rocket.Chat PR: 0
File: .cursor/rules/playwright.mdc:0-0
Timestamp: 2025-11-24T17:08:17.065Z
Learning: Applies to apps/meteor/tests/e2e/**/*.spec.ts : Use `expect` matchers for assertions (`toEqual`, `toContain`, `toBeTruthy`, `toHaveLength`, etc.) instead of `assert` statements in Playwright tests

Applied to files:

  • apps/meteor/client/components/message/variants/RoomMessageEmoji.spec.tsx
📚 Learning: 2025-11-24T17:08:17.065Z
Learnt from: CR
Repo: RocketChat/Rocket.Chat PR: 0
File: .cursor/rules/playwright.mdc:0-0
Timestamp: 2025-11-24T17:08:17.065Z
Learning: Applies to apps/meteor/tests/e2e/**/*.spec.ts : Ensure tests run reliably in parallel without shared state conflicts

Applied to files:

  • apps/meteor/client/components/message/variants/RoomMessageEmoji.spec.tsx
📚 Learning: 2025-11-24T17:08:17.065Z
Learnt from: CR
Repo: RocketChat/Rocket.Chat PR: 0
File: .cursor/rules/playwright.mdc:0-0
Timestamp: 2025-11-24T17:08:17.065Z
Learning: Applies to apps/meteor/tests/e2e/**/*.spec.ts : Group related tests in the same file

Applied to files:

  • apps/meteor/client/components/message/variants/RoomMessageEmoji.spec.tsx
📚 Learning: 2025-11-24T17:08:17.065Z
Learnt from: CR
Repo: RocketChat/Rocket.Chat PR: 0
File: .cursor/rules/playwright.mdc:0-0
Timestamp: 2025-11-24T17:08:17.065Z
Learning: Applies to apps/meteor/tests/e2e/**/*.spec.ts : All test files must be created in `apps/meteor/tests/e2e/` directory

Applied to files:

  • apps/meteor/client/components/message/variants/RoomMessageEmoji.spec.tsx
🧬 Code graph analysis (2)
apps/meteor/client/components/message/variants/room/RoomMessageContent.tsx (1)
packages/ui-contexts/src/index.ts (1)
  • useUserPreference (86-86)
apps/meteor/client/components/message/variants/RoomMessageEmoji.spec.tsx (2)
apps/meteor/client/components/message/list/MessageListContext.tsx (2)
  • MessageListContext (79-79)
  • messageListContextDefaultValue (48-77)
packages/message-parser/src/utils.ts (1)
  • emoji (143-147)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (4)
  • GitHub Check: check
  • GitHub Check: 📦 Build Packages
  • GitHub Check: cubic · AI code reviewer
  • GitHub Check: CodeQL-Build
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@apps/meteor/client/components/message/toolbar/items/DefaultItems.tsx`:
- Around line 13-17: The DefaultItemsProps type includes an unused enableEmojis
field; remove that property from the DefaultItemsProps declaration and export so
the props type only contains message, room, and subscription, and update any
related imports/uses if referenced; confirm DefaultItems component
(DefaultItems) continues to derive enableEmojis via
useUserPreference<boolean>('useEmojis') and no callers pass enableEmojis.

In `@apps/meteor/client/components/message/variants/room/RoomMessageContent.tsx`:
- Around line 92-94: The JSX condition in RoomMessageContent renders a stray "0"
when normalizedMessage.reactions is an empty object because
Object.keys(...).length is a number; change the conditional to explicitly
produce a boolean (e.g., use
Boolean(Object.keys(normalizedMessage.reactions).length) or
Object.keys(normalizedMessage.reactions).length > 0) so the expression
enableEmojis && <boolean> && <Reactions .../> does not ever evaluate to 0;
update the check around normalizedMessage.reactions that decides whether to
render <Reactions message={normalizedMessage} /> accordingly.

In `@apps/meteor/client/components/message/variants/RoomMessageEmoji.spec.tsx`:
- Line 43: The test currently mocks modules to undefined which breaks named
imports (e.g., useGetMessageByID used by ReactionTooltip rendered via the
Reactions component, and actionLinks used by MessageActions); update the
jest.mock calls in RoomMessageEmoji.spec.tsx to return an object (e.g., () =>
({})) or provide the specific named export stubs so imports like
useGetMessageByID and actionLinks resolve to defined values instead of
undefined, ensuring ReactionTooltip/Reactions/MessageActions can import their
named exports at runtime.
- Line 100: Replace the fragile toolbar assertion in RoomMessageEmoji.spec.tsx
with a direct check for the reaction button to assert emojis are disabled:
instead of asserting on the toolbar role (which can be missing due to mock
deps), update the test that renders DefaultItems/ReactionMessageAction to use
screen.queryByRole('button', { name: /add reaction/i }) and assert
.not.toBeInTheDocument() so the test explicitly verifies the absence of the
reaction action when enableEmojis=false.

---

Nitpick comments:
In `@apps/meteor/client/components/message/variants/RoomMessageEmoji.spec.tsx`:
- Line 73: The test's assertion on DOM internals is brittle: remove the tagName
check (expect(emoji.tagName).toBe('SPAN')) and rely on the existing accessible
query (getByRole('img') / the emoji variable) and any semantic/attribute checks
you need (e.g., aria-label, role, textContent) instead; update the test in
RoomMessageEmoji.spec.tsx to delete the tagName assertion so it only asserts
accessible behavior such as that the element with role="img" exists and has the
expected aria-label or content.

Comment on lines +92 to +94
{enableEmojis && normalizedMessage.reactions && Object.keys(normalizedMessage.reactions).length && (
<Reactions message={normalizedMessage} />
)}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Stray 0 rendered when reactions is an empty object.

Object.keys(normalizedMessage.reactions).length is a number. If the left side of && is 0, the whole JSX expression gets that value and React will happily render 0 rather than nothing. If normalizedMessage.reactions is ever {}, this renders a visible 0 text node.

🐛 Proposed fix
-		{enableEmojis && normalizedMessage.reactions && Object.keys(normalizedMessage.reactions).length && (
+		{enableEmojis && normalizedMessage.reactions && Object.keys(normalizedMessage.reactions).length > 0 && (
 			<Reactions message={normalizedMessage} />
 		)}
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
{enableEmojis && normalizedMessage.reactions && Object.keys(normalizedMessage.reactions).length && (
<Reactions message={normalizedMessage} />
)}
{enableEmojis && normalizedMessage.reactions && Object.keys(normalizedMessage.reactions).length > 0 && (
<Reactions message={normalizedMessage} />
)}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/meteor/client/components/message/variants/room/RoomMessageContent.tsx`
around lines 92 - 94, The JSX condition in RoomMessageContent renders a stray
"0" when normalizedMessage.reactions is an empty object because
Object.keys(...).length is a number; change the conditional to explicitly
produce a boolean (e.g., use
Boolean(Object.keys(normalizedMessage.reactions).length) or
Object.keys(normalizedMessage.reactions).length > 0) so the expression
enableEmojis && <boolean> && <Reactions .../> does not ever evaluate to 0;
update the check around normalizedMessage.reactions that decides whether to
render <Reactions message={normalizedMessage} /> accordingly.

}));
jest.mock('../../../lib/utils/fireGlobalEvent', () => ({ fireGlobalEvent: () => undefined }));
jest.mock('../../../views/room/hooks/useGoToRoom', () => ({ useGoToRoom: () => undefined }));
jest.mock('../../../views/room/contextualBar/Threads/hooks/useGetMessageByID', () => undefined);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

🧩 Analysis chain

🏁 Script executed:

cat -n apps/meteor/client/components/message/variants/RoomMessageEmoji.spec.tsx | head -60

Repository: RocketChat/Rocket.Chat

Length of output: 2177


🏁 Script executed:

rg -n "from.*useGetMessageByID|require.*useGetMessageByID" --type=ts --type=tsx -g "!*.spec.*" -A2 -B2

Repository: RocketChat/Rocket.Chat

Length of output: 93


🏁 Script executed:

rg -n "from.*actionLinks|require.*actionLinks" --type=ts --type=tsx -g "!*.spec.*" -A2 -B2

Repository: RocketChat/Rocket.Chat

Length of output: 93


🏁 Script executed:

rg "from.*useGetMessageByID|require.*useGetMessageByID" -g "!*.spec.*" -A2 -B2

Repository: RocketChat/Rocket.Chat

Length of output: 1370


🏁 Script executed:

rg "from.*actionLinks|require.*actionLinks" -g "!*.spec.*" -A2 -B2

Repository: RocketChat/Rocket.Chat

Length of output: 531


🏁 Script executed:

# Also check the actual imports in the main RoomMessage.tsx file
fd -e tsx -e ts "RoomMessage\.tsx" | grep -v spec | head -5

Repository: RocketChat/Rocket.Chat

Length of output: 128


🏁 Script executed:

cat -n apps/meteor/client/components/message/variants/RoomMessage.tsx | head -50

Repository: RocketChat/Rocket.Chat

Length of output: 2128


🏁 Script executed:

rg "useGetMessageByID|actionLinks" apps/meteor/client/components/message/variants/RoomMessage.tsx -A2 -B2

Repository: RocketChat/Rocket.Chat

Length of output: 48


🏁 Script executed:

# Check dependencies of RoomMessage
rg "import.*from" apps/meteor/client/components/message/variants/RoomMessage.tsx | head -20

Repository: RocketChat/Rocket.Chat

Length of output: 1099


🏁 Script executed:

fd RoomMessageEmoji -e tsx -e ts

Repository: RocketChat/Rocket.Chat

Length of output: 138


🏁 Script executed:

rg "useGetMessageByID|actionLinks" apps/meteor/client/components/message/ -R --max-depth=5

Repository: RocketChat/Rocket.Chat

Length of output: 470


🏁 Script executed:

# Check RoomMessageContent
cat -n apps/meteor/client/components/message/variants/room/RoomMessageContent.tsx | head -60

Repository: RocketChat/Rocket.Chat

Length of output: 3376


🏁 Script executed:

# Check if MessageActions is used/rendered in RoomMessageContent
cat -n apps/meteor/client/components/message/variants/room/RoomMessageContent.tsx | grep -A 80 "return"

Repository: RocketChat/Rocket.Chat

Length of output: 3097


🏁 Script executed:

# Check what MessageActions imports
head -30 apps/meteor/client/components/message/content/MessageActions.tsx

Repository: RocketChat/Rocket.Chat

Length of output: 1057


🏁 Script executed:

# Check what's in the actual test - does it render the component tree that uses these modules?
cat -n apps/meteor/client/components/message/variants/RoomMessageEmoji.spec.tsx

Repository: RocketChat/Rocket.Chat

Length of output: 3696


🏁 Script executed:

# Check Reactions component
head -40 apps/meteor/client/components/message/content/Reactions.tsx

Repository: RocketChat/Rocket.Chat

Length of output: 1771


🏁 Script executed:

# Check ReactionTooltip imports
head -20 apps/meteor/client/components/message/content/reactions/ReactionTooltip.tsx

Repository: RocketChat/Rocket.Chat

Length of output: 723


🏁 Script executed:

# Check if Reactions renders ReactionTooltip
rg "ReactionTooltip" apps/meteor/client/components/message/content/Reactions.tsx -A3 -B3

Repository: RocketChat/Rocket.Chat

Length of output: 48


🏁 Script executed:

# Check if Reaction component uses ReactionTooltip
head -50 apps/meteor/client/components/message/content/reactions/Reaction.tsx

Repository: RocketChat/Rocket.Chat

Length of output: 1937


🏁 Script executed:

# Verify the Reaction component imports
rg "import.*ReactionTooltip|ReactionTooltip" apps/meteor/client/components/message/content/reactions/Reaction.tsx -B5 -A5

Repository: RocketChat/Rocket.Chat

Length of output: 876


Mocking modules to undefined is non-idiomatic and causes runtime errors when code imports named exports.

jest.mock('...', () => undefined) makes the module itself undefined. Code that imports named exports from it (e.g. import { useGetMessageByID } from '...') will fail at runtime.

useGetMessageByID is imported in ReactionTooltip.tsx, which is rendered by this test via the Reactions component (present in the message fixture). Mocking it to undefined will cause the component to fail during rendering.

Similarly, actionLinks is imported as a named export in MessageActions.tsx. While not triggered in this specific test (message lacks actionLinks), it's still non-idiomatic.

Use () => ({}) instead:

Proposed fix
-jest.mock('../../../views/room/contextualBar/Threads/hooks/useGetMessageByID', () => undefined);
+jest.mock('../../../views/room/contextualBar/Threads/hooks/useGetMessageByID', () => ({}));
-jest.mock('../../../lib/actionLinks', () => undefined);
+jest.mock('../../../lib/actionLinks', () => ({}));
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
jest.mock('../../../views/room/contextualBar/Threads/hooks/useGetMessageByID', () => undefined);
jest.mock('../../../views/room/contextualBar/Threads/hooks/useGetMessageByID', () => ({}));
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/meteor/client/components/message/variants/RoomMessageEmoji.spec.tsx` at
line 43, The test currently mocks modules to undefined which breaks named
imports (e.g., useGetMessageByID used by ReactionTooltip rendered via the
Reactions component, and actionLinks used by MessageActions); update the
jest.mock calls in RoomMessageEmoji.spec.tsx to return an object (e.g., () =>
({})) or provide the specific named export stubs so imports like
useGetMessageByID and actionLinks resolve to defined values instead of
undefined, ensuring ReactionTooltip/Reactions/MessageActions can import their
named exports at runtime.


expect(screen.queryByRole('img')).not.toBeInTheDocument();
expect(screen.getByText('message body :emoji:')).toBeInTheDocument();
expect(screen.queryByRole('toolbar')).not.toBeInTheDocument();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

🧩 Analysis chain

🏁 Script executed:

# First, locate and read the test file around line 100
fd -e spec.tsx "RoomMessageEmoji" --exec wc -l {} \;

Repository: RocketChat/Rocket.Chat

Length of output: 144


🏁 Script executed:

# Read the test file to understand the context
fd -e spec.tsx "RoomMessageEmoji" --exec cat -n {} \; | head -150

Repository: RocketChat/Rocket.Chat

Length of output: 3696


🏁 Script executed:

# Search for ReactionMessageAction implementation
rg "ReactionMessageAction" --type=tsx -B 3 -A 10 | head -100

Repository: RocketChat/Rocket.Chat

Length of output: 93


🏁 Script executed:

# Search for DefaultItems to understand what it renders
rg "DefaultItems" --type=tsx -B 2 -A 5 | head -100

Repository: RocketChat/Rocket.Chat

Length of output: 93


🏁 Script executed:

# Find RoomMessage component
fd -e "RoomMessage" -type f | grep -v spec | grep -v node_modules | head -20

Repository: RocketChat/Rocket.Chat

Length of output: 236


🏁 Script executed:

# Search for ReactionMessageAction without type restriction
rg "ReactionMessageAction" -B 3 -A 10 | head -80

Repository: RocketChat/Rocket.Chat

Length of output: 8374


🏁 Script executed:

# Search for toolbar role in the codebase to understand what creates it
rg "toolbar" --type=ts -B 2 -A 2 | head -100

Repository: RocketChat/Rocket.Chat

Length of output: 7664


🏁 Script executed:

# Check if RoomMessage imports or renders DefaultItems
rg "DefaultItems" -B 2 -A 5 | head -80

Repository: RocketChat/Rocket.Chat

Length of output: 3580


🏁 Script executed:

# Get full DefaultItems implementation
rg "DefaultItems = \({" -A 30 apps/meteor/client/components/message/toolbar/items/DefaultItems.tsx

Repository: RocketChat/Rocket.Chat

Length of output: 165


🏁 Script executed:

# Get full ReactionMessageAction implementation to see what it renders
rg "const ReactionMessageAction = " -A 40 apps/meteor/client/components/message/toolbar/items/actions/ReactionMessageAction.tsx

Repository: RocketChat/Rocket.Chat

Length of output: 1113


🏁 Script executed:

# Check MessageToolbar to understand how DefaultItems is used and how toolbar is rendered
rg "MessageToolbar" -A 50 apps/meteor/client/components/message/toolbar/MessageToolbar.tsx | head -100

Repository: RocketChat/Rocket.Chat

Length of output: 3187


🏁 Script executed:

# Get the complete DefaultItems implementation
cat -n apps/meteor/client/components/message/toolbar/items/DefaultItems.tsx

Repository: RocketChat/Rocket.Chat

Length of output: 1350


🏁 Script executed:

# Check QuoteMessageAction implementation to see if it can render null
rg "const QuoteMessageAction" -A 30 apps/meteor/client/components/message/toolbar/items/actions/

Repository: RocketChat/Rocket.Chat

Length of output: 3529


🏁 Script executed:

# Check ForwardMessageAction
rg "const ForwardMessageAction" -A 30 apps/meteor/client/components/message/toolbar/items/actions/

Repository: RocketChat/Rocket.Chat

Length of output: 3593


🏁 Script executed:

# Check ReplyInThreadMessageAction
rg "const ReplyInThreadMessageAction" -A 30 apps/meteor/client/components/message/toolbar/items/actions/

Repository: RocketChat/Rocket.Chat

Length of output: 3750


🏁 Script executed:

# Get complete ForwardMessageAction implementation
cat -n apps/meteor/client/components/message/toolbar/items/actions/ForwardMessageAction.tsx | head -50

Repository: RocketChat/Rocket.Chat

Length of output: 1904


🏁 Script executed:

# Check MessageToolbarItem to understand what it renders
rg "const MessageToolbarItem" -A 20 apps/meteor/client/components/message/toolbar/

Repository: RocketChat/Rocket.Chat

Length of output: 3690


🏁 Script executed:

# Get complete ReactionMessageAction to see what it returns
cat -n apps/meteor/client/components/message/toolbar/items/actions/ReactionMessageAction.tsx | tail -30

Repository: RocketChat/Rocket.Chat

Length of output: 977


🏁 Script executed:

# Check if MessageToolbar conditionally renders based on empty children
rg "FuselageMessageToolbar" -B 5 -A 10 apps/meteor/client/components/message/toolbar/MessageToolbar.tsx

Repository: RocketChat/Rocket.Chat

Length of output: 2043


🏁 Script executed:

# Check RoomMessage implementation to understand if it conditionally renders MessageToolbar
rg "RoomMessage" -B 5 -A 30 apps/meteor/client/components/message/variants/RoomMessage.tsx | head -80

Repository: RocketChat/Rocket.Chat

Length of output: 2349


🏁 Script executed:

# Check if there's logic preventing toolbar rendering in specific test contexts
fd "RoomMessage.tsx" -type f | grep -v spec | head -1 | xargs wc -l

Repository: RocketChat/Rocket.Chat

Length of output: 255


🏁 Script executed:

# Get more context around how MessageToolbar is used in RoomMessage
fd "RoomMessage.tsx" -type f | grep -v spec | head -1 | xargs cat | head -100

Repository: RocketChat/Rocket.Chat

Length of output: 236


🏁 Script executed:

# Check MessageToolbarHolder implementation
fd "MessageToolbarHolder" -type f | grep -v spec | xargs cat

Repository: RocketChat/Rocket.Chat

Length of output: 236


🏁 Script executed:

# Check if FuselageMessageToolbar from fuselage actually creates a toolbar role
rg "MessageToolbar as FuselageMessageToolbar" -B 5 -A 5 apps/meteor/client/components/message/toolbar/MessageToolbar.tsx

Repository: RocketChat/Rocket.Chat

Length of output: 633


🏁 Script executed:

# Look for FuselageMessageToolbar in fuselage package
rg "MessageToolbar" apps/meteor/node_modules/@rocket.chat/fuselage/dist/ 2>/dev/null | head -5 || echo "Checking fuselage source..."

Repository: RocketChat/Rocket.Chat

Length of output: 48


🏁 Script executed:

# Check test to see if toolbar actually appears when useEmojis is true
rg "should render emoji and show reactions if enabled" -A 30 apps/meteor/client/components/message/variants/RoomMessageEmoji.spec.tsx

Repository: RocketChat/Rocket.Chat

Length of output: 943


🏁 Script executed:

# Find and read MessageToolbarHolder
find apps/meteor/client/components/message -name "MessageToolbarHolder*" | head -1 | xargs cat

Repository: RocketChat/Rocket.Chat

Length of output: 1826


🏁 Script executed:

# Check what FuselageMessageToolbar actually is from fuselage
find . -path "*/node_modules/@rocket.chat/fuselage*" -name "*.d.ts" -o -name "*.tsx" -o -name "*.ts" 2>/dev/null | xargs grep -l "export.*MessageToolbar" | head -3

Repository: RocketChat/Rocket.Chat

Length of output: 473


🏁 Script executed:

# Let's check the actual test result by searching for how toolbar is used in similar tests
rg "queryByRole.*toolbar" apps/meteor/client/components/message/ -B 5 -A 2

Repository: RocketChat/Rocket.Chat

Length of output: 785


🏁 Script executed:

# Check if MessageToolbarStarsActionMenu or MessageToolbarActionMenu might return null
rg "MessageToolbarStarsActionMenu\|MessageToolbarActionMenu" -A 20 apps/meteor/client/components/message/toolbar/ | head -60

Repository: RocketChat/Rocket.Chat

Length of output: 48


🏁 Script executed:

# Check what happens in the test - see if the toolbar actually renders or if room is missing
# Look at how useIsVisible works - it might prevent toolbar from rendering
rg "useIsVisible" -B 2 -A 10 apps/meteor/client/views/room/hooks/useIsVisible.tsx

Repository: RocketChat/Rocket.Chat

Length of output: 158


🏁 Script executed:

# Check what MessageToolbarWrapper does
rg "MessageToolbarWrapper" -B 2 -A 10

Repository: RocketChat/Rocket.Chat

Length of output: 11787


🏁 Script executed:

# Double-check: when useEmojis=false, what actually prevents the toolbar from appearing?
# Let's trace through: Does ReactionMessageAction render a toolbar role?
rg "role.*toolbar\|aria-label.*Message_actions" apps/meteor/client/components/message/toolbar/

Repository: RocketChat/Rocket.Chat

Length of output: 48


🏁 Script executed:

# Most importantly: Let's check if FuselageMessageToolbar is what creates the toolbar role
# by looking at what it actually renders
python3 << 'EOF'
import json
# Search for MessageToolbar export from fuselage
import subprocess
result = subprocess.run(['rg', 'export.*MessageToolbar', '-g', '*.ts', '-g', '*.tsx', '-g', '*.d.ts'], 
                       capture_output=True, text=True, cwd='.')
for line in result.stdout.split('\n')[:20]:
    if 'fuselage' in line.lower() and 'node_modules' not in line:
        print(line)
EOF

Repository: RocketChat/Rocket.Chat

Length of output: 48


🏁 Script executed:

# Find useIsVisible hook
find apps/meteor/client -name "useIsVisible*" -o -type f -path "*hooks*" | xargs grep -l "useIsVisible" 2>/dev/null | head -5

Repository: RocketChat/Rocket.Chat

Length of output: 117


🏁 Script executed:

# Search for useIsVisible definition anywhere in the codebase
rg "export.*useIsVisible\|const useIsVisible" -B 2 -A 10 | head -40

Repository: RocketChat/Rocket.Chat

Length of output: 48


🏁 Script executed:

# Most importantly: verify MessageToolbarHolder condition - does it prevent toolbar rendering when room is null?
rg "depsQueryResult.data.room" -B 5 -A 5 apps/meteor/client/components/message/MessageToolbarHolder.tsx

Repository: RocketChat/Rocket.Chat

Length of output: 531


🏁 Script executed:

# Read the useIsVisible hook to understand the complete flow
cat apps/meteor/client/views/room/hooks/useIsVisible.ts

Repository: RocketChat/Rocket.Chat

Length of output: 762


🏁 Script executed:

# Let's verify: In the test, what is the state of depsQueryResult.data.room?
# The test uses mockAppRoot() - let's check what ChatContext provides
rg "mockAppRoot" -B 5 -A 20 apps/meteor/client/components/message/variants/RoomMessageEmoji.spec.tsx | head -50

Repository: RocketChat/Rocket.Chat

Length of output: 1443


🏁 Script executed:

# Check what mockAppRoot actually provides for chat context
rg "mockAppRoot" --type=ts -B 3 -A 15 | grep -A 15 "export.*mockAppRoot" | head -40

Repository: RocketChat/Rocket.Chat

Length of output: 1233


🏁 Script executed:

# Check MockedAppRootBuilder to see what it provides for chat context
rg "MockedAppRootBuilder\|class.*AppRoot" -B 5 -A 30 packages/mock-providers/src/ | head -80

Repository: RocketChat/Rocket.Chat

Length of output: 48


🏁 Script executed:

# Check if the mock provides a default room/subscription for chat context
rg "ChatContext\|chat.*data.*findRoom" packages/mock-providers/src/ -B 3 -A 10

Repository: RocketChat/Rocket.Chat

Length of output: 48


🏁 Script executed:

# Let's verify: does the toolbar actually appear in the first test (useEmojis=true)?
# If so, what's different about the mock setup?
rg "should render emoji and show reactions if enabled" -A 28 apps/meteor/client/components/message/variants/RoomMessageEmoji.spec.tsx

Repository: RocketChat/Rocket.Chat

Length of output: 900


🏁 Script executed:

# Find and read MockedAppRootBuilder implementation
fd "MockedAppRootBuilder" packages/mock-providers/src/ | head -1 | xargs cat | head -100

Repository: RocketChat/Rocket.Chat

Length of output: 2972


🏁 Script executed:

# Search more broadly for the AppRoot builder
fd -e "ts" -e "tsx" packages/mock-providers/src | xargs grep -l "class.*AppRootBuilder\|export.*mockAppRoot" | head -3

Repository: RocketChat/Rocket.Chat

Length of output: 479


🏁 Script executed:

# Let's check if there's something conditional in MessageToolbarHolder based on useEmojis
rg "useEmojis\|enableEmojis" apps/meteor/client/components/message/ -B 3 -A 3

Repository: RocketChat/Rocket.Chat

Length of output: 48


🏁 Script executed:

# Key question: does the toolbar actually get rendered to the DOM in test 2?
# Let's check what FuselageMessageToolbar is - it might conditionally render children
rg "FuselageMessageToolbar\|as FuselageMessageToolbar" -B 2 -A 10 packages/ui-client/src/ 2>/dev/null | head -60

Repository: RocketChat/Rocket.Chat

Length of output: 48


🏁 Script executed:

# Let's check the MockedAppRootBuilder more carefully - look at the full file
cat packages/mock-providers/src/MockedAppRootBuilder.tsx | head -200

Repository: RocketChat/Rocket.Chat

Length of output: 6623


🏁 Script executed:

# Check if there's a ChatContext provider in the builder
rg "ChatContext\|chat.*provider" packages/mock-providers/src/ -B 2 -A 5

Repository: RocketChat/Rocket.Chat

Length of output: 48


🏁 Script executed:

# Key question: In the test, when using mockAppRoot(), does chat?.data.findRoom() return a room?
# Let's check if there are any other tests that check toolbar behavior
rg "toolbar\|MessageToolbar" apps/meteor/client/components/message/ --type=tsx -l | grep -E "spec|test"

Repository: RocketChat/Rocket.Chat

Length of output: 93


🏁 Script executed:

# Let's check what actually happens in the test - verify the mock setup provides or doesn't provide a room
cat packages/mock-providers/src/MockedAppRootBuilder.tsx | grep -A 20 "build()"

Repository: RocketChat/Rocket.Chat

Length of output: 731


🏁 Script executed:

# Look for test utilities to understand what mockAppRoot() provides
rg "class MockedAppRootBuilder" -A 300 packages/mock-providers/src/MockedAppRootBuilder.tsx | tail -150

Repository: RocketChat/Rocket.Chat

Length of output: 5050


🏁 Script executed:

# Critical: Check what this.room is by default in MockedAppRootBuilder
rg "private room\|this.room =" packages/mock-providers/src/MockedAppRootBuilder.tsx -B 2 -A 2

Repository: RocketChat/Rocket.Chat

Length of output: 48


🏁 Script executed:

# Check the full user context queryRoom implementation
rg "queryRoom:" packages/mock-providers/src/MockedAppRootBuilder.tsx -B 2 -A 3

Repository: RocketChat/Rocket.Chat

Length of output: 361


🏁 Script executed:

# So the question is: does mockAppRoot() without explicit room setup provide a room to chat context?
# Let's look at what happens in MessageToolbarHolder when room query fails
cat apps/meteor/client/components/message/MessageToolbarHolder.tsx | grep -A 15 "showToolbar"

Repository: RocketChat/Rocket.Chat

Length of output: 930


Assertion tests incidental mock behavior; verify reaction button absence instead.

expect(screen.queryByRole('toolbar')).not.toBeInTheDocument() is fragile because its absence may result from mock setup (missing room/subscription in depsQueryResult) rather than enableEmojis=false logic. Since DefaultItems conditionally renders ReactionMessageAction only when enableEmojis=true, a more resilient and intent-revealing assertion would directly verify the reaction button is absent:

expect(screen.queryByRole('button', { name: /add reaction/i })).not.toBeInTheDocument();

This tests the actual intent—that emoji reactions are disabled—rather than relying on the entire toolbar's presence, which depends on mock ChatContext and query state.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/meteor/client/components/message/variants/RoomMessageEmoji.spec.tsx` at
line 100, Replace the fragile toolbar assertion in RoomMessageEmoji.spec.tsx
with a direct check for the reaction button to assert emojis are disabled:
instead of asserting on the toolbar role (which can be missing due to mock
deps), update the test that renders DefaultItems/ReactionMessageAction to use
screen.queryByRole('button', { name: /add reaction/i }) and assert
.not.toBeInTheDocument() so the test explicitly verifies the absence of the
reaction action when enableEmojis=false.

@codecov
Copy link

codecov bot commented Feb 20, 2026

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 70.65%. Comparing base (7d23911) to head (e4a6cd8).

Additional details and impacted files

Impacted file tree graph

@@             Coverage Diff             @@
##           develop   #38863      +/-   ##
===========================================
+ Coverage    70.60%   70.65%   +0.05%     
===========================================
  Files         3189     3189              
  Lines       112703   112706       +3     
  Branches     20436    20410      -26     
===========================================
+ Hits         79573    79633      +60     
+ Misses       31069    31011      -58     
- Partials      2061     2062       +1     
Flag Coverage Δ
unit 71.66% <100.00%> (+0.07%) ⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

📜 Review details

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 94e46d1 and e4a6cd8.

📒 Files selected for processing (1)
  • apps/meteor/client/components/message/toolbar/items/DefaultItems.tsx
🧰 Additional context used
📓 Path-based instructions (1)
**/*.{ts,tsx,js}

📄 CodeRabbit inference engine (.cursor/rules/playwright.mdc)

**/*.{ts,tsx,js}: Write concise, technical TypeScript/JavaScript with accurate typing in Playwright tests
Avoid code comments in the implementation

Files:

  • apps/meteor/client/components/message/toolbar/items/DefaultItems.tsx
🧠 Learnings (3)
📚 Learning: 2025-11-19T18:20:07.720Z
Learnt from: gabriellsh
Repo: RocketChat/Rocket.Chat PR: 37419
File: packages/i18n/src/locales/en.i18n.json:918-921
Timestamp: 2025-11-19T18:20:07.720Z
Learning: Repo: RocketChat/Rocket.Chat — i18n/formatting
Learning: This repository uses a custom message formatting parser in UI blocks/messages; do not assume standard Markdown rules. For keys like Call_ended_bold, Call_not_answered_bold, Call_failed_bold, and Call_transferred_bold in packages/i18n/src/locales/en.i18n.json, retain the existing single-asterisk emphasis unless maintainers request otherwise.

Applied to files:

  • apps/meteor/client/components/message/toolbar/items/DefaultItems.tsx
📚 Learning: 2026-01-17T01:51:47.764Z
Learnt from: tassoevan
Repo: RocketChat/Rocket.Chat PR: 38219
File: packages/core-typings/src/cloud/Announcement.ts:5-6
Timestamp: 2026-01-17T01:51:47.764Z
Learning: In packages/core-typings/src/cloud/Announcement.ts, the AnnouncementSchema.createdBy field intentionally overrides IBannerSchema.createdBy (object with _id and optional username) with a string enum ['cloud', 'system'] to match existing runtime behavior. This is documented as technical debt with a FIXME comment at apps/meteor/app/cloud/server/functions/syncWorkspace/handleCommsSync.ts:53 and should not be flagged as an error until the runtime behavior is corrected.

Applied to files:

  • apps/meteor/client/components/message/toolbar/items/DefaultItems.tsx
📚 Learning: 2025-10-06T20:32:23.658Z
Learnt from: d-gubert
Repo: RocketChat/Rocket.Chat PR: 37152
File: packages/apps-engine/tests/test-data/utilities.ts:557-573
Timestamp: 2025-10-06T20:32:23.658Z
Learning: In packages/apps-engine/tests/test-data/utilities.ts, the field name `isSubscripbedViaBundle` in the `IMarketplaceSubscriptionInfo` type should not be flagged as a typo, as it may match the upstream API's field name.

Applied to files:

  • apps/meteor/client/components/message/toolbar/items/DefaultItems.tsx
🧬 Code graph analysis (1)
apps/meteor/client/components/message/toolbar/items/DefaultItems.tsx (1)
packages/ui-contexts/src/index.ts (1)
  • useUserPreference (86-86)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (3)
  • GitHub Check: cubic · AI code reviewer
  • GitHub Check: 📦 Build Packages
  • GitHub Check: CodeQL-Build
🔇 Additional comments (1)
apps/meteor/client/components/message/toolbar/items/DefaultItems.tsx (1)

9-26: LGTM — past prop issue resolved, conditional guard is logically correct.

enableEmojis: boolean has been correctly removed from DefaultItemsProps (addressed from the previous review), the hook call is the single source of truth, and all other actions remain unaffected.

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@apps/meteor/client/components/message/toolbar/items/DefaultItems.tsx`:
- Around line 16-20: The optional return from
useUserPreference<boolean>('useEmojis') can be undefined and currently hides
ReactionMessageAction; change the call to provide a safe default or coalesce the
result so undefined becomes the expected default (e.g. pass a defaultValue true
to useUserPreference or replace the render condition with (enableEmojis ?? true)
&& <ReactionMessageAction .../>), updating the enableEmojis usage in
DefaultItems.tsx to ensure the reaction button shows for users without an
explicit preference.
- Around line 16-20: The enableEmojis variable can be undefined because
useUserPreference<boolean>('useEmojis') returns T | undefined; update the
initialization of enableEmojis to provide a default true using the nullish
coalescing operator (e.g., replace the current assignment to
useUserPreference<boolean>('useEmojis') with
useUserPreference<boolean>('useEmojis') ?? true) so that ReactionMessageAction
is shown by default while the preference is loading.

Comment on lines +16 to +20
const enableEmojis = useUserPreference<boolean>('useEmojis');

return (
<>
<ReactionMessageAction message={message} room={room} subscription={subscription} />
{enableEmojis && <ReactionMessageAction message={message} room={room} subscription={subscription} />}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Find the useUserPreference hook definition
rg -n "useUserPreference" packages/ui-contexts/src/ -A 5 -B 2

Repository: RocketChat/Rocket.Chat

Length of output: 3012


🏁 Script executed:

#!/bin/bash
# Also check the DefaultItems.tsx file to see the current state
cat -n apps/meteor/client/components/message/toolbar/items/DefaultItems.tsx | head -30

Repository: RocketChat/Rocket.Chat

Length of output: 1319


🏁 Script executed:

#!/bin/bash
# Search for useUserPreference export/definition
fd -e ts -e tsx "ui-contexts" --exec grep -l "useUserPreference" {}

Repository: RocketChat/Rocket.Chat

Length of output: 48


useUserPreference<boolean> returns undefined, silently hiding reactions when preference is uninitialized.

The hook signature is useUserPreference = <T>(key: string, defaultValue?: T): T | undefined. Since useUserPreference<boolean>('useEmojis') is called without a defaultValue, the result can be boolean | undefined at runtime. The conditional render {enableEmojis && <ReactionMessageAction …/>} treats undefined as falsy, hiding the reaction button for users who have never set the preference, breaking the expected default behavior.

Provide a safe default that coalesces undefined to the expected value:

Fix
-	const enableEmojis = useUserPreference<boolean>('useEmojis');
+	const enableEmojis = useUserPreference<boolean>('useEmojis') ?? true;
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const enableEmojis = useUserPreference<boolean>('useEmojis');
return (
<>
<ReactionMessageAction message={message} room={room} subscription={subscription} />
{enableEmojis && <ReactionMessageAction message={message} room={room} subscription={subscription} />}
const enableEmojis = useUserPreference<boolean>('useEmojis') ?? true;
return (
<>
{enableEmojis && <ReactionMessageAction message={message} room={room} subscription={subscription} />}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/meteor/client/components/message/toolbar/items/DefaultItems.tsx` around
lines 16 - 20, The optional return from useUserPreference<boolean>('useEmojis')
can be undefined and currently hides ReactionMessageAction; change the call to
provide a safe default or coalesce the result so undefined becomes the expected
default (e.g. pass a defaultValue true to useUserPreference or replace the
render condition with (enableEmojis ?? true) && <ReactionMessageAction .../>),
updating the enableEmojis usage in DefaultItems.tsx to ensure the reaction
button shows for users without an explicit preference.

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

# Find the useUserPreference hook definition
fd -e "ts" -e "tsx" -e "js" -e "jsx" | xargs rg "export.*useUserPreference" | head -20

Repository: RocketChat/Rocket.Chat

Length of output: 798


🏁 Script executed:

# Search in `@rocket.chat/ui-contexts` or similar packages
fd -type f -path "*/ui-contexts*" \( -name "*.ts" -o -name "*.tsx" \) | head -20

Repository: RocketChat/Rocket.Chat

Length of output: 236


🏁 Script executed:

# Look for the hook implementation more broadly
rg "function useUserPreference|const useUserPreference" -A 10 | head -50

Repository: RocketChat/Rocket.Chat

Length of output: 647


🏁 Script executed:

# Check the DefaultItems.tsx file to see the import and context
cat -n apps/meteor/client/components/message/toolbar/items/DefaultItems.tsx | head -30

Repository: RocketChat/Rocket.Chat

Length of output: 1319


🏁 Script executed:

# Check other usages of useUserPreference in the codebase to understand common patterns
rg "useUserPreference\<boolean\>" -A 1 | head -40

Repository: RocketChat/Rocket.Chat

Length of output: 177


🏁 Script executed:

# Check if there are usages with defaultValue to understand pattern
rg "useUserPreference.*??|useUserPreference.*\|\|" -B 1 -A 1 | head -30

Repository: RocketChat/Rocket.Chat

Length of output: 2636


Use nullish coalescing to provide default value for emoji preference.

The useUserPreference<T> hook returns T | undefined, and the call to useUserPreference<boolean>('useEmojis') on line 16 provides no default value. This means enableEmojis will be undefined on initial render or until the preference loads, causing the conditional on line 20 to hide ReactionMessageAction unintentionally. Since emoji reactions should be enabled by default, add a nullish coalescing operator:

Fix
-	const enableEmojis = useUserPreference<boolean>('useEmojis');
+	const enableEmojis = useUserPreference<boolean>('useEmojis') ?? true;
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const enableEmojis = useUserPreference<boolean>('useEmojis');
return (
<>
<ReactionMessageAction message={message} room={room} subscription={subscription} />
{enableEmojis && <ReactionMessageAction message={message} room={room} subscription={subscription} />}
const enableEmojis = useUserPreference<boolean>('useEmojis') ?? true;
return (
<>
{enableEmojis && <ReactionMessageAction message={message} room={room} subscription={subscription} />}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/meteor/client/components/message/toolbar/items/DefaultItems.tsx` around
lines 16 - 20, The enableEmojis variable can be undefined because
useUserPreference<boolean>('useEmojis') returns T | undefined; update the
initialization of enableEmojis to provide a default true using the nullish
coalescing operator (e.g., replace the current assignment to
useUserPreference<boolean>('useEmojis') with
useUserPreference<boolean>('useEmojis') ?? true) so that ReactionMessageAction
is shown by default while the preference is loading.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant