refactor: derive isMasterDetail per-component and remove Dimensions provider#7422
refactor: derive isMasterDetail per-component and remove Dimensions provider#7422diegolmello wants to merge 4 commits into
Conversation
useMasterDetail derives the master-detail flag per-component from useWindowDimensions, replacing the Redux state.app.isMasterDetail field. withMasterDetail/withDimensions bridge the hooks into class components, injecting the values as props and stripping them from the public prop type. Claude-Session: https://claude.ai/code/session_01G1Y1nFCGsaMDy5XaYYmGhX
Remove the root Dimensions.addEventListener -> setState pipeline in app/index.tsx and the DimensionsContext it fed, along with the Redux state.app.isMasterDetail field, its action, and reducer case. Every reader now derives the flag locally: function components call useMasterDetail(); class components receive it via the withMasterDetail HOC in their connect chain. The three views that consumed dimension props move to the hook-backed withDimensions. Delete app/dimensions.tsx; its only remaining consumer (List stories) drives fontScale through ResponsiveLayoutContext. The flag now tracks window resize directly instead of a debounced Redux round-trip, so split-view changes on tablets apply without a store update. Claude-Session: https://claude.ai/code/session_01G1Y1nFCGsaMDy5XaYYmGhX
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Organization UI Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (6)
📜 Recent review details🧰 Additional context used📓 Path-based instructions (4)**/*.{js,ts,jsx,tsx}📄 CodeRabbit inference engine (AGENTS.md)
Files:
**/*.{js,jsx,ts,tsx,json}📄 CodeRabbit inference engine (CLAUDE.md)
Files:
**/*.{js,jsx,ts,tsx}📄 CodeRabbit inference engine (CLAUDE.md)
Files:
**/*.{ts,tsx}📄 CodeRabbit inference engine (AGENTS.md)
Files:
🧠 Learnings (2)📚 Learning: 2026-05-07T13:19:52.152ZApplied to files:
📚 Learning: 2026-04-30T17:07:51.020ZApplied to files:
🔇 Additional comments (6)
WalkthroughIntroduces ChangesisMasterDetail Redux-to-hook migration
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~25 minutes Suggested reviewers
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. Warning Review ran into problems🔥 ProblemsErrors were encountered while retrieving linked issues. Errors (1)
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. Comment |
connect(..., { forwardRef: true }) wraps forwardRef screens (MessageActions,
JoinCode) whose parents hold a ref and call imperative methods. The HOC sat
between connect and the component as a plain function component, swallowing
the ref. Make both HOCs forwardRef so the ref reaches the wrapped component.
Claude-Session: https://claude.ai/code/session_01G1Y1nFCGsaMDy5XaYYmGhX
…ield
Sagas can't call the useMasterDetail hook, and the Redux state.app.isMasterDetail
field no longer exists. Add getIsMasterDetail(), a synchronous snapshot from
Dimensions.get('window'), and use it in the createChannel, deepLinking, login,
room, and messages sagas so master-detail navigation keeps working.
Claude-Session: https://claude.ai/code/session_01G1Y1nFCGsaMDy5XaYYmGhX
Review summaryReviewed the full diff (≈50 readers migrated, 2 HOCs added, root pipeline + Two correctness issues were found and fixed while reviewing: 1. Refs were swallowed by the new HOCs. 2. Five sagas still read the removed Redux field. NitNo dedicated unit test for Otherwise the migration is consistent and the refactor preserves behavior. LGTM. |
There was a problem hiding this comment.
Actionable comments posted: 2
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
app/views/AddExistingChannelView/index.tsx (1)
47-52:⚠️ Potential issue | 🟠 Major | ⚡ Quick winHeader options do not react to master-detail toggles.
isMasterDetailnow changes with window width, butuseLayoutEffectonly depends onselected.length. Crossing the tablet threshold will not refreshheaderLeftuntil selection changes.Suggested fix
- useLayoutEffect(() => { - setHeader(); - }, [selected.length]); + useLayoutEffect(() => { + setHeader(); + }, [selected.length, isMasterDetail, navigation]);🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@app/views/AddExistingChannelView/index.tsx` around lines 47 - 52, The useLayoutEffect hook that calls setHeader() only includes selected.length in its dependency array, but the effect also depends on isMasterDetail which changes when the window crosses the tablet threshold. Add isMasterDetail to the dependency array of the useLayoutEffect hook so that setHeader() is properly invoked whenever either selected.length or isMasterDetail changes, ensuring header options update correctly during master-detail mode toggles.
🧹 Nitpick comments (2)
app/views/UserNotificationPreferencesView/index.tsx (1)
33-35: Select the primitiveiddirectly to avoid unnecessary rerenders.The current selector wraps the result in an object literal, creating a new reference on every store update. Since
useAppSelectoruses reference equality, this triggers rerenders even when theuserIdvalue hasn't changed. Select the primitive directly instead:Suggested change
- const { userId } = useAppSelector(state => ({ - userId: getUserSelector(state).id - })); + const userId = useAppSelector(state => getUserSelector(state).id);🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@app/views/UserNotificationPreferencesView/index.tsx` around lines 33 - 35, The useAppSelector call in the UserNotificationPreferencesView is wrapping the userId value in an object literal, which creates a new reference on every store update even when the userId itself hasn't changed, triggering unnecessary rerenders. Instead of selecting an object and destructuring it, modify the selector to return the primitive id value directly by removing the object wrapper and calling getUserSelector(state).id directly as the return value of the useAppSelector callback, then assign it directly to userId without destructuring.app/views/SelectListView.tsx (1)
211-213: ⚡ Quick winAvoid a no-op
mapStateToPropssubscription.
connect(() => ({}))subscribes this component to store updates without consuming state. Preferconnect(null)or removeconnectentirely if no dispatch props are needed.Proposed change
-const mapStateToProps = () => ({}); - -export default connect(mapStateToProps)(withTheme(withMasterDetail(SelectListView))); +export default withTheme(withMasterDetail(SelectListView));🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@app/views/SelectListView.tsx` around lines 211 - 213, The mapStateToProps function in SelectListView is a no-op that returns an empty object and creates an unnecessary Redux subscription. Replace the mapStateToProps function call in the connect() invocation with null instead, by changing connect(mapStateToProps) to connect(null), or remove the connect wrapper entirely if no dispatch props are required. This eliminates the unnecessary store subscription and simplifies the component definition.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@app/views/AccessibilityAndAppearanceView/index.tsx`:
- Line 25: The useLayoutEffect hook that sets up headerLeft needs to be updated
to respond to changes in the isMasterDetail value. Add isMasterDetail to the
dependency array of the useLayoutEffect hook (the one that configures the
navigation header options) so that the effect re-runs whenever the master-detail
mode changes due to resize, rotation, or other layout changes. This ensures that
headerLeft and other header options remain synchronized with the current
master-detail state.
In `@app/views/RoomsListView/components/TabletHeader.tsx`:
- Around line 8-13: In the TabletHeader component, replace the `any` type
parameters in the useNavigation and useRoute hooks with proper TypeScript types.
Import NativeStackNavigationProp and RouteProp from
`@react-navigation/native-stack` and MasterDetailInsideStackParamList from the
navigation types, then apply these types to the respective hooks. Additionally,
add an explicit return type annotation of ReactElement | null to the
TabletHeader function declaration to ensure proper type safety.
---
Outside diff comments:
In `@app/views/AddExistingChannelView/index.tsx`:
- Around line 47-52: The useLayoutEffect hook that calls setHeader() only
includes selected.length in its dependency array, but the effect also depends on
isMasterDetail which changes when the window crosses the tablet threshold. Add
isMasterDetail to the dependency array of the useLayoutEffect hook so that
setHeader() is properly invoked whenever either selected.length or
isMasterDetail changes, ensuring header options update correctly during
master-detail mode toggles.
---
Nitpick comments:
In `@app/views/SelectListView.tsx`:
- Around line 211-213: The mapStateToProps function in SelectListView is a no-op
that returns an empty object and creates an unnecessary Redux subscription.
Replace the mapStateToProps function call in the connect() invocation with null
instead, by changing connect(mapStateToProps) to connect(null), or remove the
connect wrapper entirely if no dispatch props are required. This eliminates the
unnecessary store subscription and simplifies the component definition.
In `@app/views/UserNotificationPreferencesView/index.tsx`:
- Around line 33-35: The useAppSelector call in the
UserNotificationPreferencesView is wrapping the userId value in an object
literal, which creates a new reference on every store update even when the
userId itself hasn't changed, triggering unnecessary rerenders. Instead of
selecting an object and destructuring it, modify the selector to return the
primitive id value directly by removing the object wrapper and calling
getUserSelector(state).id directly as the return value of the useAppSelector
callback, then assign it directly to userId without destructuring.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: d1f6a55b-f099-4c25-9b69-77775209d6bd
📒 Files selected for processing (62)
app/AppContainer.tsxapp/actions/actionsTypes.tsapp/actions/app.tsapp/containers/Header/index.tsxapp/containers/InAppNotification/IncomingCallNotification/index.tsxapp/containers/InAppNotification/NotifierComponent.tsxapp/containers/List/List.stories.tsxapp/containers/MediaCallHeader/components/Content.tsxapp/containers/MessageActions/index.tsxapp/containers/MessageComposer/components/Buttons/ActionsButton.tsxapp/containers/MessageComposer/components/ComposerInput.tsxapp/containers/RoomHeader/RoomHeader.tsxapp/containers/TwoFactor/index.tsxapp/containers/markdown/components/mentions/Hashtag.tsxapp/dimensions.tsxapp/ee/omnichannel/containers/OmnichannelHeader/index.tsxapp/ee/omnichannel/views/QueueListView.tsxapp/index.tsxapp/lib/hooks/useMasterDetail.tsxapp/lib/hooks/withDimensions.tsxapp/reducers/app.test.tsapp/reducers/app.tsapp/views/AccessibilityAndAppearanceView/index.tsxapp/views/AddChannelTeamView.tsxapp/views/AddExistingChannelView/index.tsxapp/views/AdminPanelView/index.tsxapp/views/CallView/components/CallButtons.tsxapp/views/CannedResponseDetail.tsxapp/views/CannedResponsesListView/index.tsxapp/views/CloseLivechatView.tsxapp/views/CreateDiscussionView/index.tsxapp/views/DirectoryView/index.tsxapp/views/DiscussionsView/index.tsxapp/views/MessagesView/index.tsxapp/views/NewMessageView/index.tsxapp/views/NotificationPreferencesView/index.tsxapp/views/ProfileView/index.test.tsxapp/views/ProfileView/index.tsxapp/views/ReportUserView/index.tsxapp/views/RoomActionsView/index.tsxapp/views/RoomInfoView/index.tsxapp/views/RoomMembersView/index.tsxapp/views/RoomView/JoinCode.tsxapp/views/RoomView/RightButtons.tsxapp/views/RoomView/components/EncryptedRoom.tsxapp/views/RoomView/index.tsxapp/views/RoomsListView/components/ListHeader.tsxapp/views/RoomsListView/components/ServersList.tsxapp/views/RoomsListView/components/TabletHeader.tsxapp/views/RoomsListView/hooks/useHeader.tsxapp/views/RoomsListView/index.tsxapp/views/SearchMessagesView/index.tsxapp/views/SelectListView.tsxapp/views/SettingsView/index.tsxapp/views/SidebarView/components/Admin.tsxapp/views/SidebarView/components/Profile.tsxapp/views/SidebarView/components/Stacks.tsxapp/views/SidebarView/components/SupportedVersionsWarnItem.tsxapp/views/StatusView/index.tsxapp/views/TeamChannelsView.tsxapp/views/ThreadMessagesView/index.tsxapp/views/UserNotificationPreferencesView/index.tsx
💤 Files with no reviewable changes (3)
- app/dimensions.tsx
- app/reducers/app.ts
- app/actions/actionsTypes.ts
📜 Review details
🧰 Additional context used
📓 Path-based instructions (9)
**/*.{js,ts,jsx,tsx}
📄 CodeRabbit inference engine (AGENTS.md)
**/*.{js,ts,jsx,tsx}: Use descriptive names for functions, variables, and classes that clearly convey their purpose
Write comments that explain the 'why' behind code decisions, not the 'what'
Keep functions small and focused on a single responsibility
Use const by default, let when reassignment is needed, and avoid var
Prefer async/await over .then() chains for handling asynchronous operations
Use explicit error handling with try/catch blocks for async operations
Avoid deeply nested code; refactor complex logic into helper functions
Files:
app/containers/MediaCallHeader/components/Content.tsxapp/containers/Header/index.tsxapp/ee/omnichannel/containers/OmnichannelHeader/index.tsxapp/views/RoomsListView/components/TabletHeader.tsxapp/views/SidebarView/components/SupportedVersionsWarnItem.tsxapp/views/SelectListView.tsxapp/views/RoomsListView/components/ListHeader.tsxapp/views/NotificationPreferencesView/index.tsxapp/views/AddChannelTeamView.tsxapp/views/ProfileView/index.test.tsxapp/views/NewMessageView/index.tsxapp/lib/hooks/withDimensions.tsxapp/containers/InAppNotification/IncomingCallNotification/index.tsxapp/views/RoomsListView/components/ServersList.tsxapp/containers/MessageComposer/components/Buttons/ActionsButton.tsxapp/views/AccessibilityAndAppearanceView/index.tsxapp/ee/omnichannel/views/QueueListView.tsxapp/views/ReportUserView/index.tsxapp/containers/MessageComposer/components/ComposerInput.tsxapp/views/SidebarView/components/Profile.tsxapp/views/SettingsView/index.tsxapp/containers/TwoFactor/index.tsxapp/views/CloseLivechatView.tsxapp/views/CallView/components/CallButtons.tsxapp/views/StatusView/index.tsxapp/views/AdminPanelView/index.tsxapp/views/SearchMessagesView/index.tsxapp/containers/List/List.stories.tsxapp/views/RoomsListView/index.tsxapp/views/ProfileView/index.tsxapp/views/CannedResponsesListView/index.tsxapp/views/RoomView/JoinCode.tsxapp/lib/hooks/useMasterDetail.tsxapp/views/SidebarView/components/Admin.tsxapp/views/SidebarView/components/Stacks.tsxapp/AppContainer.tsxapp/views/RoomView/components/EncryptedRoom.tsxapp/reducers/app.test.tsapp/views/MessagesView/index.tsxapp/containers/markdown/components/mentions/Hashtag.tsxapp/containers/RoomHeader/RoomHeader.tsxapp/views/RoomMembersView/index.tsxapp/views/DiscussionsView/index.tsxapp/views/AddExistingChannelView/index.tsxapp/views/CannedResponseDetail.tsxapp/views/CreateDiscussionView/index.tsxapp/views/UserNotificationPreferencesView/index.tsxapp/views/RoomsListView/hooks/useHeader.tsxapp/containers/InAppNotification/NotifierComponent.tsxapp/views/RoomInfoView/index.tsxapp/views/RoomView/RightButtons.tsxapp/views/TeamChannelsView.tsxapp/views/DirectoryView/index.tsxapp/containers/MessageActions/index.tsxapp/views/RoomActionsView/index.tsxapp/views/RoomView/index.tsxapp/actions/app.tsapp/views/ThreadMessagesView/index.tsxapp/index.tsx
**/*.{ts,tsx}
📄 CodeRabbit inference engine (AGENTS.md)
**/*.{ts,tsx}: Use TypeScript for type safety; add explicit type annotations to function parameters and return types
Prefer interfaces over type aliases for defining object shapes in TypeScript
Use enums for sets of related constants rather than magic strings or numbersUse TypeScript with strict mode enabled
Files:
app/containers/MediaCallHeader/components/Content.tsxapp/containers/Header/index.tsxapp/ee/omnichannel/containers/OmnichannelHeader/index.tsxapp/views/RoomsListView/components/TabletHeader.tsxapp/views/SidebarView/components/SupportedVersionsWarnItem.tsxapp/views/SelectListView.tsxapp/views/RoomsListView/components/ListHeader.tsxapp/views/NotificationPreferencesView/index.tsxapp/views/AddChannelTeamView.tsxapp/views/ProfileView/index.test.tsxapp/views/NewMessageView/index.tsxapp/lib/hooks/withDimensions.tsxapp/containers/InAppNotification/IncomingCallNotification/index.tsxapp/views/RoomsListView/components/ServersList.tsxapp/containers/MessageComposer/components/Buttons/ActionsButton.tsxapp/views/AccessibilityAndAppearanceView/index.tsxapp/ee/omnichannel/views/QueueListView.tsxapp/views/ReportUserView/index.tsxapp/containers/MessageComposer/components/ComposerInput.tsxapp/views/SidebarView/components/Profile.tsxapp/views/SettingsView/index.tsxapp/containers/TwoFactor/index.tsxapp/views/CloseLivechatView.tsxapp/views/CallView/components/CallButtons.tsxapp/views/StatusView/index.tsxapp/views/AdminPanelView/index.tsxapp/views/SearchMessagesView/index.tsxapp/containers/List/List.stories.tsxapp/views/RoomsListView/index.tsxapp/views/ProfileView/index.tsxapp/views/CannedResponsesListView/index.tsxapp/views/RoomView/JoinCode.tsxapp/lib/hooks/useMasterDetail.tsxapp/views/SidebarView/components/Admin.tsxapp/views/SidebarView/components/Stacks.tsxapp/AppContainer.tsxapp/views/RoomView/components/EncryptedRoom.tsxapp/reducers/app.test.tsapp/views/MessagesView/index.tsxapp/containers/markdown/components/mentions/Hashtag.tsxapp/containers/RoomHeader/RoomHeader.tsxapp/views/RoomMembersView/index.tsxapp/views/DiscussionsView/index.tsxapp/views/AddExistingChannelView/index.tsxapp/views/CannedResponseDetail.tsxapp/views/CreateDiscussionView/index.tsxapp/views/UserNotificationPreferencesView/index.tsxapp/views/RoomsListView/hooks/useHeader.tsxapp/containers/InAppNotification/NotifierComponent.tsxapp/views/RoomInfoView/index.tsxapp/views/RoomView/RightButtons.tsxapp/views/TeamChannelsView.tsxapp/views/DirectoryView/index.tsxapp/containers/MessageActions/index.tsxapp/views/RoomActionsView/index.tsxapp/views/RoomView/index.tsxapp/actions/app.tsapp/views/ThreadMessagesView/index.tsxapp/index.tsx
**/*.{js,jsx,ts,tsx,json}
📄 CodeRabbit inference engine (CLAUDE.md)
Use Prettier formatting with tabs, single quotes, 130 character line width, no trailing commas, and avoid arrow function parentheses
Files:
app/containers/MediaCallHeader/components/Content.tsxapp/containers/Header/index.tsxapp/ee/omnichannel/containers/OmnichannelHeader/index.tsxapp/views/RoomsListView/components/TabletHeader.tsxapp/views/SidebarView/components/SupportedVersionsWarnItem.tsxapp/views/SelectListView.tsxapp/views/RoomsListView/components/ListHeader.tsxapp/views/NotificationPreferencesView/index.tsxapp/views/AddChannelTeamView.tsxapp/views/ProfileView/index.test.tsxapp/views/NewMessageView/index.tsxapp/lib/hooks/withDimensions.tsxapp/containers/InAppNotification/IncomingCallNotification/index.tsxapp/views/RoomsListView/components/ServersList.tsxapp/containers/MessageComposer/components/Buttons/ActionsButton.tsxapp/views/AccessibilityAndAppearanceView/index.tsxapp/ee/omnichannel/views/QueueListView.tsxapp/views/ReportUserView/index.tsxapp/containers/MessageComposer/components/ComposerInput.tsxapp/views/SidebarView/components/Profile.tsxapp/views/SettingsView/index.tsxapp/containers/TwoFactor/index.tsxapp/views/CloseLivechatView.tsxapp/views/CallView/components/CallButtons.tsxapp/views/StatusView/index.tsxapp/views/AdminPanelView/index.tsxapp/views/SearchMessagesView/index.tsxapp/containers/List/List.stories.tsxapp/views/RoomsListView/index.tsxapp/views/ProfileView/index.tsxapp/views/CannedResponsesListView/index.tsxapp/views/RoomView/JoinCode.tsxapp/lib/hooks/useMasterDetail.tsxapp/views/SidebarView/components/Admin.tsxapp/views/SidebarView/components/Stacks.tsxapp/AppContainer.tsxapp/views/RoomView/components/EncryptedRoom.tsxapp/reducers/app.test.tsapp/views/MessagesView/index.tsxapp/containers/markdown/components/mentions/Hashtag.tsxapp/containers/RoomHeader/RoomHeader.tsxapp/views/RoomMembersView/index.tsxapp/views/DiscussionsView/index.tsxapp/views/AddExistingChannelView/index.tsxapp/views/CannedResponseDetail.tsxapp/views/CreateDiscussionView/index.tsxapp/views/UserNotificationPreferencesView/index.tsxapp/views/RoomsListView/hooks/useHeader.tsxapp/containers/InAppNotification/NotifierComponent.tsxapp/views/RoomInfoView/index.tsxapp/views/RoomView/RightButtons.tsxapp/views/TeamChannelsView.tsxapp/views/DirectoryView/index.tsxapp/containers/MessageActions/index.tsxapp/views/RoomActionsView/index.tsxapp/views/RoomView/index.tsxapp/actions/app.tsapp/views/ThreadMessagesView/index.tsxapp/index.tsx
**/*.{js,jsx,ts,tsx}
📄 CodeRabbit inference engine (CLAUDE.md)
Enforce ESLint rules from
@rocket.chat/eslint-configwith React, React Native, TypeScript, and Jest plugins
Files:
app/containers/MediaCallHeader/components/Content.tsxapp/containers/Header/index.tsxapp/ee/omnichannel/containers/OmnichannelHeader/index.tsxapp/views/RoomsListView/components/TabletHeader.tsxapp/views/SidebarView/components/SupportedVersionsWarnItem.tsxapp/views/SelectListView.tsxapp/views/RoomsListView/components/ListHeader.tsxapp/views/NotificationPreferencesView/index.tsxapp/views/AddChannelTeamView.tsxapp/views/ProfileView/index.test.tsxapp/views/NewMessageView/index.tsxapp/lib/hooks/withDimensions.tsxapp/containers/InAppNotification/IncomingCallNotification/index.tsxapp/views/RoomsListView/components/ServersList.tsxapp/containers/MessageComposer/components/Buttons/ActionsButton.tsxapp/views/AccessibilityAndAppearanceView/index.tsxapp/ee/omnichannel/views/QueueListView.tsxapp/views/ReportUserView/index.tsxapp/containers/MessageComposer/components/ComposerInput.tsxapp/views/SidebarView/components/Profile.tsxapp/views/SettingsView/index.tsxapp/containers/TwoFactor/index.tsxapp/views/CloseLivechatView.tsxapp/views/CallView/components/CallButtons.tsxapp/views/StatusView/index.tsxapp/views/AdminPanelView/index.tsxapp/views/SearchMessagesView/index.tsxapp/containers/List/List.stories.tsxapp/views/RoomsListView/index.tsxapp/views/ProfileView/index.tsxapp/views/CannedResponsesListView/index.tsxapp/views/RoomView/JoinCode.tsxapp/lib/hooks/useMasterDetail.tsxapp/views/SidebarView/components/Admin.tsxapp/views/SidebarView/components/Stacks.tsxapp/AppContainer.tsxapp/views/RoomView/components/EncryptedRoom.tsxapp/reducers/app.test.tsapp/views/MessagesView/index.tsxapp/containers/markdown/components/mentions/Hashtag.tsxapp/containers/RoomHeader/RoomHeader.tsxapp/views/RoomMembersView/index.tsxapp/views/DiscussionsView/index.tsxapp/views/AddExistingChannelView/index.tsxapp/views/CannedResponseDetail.tsxapp/views/CreateDiscussionView/index.tsxapp/views/UserNotificationPreferencesView/index.tsxapp/views/RoomsListView/hooks/useHeader.tsxapp/containers/InAppNotification/NotifierComponent.tsxapp/views/RoomInfoView/index.tsxapp/views/RoomView/RightButtons.tsxapp/views/TeamChannelsView.tsxapp/views/DirectoryView/index.tsxapp/containers/MessageActions/index.tsxapp/views/RoomActionsView/index.tsxapp/views/RoomView/index.tsxapp/actions/app.tsapp/views/ThreadMessagesView/index.tsxapp/index.tsx
app/containers/**/*.{ts,tsx}
📄 CodeRabbit inference engine (CLAUDE.md)
Place reusable UI components in 'app/containers/' directory
Files:
app/containers/MediaCallHeader/components/Content.tsxapp/containers/Header/index.tsxapp/containers/InAppNotification/IncomingCallNotification/index.tsxapp/containers/MessageComposer/components/Buttons/ActionsButton.tsxapp/containers/MessageComposer/components/ComposerInput.tsxapp/containers/TwoFactor/index.tsxapp/containers/List/List.stories.tsxapp/containers/markdown/components/mentions/Hashtag.tsxapp/containers/RoomHeader/RoomHeader.tsxapp/containers/InAppNotification/NotifierComponent.tsxapp/containers/MessageActions/index.tsx
app/ee/**/*.{ts,tsx}
📄 CodeRabbit inference engine (CLAUDE.md)
Place enterprise features (Omnichannel/livechat) in 'app/ee/' directory
Files:
app/ee/omnichannel/containers/OmnichannelHeader/index.tsxapp/ee/omnichannel/views/QueueListView.tsx
app/views/**/*.{ts,tsx}
📄 CodeRabbit inference engine (CLAUDE.md)
Place screen components in 'app/views/' directory
Files:
app/views/RoomsListView/components/TabletHeader.tsxapp/views/SidebarView/components/SupportedVersionsWarnItem.tsxapp/views/SelectListView.tsxapp/views/RoomsListView/components/ListHeader.tsxapp/views/NotificationPreferencesView/index.tsxapp/views/AddChannelTeamView.tsxapp/views/ProfileView/index.test.tsxapp/views/NewMessageView/index.tsxapp/views/RoomsListView/components/ServersList.tsxapp/views/AccessibilityAndAppearanceView/index.tsxapp/views/ReportUserView/index.tsxapp/views/SidebarView/components/Profile.tsxapp/views/SettingsView/index.tsxapp/views/CloseLivechatView.tsxapp/views/CallView/components/CallButtons.tsxapp/views/StatusView/index.tsxapp/views/AdminPanelView/index.tsxapp/views/SearchMessagesView/index.tsxapp/views/RoomsListView/index.tsxapp/views/ProfileView/index.tsxapp/views/CannedResponsesListView/index.tsxapp/views/RoomView/JoinCode.tsxapp/views/SidebarView/components/Admin.tsxapp/views/SidebarView/components/Stacks.tsxapp/views/RoomView/components/EncryptedRoom.tsxapp/views/MessagesView/index.tsxapp/views/RoomMembersView/index.tsxapp/views/DiscussionsView/index.tsxapp/views/AddExistingChannelView/index.tsxapp/views/CannedResponseDetail.tsxapp/views/CreateDiscussionView/index.tsxapp/views/UserNotificationPreferencesView/index.tsxapp/views/RoomsListView/hooks/useHeader.tsxapp/views/RoomInfoView/index.tsxapp/views/RoomView/RightButtons.tsxapp/views/TeamChannelsView.tsxapp/views/DirectoryView/index.tsxapp/views/RoomActionsView/index.tsxapp/views/RoomView/index.tsxapp/views/ThreadMessagesView/index.tsx
app/reducers/**/*.{ts,tsx}
📄 CodeRabbit inference engine (CLAUDE.md)
Place reducers in 'app/reducers/' directory
Files:
app/reducers/app.test.ts
app/actions/**/*.{ts,tsx}
📄 CodeRabbit inference engine (CLAUDE.md)
Place action creators in 'app/actions/' directory
Files:
app/actions/app.ts
🧠 Learnings (2)
📚 Learning: 2026-04-30T17:07:51.020Z
Learnt from: diegolmello
Repo: RocketChat/Rocket.Chat.ReactNative PR: 7274
File: app/lib/services/voip/MediaCallEvents.ts:0-0
Timestamp: 2026-04-30T17:07:51.020Z
Learning: In this Rocket.Chat React Native codebase, the ESLint rule `no-void: error` is enforced. When you see a promise returned from an async call that is not awaited (a “floating promise”), do not silence it with the `void somePromise()` pattern. Instead, handle the promise explicitly by attaching `.catch(...)` (or otherwise awaiting/handling the error) so unhandled-rejection risks are addressed in a way that satisfies the existing ESLint configuration.
Applied to files:
app/containers/MediaCallHeader/components/Content.tsxapp/containers/Header/index.tsxapp/ee/omnichannel/containers/OmnichannelHeader/index.tsxapp/views/RoomsListView/components/TabletHeader.tsxapp/views/SidebarView/components/SupportedVersionsWarnItem.tsxapp/views/SelectListView.tsxapp/views/RoomsListView/components/ListHeader.tsxapp/views/NotificationPreferencesView/index.tsxapp/views/AddChannelTeamView.tsxapp/views/ProfileView/index.test.tsxapp/views/NewMessageView/index.tsxapp/lib/hooks/withDimensions.tsxapp/containers/InAppNotification/IncomingCallNotification/index.tsxapp/views/RoomsListView/components/ServersList.tsxapp/containers/MessageComposer/components/Buttons/ActionsButton.tsxapp/views/AccessibilityAndAppearanceView/index.tsxapp/ee/omnichannel/views/QueueListView.tsxapp/views/ReportUserView/index.tsxapp/containers/MessageComposer/components/ComposerInput.tsxapp/views/SidebarView/components/Profile.tsxapp/views/SettingsView/index.tsxapp/containers/TwoFactor/index.tsxapp/views/CloseLivechatView.tsxapp/views/CallView/components/CallButtons.tsxapp/views/StatusView/index.tsxapp/views/AdminPanelView/index.tsxapp/views/SearchMessagesView/index.tsxapp/containers/List/List.stories.tsxapp/views/RoomsListView/index.tsxapp/views/ProfileView/index.tsxapp/views/CannedResponsesListView/index.tsxapp/views/RoomView/JoinCode.tsxapp/lib/hooks/useMasterDetail.tsxapp/views/SidebarView/components/Admin.tsxapp/views/SidebarView/components/Stacks.tsxapp/AppContainer.tsxapp/views/RoomView/components/EncryptedRoom.tsxapp/reducers/app.test.tsapp/views/MessagesView/index.tsxapp/containers/markdown/components/mentions/Hashtag.tsxapp/containers/RoomHeader/RoomHeader.tsxapp/views/RoomMembersView/index.tsxapp/views/DiscussionsView/index.tsxapp/views/AddExistingChannelView/index.tsxapp/views/CannedResponseDetail.tsxapp/views/CreateDiscussionView/index.tsxapp/views/UserNotificationPreferencesView/index.tsxapp/views/RoomsListView/hooks/useHeader.tsxapp/containers/InAppNotification/NotifierComponent.tsxapp/views/RoomInfoView/index.tsxapp/views/RoomView/RightButtons.tsxapp/views/TeamChannelsView.tsxapp/views/DirectoryView/index.tsxapp/containers/MessageActions/index.tsxapp/views/RoomActionsView/index.tsxapp/views/RoomView/index.tsxapp/actions/app.tsapp/views/ThreadMessagesView/index.tsxapp/index.tsx
📚 Learning: 2026-03-15T13:55:42.038Z
Learnt from: Rohit3523
Repo: RocketChat/Rocket.Chat.ReactNative PR: 6911
File: app/containers/markdown/Markdown.stories.tsx:104-104
Timestamp: 2026-03-15T13:55:42.038Z
Learning: In Rocket.Chat React Native, the markdown parser requires a space between the underscore wrapping italic text and a mention sigil (_ mention _ instead of _mention_). Ensure stories and tests that include italic-wrapped mentions follow this form to guarantee proper parsing. Specifically, for files like app/containers/markdown/Markdown.stories.tsx, and any test/content strings that exercise italic-mentions, use the pattern _ mention _ (with spaces) to prevent the mention from being treated as plain text. Validate any test strings or story content accordingly.
Applied to files:
app/containers/List/List.stories.tsx
🔇 Additional comments (55)
app/lib/hooks/useMasterDetail.tsx (1)
9-12: LGTM!Also applies to: 14-25
app/lib/hooks/withDimensions.tsx (1)
11-22: LGTM!app/actions/app.ts (1)
20-20: LGTM!app/reducers/app.test.ts (1)
1-1: LGTM!app/views/ProfileView/index.test.tsx (1)
64-64: LGTM!app/index.tsx (1)
2-2: LGTM!Also applies to: 11-11, 88-88, 182-182, 194-207
app/containers/List/List.stories.tsx (1)
7-7: LGTM!Also applies to: 245-247
app/containers/InAppNotification/NotifierComponent.tsx (1)
12-15: LGTM!Also applies to: 134-136
app/containers/MessageActions/index.tsx (1)
39-39: LGTM!Also applies to: 631-631
app/views/MessagesView/index.tsx (1)
39-39: LGTM!Also applies to: 386-389
app/views/RoomView/RightButtons.tsx (1)
33-33: LGTM!Also applies to: 574-574
app/views/RoomView/components/EncryptedRoom.tsx (1)
10-10: LGTM!Also applies to: 26-26
app/views/SidebarView/components/SupportedVersionsWarnItem.tsx (1)
7-7: LGTM!Also applies to: 17-17
app/views/StatusView/index.tsx (1)
18-18: LGTM!Also applies to: 110-110
app/views/UserNotificationPreferencesView/index.tsx (1)
13-13: LGTM!Also applies to: 36-37
app/views/RoomActionsView/index.tsx (1)
27-28: LGTM!Also applies to: 1333-1333
app/views/RoomView/JoinCode.tsx (1)
14-14: LGTM!Also applies to: 132-134
app/views/AdminPanelView/index.tsx (1)
13-20: LGTM!app/views/CallView/components/CallButtons.tsx (1)
5-5: LGTM!Also applies to: 30-30
app/views/CannedResponseDetail.tsx (1)
16-16: LGTM!Also applies to: 90-90
app/views/CannedResponsesListView/index.tsx (1)
27-27: LGTM!Also applies to: 69-69
app/views/RoomView/index.tsx (1)
44-45: LGTM!Also applies to: 1723-1725
app/AppContainer.tsx (1)
8-8: LGTM!Also applies to: 37-39, 93-93
app/containers/MediaCallHeader/components/Content.tsx (1)
3-3: LGTM!Also applies to: 23-23
app/views/AddChannelTeamView.tsx (1)
13-13: LGTM!Also applies to: 50-50
app/views/RoomsListView/components/ServersList.tsx (1)
18-18: LGTM!Also applies to: 39-39
app/views/SidebarView/components/Profile.tsx (1)
13-13: LGTM!Also applies to: 15-20
app/views/SidebarView/components/Stacks.tsx (1)
4-5: LGTM!Also applies to: 7-12
app/views/SearchMessagesView/index.tsx (1)
44-44: LGTM!Also applies to: 360-360
app/views/NotificationPreferencesView/index.tsx (1)
13-13: LGTM!Also applies to: 94-98
app/views/ProfileView/index.tsx (1)
36-36: LGTM!Also applies to: 83-83
app/views/ReportUserView/index.tsx (1)
19-19: LGTM!Also applies to: 44-44
app/views/RoomInfoView/index.tsx (1)
16-16: LGTM!Also applies to: 77-77
app/views/RoomMembersView/index.tsx (1)
19-19: LGTM!Also applies to: 81-91
app/views/TeamChannelsView.tsx (1)
20-21: LGTM!Also applies to: 600-600
app/views/ThreadMessagesView/index.tsx (1)
46-46: LGTM!Also applies to: 536-537, 539-539
app/views/CloseLivechatView.tsx (1)
15-15: LGTM!Also applies to: 48-52
app/views/CreateDiscussionView/index.tsx (1)
27-27: LGTM!Also applies to: 65-65
app/views/DirectoryView/index.tsx (1)
27-27: LGTM!Also applies to: 41-49
app/views/DiscussionsView/index.tsx (1)
22-22: LGTM!Also applies to: 41-41
app/views/NewMessageView/index.tsx (1)
20-20: LGTM!Also applies to: 37-45
app/containers/Header/index.tsx (1)
8-8: LGTM!Also applies to: 19-19
app/containers/InAppNotification/IncomingCallNotification/index.tsx (1)
10-10: LGTM!Also applies to: 42-42
app/containers/MessageComposer/components/Buttons/ActionsButton.tsx (1)
9-9: LGTM!Also applies to: 27-27
app/containers/MessageComposer/components/ComposerInput.tsx (1)
40-40: LGTM!Also applies to: 61-61
app/containers/RoomHeader/RoomHeader.tsx (1)
14-14: LGTM!Also applies to: 172-172
app/containers/TwoFactor/index.tsx (1)
21-21: LGTM!Also applies to: 70-70
app/containers/markdown/components/mentions/Hashtag.tsx (1)
8-8: LGTM!Also applies to: 29-29
app/ee/omnichannel/containers/OmnichannelHeader/index.tsx (1)
16-16: LGTM!Also applies to: 26-26
app/ee/omnichannel/views/QueueListView.tsx (1)
22-22: LGTM!Also applies to: 57-57
app/views/RoomsListView/components/ListHeader.tsx (1)
9-9: LGTM!Also applies to: 22-22
app/views/RoomsListView/hooks/useHeader.tsx (1)
7-7: LGTM!Also applies to: 23-23
app/views/RoomsListView/index.tsx (1)
16-16: LGTM!Also applies to: 45-45
app/views/SettingsView/index.tsx (1)
21-21: LGTM!Also applies to: 43-43
app/views/SidebarView/components/Admin.tsx (1)
4-12: LGTM!
| const AccessibilityAndAppearanceView = () => { | ||
| const navigation = useNavigation<NativeStackNavigationProp<AccessibilityStackParamList>>(); | ||
| const isMasterDetail = useAppSelector(state => state.app.isMasterDetail as boolean); | ||
| const isMasterDetail = useMasterDetail(); |
There was a problem hiding this comment.
Update header options when master-detail mode changes.
Line 25 introduces a dynamic isMasterDetail, but useLayoutEffect still runs only once. On resize/rotation across the breakpoint, headerLeft can stay stale.
Suggested fix
- useLayoutEffect(() => {
+ useLayoutEffect(() => {
navigation.setOptions({
title: I18n.t('Accessibility_and_Appearance'),
headerLeft: isMasterDetail
? undefined
: () => <HeaderButton.Drawer navigation={navigation} testID='accessibility-view-drawer' />
});
- }, []);
+ }, [navigation, isMasterDetail]);🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@app/views/AccessibilityAndAppearanceView/index.tsx` at line 25, The
useLayoutEffect hook that sets up headerLeft needs to be updated to respond to
changes in the isMasterDetail value. Add isMasterDetail to the dependency array
of the useLayoutEffect hook (the one that configures the navigation header
options) so that the effect re-runs whenever the master-detail mode changes due
to resize, rotation, or other layout changes. This ensures that headerLeft and
other header options remain synchronized with the current master-detail state.
| const TabletHeader = () => { | ||
| 'use memo'; | ||
|
|
||
| const navigation = useNavigation<any>(); | ||
| const route = useRoute<any>(); | ||
| const isMasterDetail = useAppSelector(state => state.app.isMasterDetail); | ||
| const isMasterDetail = useMasterDetail(); |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
set -euo pipefail
# Find existing typed navigation/route patterns to reuse in this view flow
rg -n --type=tsx "useNavigation<|useRoute<|NativeStackNavigationProp|RouteProp" app/views/RoomsListView app/views app/containers | sed -n '1,200p'Repository: RocketChat/Rocket.Chat.ReactNative
Length of output: 106
🏁 Script executed:
#!/bin/bash
set -euo pipefail
# Read the file in question
echo "=== TabletHeader.tsx content ==="
cat -n app/views/RoomsListView/components/TabletHeader.tsx | head -30
# Search for navigation type patterns using correct syntax
echo -e "\n=== Navigation/Route type patterns in codebase ==="
rg -n "useNavigation<|useRoute<|NativeStackNavigationProp|RouteProp" -g "*.ts" -g "*.tsx" app/views/ | head -50
# Check specifically in RoomsListView for patterns
echo -e "\n=== RoomsListView navigation patterns ==="
rg -n "useNavigation|useRoute" -g "*.ts" -g "*.tsx" app/views/RoomsListView/ -A 2Repository: RocketChat/Rocket.Chat.ReactNative
Length of output: 9221
🏁 Script executed:
#!/bin/bash
set -euo pipefail
# Search for navigation param list definitions
echo "=== ParamList definitions ==="
rg -n "ParamList|StackParamList" -g "*.ts" -g "*.tsx" --max-count=50 | grep -i "rooms\|master" | head -30
# Check Header component to see what it expects
echo -e "\n=== Header component type requirements ==="
cat -n app/containers/Header/index.tsx | head -50
# Look for InsideStack or navigation type definitions
echo -e "\n=== Navigation type files ==="
fd -e ts -e tsx "navigation" app/ | head -20
</scriptRepository: RocketChat/Rocket.Chat.ReactNative
Length of output: 3599
🏁 Script executed:
#!/bin/bash
set -euo pipefail
# Read Header component to see type requirements
echo "=== Header component interface ==="
head -100 app/containers/Header/index.tsx
# Read MasterDetailStack types
echo -e "\n=== MasterDetailStack types ==="
cat -n app/stacks/MasterDetailStack/types.ts | head -250
# Check parent RoomsListView to understand navigation context
echo -e "\n=== RoomsListView navigation setup ==="
head -60 app/views/RoomsListView/index.tsxRepository: RocketChat/Rocket.Chat.ReactNative
Length of output: 12418
🏁 Script executed:
#!/bin/bash
set -euo pipefail
# Check how NativeStackHeaderProps is used in Header and what generics it has
echo "=== NativeStackHeaderProps import and usage ==="
rg -n "NativeStackHeaderProps" -g "*.ts" -g "*.tsx" -A 3 | head -40
# Check React types for return type
echo -e "\n=== React types usage in similar components ==="
rg -n "React\.ReactElement|React\.FC|ReactElement" app/views/RoomsListView -g "*.ts" -g "*.tsx" | head -20Repository: RocketChat/Rocket.Chat.ReactNative
Length of output: 1198
Replace any with proper navigation/route types in TabletHeader
The useNavigation<any>() and useRoute<any>() calls bypass TypeScript strict mode checks. Based on the navigation structure and how other components in the codebase are typed, use NativeStackNavigationProp and RouteProp from @react-navigation/native-stack with MasterDetailInsideStackParamList from the navigation types. Also add an explicit return type (ReactElement | null) to the component.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@app/views/RoomsListView/components/TabletHeader.tsx` around lines 8 - 13, In
the TabletHeader component, replace the `any` type parameters in the
useNavigation and useRoute hooks with proper TypeScript types. Import
NativeStackNavigationProp and RouteProp from `@react-navigation/native-stack` and
MasterDetailInsideStackParamList from the navigation types, then apply these
types to the respective hooks. Additionally, add an explicit return type
annotation of ReactElement | null to the TabletHeader function declaration to
ensure proper type safety.
Source: Coding guidelines
Proposed changes
The app tracked the master-detail layout flag through a root pipeline:
Dimensions.addEventListenerinapp/index.tsxrecomputedisMasterDetailon every window change, wrote it tostate.app.isMasterDetail, and fedwidth/height/scale/fontScaleinto aDimensionsContextconsumed app-wide. Every dimension change triggered a Redux dispatch plus a context update that re-rendered unrelated subtrees.This removes that pipeline and derives the flag where it's used:
useMasterDetail()hook computesisTablet && width > MIN_WIDTH_MASTER_DETAIL_LAYOUTfromuseWindowDimensions().withMasterDetailHOC in theirconnectchain (and the three views that needed raw dimensions move to a hook-backedwithDimensions).getIsMasterDetail()snapshot fromDimensions.get('window'), since hooks can't run there.state.app.isMasterDetail(field, action, reducer case), the rootDimensionslistener, andapp/dimensions.tsx.The flag now reacts to window resize directly instead of a debounced Redux round-trip, and dimension changes no longer fan out through a global context.
Issue(s)
https://rocketchat.atlassian.net/browse/NATIVE-886
How to test or reproduce
MasterDetailStackandInsideStackas before.Types of changes
Checklist
Further comments
IBaseScreen.isMasterDetailis kept — it's the prop the HOC injects into class screens, distinct from the removed Redux field.Summary by CodeRabbit