Skip to content

Conversation

@gabrieleandro
Copy link
Contributor

@gabrieleandro gabrieleandro commented Sep 23, 2025

Abstraction of RoomsList component for RN chat

Summary by CodeRabbit

  • New Features

    • Chat Rooms screen with header search, tab filters (Active, Unread, Archived, Groups), live updates, infinite scroll, suspended loading, and a New Chat floating button.
    • Rooms list and chat cards with avatar, title, last-message preview/time, unread badges, long-press options (archive/mark/delete/details), and contextual empty/no-results states.
    • Native search input component, themed FAB, and two SVG illustrations.
  • Documentation

    • Updated package changelogs.
  • Chores

    • Package version bumps and design-system export adjustments; removed estimatedItemSize from infinite scroller API.

@changeset-bot
Copy link

changeset-bot bot commented Sep 23, 2025

⚠️ No Changeset found

Latest commit: 05ad890

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

coderabbitai bot commented Sep 23, 2025

Walkthrough

Adds a native ChatRooms UI and supporting primitives: chat container with search/tabs and live subscription, paginated RoomsList and ChatCard (with options/archive mutation), EmptyView states, NewChatButton, design-system FabButton/SearchInput/illustrations, GraphQL fragment, types/styles, and package metadata updates.

Changes

Cohort / File(s) Summary
ChatRooms container
packages/components/modules/messages/native/ChatRooms/index.tsx, packages/components/modules/messages/native/ChatRooms/styles.ts
New ChatRooms component (Suspense-wrapped default export) with search form, tab state, Relay query + room-list subscription, refetch on focus/app state and filters; renders header, SearchInput, Tabs, RoomsList (non-Groups) and NewChatButton; styles added.
Rooms list feature
packages/components/modules/messages/native/RoomsList/index.tsx, packages/components/modules/messages/native/RoomsList/types.ts, packages/components/modules/messages/native/RoomsList/RoomsListComponent/index.tsx, .../RoomsList/RoomsListComponent/styles.ts, .../RoomsList/RoomsListComponent/types.ts, .../RoomsList/RoomsListComponent/constants.ts
RoomsList wrapper + Suspense export and RoomsListComponent: Relay-backed paginated InfiniteScrollerView, auto-load when content < screen height, focus-triggered refetch with q/unread/archived filters, empty-state selection and related types/constants.
Chat card and options
packages/components/modules/messages/native/RoomsList/ChatCard/index.tsx, .../ChatCard/styles.ts, .../ChatCard/ChatCardComponent/index.tsx, .../ChatCard/ChatCardComponent/styles.ts, .../ChatCard/ChatCardOptions/index.tsx, .../ChatCard/ChatCardOptions/styles.ts, .../ChatCard/ChatCardOptions/type.ts, .../ChatCard/ChatCardComponent/type.ts
ChatCard wrapper and ChatCardComponent using Relay fragments: press navigation, long-press opens ChatCardOptions bottom-sheet; ChatCardOptions wires archive mutation and exposes Mark as Unread, Chat Details, Go to Profile and Delete handlers; themed styles and option prop types added.
Empty/search states & shared EmptyView
packages/components/modules/messages/native/RoomsList/EmptyChatRoomsState/index.tsx, packages/components/modules/messages/native/SearchNotFoundState/index.tsx, packages/components/modules/__shared__/native/EmptyView/index.tsx, .../EmptyView/styles.ts, .../EmptyView/types.ts, .../__shared__/native/index.ts
New reusable EmptyView (types/styles) and two concrete states (EmptyChatRoomsState, SearchNotFoundState) using design-system illustrations; re-exports added.
New chat action
packages/components/modules/messages/native/NewChatButton/index.tsx
New NewChatButton renders themed FabButton and navigates to /create-room.
Design-system: FabButton
packages/design-system/components/native/buttons/FabButton/index.tsx, .../FabButton/styles.ts, .../FabButton/types.ts, .../buttons/index.ts
New FabButton (themed floating action button), prop types, styles, and re-export.
Design-system: SearchInput
packages/design-system/components/native/inputs/SearchInput/index.tsx, .../SearchInput/styles.ts, .../SearchInput/types.ts, .../inputs/index.ts, .../SearchInput/constants.ts
New SearchInput (Paper TextInput outlined) with left search icon and conditional clear; controlled by searchParam/resetInput; styles, types, constants and re-exports added.
Design-system: illustrations
packages/design-system/components/native/illustrations/SearchingImage/index.tsx, .../SocialMediaDiscussionImage/index.tsx, .../illustrations/types.ts, .../illustrations/index.ts, packages/design-system/package.json
New SVG illustrations SearchingImage and SocialMediaDiscussionImage with theme-aware colors; new SvgIconProps type; index re-exports; design-system package.json exports map updated.
Shared module & package metadata
packages/components/modules/messages/native/index.ts, packages/design-system/package.json, packages/design-system/CHANGELOG.md, packages/components/package.json, packages/components/CHANGELOG.md, packages/wagtail/package.json, packages/wagtail/CHANGELOG.md, pnpm-workspace.yaml
Re-exports ChatRooms/RoomsList/SearchNotFoundState; package versions bumped and changelogs updated; pnpm-workspace updated (flash-list, luxon).
InfiniteScrollerView API change
packages/design-system/components/native/views/InfiniteScrollerView/index.tsx, packages/components/modules/notifications/native/NotificationsList/index.tsx
Removed estimatedItemSize from InfiniteScrollerView public API and its usage; downstream usage updated (NotificationsList).
GraphQL fragments/queries
packages/components/modules/messages/common/graphql/fragments/ChatRoom.ts, .../queries/ChatRoomQuery.ts
Added refetchable ChatRoom fragment (id, isGroup, isArchived, unreadMessages, participantsCount, nested fragments) and included its spread in ChatRoomQuery selection.

Sequence Diagram(s)

sequenceDiagram
  autonumber
  actor User
  participant ChatRooms
  participant Relay as Relay/GraphQL
  participant Subscription as RoomListSubscription
  participant RoomsList
  participant AppState

  User->>ChatRooms: open screen
  ChatRooms->>Relay: useLazyLoadQuery(ChatRoomsQuery)
  ChatRooms->>Subscription: subscribe to room list updates
  AppState-->>ChatRooms: app focused / becomes active
  ChatRooms->>Relay: refetch({ q, unread, archived })
  ChatRooms->>RoomsList: render(targetRef, searchParam, selectedTab)
Loading
sequenceDiagram
  autonumber
  actor User
  participant ChatCard
  participant Options as ChatCardOptions
  participant Relay as Relay/GraphQL

  User->>ChatCard: long-press
  ChatCard->>Options: open bottom sheet
  User->>Options: tap Archive
  Options->>Relay: mutate(archiveRoom)
  Relay-->>Options: mutation result
  Options->>ChatCard: close/update UI
Loading
sequenceDiagram
  autonumber
  actor User
  participant ChatRooms
  participant Router

  User->>ChatRooms: tap NewChatButton
  ChatRooms->>Router: router.push("/create-room")
  Router-->>User: navigated
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Files/areas needing extra attention:

  • Relay queries/subscriptions and refetch arguments in packages/components/modules/messages/native/ChatRooms/index.tsx and GraphQL fragments.
  • Pagination, auto-load-by-height logic and startTransition/fetchPolicy usage in RoomsListComponent.
  • Archive mutation correctness and bottom-sheet lifecycle in ChatCardComponent and ChatCardOptions.
  • Public API change: removal of estimatedItemSize in InfiniteScrollerView and downstream consumers.
  • Design-system export map change in packages/design-system/package.json.

Possibly related PRs

Suggested labels

needs review

Suggested reviewers

  • priscilladeroode
  • anicioalexandre
  • tsl-ps2
  • Ronan-Fernandes

Poem

Hop hop, I tidy threads and screens,
Tabs and search where daylight gleams.
A tiny FAB to start a chat,
Empty views and icons — fancy that!
I nibble code and ship with cheer, new rooms sprout, the rabbit's here. 🐇✨

Pre-merge checks and finishing touches

❌ Failed checks (1 warning, 1 inconclusive)
Check name Status Explanation Resolution
Description check ⚠️ Warning The PR description is minimal and does not follow the provided template structure with changelog sections and version information. Expand the description to match the template format, including package names, version numbers, and detailed changelog entries for the changes made.
Title check ❓ Inconclusive The title 'feature/BA-2626-chatroom-list' is branch naming convention rather than a clear pull request title describing the main changes. Change the PR title to a concise, descriptive summary such as 'Add ChatRooms and RoomsList components for native chat interface' or similar.
✅ Passed checks (1 passed)
Check name Status Explanation
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch feature/BA-2626-rooms-list

📜 Recent review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 1967742 and 05ad890.

⛔ Files ignored due to path filters (1)
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (1)
  • packages/components/modules/messages/common/graphql/queries/ChatRoomQuery.ts (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • packages/components/modules/messages/common/graphql/queries/ChatRoomQuery.ts
⏰ 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). (2)
  • GitHub Check: Build and Lint Packages
  • GitHub Check: Component Test Packages

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.

@gabrieleandro gabrieleandro changed the title chatroom-list feature/ba-2626-chatroom-list Sep 23, 2025
@gabrieleandro gabrieleandro changed the title feature/ba-2626-chatroom-list feature/BA-2626-chatroom-list Sep 23, 2025
Copy link

@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: 8

🧹 Nitpick comments (33)
packages/design-system/components/native/inputs/SearchInput/styles.ts (1)

7-13: Minor style tweaks for clarity and accessibility.

  • Use marginVertical instead of separate margins.
  • Prefer minHeight over fixed height to better respect large text settings.

Apply this diff:

-      marginTop: 12,
-      marginBottom: 12,
+      marginVertical: 12,
-      height: 45,
+      minHeight: 45,
packages/design-system/components/native/inputs/SearchInput/index.tsx (1)

26-37: Attach onPress to TextInput.Icon, not the nested Ionicon.

Leverage Paper’s press handling/ripple; keep the icon render purely visual.

Apply this diff (pairs with the previous change):

       searchParam && searchParam.length > 0 ? (
-        <Ionicons
-          name="close"
-          size={24}
-          color={theme.colors.object.disabled}
-          onPress={resetInput}
-        />
+        <Ionicons name="close" size={24} color={theme.colors.object.disabled} />
       ) : null,
packages/components/modules/messages/native/RoomsList/EmptyChatRoomsState/styles.ts (1)

19-26: Make textWrapper responsive (avoid fixed width).

A fixed width of 393 can clip on smaller screens. Prefer full width with a maxWidth cap.

     textWrapper: {
       flex: 1,
-      width: 393,
+      width: '100%',
+      maxWidth: 393,
       padding: 16,
       justifyContent: 'flex-end',
       alignItems: 'center',
       gap: 10,
     },
packages/design-system/components/native/buttons/FabButton/styles.ts (1)

7-25: Tweak FAB positioning and iOS shadow color.

  • Add right margin so the FAB isn’t flush to the edge.
  • Provide shadowColor for iOS shadows.

If the FAB can overlap the home indicator, consider adding bottom safe-area insets in the component.

     button: {
       position: 'absolute',
-      right: 0,
+      right: 16,
       bottom: 16,
       backgroundColor: theme.colors.primary.main,
       width: 56,
       height: 56,
       borderRadius: 500,
       justifyContent: 'center',
       alignItems: 'center',
       zIndex: 10,
+      shadowColor: '#000',
       shadowOffset: {
         width: 0,
         height: 8,
       },
       shadowOpacity: 0.24,
       shadowRadius: 8,
       elevation: 8,
     },
packages/components/modules/messages/native/RoomsList/ChatCard/ChatCardComponent/styles.ts (1)

5-39: DRY up duplicated ChatCard styles.

This largely duplicates styles in RoomsList/ChatCard/styles.ts. Extract shared base style objects (not StyleSheet-created) into a single module and reuse to avoid drift.

packages/components/modules/messages/native/RoomsList/ChatCard/styles.ts (1)

5-44: Consolidate with ChatCardComponent styles to prevent divergence.

These definitions overlap with ChatCardComponent/styles.ts. Recommend a shared base style factory to keep one source of truth.

packages/components/modules/messages/native/RoomsList/RoomsListComponent/constants.ts (1)

1-13: Strengthen typing of CHAT_TAB_LABEL with satisfies.

Enforce that all tab values have labels and catch missing/extra keys at compile time.

Please confirm the TS version supports satisfies (TS ≥ 4.9).

 export const CHAT_TAB_VALUES = {
   active: 'active',
   unread: 'unread',
   archived: 'archived',
   groups: 'groups',
 } as const

-export const CHAT_TAB_LABEL = {
+type ChatTabValue = (typeof CHAT_TAB_VALUES)[keyof typeof CHAT_TAB_VALUES]
+
+export const CHAT_TAB_LABEL = {
   [CHAT_TAB_VALUES.active]: 'Active',
   [CHAT_TAB_VALUES.unread]: 'Unread',
   [CHAT_TAB_VALUES.archived]: 'Archived',
   [CHAT_TAB_VALUES.groups]: 'Groups',
-} as const
+} as const satisfies Record<ChatTabValue, string>
packages/design-system/components/native/buttons/index.ts (1)

4-4: Re-export FabButton types for consumers.

Expose the props type like other buttons to improve DX.

 export { default as IconButton } from './IconButton'
 export { default as FabButton } from './FabButton'
+export type * from './FabButton/types'
packages/components/modules/messages/native/SearchNotFoundState/types.ts (1)

1-3: Allow richer content for message

Consider accepting ReactNode to support localized/styled content.

+import { type ReactNode } from 'react'
 
 export interface SearchNotFoundStateProps {
-  message?: string
+  message?: ReactNode
 }
packages/components/modules/messages/native/RoomsList/RoomsListComponent/styles.ts (1)

1-9: Align createStyles signature with theme-based convention (and remove commented import)

Follow the pattern used elsewhere: accept Theme and ignore it if unused for now.

-// import { Theme } from '@baseapp-frontend/design-system/styles/native'
+import { Theme } from '@baseapp-frontend/design-system/styles/native'
 import { StyleSheet } from 'react-native'
 
-export const createStyles = () =>
+export const createStyles = (_theme: Theme) =>
   StyleSheet.create({
     chatRoomsContainer: {
       flex: 1,
     },
   })
packages/components/modules/messages/native/RoomsList/types.ts (1)

3-7: Type selectedTab more strictly

Use the new ChatTabValues instead of string to prevent invalid values.

+import type { ChatTabValues } from './RoomsListComponent/types'
 
 export interface RoomsListProps {
   targetRef: ChatRoomsQuery$data
   searchParam: string
-  selectedTab: string
+  selectedTab: ChatTabValues
 }
packages/components/modules/messages/native/RoomsList/EmptyChatRoomsState/index.tsx (1)

8-24: Make message customizable and prep for i18n

Accept an optional message prop with a sensible default to ease localization.

-const EmptyChatRoomsState = () => {
+interface Props {
+  message?: string
+}
+
+const EmptyChatRoomsState = ({ message }: Props) => {
   const theme = useTheme()
   const styles = createStyles(theme)
 
   return (
     <View style={styles.container}>
       <View style={styles.imageWrapper}>
         <SocialMediaDiscussionImage />
       </View>
       <View style={styles.textWrapper}>
         <Text variant="subtitle2" style={styles.text}>
-          No messages to be displayed.
+          {message ?? 'No messages to be displayed.'}
         </Text>
       </View>
     </View>
   )
 }
packages/design-system/components/native/buttons/FabButton/index.tsx (1)

11-25: Improve accessibility and touch ergonomics; keep consumer override precedence

Set an accessibility role and provide a default hitSlop without overriding consumer-provided props.

   return (
-    <TouchableOpacity style={[styles.button, style]} {...touchableProps}>
+    <TouchableOpacity
+      {...touchableProps}
+      accessibilityRole="button"
+      hitSlop={touchableProps.hitSlop ?? { top: 8, right: 8, bottom: 8, left: 8 }}
+      style={[styles.button, style]}
+    >
       <Ionicons name={iconName} size={iconSize} color={iconColor} />
     </TouchableOpacity>
   )
packages/components/modules/messages/native/SearchNotFoundState/index.tsx (2)

21-26: Localize hard‑coded title ("No results found").

Expose it as a prop (or use your i18n util) to enable translations and customization.

-        <Text variant="subtitle2" style={styles.text}>
-          No results found
-        </Text>
+        <Text variant="subtitle2" style={styles.text}>
+          {title}
+        </Text>

Additionally update the props:

-const SearchNotFoundState = ({
-  message = 'Check your spelling or try another search.',
-}: SearchNotFoundStateProps) => {
+const SearchNotFoundState = ({
+  title = 'No results found',
+  message = 'Check your spelling or try another search.',
+}: SearchNotFoundStateProps) => {

And in types.ts:

export interface SearchNotFoundStateProps {
  title?: string
  message?: string
}

16-21: Add basic accessibility and testID.

Help screen readers and E2E tests.

-    <View style={styles.container}>
-      <View style={styles.imageWrapper}>
+    <View style={styles.container} testID="searchNotFoundState">
+      <View
+        style={styles.imageWrapper}
+        accessible
+        accessibilityRole="image"
+        accessibilityLabel="No search results illustration"
+      >
         <SearchingImage />
       </View>
packages/components/modules/messages/native/index.ts (1)

4-6: Consider re-exporting NewChatButton for convenience.

Keeps the public API cohesive under the native messages namespace.

 export { default as ChatRooms } from './ChatRooms'
 export { default as RoomsList } from './RoomsList'
 export { default as SearchNotFoundState } from './SearchNotFoundState'
+export { NewChatButton } from './NewChatButton'
packages/components/modules/messages/native/SearchNotFoundState/styles.ts (1)

21-26: Avoid hard‑coded width (393).

Use responsive width with an optional maxWidth for large screens.

-      width: 393,
+      width: '100%',
+      maxWidth: 393,
packages/components/modules/messages/native/RoomsList/index.tsx (2)

10-14: Add an explicit Suspense fallback.

Avoid a blank state while loading; even a null fallback declared explicitly improves intent. Prefer a DS loader if available.

-const SuspendedRoomsList = (props: RoomsListProps) => (
-  <Suspense>
+const SuspendedRoomsList = (props: RoomsListProps) => (
+  <Suspense fallback={null}>
     <RoomsList {...props} />
   </Suspense>
 )

6-8: Optionally export the non‑suspended variant.

Useful for embedding in parent Suspense boundaries.

 const RoomsList: FC<RoomsListProps> = ({ targetRef, searchParam, selectedTab }) => (
   <RoomsListComponent targetRef={targetRef} searchParam={searchParam} selectedTab={selectedTab} />
 )
 
 const SuspendedRoomsList = (props: RoomsListProps) => (
@@
-export default SuspendedRoomsList
+export default SuspendedRoomsList
+export { RoomsList }

Also applies to: 16-16

packages/components/modules/messages/native/RoomsList/ChatCard/index.tsx (1)

7-15: Align prop type with runtime null guard.

Since you allow a falsy roomRef, reflect it in the type to prevent misuse upstream.

-}: {
-  roomRef: RoomsListFragment$key
+}: {
+  roomRef: RoomsListFragment$key | null | undefined
   isArchived: boolean
 }) => {
   if (!roomRef) {
     return null
   }
packages/components/modules/messages/native/ChatRooms/styles.ts (2)

7-15: Remove redundant flexGrow; prefer consistent flex usage.

flex: 1 already implies flexGrow: 1. Also prefer flex: 1 for chatRoomsContainer to match other styles.

     container: {
       backgroundColor: theme.colors.surface.background,
-      flexGrow: 1,
       flex: 1,
       position: 'relative',
     },
     chatRoomsContainer: {
-      flexGrow: 1,
+      flex: 1,
     },

16-19: gap: 0 is a no‑op; remove or replace if spacing is needed.

If gaps are intended later, ensure RN version supports it.

packages/design-system/components/native/illustrations/SocialMediaDiscussionImage/index.tsx (1)

17-18: Consider memoizing the color computation.

The color calculation is recomputed on every render. Since this is an SVG component that might be rendered frequently in lists, consider memoizing the result.

+import { FC, useMemo } from 'react'
-import { FC } from 'react'

 const SocialMediaDiscussionImage: FC<SvgIconProps> = ({
   isActive = false,
   color,
   width = '200',
   height = '200',
   ...props
 }) => {
   const { colors } = useTheme()

-  const defaultColor = color ?? colors.object.high
-  const svgColor = isActive ? colors.primary.high : defaultColor
+  const svgColor = useMemo(() => {
+    const defaultColor = color ?? colors.object.high
+    return isActive ? colors.primary.high : defaultColor
+  }, [color, colors.object.high, colors.primary.high, isActive])
packages/design-system/components/native/illustrations/SearchingImage/index.tsx (1)

1-58: Component mirrors SocialMediaDiscussionImage pattern correctly.

The implementation is consistent with the SocialMediaDiscussionImage component structure and follows the same theming approach.

Consider applying the same memoization optimization suggested for SocialMediaDiscussionImage to maintain consistency across illustration components.

packages/components/modules/messages/native/ChatRooms/index.tsx (2)

57-66: Consider optimizing the refetch on app state changes.

The refetch occurs on every app resume, which might be unnecessary if the data is fresh. Consider implementing a time-based cache invalidation.

+import { useRef } from 'react'

 const ChatRooms: FC = () => {
+  const lastRefetchTime = useRef<number>(Date.now())
   // ... existing code ...

   useAppStateSubscription(() => {
+    const timeSinceLastRefetch = Date.now() - lastRefetchTime.current
+    // Only refetch if more than 30 seconds have passed
+    if (timeSinceLastRefetch < 30000) return
+    
+    lastRefetchTime.current = Date.now()
     refetch(
       {
         q: searchParam,
         unreadMessages: selectedTab === CHAT_TAB_VALUES.unread,
         archived: selectedTab === CHAT_TAB_VALUES.archived,
       },
       { fetchPolicy: 'store-and-network' },
     )
   })

104-107: Track the Groups tab implementation.

The TODO comment indicates the Groups tab is not yet implemented.

Would you like me to create an issue to track the implementation of the Groups tab functionality?

packages/components/modules/messages/native/RoomsList/ChatCard/ChatCardComponent/index.tsx (2)

87-102: Replace placeholder alerts with proper implementation tracking.

Multiple features are marked with alert placeholders. These should be tracked properly for implementation.

Would you like me to create issues for the following unimplemented features:

  • Mark as Unread functionality
  • Chat Details functionality
  • Go to Profile functionality
  • Delete Chat functionality

Each issue can include implementation requirements and acceptance criteria.


43-54: Consider type safety improvement for fragment casting.

The multiple type castings to unknown suggest potential type misalignment. Consider creating properly typed fragment references.

-  const lastMessageFragment = useFragment<LastMessageFragment$key>(
-    LastMessageFragment,
-    roomRef as unknown as LastMessageFragment$key,
-  )
-  const headerFragment = useFragment<TitleFragment$key>(
-    TitleFragment,
-    roomRef as unknown as TitleFragment$key,
-  )
-  const unreadMessagesCountFragment = useFragment<UnreadMessagesCountFragment$key>(
-    UnreadMessagesCountFragment,
-    roomRef as unknown as UnreadMessagesCountFragment$key,
-  )
+  // If roomRef contains all these fragments, consider using a union type or interface
+  const lastMessageFragment = useFragment(LastMessageFragment, roomRef)
+  const headerFragment = useFragment(TitleFragment, roomRef)
+  const unreadMessagesCountFragment = useFragment(UnreadMessagesCountFragment, roomRef)
packages/components/modules/messages/native/RoomsList/ChatCard/ChatCardOptions/index.tsx (4)

29-33: Ensure handleSheetChanges matches BottomDrawer's (index:number) => void signature

Wrap your zero‑arg handler to accept the index so it always matches the drawer API.

Apply this diff:

-import { FC, useMemo } from 'react'
+import { FC, useCallback, useMemo } from 'react'
@@
   const styles = createStyles(theme)
   const snapPoints = useMemo(() => ['50%', '90%'], [])
 
+  const onSheetChange = useCallback((_index: number) => {
+    handleSheetChanges()
+  }, [handleSheetChanges])
+
   return (
     <BottomDrawer
       bottomDrawerRef={bottomDrawerRef}
-      handleSheetChanges={handleSheetChanges}
+      handleSheetChanges={onSheetChange}
       snapPoints={snapPoints}
     >

35-43: Add basic accessibility and disabled state hints to Pressables

Expose role/labels and disabled state for assistive tech; keep consistent across items.

Apply this diff:

-        <Pressable
-          onPress={handleArchiveChat}
-          style={styles.modalItem}
-          disabled={isArchiveMutationInFlight}
-        >
+        <Pressable
+          onPress={handleArchiveChat}
+          style={styles.modalItem}
+          disabled={isArchiveMutationInFlight}
+          accessibilityRole="button"
+          accessibilityLabel={isArchived ? 'Unarchive chat' : 'Archive chat'}
+          accessibilityState={{ disabled: isArchiveMutationInFlight }}
+        >
@@
-        <Pressable onPress={handleMarkAsUnread} style={styles.modalItem}>
+        <Pressable
+          onPress={handleMarkAsUnread}
+          style={styles.modalItem}
+          accessibilityRole="button"
+          accessibilityLabel="Mark as unread"
+        >
@@
-        <Pressable onPress={handleChatDetails} style={styles.modalItem}>
+        <Pressable
+          onPress={handleChatDetails}
+          style={styles.modalItem}
+          accessibilityRole="button"
+          accessibilityLabel="Open chat details"
+        >
@@
-        <Pressable onPress={handleGoToProfile} style={styles.modalItem}>
+        <Pressable
+          onPress={handleGoToProfile}
+          style={styles.modalItem}
+          accessibilityRole="button"
+          accessibilityLabel="Go to profile"
+        >
@@
-        <Pressable onPress={handleDeleteChat} style={styles.modalItem}>
+        <Pressable
+          onPress={handleDeleteChat}
+          style={styles.modalItem}
+          accessibilityRole="button"
+          accessibilityLabel="Delete chat"
+        >

Also applies to: 44-58, 61-65


40-44: Externalize labels for i18n

These strings should live in your translations bundle to support localization.

Also applies to: 45-58, 62-64


62-64: Prefer theme/Text props over inline color style (if supported)

Keeps styling consistent with the DS.

Apply this diff if Text supports semantic color tokens:

-          <Text variant="body2" style={{ color: theme.colors.error.main }}>
+          <Text variant="body2" color="error">
             Delete Chat
           </Text>
packages/components/modules/messages/native/RoomsList/RoomsListComponent/index.tsx (1)

30-39: Replace placeholder empty-state logic

Use concrete conditions and return null instead of undefined.

Apply this diff:

-  const handleEmptyState = () => {
-    const hasEmptyStates = true //! isPending && data?.chatRooms?.edges.length === 0
-
-    if (hasEmptyStates) {
-      if (searchParam) return <SearchNotFoundState />
-      return <EmptyChatRoomsState />
-    }
-
-    return undefined
-  }
+  const handleEmptyState = () => {
+    const count =
+      (data?.chatRooms?.edges?.filter((e) => e?.node)?.length ?? 0)
+    const isEmpty = !isPending && count === 0
+    if (!isEmpty) return null
+    return searchParam ? <SearchNotFoundState /> : <EmptyChatRoomsState />
+  }
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between bc7ddf6 and 798e2ef.

⛔ Files ignored due to path filters (1)
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (35)
  • packages/components/modules/messages/native/ChatRooms/index.tsx (1 hunks)
  • packages/components/modules/messages/native/ChatRooms/styles.ts (1 hunks)
  • packages/components/modules/messages/native/NewChatButton/index.tsx (1 hunks)
  • packages/components/modules/messages/native/RoomsList/ChatCard/ChatCardComponent/index.tsx (1 hunks)
  • packages/components/modules/messages/native/RoomsList/ChatCard/ChatCardComponent/styles.ts (1 hunks)
  • packages/components/modules/messages/native/RoomsList/ChatCard/ChatCardOptions/index.tsx (1 hunks)
  • packages/components/modules/messages/native/RoomsList/ChatCard/ChatCardOptions/styles.ts (1 hunks)
  • packages/components/modules/messages/native/RoomsList/ChatCard/ChatCardOptions/type.ts (1 hunks)
  • packages/components/modules/messages/native/RoomsList/ChatCard/index.tsx (1 hunks)
  • packages/components/modules/messages/native/RoomsList/ChatCard/styles.ts (1 hunks)
  • packages/components/modules/messages/native/RoomsList/EmptyChatRoomsState/index.tsx (1 hunks)
  • packages/components/modules/messages/native/RoomsList/EmptyChatRoomsState/styles.ts (1 hunks)
  • packages/components/modules/messages/native/RoomsList/RoomsListComponent/constants.ts (1 hunks)
  • packages/components/modules/messages/native/RoomsList/RoomsListComponent/index.tsx (1 hunks)
  • packages/components/modules/messages/native/RoomsList/RoomsListComponent/styles.ts (1 hunks)
  • packages/components/modules/messages/native/RoomsList/RoomsListComponent/types.ts (1 hunks)
  • packages/components/modules/messages/native/RoomsList/index.tsx (1 hunks)
  • packages/components/modules/messages/native/RoomsList/types.ts (1 hunks)
  • packages/components/modules/messages/native/SearchNotFoundState/index.tsx (1 hunks)
  • packages/components/modules/messages/native/SearchNotFoundState/styles.ts (1 hunks)
  • packages/components/modules/messages/native/SearchNotFoundState/types.ts (1 hunks)
  • packages/components/modules/messages/native/index.ts (1 hunks)
  • packages/design-system/components/native/buttons/FabButton/index.tsx (1 hunks)
  • packages/design-system/components/native/buttons/FabButton/styles.ts (1 hunks)
  • packages/design-system/components/native/buttons/FabButton/types.ts (1 hunks)
  • packages/design-system/components/native/buttons/index.ts (1 hunks)
  • packages/design-system/components/native/illustrations/SearchingImage/index.tsx (1 hunks)
  • packages/design-system/components/native/illustrations/SocialMediaDiscussionImage/index.tsx (1 hunks)
  • packages/design-system/components/native/illustrations/index.ts (1 hunks)
  • packages/design-system/components/native/illustrations/types.ts (1 hunks)
  • packages/design-system/components/native/inputs/SearchInput/index.tsx (1 hunks)
  • packages/design-system/components/native/inputs/SearchInput/styles.ts (1 hunks)
  • packages/design-system/components/native/inputs/SearchInput/types.ts (1 hunks)
  • packages/design-system/components/native/inputs/index.ts (1 hunks)
  • packages/design-system/package.json (1 hunks)
🧰 Additional context used
🧬 Code graph analysis (20)
packages/components/modules/messages/native/RoomsList/ChatCard/ChatCardComponent/styles.ts (2)
packages/components/modules/messages/native/RoomsList/ChatCard/ChatCardOptions/styles.ts (1)
  • createStyles (5-23)
packages/components/modules/messages/native/RoomsList/ChatCard/styles.ts (1)
  • createStyles (5-44)
packages/design-system/components/native/buttons/FabButton/index.tsx (2)
packages/design-system/components/native/buttons/FabButton/types.ts (1)
  • FabButtonProps (4-8)
packages/design-system/components/native/buttons/FabButton/styles.ts (1)
  • createStyles (5-26)
packages/design-system/components/native/inputs/SearchInput/index.tsx (2)
packages/design-system/components/native/inputs/SearchInput/types.ts (1)
  • SearchInputProps (3-6)
packages/design-system/components/native/inputs/SearchInput/styles.ts (1)
  • createStyles (5-14)
packages/components/modules/messages/native/RoomsList/ChatCard/styles.ts (1)
packages/components/modules/messages/native/RoomsList/ChatCard/ChatCardComponent/styles.ts (1)
  • createStyles (5-39)
packages/components/modules/messages/native/RoomsList/ChatCard/ChatCardOptions/index.tsx (2)
packages/components/modules/messages/native/RoomsList/ChatCard/ChatCardOptions/type.ts (1)
  • ChatCardOptionsProps (5-16)
packages/components/modules/messages/native/RoomsList/ChatCard/ChatCardOptions/styles.ts (1)
  • createStyles (5-23)
packages/components/modules/messages/native/RoomsList/EmptyChatRoomsState/index.tsx (1)
packages/components/modules/messages/native/RoomsList/EmptyChatRoomsState/styles.ts (1)
  • createStyles (5-30)
packages/design-system/components/native/illustrations/SocialMediaDiscussionImage/index.tsx (1)
packages/design-system/components/native/illustrations/types.ts (1)
  • SvgIconProps (3-5)
packages/components/modules/messages/native/RoomsList/index.tsx (1)
packages/components/modules/messages/native/RoomsList/types.ts (1)
  • RoomsListProps (3-7)
packages/components/modules/messages/native/RoomsList/RoomsListComponent/index.tsx (2)
packages/components/modules/messages/native/RoomsList/types.ts (1)
  • RoomsListProps (3-7)
packages/components/modules/messages/native/RoomsList/RoomsListComponent/constants.ts (1)
  • CHAT_TAB_VALUES (1-6)
packages/components/modules/messages/native/RoomsList/EmptyChatRoomsState/styles.ts (3)
packages/components/modules/messages/native/ChatRooms/styles.ts (1)
  • createStyles (5-20)
packages/components/modules/messages/native/RoomsList/RoomsListComponent/styles.ts (1)
  • createStyles (4-9)
packages/components/modules/messages/native/SearchNotFoundState/styles.ts (1)
  • createStyles (5-30)
packages/components/modules/messages/native/ChatRooms/index.tsx (3)
packages/components/modules/messages/native/ChatRooms/styles.ts (1)
  • createStyles (5-20)
packages/components/modules/messages/native/RoomsList/RoomsListComponent/constants.ts (2)
  • CHAT_TAB_VALUES (1-6)
  • CHAT_TAB_LABEL (8-13)
packages/utils/hooks/useAppStateSubscription/index.ts (1)
  • useAppStateSubscription (7-23)
packages/components/modules/messages/native/ChatRooms/styles.ts (4)
packages/components/modules/messages/native/RoomsList/EmptyChatRoomsState/styles.ts (1)
  • createStyles (5-30)
packages/components/modules/messages/native/RoomsList/RoomsListComponent/styles.ts (1)
  • createStyles (4-9)
packages/design-system/components/native/buttons/FabButton/styles.ts (1)
  • createStyles (5-26)
packages/design-system/components/native/inputs/SearchInput/styles.ts (1)
  • createStyles (5-14)
packages/components/modules/messages/native/SearchNotFoundState/index.tsx (2)
packages/components/modules/messages/native/SearchNotFoundState/types.ts (1)
  • SearchNotFoundStateProps (1-3)
packages/components/modules/messages/native/SearchNotFoundState/styles.ts (1)
  • createStyles (5-30)
packages/design-system/components/native/inputs/SearchInput/styles.ts (3)
packages/components/modules/messages/native/ChatRooms/styles.ts (1)
  • createStyles (5-20)
packages/components/modules/messages/native/RoomsList/ChatCard/ChatCardComponent/styles.ts (1)
  • createStyles (5-39)
packages/design-system/components/native/buttons/FabButton/styles.ts (1)
  • createStyles (5-26)
packages/components/modules/messages/native/RoomsList/RoomsListComponent/styles.ts (1)
packages/components/modules/messages/native/ChatRooms/styles.ts (1)
  • createStyles (5-20)
packages/components/modules/messages/native/RoomsList/ChatCard/ChatCardOptions/styles.ts (2)
packages/components/modules/messages/native/RoomsList/ChatCard/ChatCardComponent/styles.ts (1)
  • createStyles (5-39)
packages/components/modules/messages/native/RoomsList/ChatCard/styles.ts (1)
  • createStyles (5-44)
packages/components/modules/messages/native/RoomsList/RoomsListComponent/types.ts (2)
packages/utils/types/typescript.ts (1)
  • ValueOf (3-3)
packages/components/modules/messages/native/RoomsList/RoomsListComponent/constants.ts (1)
  • CHAT_TAB_VALUES (1-6)
packages/components/modules/messages/native/SearchNotFoundState/styles.ts (1)
packages/components/modules/messages/native/RoomsList/EmptyChatRoomsState/styles.ts (1)
  • createStyles (5-30)
packages/design-system/components/native/illustrations/SearchingImage/index.tsx (1)
packages/design-system/components/native/illustrations/types.ts (1)
  • SvgIconProps (3-5)
packages/components/modules/messages/native/RoomsList/ChatCard/ChatCardComponent/index.tsx (4)
packages/components/modules/messages/native/RoomsList/ChatCard/ChatCardComponent/styles.ts (1)
  • createStyles (5-39)
packages/components/modules/messages/native/RoomsList/ChatCard/ChatCardOptions/styles.ts (1)
  • createStyles (5-23)
packages/components/modules/messages/common/graphql/mutations/ArchiveChatRoom.ts (1)
  • useArchiveChatRoomMutation (24-63)
packages/components/modules/messages/common/utils.ts (1)
  • useNameAndAvatar (53-58)
🪛 GitHub Actions: Main Workflow
packages/components/modules/messages/native/RoomsList/RoomsListComponent/index.tsx

[error] 62-62: Type '{ readonly id: string; readonly " $fragmentSpreads": FragmentRefs<"LastMessageFragment" | "TitleFragment" | "UnreadMessagesCountFragment">; } | null | undefined' is not assignable to type 'RoomsListFragment$key'.

🔇 Additional comments (15)
packages/design-system/components/native/inputs/SearchInput/types.ts (1)

3-6: LGTM on the props contract.

Extends Paper’s TextInputProps cleanly; searchParam + resetInput are clear.

packages/design-system/components/native/inputs/index.ts (1)

4-5: Public exports look good.

SearchInput and its types are correctly re-exported.

packages/design-system/components/native/inputs/SearchInput/index.tsx (1)

3-3: Confirm @expo/vector-icons usage in design-system is acceptable.

This couples the DS to Expo. If the DS is used outside Expo, prefer Paper’s default icons or react-native-vector-icons.

packages/components/modules/messages/native/RoomsList/ChatCard/ChatCardOptions/styles.ts (1)

7-22: LGTM.

Styles look consistent with the design system and RN best practices.

packages/design-system/components/native/illustrations/types.ts (1)

3-5: LGTM; ensure isActive is not forwarded to <Svg>

If consuming illustrations spread SvgIconProps into <Svg {...props} />, isActive will leak to native and may warn. Destructure it out before spreading:
const { isActive, ...svgProps } = props; return <Svg {...svgProps} />

packages/components/modules/messages/native/RoomsList/RoomsListComponent/types.ts (1)

1-5: Type alias looks good — import path is valid

ValueOf is defined in packages/utils/types/typescript.ts and re‑exported from packages/utils/index.ts (export type * from './types/typescript'), so importing from '@baseapp-frontend/utils' is correct.

packages/design-system/components/native/illustrations/index.ts (1)

1-3: LGTM.

Clear and minimal re-exports; type-only export is appropriate.

packages/components/modules/messages/native/NewChatButton/index.tsx (1)

12-20: Add accessibility props to FabButton and verify /create-room route

Add screen-reader props + testID and ensure FabButton forwards them. I couldn't find a file-based Expo Router route for /create-room — confirm an app/create-room route exists or update the navigation target.

File: packages/components/modules/messages/native/NewChatButton/index.tsx

   return (
     <FabButton
       onPress={navigateToCreateRoom}
       iconName="add"
       iconSize={28}
       iconColor={theme.colors.primary.contrast}
+      accessibilityRole="button"
+      accessibilityLabel="Start new chat"
+      accessibilityHint="Opens the new chat screen"
+      testID="newChatButton"
     />
   )
packages/components/modules/messages/native/SearchNotFoundState/styles.ts (1)

11-12: Verify RN support for gap or provide fallback.

styles.ts uses gap in two places but package.json entries show catalog:react-native (actual RN version unclear) — confirm the RN version supports gap or replace with explicit sibling margins / a small Spacer component.

  • packages/components/modules/messages/native/SearchNotFoundState/styles.ts — container: gap: 12 (≈lines 11–12); textWrapper: gap: 10 (≈line 25)
packages/design-system/components/native/illustrations/SocialMediaDiscussionImage/index.tsx (1)

1-14: LGTM! Clean component structure with proper typing.

The component follows React Native best practices with typed props and appropriate default values.

packages/components/modules/messages/native/ChatRooms/index.tsx (1)

38-43: Prevent search updates during pending transitions.

Good use of transitions for non-blocking UI updates. The early return prevents race conditions.

packages/components/modules/messages/native/RoomsList/ChatCard/ChatCardComponent/index.tsx (2)

72-85: Good implementation of archive mutation with proper null checks.

The archive functionality correctly checks for required data before committing the mutation.


115-116: Address the TODO for lastMessageTime formatting.

There's a TODO comment about fixing date formatting. This should be resolved before production.

Can you provide more details about what date formatting fixes are needed? Is this related to timezone handling, relative time display (e.g., "2 hours ago"), or date format localization?

packages/components/modules/messages/native/RoomsList/RoomsListComponent/index.tsx (2)

5-5: Confirm FlatList source

Unless you rely on RNGH’s wrappers, prefer FlatList from react-native to avoid subtle prop differences.


15-19: No change required — fragment type matches useRoomsList parameter

RoomsListFragment is defined on ChatRoomsInterface and useRoomsList explicitly accepts RoomsListFragment$key; ChatRoomsQuery spreads ...RoomsListFragment into profile, so casting targetRef?.me?.profile as RoomsListFragment$key is correct.

Copy link

@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: 0

🧹 Nitpick comments (3)
packages/components/modules/__shared__/native/index.ts (1)

2-2: Prefer wider TS compatibility for type re-exports.

export type * from requires newer TS; many codebases still use export type { ... } from. Consider switching to avoid build breaks.

Apply:

-export type * from './EmptyView/types'
+export type { EmptyViewProps } from './EmptyView/types'
packages/components/modules/__shared__/native/EmptyView/styles.ts (1)

22-22: Avoid hard-coded width; make it responsive.

width: 393 will misrender on smaller/larger screens. Stretch to container width (center content with alignItems as you already do).

Apply:

-      width: 393,
+      alignSelf: 'stretch',
+      width: '100%',
packages/components/modules/__shared__/native/EmptyView/index.tsx (1)

8-8: Forward the style prop to the root container.

style exists in the props type but isn’t applied, preventing consumers from customizing layout.

Apply:

-const EmptyView = ({ icon, title, message }: EmptyViewProps) => {
+const EmptyView = ({ icon, title, message, style }: EmptyViewProps) => {
...
-    <View style={styles.container}>
+    <View style={[styles.container, style]}>

Also applies to: 13-13

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 5668dad and c257f7a.

📒 Files selected for processing (6)
  • packages/components/modules/__shared__/native/EmptyView/index.tsx (1 hunks)
  • packages/components/modules/__shared__/native/EmptyView/styles.ts (1 hunks)
  • packages/components/modules/__shared__/native/EmptyView/types.ts (1 hunks)
  • packages/components/modules/__shared__/native/index.ts (1 hunks)
  • packages/components/modules/messages/native/RoomsList/EmptyChatRoomsState/index.tsx (1 hunks)
  • packages/components/modules/messages/native/SearchNotFoundState/index.tsx (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (2)
  • packages/components/modules/messages/native/RoomsList/EmptyChatRoomsState/index.tsx
  • packages/components/modules/messages/native/SearchNotFoundState/index.tsx
🧰 Additional context used
🧠 Learnings (1)
📚 Learning: 2025-04-09T22:06:40.026Z
Learnt from: davidbermudez-tsl
PR: silverlogic/baseapp-frontend#209
File: packages/components/modules/content-feed/web/ContentFeed/types.ts:1-1
Timestamp: 2025-04-09T22:06:40.026Z
Learning: The empty ContentFeedProps interface in packages/components/modules/content-feed/web/ContentFeed/types.ts will be populated with properties in a future PR rather than being converted to a type alias.

Applied to files:

  • packages/components/modules/__shared__/native/EmptyView/types.ts
🧬 Code graph analysis (1)
packages/components/modules/__shared__/native/EmptyView/index.tsx (2)
packages/components/modules/__shared__/native/EmptyView/types.ts (1)
  • EmptyViewProps (5-10)
packages/components/modules/__shared__/native/EmptyView/styles.ts (1)
  • createStyles (5-30)
⏰ 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). (1)
  • GitHub Check: Component Test Packages
🔇 Additional comments (2)
packages/components/modules/__shared__/native/EmptyView/types.ts (1)

5-10: Props shape looks good.

Clear, flexible API (icon/title/message/style) for an empty state component.

packages/components/modules/__shared__/native/EmptyView/styles.ts (1)

12-12: Verify RN version supports gap. Provide fallback if not.

gap/rowGap support lands in newer RN; on older versions it’s ignored, collapsing spacing.

If you need a fallback, replace gap with explicit margins (e.g., add marginTop: 12 to the second block when icon is present, and marginTop: 10 between texts), or use conditional styles in the component. I can draft that if needed.

Also applies to: 26-26

Copy link

@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: 0

🧹 Nitpick comments (2)
packages/components/modules/messages/native/RoomsList/ChatCard/index.tsx (2)

3-8: Replace any + non-null assertion with inferred, type-safe props.

Avoid any and roomRef!. Derive props from the inner component so types stay in sync and the null check narrows correctly.

Apply this diff:

 import { ChatCard as ChatCardComponent } from './ChatCardComponent'
+import type { ComponentProps } from 'react'
 
-const ChatCard = ({ roomRef, isArchived }: { roomRef: any | null; isArchived: boolean }) => {
-  if (!roomRef) {
+type InnerProps = ComponentProps<typeof ChatCardComponent>
+type Props = {
+  roomRef: NonNullable<InnerProps['roomRef']> | null
+  isArchived: InnerProps['isArchived']
+}
+
+const ChatCard = ({ roomRef, isArchived }: Props) => {
+  if (roomRef == null) {
     return null
   }
-  return <ChatCardComponent roomRef={roomRef!} isArchived={isArchived} />
+  return <ChatCardComponent roomRef={roomRef} isArchived={isArchived} />
 }
 
-export { ChatCard }
+export { ChatCard }
+export type { Props as ChatCardProps }

3-9: Optional: memoize the wrapper to cut FlatList re-renders.

Small wrapper, but in long lists this helps avoid needless re-renders when props don’t change.

Apply on top of the previous suggestion:

-import type { ComponentProps } from 'react'
+import { memo } from 'react'
+import type { ComponentProps } from 'react'
@@
-const ChatCard = ({ roomRef, isArchived }: Props) => {
+const ChatCard = memo(({ roomRef, isArchived }: Props) => {
   if (roomRef == null) {
     return null
   }
   return <ChatCardComponent roomRef={roomRef} isArchived={isArchived} />
-}
+})
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between c257f7a and 236e56d.

📒 Files selected for processing (2)
  • packages/components/modules/messages/native/RoomsList/ChatCard/index.tsx (1 hunks)
  • packages/components/modules/messages/native/RoomsList/RoomsListComponent/index.tsx (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • packages/components/modules/messages/native/RoomsList/RoomsListComponent/index.tsx
⏰ 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: Analyze (javascript)
  • GitHub Check: Build and Lint Packages
  • GitHub Check: Component Test Packages
🔇 Additional comments (1)
packages/components/modules/messages/native/RoomsList/ChatCard/index.tsx (1)

1-1: Confirm consumers import named ChatCard (not default).

ChatCardComponent exports a named ChatCard and the wrapper re-exports it as named:
packages/components/modules/messages/native/RoomsList/ChatCard/ChatCardComponent/index.tsx — export { ChatCard }
packages/components/modules/messages/native/RoomsList/ChatCard/index.tsx — imports { ChatCard as ChatCardComponent } and exports { ChatCard }

Search found no consumers importing the wrapper; verify all consumers use a named import: import { ChatCard } from '.../RoomsList/ChatCard' (not a default import).

@gabrieleandro gabrieleandro force-pushed the feature/BA-2626-rooms-list branch from 236e56d to 397c3cd Compare September 24, 2025 12:34
Copy link

@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 (18)
packages/design-system/components/native/illustrations/SearchingImage/index.tsx (3)

1-1: Memoize the component to avoid unnecessary re-renders.

Apply:

-import { FC } from 'react'
+import { FC, memo } from 'react'
@@
-export default SearchingImage
+export default memo(SearchingImage)

Also applies to: 57-57


21-28: Add basic accessibility defaults.

Set an explicit role and make it non-focusable by default.

Apply:

     <Svg
       width={width}
       height={height}
       viewBox="0 0 200 200"
       color={svgColor}
       fill="none"
+      accessibilityRole="image"
+      focusable={false}
       {...props}
     >

11-12: Prefer numeric defaults for width/height.

Avoid string defaults unless required for consistency. Numeric is typical for RN.

Apply:

-  width = '200',
-  height = '200',
+  width = 200,
+  height = 200,
packages/components/modules/messages/native/RoomsList/ChatCard/ChatCardComponent/index.tsx (5)

38-50: Avoid double useFragment(TitleFragment); reuse headerFragment for id.

Read the header once and derive roomId from it.

-  const roomId = useFragment(TitleFragment, roomRef)?.id
+  // headerFragment read below; derive id from it

And after defining headerFragment:

-  const headerFragment = useFragment(TitleFragment, roomRef)
+  const headerFragment = useFragment(TitleFragment, roomRef)
+  const roomId = headerFragment?.id

39-39: Ref typing: prefer useRef(null).

Aligns with common RN patterns and BottomSheet’s examples.

-  const bottomDrawerRef = useRef<BottomSheetModal | undefined>(undefined)
+  const bottomDrawerRef = useRef<BottomSheetModal>(null)

64-66: Guard navigation when roomId is absent.

Prevents a malformed route when data is stale/not yet available.

-  const onChatCardPress = () => {
-    router.push(`/rooms/${roomId}`)
-  }
+  const onChatCardPress = () => {
+    if (!roomId) return
+    router.push(`/rooms/${roomId}`)
+  }

59-63: Avoid rendering “undefined • …”; build the subtitle safely.

Compose the caption with available parts only.

   const lastMessage = lastMessageFragment.lastMessage?.content
   const hasUnreadMessages =
     unreadMessagesCountFragment?.unreadMessages?.markedUnread ||
     !!unreadMessagesCountFragment?.unreadMessages?.count
+
+  const subtitle = [lastMessageTime, lastMessage].filter(Boolean).join(' • ')
-            <Text
+            <Text
               variant="caption"
               style={styles.lastMessageText}
               numberOfLines={1}
               ellipsizeMode="tail"
             >
-              {lastMessageTime} • {lastMessage}
+              {subtitle}
             </Text>

Also applies to: 116-123


105-109: Remove redundant key on Pressable or use a stable id.

FlatList manages keys; the current key interpolates an object and is not stable/unique.

     <Pressable
-      key={`chat-card-${roomRef}`}
       onPress={onChatCardPress}
       onLongPress={onChatCardLongPress}
     >
packages/design-system/components/native/buttons/FabButton/index.tsx (2)

6-6: Import safe-area hook

Required for the FAB bottom offset.

-import { TouchableOpacity } from 'react-native'
+import { TouchableOpacity } from 'react-native'
+import { useSafeAreaInsets } from 'react-native-safe-area-context'

1-1: Memoize styles to avoid re-creating StyleSheet per render

Small perf win; theme changes still re-compute.

-import { FC } from 'react'
+import { FC, useMemo } from 'react'
@@
-  const styles = createStyles(theme)
+  const styles = useMemo(() => createStyles(theme), [theme])

Also applies to: 19-19

packages/design-system/components/native/buttons/index.ts (1)

4-4: Also export FabButton types from the barrel

Improves DX and consistency with Button type exports.

 export { default as IconButton } from './IconButton'
 export { default as FabButton } from './FabButton'
+export type { FabButtonProps } from './FabButton/types'
packages/design-system/components/native/inputs/SearchInput/index.tsx (1)

26-37: Remove now-unused renderClearIcon.

If you switch to conditional right TextInput.Icon, this function becomes dead code.

-  const renderClearIcon = useCallback(
-    () =>
-      searchParam && searchParam.length > 0 ? (
-        <Ionicons
-          name="close"
-          size={24}
-          color={theme.colors.object.disabled}
-          onPress={resetInput}
-        />
-      ) : null,
-    [resetInput, searchParam, theme.colors.object.disabled],
-  )
packages/components/modules/messages/native/ChatRooms/index.tsx (6)

28-29: Tighten selectedTab typing to ChatTabValues.

Keeps type safety across tabs and filters.

-  const [selectedTab, setSelectedTab] = useState<string>(CHAT_TAB_VALUES.active)
+  const [selectedTab, setSelectedTab] = useState<ChatTabValues>(CHAT_TAB_VALUES.active)

53-55: Align onChange signature with ChatTabValues.

Avoid unnecessary casts and ensure correctness.

-  const handleChange = (newValue: string) => {
-    setSelectedTab(newValue as ChatTabValues)
+  const handleChange = (newValue: ChatTabValues) => {
+    setSelectedTab(newValue)
   }

1-1: Stabilize app-resume callback to avoid listener churn.

Inline arrow recreates on every render and resubscribes. Memoize with useCallback.

-import { FC, Suspense, useState, useTransition } from 'react'
+import { FC, Suspense, useState, useTransition, useCallback } from 'react'
@@
-  useAppStateSubscription(() => {
-    refetch(
-      {
-        q: searchParam,
-        unreadMessages: selectedTab === CHAT_TAB_VALUES.unread,
-        archived: selectedTab === CHAT_TAB_VALUES.archived,
-      },
-      { fetchPolicy: 'store-and-network' },
-    )
-  })
+  const handleAppResume = useCallback(() => {
+    refetch(
+      {
+        q: searchParam,
+        unreadMessages: selectedTab === CHAT_TAB_VALUES.unread,
+        archived: selectedTab === CHAT_TAB_VALUES.archived,
+      },
+      { fetchPolicy: 'store-and-network' },
+    )
+  }, [refetch, searchParam, selectedTab])
+  useAppStateSubscription(handleAppResume)

Also applies to: 57-66


27-27: Avoid mixing RHF with local state for this search field.

You already manage searchParam; passing control/name adds complexity and risks leaking unknown props downstream. Drop them and avoid an unused control variable.

-  const { control, reset } = useForm({ defaultValues: { search: '' } })
+  const { reset } = useForm({ defaultValues: { search: '' } })
         <SearchInput
           placeholder="Search"
           onChangeText={handleSearchChange}
-          control={control}
-          name="search"
           searchParam={searchParam}
           resetInput={resetInput}
         />

Also applies to: 72-79


45-48: resetInput doesn’t need RHF reset once the input is controlled.

If you bind value to searchParam in SearchInput, this reset is redundant.

   const resetInput = () => {
     setSearchParam('')
-    reset({ search: '' })
   }

103-107: Groups tab TODO — offer help.

Happy to scaffold the Groups tab and guard behind a feature flag until ready.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 236e56d and 397c3cd.

⛔ Files ignored due to path filters (1)
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (41)
  • packages/components/CHANGELOG.md (1 hunks)
  • packages/components/modules/__shared__/native/EmptyView/index.tsx (1 hunks)
  • packages/components/modules/__shared__/native/EmptyView/styles.ts (1 hunks)
  • packages/components/modules/__shared__/native/EmptyView/types.ts (1 hunks)
  • packages/components/modules/__shared__/native/index.ts (1 hunks)
  • packages/components/modules/messages/native/ChatRooms/index.tsx (1 hunks)
  • packages/components/modules/messages/native/ChatRooms/styles.ts (1 hunks)
  • packages/components/modules/messages/native/NewChatButton/index.tsx (1 hunks)
  • packages/components/modules/messages/native/RoomsList/ChatCard/ChatCardComponent/index.tsx (1 hunks)
  • packages/components/modules/messages/native/RoomsList/ChatCard/ChatCardComponent/styles.ts (1 hunks)
  • packages/components/modules/messages/native/RoomsList/ChatCard/ChatCardOptions/index.tsx (1 hunks)
  • packages/components/modules/messages/native/RoomsList/ChatCard/ChatCardOptions/styles.ts (1 hunks)
  • packages/components/modules/messages/native/RoomsList/ChatCard/ChatCardOptions/type.ts (1 hunks)
  • packages/components/modules/messages/native/RoomsList/ChatCard/index.tsx (1 hunks)
  • packages/components/modules/messages/native/RoomsList/ChatCard/styles.ts (1 hunks)
  • packages/components/modules/messages/native/RoomsList/EmptyChatRoomsState/index.tsx (1 hunks)
  • packages/components/modules/messages/native/RoomsList/RoomsListComponent/constants.ts (1 hunks)
  • packages/components/modules/messages/native/RoomsList/RoomsListComponent/index.tsx (1 hunks)
  • packages/components/modules/messages/native/RoomsList/RoomsListComponent/styles.ts (1 hunks)
  • packages/components/modules/messages/native/RoomsList/RoomsListComponent/types.ts (1 hunks)
  • packages/components/modules/messages/native/RoomsList/index.tsx (1 hunks)
  • packages/components/modules/messages/native/RoomsList/types.ts (1 hunks)
  • packages/components/modules/messages/native/SearchNotFoundState/index.tsx (1 hunks)
  • packages/components/modules/messages/native/index.ts (1 hunks)
  • packages/components/package.json (1 hunks)
  • packages/design-system/CHANGELOG.md (1 hunks)
  • packages/design-system/components/native/buttons/FabButton/index.tsx (1 hunks)
  • packages/design-system/components/native/buttons/FabButton/styles.ts (1 hunks)
  • packages/design-system/components/native/buttons/FabButton/types.ts (1 hunks)
  • packages/design-system/components/native/buttons/index.ts (1 hunks)
  • packages/design-system/components/native/illustrations/SearchingImage/index.tsx (1 hunks)
  • packages/design-system/components/native/illustrations/SocialMediaDiscussionImage/index.tsx (1 hunks)
  • packages/design-system/components/native/illustrations/index.ts (1 hunks)
  • packages/design-system/components/native/illustrations/types.ts (1 hunks)
  • packages/design-system/components/native/inputs/SearchInput/index.tsx (1 hunks)
  • packages/design-system/components/native/inputs/SearchInput/styles.ts (1 hunks)
  • packages/design-system/components/native/inputs/SearchInput/types.ts (1 hunks)
  • packages/design-system/components/native/inputs/index.ts (1 hunks)
  • packages/design-system/package.json (2 hunks)
  • packages/wagtail/CHANGELOG.md (1 hunks)
  • packages/wagtail/package.json (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (34)
  • packages/design-system/components/native/inputs/SearchInput/types.ts
  • packages/components/modules/messages/native/ChatRooms/styles.ts
  • packages/components/modules/messages/native/RoomsList/index.tsx
  • packages/components/modules/shared/native/EmptyView/styles.ts
  • packages/components/modules/messages/native/RoomsList/ChatCard/ChatCardOptions/styles.ts
  • packages/design-system/components/native/inputs/SearchInput/styles.ts
  • packages/wagtail/CHANGELOG.md
  • packages/components/modules/messages/native/RoomsList/ChatCard/ChatCardOptions/type.ts
  • packages/design-system/components/native/inputs/index.ts
  • packages/design-system/components/native/illustrations/index.ts
  • packages/design-system/package.json
  • packages/components/modules/messages/native/RoomsList/ChatCard/ChatCardOptions/index.tsx
  • packages/components/modules/messages/native/RoomsList/ChatCard/styles.ts
  • packages/design-system/components/native/buttons/FabButton/styles.ts
  • packages/components/modules/messages/native/NewChatButton/index.tsx
  • packages/components/modules/messages/native/SearchNotFoundState/index.tsx
  • packages/components/modules/messages/native/RoomsList/RoomsListComponent/types.ts
  • packages/components/modules/messages/native/RoomsList/EmptyChatRoomsState/index.tsx
  • packages/components/modules/messages/native/RoomsList/types.ts
  • packages/components/modules/messages/native/RoomsList/ChatCard/ChatCardComponent/styles.ts
  • packages/components/package.json
  • packages/components/modules/shared/native/EmptyView/index.tsx
  • packages/components/modules/messages/native/RoomsList/ChatCard/index.tsx
  • packages/components/modules/shared/native/EmptyView/types.ts
  • packages/design-system/components/native/illustrations/types.ts
  • packages/components/modules/shared/native/index.ts
  • packages/components/CHANGELOG.md
  • packages/design-system/components/native/illustrations/SocialMediaDiscussionImage/index.tsx
  • packages/design-system/CHANGELOG.md
  • packages/components/modules/messages/native/index.ts
  • packages/design-system/components/native/buttons/FabButton/types.ts
  • packages/components/modules/messages/native/RoomsList/RoomsListComponent/constants.ts
  • packages/wagtail/package.json
  • packages/components/modules/messages/native/RoomsList/RoomsListComponent/styles.ts
🧰 Additional context used
🧬 Code graph analysis (6)
packages/components/modules/messages/native/ChatRooms/index.tsx (3)
packages/components/modules/messages/native/ChatRooms/styles.ts (1)
  • createStyles (5-20)
packages/components/modules/messages/native/RoomsList/RoomsListComponent/constants.ts (2)
  • CHAT_TAB_VALUES (1-6)
  • CHAT_TAB_LABEL (8-13)
packages/utils/hooks/useAppStateSubscription/index.ts (1)
  • useAppStateSubscription (7-23)
packages/components/modules/messages/native/RoomsList/ChatCard/ChatCardComponent/index.tsx (3)
packages/components/modules/messages/native/RoomsList/ChatCard/ChatCardComponent/styles.ts (1)
  • createStyles (5-39)
packages/components/modules/messages/common/graphql/mutations/ArchiveChatRoom.ts (1)
  • useArchiveChatRoomMutation (24-63)
packages/components/modules/messages/common/utils.ts (1)
  • useNameAndAvatar (53-58)
packages/components/modules/messages/native/RoomsList/RoomsListComponent/index.tsx (2)
packages/components/modules/messages/native/RoomsList/types.ts (1)
  • RoomsListProps (3-7)
packages/components/modules/messages/native/RoomsList/RoomsListComponent/constants.ts (1)
  • CHAT_TAB_VALUES (1-6)
packages/design-system/components/native/buttons/FabButton/index.tsx (2)
packages/design-system/components/native/buttons/FabButton/types.ts (1)
  • FabButtonProps (4-8)
packages/design-system/components/native/buttons/FabButton/styles.ts (1)
  • createStyles (5-26)
packages/design-system/components/native/inputs/SearchInput/index.tsx (2)
packages/design-system/components/native/inputs/SearchInput/types.ts (1)
  • SearchInputProps (3-6)
packages/design-system/components/native/inputs/SearchInput/styles.ts (1)
  • createStyles (5-14)
packages/design-system/components/native/illustrations/SearchingImage/index.tsx (1)
packages/design-system/components/native/illustrations/types.ts (1)
  • SvgIconProps (3-5)
⏰ 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). (2)
  • GitHub Check: Build and Lint Packages
  • GitHub Check: Component Test Packages
🔇 Additional comments (9)
packages/design-system/components/native/illustrations/SearchingImage/index.tsx (3)

8-14: Confirm color precedence: isActive currently overrides a provided color.

With isActive = true, the passed color is ignored in favor of colors.primary.high. Is this intended DS behavior? If not, compute color as color ?? (isActive ? colors.primary.high : colors.object.high).

Also applies to: 17-19


20-28: LGTM: Prop forwarding order.

Spreading {...props} last lets consumers override width/height/viewBox/fill while keeping color controlled by the component—good DS ergonomics.

If the intent is to allow overriding color too, don't destructure color and compute svgColor from props.color directly, or move {...props} before the color prop.


20-53: Confirm react-native-svg supports currentColor — pin/upgrade to >=15.x or test on iOS & Android.

package.json declares react-native-svg as "catalog:react-native" (no concrete lockfile version found); currentColor is reliably supported in react-native-svg 15.x+ while older releases had platform bugs — either pin/upgrade to a 15.x+ release or verify fill="currentColor" behavior on both iOS and Android.

packages/components/modules/messages/native/RoomsList/ChatCard/ChatCardComponent/index.tsx (3)

136-141: Remove commented-out prop.

Leftover dev artifact.

       <ChatCardOptions
         bottomDrawerRef={bottomDrawerRef}
         handleSheetChanges={() => {}}
-        // type={fieldType}
         handleArchiveChat={handleArchiveChat}

28-34: Fix ChatCard roomRef type to node-level fragment keys (remove RoomsListFragment$key).

This prop type is the source of the fragment mismatch and the unsafe casts below. Accept the node’s fragment keys directly.

Apply this diff:

-const ChatCard = ({
-  roomRef,
-  isArchived,
-}: {
-  roomRef: RoomsListFragment$key
-  isArchived: boolean
-}) => {
+const ChatCard = ({
+  roomRef,
+  isArchived,
+}: {
+  roomRef: LastMessageFragment$key & TitleFragment$key & UnreadMessagesCountFragment$key
+  isArchived: boolean
+}) => {

Add this helper type near the imports to keep it DRY (optional):

// e.g., just above the component
type ChatRoomNodeRef = LastMessageFragment$key & TitleFragment$key & UnreadMessagesCountFragment$key
// Then: roomRef: ChatRoomNodeRef

43-54: Remove unsafe casts to fragment keys; use roomRef directly.

Casting to unknown to satisfy useFragment defeats Relay’s safety. With the prop type fixed, call useFragment directly.

-  const lastMessageFragment = useFragment<LastMessageFragment$key>(
-    LastMessageFragment,
-    roomRef as unknown as LastMessageFragment$key,
-  )
-  const headerFragment = useFragment<TitleFragment$key>(
-    TitleFragment,
-    roomRef as unknown as TitleFragment$key,
-  )
-  const unreadMessagesCountFragment = useFragment<UnreadMessagesCountFragment$key>(
-    UnreadMessagesCountFragment,
-    roomRef as unknown as UnreadMessagesCountFragment$key,
-  )
+  const lastMessageFragment = useFragment(LastMessageFragment, roomRef)
+  const headerFragment = useFragment(TitleFragment, roomRef)
+  const unreadMessagesCountFragment = useFragment(UnreadMessagesCountFragment, roomRef)
packages/components/modules/messages/native/RoomsList/RoomsListComponent/index.tsx (1)

60-75: Harden FlatList: filter null nodes, safe keyExtractor, and guard onEndReached.

Prevents passing undefined to ChatCard, avoids unsafe casts, and reduces duplicate loads.

-    <FlatList
-      data={data?.chatRooms?.edges ?? []}
-      renderItem={({ item }) => {
-        if (!item?.node) return null
-        return (
-          <ChatCard roomRef={item.node} isArchived={selectedTab === CHAT_TAB_VALUES.archived} />
-        )
-      }}
-      onContentSizeChange={(width, height) => loadNextBasedOnHeight(height)}
-      keyExtractor={(item) => item?.node?.id as string}
-      onEndReached={() => {
-        if (hasNext) {
-          loadNext(10)
-        }
-      }}
-      ListEmptyComponent={handleEmptyState}
-    />
+    <FlatList
+      data={(data?.chatRooms?.edges ?? []).filter((e) => e?.node)}
+      renderItem={({ item }) => {
+        const node = item!.node!
+        return (
+          <ChatCard
+            roomRef={node}
+            isArchived={selectedTab === CHAT_TAB_VALUES.archived}
+          />
+        )
+      }}
+      onContentSizeChange={(_w, h) => loadNextBasedOnHeight(h)}
+      keyExtractor={(item, index) => item?.node?.id ?? `room-edge-${index}`}
+      onEndReached={() => {
+        if (hasNext && !isPending) {
+          loadNext(10)
+        }
+      }}
+      ListEmptyComponent={handleEmptyState}
+    />
packages/design-system/components/native/inputs/SearchInput/index.tsx (1)

39-49: Make input controlled and wire clear to TextInput.Icon (previous feedback not applied).

Bind TextInput.value to searchParam so resetInput clears the field, and move onPress to TextInput.Icon while rendering the right icon only when there’s text.

Apply this diff:

   return (
     <TextInput
       placeholder={placeholder}
       mode="outlined"
       style={styles.searchInput}
       outlineColor={theme.colors.surface.active}
       left={<TextInput.Icon icon={renderSearchIcon} />}
-      right={<TextInput.Icon icon={renderClearIcon} />}
+      value={searchParam ?? ''}
+      right={
+        searchParam?.length
+          ? (
+            <TextInput.Icon
+              icon={() => (
+                <Ionicons name="close" size={24} color={theme.colors.object.disabled} />
+              )}
+              onPress={resetInput}
+            />
+          )
+          : undefined
+      }
       onChangeText={onChangeText}
       {...props}
     />
   )
packages/components/modules/messages/native/ChatRooms/index.tsx (1)

50-52: No action needed — empty connections array is safe here

The hook's updater derives connections from the store via getChatRoomConnections and performs delete/insert operations, so passing [] only makes the @deleteEdge directive a no-op but does not prevent the subscription updater from updating the store.

@gabrieleandro gabrieleandro force-pushed the feature/BA-2626-rooms-list branch from 397c3cd to d853924 Compare October 7, 2025 17:31
Copy link

@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

♻️ Duplicate comments (7)
packages/design-system/components/native/inputs/SearchInput/index.tsx (1)

39-50: Address the uncontrolled input issue from the previous review.

The TextInput remains uncontrolled without binding the value prop to searchParam, which means calling resetInput() won't visually clear the field. This issue was already flagged in a previous review comment.

Please implement the suggested fix from the previous review to make this a controlled component and conditionally render the clear icon.

packages/components/modules/messages/native/RoomsList/index.tsx (1)

10-14: Add required fallback prop to Suspense.

React.Suspense requires a fallback prop. Without it, TypeScript will produce a compile error.

Apply this diff:

 const SuspendedRoomsList = (props: RoomsListProps) => (
-  <Suspense>
+  <Suspense fallback={null}>
     <RoomsList {...props} />
   </Suspense>
 )
packages/design-system/components/native/buttons/FabButton/index.tsx (1)

11-26: Apply accessibility, theming, and safe-area improvements from previous review.

The previous review identified several issues that should be addressed:

  1. Hardcoded iconColor default should derive from theme
  2. Missing accessibilityRole, activeOpacity, and hitSlop props
  3. Button position should offset for safe-area insets (home indicator)
  4. Consumers must provide accessibilityLabel

These improvements ensure the FAB is theme-aware, accessible, and respects device safe areas.

Refer to the previous review comment for the complete diff and verification script.

packages/components/modules/messages/native/NewChatButton/index.tsx (1)

15-20: Add accessibilityLabel for screen reader support.

The FabButton is missing an accessibilityLabel, making it inaccessible to screen reader users.

Apply this diff:

     <FabButton
+      accessibilityLabel="Start new chat"
       onPress={navigateToCreateRoom}
       iconName="add"
       iconSize={28}
       iconColor={theme.colors.primary.contrast}
     />
packages/components/modules/messages/native/ChatRooms/index.tsx (2)

38-43: Remove isPending guard to prevent dropped keystrokes.

The isPending check prevents user input from being captured during transitions, resulting in lost keystrokes. Users expect immediate visual feedback when typing.

Apply this diff:

 const handleSearchChange = (text: string) => {
-  if (isPending) return
   startTransition(() => {
     setSearchParam(text)
   })
 }

121-125: Add required fallback prop to Suspense.

React.Suspense requires a fallback prop. Without it, TypeScript will produce a compile error.

Apply this diff:

 const SuspendedChatRooms = () => (
-  <Suspense>
+  <Suspense fallback={null}>
     <ChatRooms />
   </Suspense>
 )
packages/components/modules/messages/native/RoomsList/RoomsListComponent/index.tsx (1)

61-65: Fix Relay fragment type mismatch for ChatCard.

The item.node passed to ChatCard has type issues. According to previous reviews, ChatCard expects RoomsListFragment$key, but the node only contains LastMessageFragment, TitleFragment, and UnreadMessagesCountFragment. This type mismatch will cause runtime errors with useFragment.

Update ChatCard prop types to accept the actual node-level fragment keys instead of RoomsListFragment$key, and remove any unsafe casts.

Refer to the previous review for detailed guidance on fixing the fragment type definitions in ChatCard and ChatCardComponent.

🧹 Nitpick comments (5)
packages/components/modules/messages/native/RoomsList/ChatCard/styles.ts (1)

5-44: Consider consolidating duplicate styles to reduce maintenance burden.

This file shares 7 out of 8 style definitions with ChatCardComponent/styles.ts (the only difference being the profileImage style present here). Consider extracting the common styles into a shared module or determining whether both files are necessary, as this duplication violates DRY principles and increases the risk of inconsistencies during future updates.

For example, you could create a shared styles module:

// ChatCard/shared-styles.ts
export const createSharedStyles = (theme: Theme) => ({
  profileCard: {
    flexDirection: 'row' as const,
    alignItems: 'center' as const,
    gap: 12,
    paddingVertical: 12,
  },
  profileInfo: {
    flex: 1,
  },
  lastMessageContainer: {
    flexDirection: 'row' as const,
    gap: 4,
  },
  profileCounterContainer: {
    justifyContent: 'center' as const,
    alignItems: 'center' as const,
    padding: 4,
  },
  lastMessageText: {
    color: theme.colors.object.low,
  },
  profileCounter: {
    backgroundColor: theme.colors.error.main,
    width: 20,
    height: 20,
    borderRadius: 12,
    justifyContent: 'center' as const,
    alignItems: 'center' as const,
  },
  profileCounterText: {
    color: theme.colors.error.contrast,
  },
});

Then import and extend in each file as needed:

// ChatCard/styles.ts
import { createSharedStyles } from './shared-styles'

export const createStyles = (theme: Theme) =>
  StyleSheet.create({
    ...createSharedStyles(theme),
    profileImage: {
      width: 48,
      height: 48,
      borderRadius: 24,
    },
  })
packages/components/modules/messages/native/ChatRooms/styles.ts (1)

7-12: Remove redundant flex property.

Using both flex: 1 and flexGrow: 1 is redundant. Also, position: 'relative' is the default positioning in React Native and can be removed.

Apply this diff:

 container: {
   backgroundColor: theme.colors.surface.background,
   flexGrow: 1,
-  flex: 1,
-  position: 'relative',
 },
packages/design-system/components/native/buttons/FabButton/styles.ts (1)

14-14: Use proper borderRadius for circular button.

For a 56x56 button, borderRadius: 500 is excessive. Use 28 (half the width/height) for a perfect circle.

Apply this diff:

-      borderRadius: 500,
+      borderRadius: 28,
packages/components/modules/messages/native/RoomsList/RoomsListComponent/index.tsx (2)

41-56: Remove isPending guard from useFocusEffect callback.

The isPending check on Line 44 prevents the refetch from occurring when needed. The startTransition wrapper already handles the pending state, so blocking the entire callback is unnecessary.

Apply this diff:

 useFocusEffect(
   useCallback(() => {
     layoutTriggeredRef.current = false
-    if (isPending) return
     startTransition(() => {
       refetch(
         {
           q: searchParam,
           unreadMessages: selectedTab === CHAT_TAB_VALUES.unread,
           archived: selectedTab === CHAT_TAB_VALUES.archived,
         },
         { fetchPolicy: 'store-and-network' },
       )
     })
   }, [refetch, searchParam, selectedTab, isPending]),
 )

68-73: Improve keyExtractor safety and add isPending guard to onEndReached.

The keyExtractor uses an unsafe type assertion (as string), and onEndReached should check isPending before loading more data to prevent redundant fetches.

Apply this diff:

-      keyExtractor={(item) => item?.node?.id as string}
+      keyExtractor={(item, index) => item?.node?.id ?? `room-${index}`}
       onEndReached={() => {
-        if (hasNext) {
+        if (hasNext && !isPending) {
           loadNext(10)
         }
       }}
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 397c3cd and d853924.

⛔ Files ignored due to path filters (1)
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (41)
  • packages/components/CHANGELOG.md (1 hunks)
  • packages/components/modules/__shared__/native/EmptyView/index.tsx (1 hunks)
  • packages/components/modules/__shared__/native/EmptyView/styles.ts (1 hunks)
  • packages/components/modules/__shared__/native/EmptyView/types.ts (1 hunks)
  • packages/components/modules/__shared__/native/index.ts (1 hunks)
  • packages/components/modules/messages/native/ChatRooms/index.tsx (1 hunks)
  • packages/components/modules/messages/native/ChatRooms/styles.ts (1 hunks)
  • packages/components/modules/messages/native/NewChatButton/index.tsx (1 hunks)
  • packages/components/modules/messages/native/RoomsList/ChatCard/ChatCardComponent/index.tsx (1 hunks)
  • packages/components/modules/messages/native/RoomsList/ChatCard/ChatCardComponent/styles.ts (1 hunks)
  • packages/components/modules/messages/native/RoomsList/ChatCard/ChatCardOptions/index.tsx (1 hunks)
  • packages/components/modules/messages/native/RoomsList/ChatCard/ChatCardOptions/styles.ts (1 hunks)
  • packages/components/modules/messages/native/RoomsList/ChatCard/ChatCardOptions/type.ts (1 hunks)
  • packages/components/modules/messages/native/RoomsList/ChatCard/index.tsx (1 hunks)
  • packages/components/modules/messages/native/RoomsList/ChatCard/styles.ts (1 hunks)
  • packages/components/modules/messages/native/RoomsList/EmptyChatRoomsState/index.tsx (1 hunks)
  • packages/components/modules/messages/native/RoomsList/RoomsListComponent/constants.ts (1 hunks)
  • packages/components/modules/messages/native/RoomsList/RoomsListComponent/index.tsx (1 hunks)
  • packages/components/modules/messages/native/RoomsList/RoomsListComponent/styles.ts (1 hunks)
  • packages/components/modules/messages/native/RoomsList/RoomsListComponent/types.ts (1 hunks)
  • packages/components/modules/messages/native/RoomsList/index.tsx (1 hunks)
  • packages/components/modules/messages/native/RoomsList/types.ts (1 hunks)
  • packages/components/modules/messages/native/SearchNotFoundState/index.tsx (1 hunks)
  • packages/components/modules/messages/native/index.ts (1 hunks)
  • packages/components/package.json (1 hunks)
  • packages/design-system/CHANGELOG.md (1 hunks)
  • packages/design-system/components/native/buttons/FabButton/index.tsx (1 hunks)
  • packages/design-system/components/native/buttons/FabButton/styles.ts (1 hunks)
  • packages/design-system/components/native/buttons/FabButton/types.ts (1 hunks)
  • packages/design-system/components/native/buttons/index.ts (1 hunks)
  • packages/design-system/components/native/illustrations/SearchingImage/index.tsx (1 hunks)
  • packages/design-system/components/native/illustrations/SocialMediaDiscussionImage/index.tsx (1 hunks)
  • packages/design-system/components/native/illustrations/index.ts (1 hunks)
  • packages/design-system/components/native/illustrations/types.ts (1 hunks)
  • packages/design-system/components/native/inputs/SearchInput/index.tsx (1 hunks)
  • packages/design-system/components/native/inputs/SearchInput/styles.ts (1 hunks)
  • packages/design-system/components/native/inputs/SearchInput/types.ts (1 hunks)
  • packages/design-system/components/native/inputs/index.ts (1 hunks)
  • packages/design-system/package.json (2 hunks)
  • packages/wagtail/CHANGELOG.md (1 hunks)
  • packages/wagtail/package.json (1 hunks)
✅ Files skipped from review due to trivial changes (1)
  • packages/wagtail/package.json
🚧 Files skipped from review as they are similar to previous changes (25)
  • packages/components/modules/messages/native/RoomsList/RoomsListComponent/constants.ts
  • packages/design-system/CHANGELOG.md
  • packages/components/modules/messages/native/index.ts
  • packages/components/CHANGELOG.md
  • packages/design-system/components/native/inputs/SearchInput/styles.ts
  • packages/design-system/components/native/illustrations/index.ts
  • packages/components/modules/messages/native/RoomsList/RoomsListComponent/types.ts
  • packages/components/modules/shared/native/EmptyView/types.ts
  • packages/components/modules/messages/native/RoomsList/ChatCard/ChatCardComponent/styles.ts
  • packages/components/modules/shared/native/index.ts
  • packages/components/modules/messages/native/RoomsList/types.ts
  • packages/components/modules/messages/native/RoomsList/ChatCard/ChatCardOptions/styles.ts
  • packages/components/modules/messages/native/RoomsList/ChatCard/index.tsx
  • packages/design-system/components/native/inputs/SearchInput/types.ts
  • packages/design-system/components/native/buttons/FabButton/types.ts
  • packages/design-system/components/native/illustrations/types.ts
  • packages/wagtail/CHANGELOG.md
  • packages/design-system/package.json
  • packages/components/modules/messages/native/SearchNotFoundState/index.tsx
  • packages/components/modules/messages/native/RoomsList/RoomsListComponent/styles.ts
  • packages/components/modules/messages/native/RoomsList/ChatCard/ChatCardComponent/index.tsx
  • packages/components/modules/messages/native/RoomsList/ChatCard/ChatCardOptions/index.tsx
  • packages/components/modules/messages/native/RoomsList/ChatCard/ChatCardOptions/type.ts
  • packages/components/modules/messages/native/RoomsList/EmptyChatRoomsState/index.tsx
  • packages/components/package.json
🧰 Additional context used
🧬 Code graph analysis (12)
packages/design-system/components/native/inputs/SearchInput/index.tsx (2)
packages/design-system/components/native/inputs/SearchInput/types.ts (1)
  • SearchInputProps (3-6)
packages/design-system/components/native/inputs/SearchInput/styles.ts (1)
  • createStyles (5-14)
packages/components/modules/messages/native/ChatRooms/styles.ts (1)
packages/components/modules/messages/native/RoomsList/RoomsListComponent/styles.ts (1)
  • createStyles (4-9)
packages/components/modules/messages/native/RoomsList/RoomsListComponent/index.tsx (2)
packages/components/modules/messages/native/RoomsList/types.ts (1)
  • RoomsListProps (3-7)
packages/components/modules/messages/native/RoomsList/RoomsListComponent/constants.ts (1)
  • CHAT_TAB_VALUES (1-6)
packages/components/modules/messages/native/RoomsList/index.tsx (1)
packages/components/modules/messages/native/RoomsList/types.ts (1)
  • RoomsListProps (3-7)
packages/design-system/components/native/buttons/FabButton/index.tsx (2)
packages/design-system/components/native/buttons/FabButton/types.ts (1)
  • FabButtonProps (4-8)
packages/design-system/components/native/buttons/FabButton/styles.ts (1)
  • createStyles (5-26)
packages/design-system/components/native/illustrations/SearchingImage/index.tsx (1)
packages/design-system/components/native/illustrations/types.ts (1)
  • SvgIconProps (3-5)
packages/components/modules/__shared__/native/EmptyView/styles.ts (2)
packages/components/modules/messages/native/ChatRooms/styles.ts (1)
  • createStyles (5-20)
packages/components/modules/messages/native/RoomsList/ChatCard/ChatCardComponent/styles.ts (1)
  • createStyles (5-39)
packages/design-system/components/native/illustrations/SocialMediaDiscussionImage/index.tsx (1)
packages/design-system/components/native/illustrations/types.ts (1)
  • SvgIconProps (3-5)
packages/components/modules/__shared__/native/EmptyView/index.tsx (2)
packages/components/modules/__shared__/native/EmptyView/types.ts (1)
  • EmptyViewProps (5-10)
packages/components/modules/__shared__/native/EmptyView/styles.ts (1)
  • createStyles (5-30)
packages/design-system/components/native/buttons/FabButton/styles.ts (2)
packages/components/modules/messages/native/ChatRooms/styles.ts (1)
  • createStyles (5-20)
packages/components/modules/messages/native/RoomsList/RoomsListComponent/styles.ts (1)
  • createStyles (4-9)
packages/components/modules/messages/native/ChatRooms/index.tsx (3)
packages/components/modules/messages/native/ChatRooms/styles.ts (1)
  • createStyles (5-20)
packages/components/modules/messages/native/RoomsList/RoomsListComponent/constants.ts (2)
  • CHAT_TAB_VALUES (1-6)
  • CHAT_TAB_LABEL (8-13)
packages/utils/hooks/useAppStateSubscription/index.ts (1)
  • useAppStateSubscription (7-23)
packages/components/modules/messages/native/RoomsList/ChatCard/styles.ts (2)
packages/components/modules/messages/native/RoomsList/ChatCard/ChatCardComponent/styles.ts (1)
  • createStyles (5-39)
packages/components/modules/messages/native/RoomsList/RoomsListComponent/styles.ts (1)
  • createStyles (4-9)
🔇 Additional comments (13)
packages/components/modules/messages/native/RoomsList/ChatCard/styles.ts (1)

5-44: LGTM! Well-structured styles with proper theming.

The style definitions are well-organized and follow React Native best practices. The use of theme colors ensures consistency, and the dimensions for profile images (48×48 circular) and notification badges (20×20 circular) are appropriate for a chat list UI.

packages/design-system/components/native/illustrations/SearchingImage/index.tsx (3)

1-6: LGTM! Clean and necessary imports.

The imports are well-organized and all necessary for the component implementation. The use of the shared SvgIconProps type ensures consistency across illustration components.


8-55: LGTM! Well-implemented illustration component.

The component implementation is solid:

  • Properly typed with FC<SvgIconProps> for type safety
  • Theming integration follows design system conventions
  • Color logic correctly handles both the isActive state and custom colors
  • The viewBox="0 0 200 200" aligns with the default dimensions
  • The use of fill="currentColor" on Path elements correctly inherits color from the parent Svg

This follows the established pattern for illustration components in the design system.


57-57: LGTM! Proper default export.

The default export is correct and enables the component to be re-exported by the illustrations index file, as indicated in the AI summary.

packages/design-system/components/native/illustrations/SocialMediaDiscussionImage/index.tsx (1)

1-125: LGTM! Clean implementation following design-system patterns.

The component is well-structured:

  • Props are correctly typed using SvgIconProps
  • Theming integration with useTheme provides consistent color handling
  • The isActive prop correctly switches between primary.high and the default color
  • SVG attributes (width, height, viewBox, color) are properly configured
  • fill="currentColor" on Path elements correctly inherits the color from the parent Svg

The implementation follows the design-system conventions and will integrate seamlessly with the rest of the codebase.

packages/design-system/components/native/inputs/index.ts (1)

4-5: LGTM!

The SearchInput exports follow the established pattern for other input components and correctly expose both the component and its types to the public API.

packages/design-system/components/native/inputs/SearchInput/index.tsx (3)

1-17: LGTM!

The imports and component signature are well-structured and correctly typed against the SearchInputProps interface.


18-24: LGTM!

Theme setup and search icon rendering are correctly implemented with proper memoization.


53-53: LGTM!

The component is correctly wrapped with withNativeController for export.

packages/design-system/components/native/buttons/index.ts (1)

4-4: LGTM!

The FabButton export is correctly added to the public API.

packages/components/modules/__shared__/native/EmptyView/index.tsx (1)

21-25: LGTM!

The optional message rendering is correctly implemented with appropriate null checking and styling.

packages/components/modules/__shared__/native/EmptyView/styles.ts (2)

5-14: LGTM!

The container styling provides appropriate flex layout with centering and spacing.


15-18: Verify layout behavior when icon is absent.

Both imageWrapper and textWrapper have flex: 1, which would normally split space equally. However, since the parent component conditionally renders the imageWrapper (line 14 in index.tsx), the layout should adapt correctly. Please verify that the empty state displays as expected when no icon is provided.

Copy link

@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: 0

🧹 Nitpick comments (1)
packages/design-system/components/native/inputs/SearchInput/constants.ts (1)

1-4: LGTM with a minor naming suggestion.

The constants are well-defined and serve their purpose. The DEFAULT_FORM_VALUES clearly represents initial form state. However, FORM_VALUES with { search: 'search' } reads more like a field name mapping than actual values—consider renaming to FORM_FIELD_NAMES or FORM_FIELDS for clarity.

 export const DEFAULT_FORM_VALUES = { search: '' }
-export const FORM_VALUES = {
+export const FORM_FIELD_NAMES = {
   search: 'search',
 }
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between d853924 and c97b67f.

📒 Files selected for processing (15)
  • packages/components/CHANGELOG.md (1 hunks)
  • packages/components/modules/__shared__/native/EmptyView/index.tsx (1 hunks)
  • packages/components/modules/__shared__/native/EmptyView/styles.ts (1 hunks)
  • packages/components/modules/messages/native/ChatRooms/index.tsx (1 hunks)
  • packages/components/modules/messages/native/RoomsList/ChatCard/ChatCardComponent/index.tsx (1 hunks)
  • packages/components/modules/messages/native/RoomsList/ChatCard/ChatCardOptions/type.ts (1 hunks)
  • packages/components/package.json (1 hunks)
  • packages/design-system/CHANGELOG.md (1 hunks)
  • packages/design-system/components/native/inputs/SearchInput/constants.ts (1 hunks)
  • packages/design-system/components/native/inputs/SearchInput/styles.ts (1 hunks)
  • packages/design-system/components/native/inputs/index.ts (1 hunks)
  • packages/design-system/components/native/tabs/Tab/styles.ts (1 hunks)
  • packages/design-system/package.json (2 hunks)
  • packages/wagtail/CHANGELOG.md (1 hunks)
  • packages/wagtail/package.json (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (11)
  • packages/design-system/CHANGELOG.md
  • packages/components/modules/messages/native/RoomsList/ChatCard/ChatCardOptions/type.ts
  • packages/design-system/package.json
  • packages/components/CHANGELOG.md
  • packages/components/modules/messages/native/RoomsList/ChatCard/ChatCardComponent/index.tsx
  • packages/wagtail/CHANGELOG.md
  • packages/design-system/components/native/inputs/SearchInput/styles.ts
  • packages/components/modules/messages/native/ChatRooms/index.tsx
  • packages/components/modules/shared/native/EmptyView/index.tsx
  • packages/components/package.json
  • packages/wagtail/package.json
🧰 Additional context used
🧬 Code graph analysis (1)
packages/components/modules/__shared__/native/EmptyView/styles.ts (3)
packages/design-system/components/native/inputs/SearchInput/styles.ts (1)
  • createStyles (5-13)
packages/components/modules/messages/native/ChatRooms/styles.ts (1)
  • createStyles (5-20)
packages/components/modules/messages/native/RoomsList/ChatCard/styles.ts (1)
  • createStyles (5-44)
⏰ 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: Analyze (javascript)
  • GitHub Check: Component Test Packages
  • GitHub Check: Build and Lint Packages
🔇 Additional comments (3)
packages/design-system/components/native/inputs/index.ts (1)

4-6: LGTM! Consistent barrel export pattern.

The SearchInput re-exports follow the established pattern used by PasswordInput and TextInput, properly exposing the component, types, and constants through the module's public API.

packages/design-system/components/native/tabs/Tab/styles.ts (1)

8-8: Change is appropriate for equal tab distribution in the new ChatRooms feature.

The flexGrow: 1 property enables tabs to expand equally across available space, which is the intended behavior for the new four-tab chat interface. Verification confirms only one native Tab usage exists in the codebase (the new ChatRooms component), so no breaking changes to existing implementations.

packages/components/modules/__shared__/native/EmptyView/styles.ts (1)

19-26: Previous width issue successfully resolved!

The hard-coded width: 393 has been correctly replaced with maxWidth: '100%', addressing the responsive layout concern raised in the previous review. The layout will now adapt properly across different screen sizes.

Copy link

@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

🧹 Nitpick comments (1)
packages/components/modules/messages/native/RoomsList/RoomsListComponent/index.tsx (1)

59-71: Consider using InfiniteScrollerView for consistency.

As suggested in past reviews, the notifications feature uses InfiniteScrollerView which provides a more consistent pattern for infinite scrolling lists in this codebase. This would also handle the height-based loading (lines 23-28, 65) and end-reached logic (lines 67-69) more elegantly.

Note: Lines 60-66 address previous review concerns about null filtering and key extraction. However, the underlying fragment type mismatch flagged in previous reviews still needs resolution (see earlier comment on lines 16-19).

Based on past review comments. Would you like me to generate a refactor using InfiniteScrollerView based on the notifications pattern?

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between c97b67f and 36dd6d9.

📒 Files selected for processing (6)
  • packages/components/modules/messages/native/ChatRooms/index.tsx (1 hunks)
  • packages/components/modules/messages/native/RoomsList/RoomsListComponent/index.tsx (1 hunks)
  • packages/design-system/components/native/buttons/FabButton/index.tsx (1 hunks)
  • packages/design-system/components/native/illustrations/index.ts (1 hunks)
  • packages/design-system/components/native/inputs/SearchInput/constants.ts (1 hunks)
  • packages/design-system/components/native/inputs/SearchInput/index.tsx (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (4)
  • packages/design-system/components/native/illustrations/index.ts
  • packages/design-system/components/native/inputs/SearchInput/index.tsx
  • packages/components/modules/messages/native/ChatRooms/index.tsx
  • packages/design-system/components/native/buttons/FabButton/index.tsx
🧰 Additional context used
🧬 Code graph analysis (1)
packages/components/modules/messages/native/RoomsList/RoomsListComponent/index.tsx (2)
packages/components/modules/messages/native/RoomsList/types.ts (1)
  • RoomsListProps (3-7)
packages/components/modules/messages/native/RoomsList/RoomsListComponent/constants.ts (1)
  • CHAT_TAB_VALUES (1-6)
⏰ 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). (2)
  • GitHub Check: Component Test Packages
  • GitHub Check: Build and Lint Packages
🔇 Additional comments (1)
packages/design-system/components/native/inputs/SearchInput/constants.ts (1)

1-11: LGTM! Well-structured form constants.

The implementation follows solid TypeScript patterns:

  • as const provides proper type narrowing for the form keys
  • Computed property names ensure type safety between constants and types
  • Clear separation of concerns: constants → types → defaults
  • The pattern is maintainable and extensible for future form fields

Copy link

@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

♻️ Duplicate comments (3)
packages/design-system/components/native/buttons/FabButton/types.ts (1)

1-8: Runtime bundling issue remains unresolved (duplicate).

The value import of Ionicons on line 1 still pulls the icon module into the runtime bundle whenever this types file is imported, as previously flagged. The consumer at packages/design-system/components/native/buttons/FabButton/index.tsx:9 imports FabButtonProps as a value, triggering this bundling side-effect.

Apply one of these fixes:

Option 1 (recommended): Make this file types-only by using an import type expression:

-import { Ionicons } from '@expo/vector-icons'
 import type { TouchableOpacityProps } from 'react-native'

 export interface FabButtonProps extends TouchableOpacityProps {
-  iconName: keyof typeof Ionicons.glyphMap
+  iconName: keyof typeof import('@expo/vector-icons').Ionicons.glyphMap
   iconSize?: number
   iconColor?: string
 }

And ensure the consumer uses a type-only import in packages/design-system/components/native/buttons/FabButton/index.tsx:9:

import type { FabButtonProps } from './types'

Option 2: Keep the current structure but enforce type-only imports at all consumer sites (more fragile).

packages/components/modules/messages/native/RoomsList/RoomsListComponent/index.tsx (2)

17-20: Remove useTransition and fix the unsafe cast.

Two persistent issues:

  1. Line 17: useTransition is for synchronous UI updates, not async operations. Wrapping refetch() in startTransition (line 46) won't track the fetch state; isPending will be unreliable. Use isLoadingNext or add a separate loading flag instead.

  2. Line 19: The as RoomsListFragment$key cast bypasses type safety and has caused pipeline errors in past reviews. The fragment mismatch between what useRoomsList provides and what ChatCard expects needs proper resolution in the type hierarchy.


42-57: Fix dependency array and remove isPending guard.

Two issues:

  1. Line 45: The isPending guard can block refetch when a transition is active, potentially showing stale data on focus.

  2. Line 56: startTransition is used in the callback but missing from dependencies—ESLint's exhaustive-deps would flag this.

Since useTransition shouldn't be used for async operations (see lines 17-20), the entire approach needs revision.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 36dd6d9 and 5ad95fd.

⛔ Files ignored due to path filters (1)
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (3)
  • packages/components/modules/messages/native/RoomsList/RoomsListComponent/index.tsx (1 hunks)
  • packages/design-system/components/native/buttons/FabButton/types.ts (1 hunks)
  • pnpm-workspace.yaml (1 hunks)
🧰 Additional context used
🧠 Learnings (1)
📚 Learning: 2025-04-09T22:06:40.026Z
Learnt from: davidbermudez-tsl
Repo: silverlogic/baseapp-frontend PR: 209
File: packages/components/modules/content-feed/web/ContentFeed/types.ts:1-1
Timestamp: 2025-04-09T22:06:40.026Z
Learning: The empty ContentFeedProps interface in packages/components/modules/content-feed/web/ContentFeed/types.ts will be populated with properties in a future PR rather than being converted to a type alias.

Applied to files:

  • packages/design-system/components/native/buttons/FabButton/types.ts
🧬 Code graph analysis (1)
packages/components/modules/messages/native/RoomsList/RoomsListComponent/index.tsx (2)
packages/components/modules/messages/native/RoomsList/types.ts (1)
  • RoomsListProps (3-7)
packages/components/modules/messages/native/RoomsList/RoomsListComponent/constants.ts (1)
  • CHAT_TAB_VALUES (1-6)
⏰ 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). (2)
  • GitHub Check: Analyze (javascript)
  • GitHub Check: Component Test Packages
🔇 Additional comments (2)
packages/components/modules/messages/native/RoomsList/RoomsListComponent/index.tsx (2)

24-29: LGTM!

The height-based auto-loading logic is well-designed with proper guards.


31-40: LGTM!

Empty state handling logic correctly differentiates between search-not-found and no-rooms scenarios.

Copy link

@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: 0

♻️ Duplicate comments (2)
packages/components/modules/messages/native/RoomsList/RoomsListComponent/index.tsx (2)

19-19: Critical: Remove unsafe type cast — this breaks Relay's type contract.

This unsafe cast as RoomsListFragment$key has been flagged in multiple previous reviews and causes pipeline errors. The fragment type mismatch remains unresolved: targetRef?.me?.profile does not guarantee it satisfies RoomsListFragment$key, and the data passed to ChatCard (node-level fragments) doesn't match what the cast claims.

Impact: Runtime failures when Relay attempts to read fragments, type safety bypass, and CI/CD pipeline errors.

Correct fix: Update the component hierarchy to use proper fragment types:

  1. Ensure the query/fragment selecting targetRef spreads ...RoomsListFragment on the profile
  2. Pass the correctly typed fragment reference without casts
  3. Update ChatCard to accept the actual node fragment keys (LastMessage, Title, UnreadMessagesCount) instead of RoomsListFragment$key
  const { data, loadNext, hasNext, isLoadingNext, refetch } = useRoomsList(
-   targetRef?.me?.profile as RoomsListFragment$key,
+   targetRef?.me?.profile,
  )

Then ensure the parent query includes the fragment spread and ChatCard prop types match the node fragments.


17-17: Major: Remove useTransition — it's designed for synchronous updates, not async operations.

As flagged in previous reviews, useTransition is intended for synchronous state changes in React 18+, not for async operations like refetch. Wrapping refetch() in startTransition provides no benefit, and isPending cannot accurately track async fetch state.

Apply this diff to remove the incorrect pattern:

- const [, startTransition] = useTransition()
  const { data, loadNext, hasNext, isLoadingNext, refetch } = useRoomsList(
    targetRef?.me?.profile as RoomsListFragment$key,
  )
  useFocusEffect(
    useCallback(() => {
      layoutTriggeredRef.current = false
-     startTransition(() => {
-       refetch(
-         {
-           q: searchParam,
-           unreadMessages: selectedTab === CHAT_TAB_VALUES.unread,
-           archived: selectedTab === CHAT_TAB_VALUES.archived,
-         },
-         { fetchPolicy: 'store-and-network' },
-       )
-     })
-   }, [refetch, searchParam, selectedTab, startTransition]),
+     refetch(
+       {
+         q: searchParam,
+         unreadMessages: selectedTab === CHAT_TAB_VALUES.unread,
+         archived: selectedTab === CHAT_TAB_VALUES.archived,
+       },
+       { fetchPolicy: 'store-and-network' },
+     )
+   }, [refetch, searchParam, selectedTab]),
  )

If loading UI is needed during refetch, expose and use a loading/pending state from useRoomsList instead.

Also applies to: 45-54

🧹 Nitpick comments (1)
packages/components/modules/messages/native/RoomsList/RoomsListComponent/index.tsx (1)

58-73: Good improvements to list rendering.

The component now addresses several items from previous reviews:

  • Uses InfiniteScrollerView as suggested by anicioalexandre
  • Properly filters null/undefined edges (line 60)
  • Includes fallback in key extractor (line 66)
  • Uses isLoadingNext consistently for pagination (lines 68, 71)

Optional refinement: Lines 62-63 use non-null assertions after filtering. While technically safe due to the filter, consider using a type guard for better type safety:

  renderItem={({ item }) => {
-   const node = item!.node!
+   if (!item?.node) return null
+   const node = item.node
    return <ChatCard roomRef={node} isArchived={selectedTab === CHAT_TAB_VALUES.archived} />
  }}

This eliminates the assertions and provides explicit null handling.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 5ad95fd and 6f0828e.

📒 Files selected for processing (4)
  • packages/components/modules/messages/native/RoomsList/RoomsListComponent/index.tsx (1 hunks)
  • packages/components/modules/notifications/native/NotificationsList/index.tsx (0 hunks)
  • packages/design-system/components/native/inputs/SearchInput/index.tsx (1 hunks)
  • packages/design-system/components/native/views/InfiniteScrollerView/index.tsx (1 hunks)
💤 Files with no reviewable changes (1)
  • packages/components/modules/notifications/native/NotificationsList/index.tsx
🚧 Files skipped from review as they are similar to previous changes (1)
  • packages/design-system/components/native/inputs/SearchInput/index.tsx
🧰 Additional context used
🧬 Code graph analysis (1)
packages/components/modules/messages/native/RoomsList/RoomsListComponent/index.tsx (2)
packages/components/modules/messages/native/RoomsList/types.ts (1)
  • RoomsListProps (3-7)
packages/components/modules/messages/native/RoomsList/RoomsListComponent/constants.ts (1)
  • CHAT_TAB_VALUES (1-6)
⏰ 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). (2)
  • GitHub Check: Build and Lint Packages
  • GitHub Check: Component Test Packages
🔇 Additional comments (1)
packages/design-system/components/native/views/InfiniteScrollerView/index.tsx (1)

69-69: No performance regression—review comment misidentifies the change.

The original review comment is based on an incorrect assumption. An analysis of the codebase reveals:

  1. estimatedItemSize was never explicitly set in InfiniteScrollerView—it does not appear anywhere in the codebase history.
  2. InfiniteScrollerViewProps fully extends FlashListProps<TItem>, meaning consumers can still pass estimatedItemSize via the spread props (...props).
  3. Line 69's change only affects ListFooterComponent handling, not estimatedItemSize.
  4. Both current consumers (RoomsListComponent and NotificationsList) don't pass estimatedItemSize, indicating it was never part of the component's public API in practice.

There is no breaking change, no performance regression, and no removal of estimatedItemSize.

Likely an incorrect or invalid review comment.

Copy link

@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: 6

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
packages/components/modules/messages/common/graphql/queries/ChatRoomQuery.ts (1)

6-11: Remove redundant fragment spreads and field selections.

The query now has duplicate selections since ChatRoomFragment already spreads TitleFragment and MessagesListFragment (lines 13-14 of ChatRoom.ts) and selects id, isArchived, and participantsCount (lines 5, 7, 12 of ChatRoom.ts). While GraphQL merges duplicates, this redundancy reduces maintainability.

Apply this diff to remove the redundant direct selections:

   query ChatRoomQuery($roomId: ID!) {
     chatRoom(id: $roomId) {
-      id
-      isArchived
-      participantsCount
-      ...TitleFragment
-      ...MessagesListFragment
       ...ChatRoomFragment
     }
   }
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 07e30ce and b5768a1.

📒 Files selected for processing (6)
  • packages/components/modules/messages/common/graphql/fragments/ChatRoom.ts (1 hunks)
  • packages/components/modules/messages/common/graphql/queries/ChatRoomQuery.ts (1 hunks)
  • packages/components/modules/messages/native/RoomsList/ChatCard/ChatCardComponent/index.tsx (1 hunks)
  • packages/components/modules/messages/native/RoomsList/ChatCard/ChatCardComponent/type.ts (1 hunks)
  • packages/components/modules/messages/native/RoomsList/ChatCard/index.tsx (1 hunks)
  • packages/components/modules/messages/native/RoomsList/RoomsListComponent/index.tsx (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • packages/components/modules/messages/native/RoomsList/ChatCard/index.tsx
🧰 Additional context used
🧠 Learnings (1)
📚 Learning: 2025-04-09T22:06:40.026Z
Learnt from: davidbermudez-tsl
Repo: silverlogic/baseapp-frontend PR: 209
File: packages/components/modules/content-feed/web/ContentFeed/types.ts:1-1
Timestamp: 2025-04-09T22:06:40.026Z
Learning: The empty ContentFeedProps interface in packages/components/modules/content-feed/web/ContentFeed/types.ts will be populated with properties in a future PR rather than being converted to a type alias.

Applied to files:

  • packages/components/modules/messages/native/RoomsList/ChatCard/ChatCardComponent/type.ts
🧬 Code graph analysis (2)
packages/components/modules/messages/native/RoomsList/RoomsListComponent/index.tsx (2)
packages/components/modules/messages/native/RoomsList/types.ts (1)
  • RoomsListProps (3-7)
packages/components/modules/messages/native/RoomsList/RoomsListComponent/constants.ts (1)
  • CHAT_TAB_VALUES (1-6)
packages/components/modules/messages/native/RoomsList/ChatCard/ChatCardComponent/index.tsx (5)
packages/components/modules/messages/native/RoomsList/ChatCard/ChatCardComponent/type.ts (1)
  • ChatCardComponentProps (5-8)
packages/components/modules/messages/native/RoomsList/ChatCard/styles.ts (1)
  • createStyles (5-44)
packages/components/modules/messages/common/graphql/mutations/ArchiveChatRoom.ts (1)
  • useArchiveChatRoomMutation (24-63)
packages/components/modules/messages/common/utils.ts (1)
  • useNameAndAvatar (53-58)
packages/utils/functions/date/index.ts (1)
  • formatRelativeTime (33-60)
⏰ 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: Analyze (javascript)
  • GitHub Check: Component Test Packages
  • GitHub Check: Build and Lint Packages
🔇 Additional comments (7)
packages/components/modules/messages/common/graphql/fragments/ChatRoom.ts (1)

1-16: LGTM! Well-structured fragment definition.

The ChatRoomFragment is properly defined with appropriate field selections and fragment composition. The use of @refetchable enables efficient data refetching.

packages/components/modules/messages/native/RoomsList/RoomsListComponent/index.tsx (2)

24-40: LGTM — helper functions are well-structured.

The loadNextBasedOnHeight and handleEmptyState helpers are clear and correctly handle their respective responsibilities.


58-73: LGTM — list rendering is robust.

The filtering of null edges/nodes (line 60), fallback key extraction (line 66), and pagination guard using isLoadingNext (line 68) all follow best practices and address previous review concerns.

packages/components/modules/messages/native/RoomsList/ChatCard/ChatCardComponent/index.tsx (4)

1-28: LGTM — imports are clean and well-organized.

All dependencies are properly imported and relevant to the component's functionality.


30-37: LGTM — component setup follows best practices.

The hooks are initialized correctly, and the archive mutation is properly wired with the current profile.


52-81: LGTM — derived state and core handlers are well-implemented.

The name/avatar derivation, unread logic, navigation, bottom sheet, and archive mutation handler are all correctly structured.


127-139: LGTM — bottom sheet options are properly wired.

The ChatCardOptions component is correctly integrated with all necessary props and handlers.

Comment on lines +39 to +50
const lastMessageFragment = useFragment<LastMessageFragment$key>(
LastMessageFragment,
roomRef as unknown as LastMessageFragment$key,
)
const headerFragment = useFragment<TitleFragment$key>(
TitleFragment,
roomRef as unknown as TitleFragment$key,
)
const unreadMessagesCountFragment = useFragment<UnreadMessagesCountFragment$key>(
UnreadMessagesCountFragment,
roomRef as unknown as UnreadMessagesCountFragment$key,
)
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

Remove unsafe type casts — they bypass Relay's type safety.

The three useFragment calls use as unknown as casts to force incompatible types. This is a code smell that indicates the roomRef prop type is incorrect (it should be an intersection, not a union — see the comment on type.ts).

Once you fix the prop type in type.ts (line 6) to use intersection (&), remove all three casts:

- const lastMessageFragment = useFragment<LastMessageFragment$key>(
+ const lastMessageFragment = useFragment(
     LastMessageFragment,
-    roomRef as unknown as LastMessageFragment$key,
+    roomRef,
   )
- const headerFragment = useFragment<TitleFragment$key>(
+ const headerFragment = useFragment(
     TitleFragment,
-    roomRef as unknown as TitleFragment$key,
+    roomRef,
   )
- const unreadMessagesCountFragment = useFragment<UnreadMessagesCountFragment$key>(
+ const unreadMessagesCountFragment = useFragment(
     UnreadMessagesCountFragment,
-    roomRef as unknown as UnreadMessagesCountFragment$key,
+    roomRef,
   )

Committable suggestion skipped: line range outside the PR's diff.

🤖 Prompt for AI Agents
In
packages/components/modules/messages/native/RoomsList/ChatCard/ChatCardComponent/index.tsx
around lines 39 to 50, the three useFragment calls currently use unsafe "as
unknown as" casts because the roomRef prop type is incorrect; update the roomRef
prop's type in type.ts (around line 6) from a union to an intersection (use &
instead of |) so it carries all fragment refs, then remove the three casts from
these useFragment calls so each call receives the correctly typed roomRef
directly; ensure any related imports/types are updated so the file compiles
without the forced casts.

Comment on lines 83 to 98
const handleMarkAsUnread = () => {
alert('Mark as Unread functionality not implemented yet.')
bottomDrawerRef.current?.close()
}
const handleChatDetails = () => {
alert('Chat Details functionality not implemented yet.')
bottomDrawerRef.current?.close()
}
const handleGoToProfile = () => {
alert('Go to Profile functionality not implemented yet.')
bottomDrawerRef.current?.close()
}
const handleDeleteChat = () => {
alert('Delete Chat functionality not implemented yet.')
bottomDrawerRef.current?.close()
}
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Replace placeholder alert() calls with proper implementations or remove handlers.

Four handlers (handleMarkAsUnread, handleChatDetails, handleGoToProfile, handleDeleteChat) use alert() placeholders and are not functional. Either implement them or remove them from the options menu to avoid a degraded user experience.

Do you want me to help scaffold these implementations, or would you prefer to remove these options from the UI until they're ready?

import { UnreadMessagesCountFragment$key } from '../../../../../../__generated__/UnreadMessagesCountFragment.graphql'

export interface ChatCardComponentProps {
roomRef: LastMessageFragment$key | TitleFragment$key | UnreadMessagesCountFragment$key
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

Fix fragment type — use intersection (&), not union (|).

The roomRef must satisfy all three fragment keys simultaneously because ChatCardComponent calls useFragment three times on the same reference (lines 39–50 in index.tsx). A union type (A | B | C) means "one of these," but you need an intersection (A & B & C) meaning "all of these."

Apply this diff:

 export interface ChatCardComponentProps {
-  roomRef: LastMessageFragment$key | TitleFragment$key | UnreadMessagesCountFragment$key
+  roomRef: LastMessageFragment$key & TitleFragment$key & UnreadMessagesCountFragment$key
   isArchived: boolean
 }
📝 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
roomRef: LastMessageFragment$key | TitleFragment$key | UnreadMessagesCountFragment$key
export interface ChatCardComponentProps {
roomRef: LastMessageFragment$key & TitleFragment$key & UnreadMessagesCountFragment$key
isArchived: boolean
}
🤖 Prompt for AI Agents
In
packages/components/modules/messages/native/RoomsList/ChatCard/ChatCardComponent/type.ts
around line 6, the roomRef type is declared as a union of fragment keys but must
be an intersection so the same reference satisfies all three fragments; change
the type from "LastMessageFragment$key | TitleFragment$key |
UnreadMessagesCountFragment$key" to "LastMessageFragment$key & TitleFragment$key
& UnreadMessagesCountFragment$key" so useFragment calls on the same ref compile
correctly.

@@ -0,0 +1,76 @@
import { FC, useCallback, useRef, useTransition } from 'react'
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Remove useTransition — it's unnecessary for async operations and isPending is unused.

React's useTransition is designed for synchronous state updates to mark them as non-blocking transitions, not for async operations like refetch. Wrapping refetch() in startTransition (line 45) provides no benefit, and the isPending flag (line 17) won't accurately reflect the fetch state. Additionally, including startTransition in the dependency array (line 55) is unnecessary.

Apply this diff:

-import { FC, useCallback, useRef, useTransition } from 'react'
+import { FC, useCallback, useRef } from 'react'
 const RoomsListComponent: FC<RoomsListProps> = ({ targetRef, searchParam, selectedTab }) => {
-  const [, startTransition] = useTransition()
   const { data, loadNext, hasNext, isLoadingNext, refetch } = useRoomsList(
   useFocusEffect(
     useCallback(() => {
       layoutTriggeredRef.current = false
-      startTransition(() => {
-        refetch(
-          {
-            q: searchParam,
-            unreadMessages: selectedTab === CHAT_TAB_VALUES.unread,
-            archived: selectedTab === CHAT_TAB_VALUES.archived,
-          },
-          { fetchPolicy: 'store-and-network' },
-        )
-      })
-    }, [refetch, searchParam, selectedTab, startTransition]),
+      refetch(
+        {
+          q: searchParam,
+          unreadMessages: selectedTab === CHAT_TAB_VALUES.unread,
+          archived: selectedTab === CHAT_TAB_VALUES.archived,
+        },
+        { fetchPolicy: 'store-and-network' },
+      )
+    }, [refetch, searchParam, selectedTab]),
   )

Also applies to: 17-17, 45-54, 55-55

🤖 Prompt for AI Agents
In
packages/components/modules/messages/native/RoomsList/RoomsListComponent/index.tsx
(lines 1, 17, 45-54, 55), remove useTransition usage: delete the import of
useTransition, remove the isPending variable, stop wrapping refetch() in
startTransition and instead call refetch() directly, and remove startTransition
from any dependency arrays; ensure no other references to
startTransition/isPending remain so the component compiles.

const RoomsListComponent: FC<RoomsListProps> = ({ targetRef, searchParam, selectedTab }) => {
const [, startTransition] = useTransition()
const { data, loadNext, hasNext, isLoadingNext, refetch } = useRoomsList(
targetRef?.me?.profile as RoomsListFragment$key,
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Remove unsafe cast to RoomsListFragment$key.

The cast on line 19 bypasses TypeScript's type checking and may cause runtime errors if the fragment reference is incompatible. Verify that targetRef?.me?.profile provides the correct fragment key type expected by useRoomsList, and remove the cast.

If useRoomsList expects a different fragment type than what targetRef.me.profile provides, update the GraphQL query or fragment spreads in the parent component to ensure type compatibility.

Copy link

@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: 0

♻️ Duplicate comments (2)
packages/components/modules/messages/native/RoomsList/ChatCard/ChatCardComponent/index.tsx (2)

39-50: Remove unsafe type casts by fixing the prop type to use intersection.

The three as unknown as casts bypass Relay's type safety and indicate the roomRef prop type is incorrect. As flagged in the previous review, ChatCardComponentProps.roomRef should be an intersection (&) rather than a union (|) so that roomRef carries all three fragment keys simultaneously.

Step 1: Update the type definition in packages/components/modules/messages/native/RoomsList/ChatCard/ChatCardComponent/type.ts (around line 5):

 export interface ChatCardComponentProps {
-  roomRef: LastMessageFragment$key | TitleFragment$key | UnreadMessagesCountFragment$key
+  roomRef: LastMessageFragment$key & TitleFragment$key & UnreadMessagesCountFragment$key
   isArchived: boolean
 }

Step 2: Remove the casts from this file:

- const lastMessageFragment = useFragment<LastMessageFragment$key>(
+ const lastMessageFragment = useFragment(
     LastMessageFragment,
-    roomRef as unknown as LastMessageFragment$key,
+    roomRef,
   )
- const headerFragment = useFragment<TitleFragment$key>(
+ const headerFragment = useFragment(
     TitleFragment,
-    roomRef as unknown as TitleFragment$key,
+    roomRef,
   )
- const unreadMessagesCountFragment = useFragment<UnreadMessagesCountFragment$key>(
+ const unreadMessagesCountFragment = useFragment(
     UnreadMessagesCountFragment,
-    roomRef as unknown as UnreadMessagesCountFragment$key,
+    roomRef,
   )

Based on learnings


83-94: Implement or remove the placeholder handlers.

As flagged in the previous review, these four handlers (handleMarkAsUnread, handleChatDetails, handleGoToProfile, handleDeleteChat) only close the drawer without performing their intended actions. This creates a degraded user experience where menu options appear functional but do nothing.

Options:

  1. Remove these options from the ChatCardOptions menu until they're implemented.
  2. Implement the functionality for each handler.

Do you want me to help scaffold these implementations, or would you prefer to open an issue to track this work and temporarily remove the non-functional menu items?

🧹 Nitpick comments (3)
packages/components/modules/messages/native/ChatRooms/index.tsx (3)

33-35: Consider extracting form configuration to follow team patterns.

Per the earlier feedback, the team pattern is to extract default values, field names, and schema validation to a separate constants.ts file (similar to the AccountSettings example referenced). While DEFAULT_FORM_VALUES and FORM_VALUES are already imported from the SearchInput module, housing the full form setup (including any validation schema if added later) in a local constants file would improve consistency and maintainability.

Based on learnings


52-55: Remove redundant setValue call—reset already handles it.

Calling setValue(FORM_VALUES.search, DEFAULT_FORM_VALUES.search) before reset(DEFAULT_FORM_VALUES) is redundant because reset will set all fields to their default values.

Apply this diff:

 const resetInput = () => {
-  setValue(FORM_VALUES.search, DEFAULT_FORM_VALUES.search)
   reset(DEFAULT_FORM_VALUES)
 }

90-106: Consider removing the unreachable Groups tab or adding a disabled tab button.

The Tabs component renders Active, Unread, and Archived tabs but omits the Groups tab, even though lines 109–111 handle CHAT_TAB_VALUES.groups. This makes the Groups tab completely inaccessible in the UI. Either add a disabled Groups tab button with a tooltip explaining it's coming soon, or remove the groups-check logic entirely until the feature is implemented.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between b5768a1 and 1967742.

📒 Files selected for processing (3)
  • packages/components/modules/messages/common/graphql/queries/ChatRoomQuery.ts (1 hunks)
  • packages/components/modules/messages/native/ChatRooms/index.tsx (1 hunks)
  • packages/components/modules/messages/native/RoomsList/ChatCard/ChatCardComponent/index.tsx (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • packages/components/modules/messages/common/graphql/queries/ChatRoomQuery.ts
🧰 Additional context used
🧠 Learnings (1)
📚 Learning: 2025-02-11T13:55:04.375Z
Learnt from: pt-tsl
Repo: silverlogic/baseapp-frontend PR: 212
File: packages/components/modules/messages/MessagesList/index.tsx:80-80
Timestamp: 2025-02-11T13:55:04.375Z
Learning: Avoid using non-null assertions (!.) in TypeScript code unless there's absolute certainty about non-nullability. Instead, prefer handling null types inside the relevant functions/hooks and use optional chaining (?.) for safer access.

Applied to files:

  • packages/components/modules/messages/native/RoomsList/ChatCard/ChatCardComponent/index.tsx
🧬 Code graph analysis (2)
packages/components/modules/messages/native/RoomsList/ChatCard/ChatCardComponent/index.tsx (5)
packages/components/modules/messages/native/RoomsList/ChatCard/ChatCardComponent/type.ts (1)
  • ChatCardComponentProps (5-8)
packages/components/modules/messages/native/RoomsList/ChatCard/ChatCardComponent/styles.ts (1)
  • createStyles (5-39)
packages/components/modules/messages/common/graphql/mutations/ArchiveChatRoom.ts (1)
  • useArchiveChatRoomMutation (24-63)
packages/components/modules/messages/common/utils.ts (1)
  • useNameAndAvatar (53-58)
packages/utils/functions/date/index.ts (1)
  • formatRelativeTime (33-60)
packages/components/modules/messages/native/ChatRooms/index.tsx (5)
packages/components/modules/messages/native/ChatRooms/styles.ts (1)
  • createStyles (5-20)
packages/design-system/components/native/inputs/SearchInput/constants.ts (3)
  • SearchInputFormValues (5-7)
  • DEFAULT_FORM_VALUES (9-11)
  • FORM_VALUES (1-3)
packages/components/modules/messages/native/RoomsList/RoomsListComponent/constants.ts (2)
  • CHAT_TAB_VALUES (1-6)
  • CHAT_TAB_LABEL (8-13)
packages/components/modules/messages/native/RoomsList/RoomsListComponent/types.ts (1)
  • ChatTabValues (5-5)
packages/utils/hooks/useAppStateSubscription/index.ts (1)
  • useAppStateSubscription (7-23)
⏰ 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: Component Test Packages
  • GitHub Check: Build and Lint Packages
  • GitHub Check: Unit Test Packages
🔇 Additional comments (7)
packages/components/modules/messages/native/ChatRooms/index.tsx (4)

107-118: LGTM—conditional rendering is clear and includes a TODO.

The conditional logic correctly routes to a placeholder for Groups and renders RoomsList for other tabs. The TODO comment provides clear context for future work.


125-135: LGTM—Suspense fallback requirement satisfied.

The fallback prop is now properly provided with a LoadingScreen, resolving the TypeScript compile error flagged in the previous review.


57-58: No action needed—empty connections array is intentional.

The empty array is a consistent pattern across all callers in the codebase (native/ChatRooms, web/AllChatRoomsList, web/GroupChatEdit). Real-time updates to the rooms list happen via the updater function in getRoomListSubscriptionConfig, not through Relay connection edge updates. This is the correct architectural design.


46-50: I need to verify the actual SearchInput component implementation to fully assess the concern. Let me query the codebase for the implementation:

Based on my research, I need to clarify a critical issue with the original review comment. The function passed to startTransition is not delayed—unlike browser setTimeout, it does not run later. React executes your function immediately, but any state updates scheduled while it is running are marked as Transitions. This means that wrapping setValue in startTransition does NOT cause input lag as the review implies.

Because startTransition() wraps the setState function, React gives this state updating code a lower priority, ensuring that the input field remains responsive and responds to keystrokes instantly. This is the correct pattern for search/filter scenarios.

However, without access to the SearchInput component implementation in the codebase, I cannot definitively verify whether passing both control (from react-hook-form) and onChangeText creates redundancy or conflicts. The review comment's core concern about input lag is technically incorrect, but there may still be a valid concern about unnecessary complexity or double updates if both props are being used.


Likely an incorrect or invalid review comment.

packages/components/modules/messages/native/RoomsList/ChatCard/ChatCardComponent/index.tsx (3)

30-37: LGTM—component initialization is clean.

The setup correctly extracts roomId, initializes the drawer ref, and retrieves the mutation hook and current profile.


52-58: LGTM—data derivation logic is correct.

The component properly extracts title, avatar, last message details, and unread status from the fragment data.


68-81: LGTM—archive handler is properly implemented.

The handler correctly guards against null values, toggles the archive state, and commits the mutation with the appropriate variables.

@sonarqubecloud
Copy link

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.

3 participants