Skip to content

Conversation

@tsl-ps2
Copy link
Collaborator

@tsl-ps2 tsl-ps2 commented Jan 2, 2025

Changes

  • Introduces a GroupDetails component
  • Introduces a EditGroup component
  • The shared components between GroupEdit and GroupCreate are extracted and moved to a __shared__ folder
  • Graphql requests for querying the group details and editing the group are added
  • Props like displayChatRoomsList were replaced with props like onBackButtonClicked or onValidSubmission: The create chat components do not need to know how the "navigation" (which is also lives on the template, not the packages!) between different components is implemented.
  • I also displayed relay errors for fields which are null or the empty string. I couldn't see a reason why this would not be desired.

Group Details page - Title Access -5

  • Given I have the group chat selected, when I click on the group name on the title bar, then I should navigate to the group details page.
  • Given I am a member of a group chat, when I navigate to the group details page, then I should see the group name, profile picture, a list of members, and the current admin(s).
  • Given the group has a large number of members, when I navigate to the group details page, then I should be able to scroll through the member list.
    • use infinite scroller
  • I should be able to edit the group name and profile pic of the group.

Guardrails

  • We are showing the list of members but we wont work on behaviors like removing members, give admin permissions, etc.

Summary by CodeRabbit

Release Notes

  • New Features

    • Added group details view with member list and pagination.
    • Introduced ability to edit group details, including title and image.
    • Enhanced chat room header with improved group information display.
    • Added admin options for managing group participants.
    • Implemented a new component for editing group title and image.
  • Improvements

    • Refined chat room creation and management workflows.
    • Updated GraphQL schema to support more detailed chat room updates.
    • Improved error handling and form validation mechanisms.
    • Enhanced participant role management within chat rooms.
  • Bug Fixes

    • Resolved issues with participant count and chat room header rendering.

@changeset-bot
Copy link

changeset-bot bot commented Jan 2, 2025

⚠️ No Changeset found

Latest commit: 1399b42

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 Jan 2, 2025

Warning

Rate limit exceeded

@tsl-ps2 has exceeded the limit for the number of commits or files that can be reviewed per hour. Please wait 6 minutes and 21 seconds before requesting another review.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

📥 Commits

Reviewing files that changed from the base of the PR and between 9d982a0 and 1399b42.

📒 Files selected for processing (14)
  • packages/authentication/CHANGELOG.md (1 hunks)
  • packages/authentication/package.json (1 hunks)
  • packages/components/CHANGELOG.md (1 hunks)
  • packages/components/package.json (1 hunks)
  • packages/design-system/CHANGELOG.md (1 hunks)
  • packages/design-system/package.json (1 hunks)
  • packages/graphql/CHANGELOG.md (1 hunks)
  • packages/graphql/package.json (1 hunks)
  • packages/provider/CHANGELOG.md (1 hunks)
  • packages/provider/package.json (1 hunks)
  • packages/utils/CHANGELOG.md (1 hunks)
  • packages/utils/package.json (1 hunks)
  • packages/wagtail/CHANGELOG.md (1 hunks)
  • packages/wagtail/package.json (1 hunks)

Walkthrough

This pull request introduces significant enhancements to the messaging module's components, focusing on group chat management, editing, and details display. The changes span multiple files across the messages module, introducing new components like EditGroup, GroupDetails, and EditGroupTitleAndImage. The modifications improve user interaction by adding more flexible props, refactoring state management, and introducing new GraphQL queries and mutations for chat room updates.

Changes

File Change Summary
packages/components/modules/messages/ChatRoom/ChatRoomHeader/index.tsx Updated props to include onDisplayGroupDetailsClicked, modified component structure
packages/components/modules/messages/ChatRoom/index.tsx Added onDisplayGroupDetailsClicked prop
packages/components/modules/messages/CreateGroup/* Refactored props, replaced state management with callback functions
packages/components/modules/messages/EditGroup/* New component for editing group details with comprehensive form handling
packages/components/modules/messages/GroupDetails/* New components for displaying group details with member list and pagination
packages/components/messages/graphql/mutations/UpdateChatRoom.ts New mutation for updating chat room details
packages/components/schema.graphql Added new input and payload types for chat room updates

Sequence Diagram

sequenceDiagram
    participant User
    participant ChatRoomHeader
    participant GroupDetails
    participant EditGroup
    
    User->>ChatRoomHeader: Click Group Details
    ChatRoomHeader->>GroupDetails: Open Group Details View
    User->>GroupDetails: Click Edit Group
    GroupDetails->>EditGroup: Open Edit Group Form
    User->>EditGroup: Update Group Details
    EditGroup->>GroupDetails: Save Changes
    GroupDetails->>ChatRoomHeader: Update Header
Loading

Possibly related PRs

Suggested Reviewers

  • Ronan-Fernandes
  • anicioalexandre
  • pt-tsl

Poem

🐰 Hop, hop, through the code we go,
Messaging magic starts to flow
Groups get details, titles shine bright
Relay mutations take their flight
A rabbit's dance of UI delight! 🌟


Thank you for using CodeRabbit. We offer it for free to the OSS community and would appreciate your support in helping us grow. If you find it useful, would you consider giving us a shout-out on your favorite social media?

❤️ Share
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Generate unit testing code for this file.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai generate unit testing code for this file.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and generate unit testing code.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR. (Beta)
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

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: 3

🧹 Nitpick comments (19)
packages/utils/functions/form/setFormRelayErrors/index.ts (1)

24-24: Consider broader null checks and user expectations.

Currently, the condition checks if form.getValues(errorField) is not undefined. If there are scenarios where null or other falsy values (like an empty string) should still trigger an error, you may want to handle those explicitly. Otherwise, this updated check is stricter than the previous truthy-based condition, which helps avoid setting errors for non-existent fields.

packages/utils/functions/form/setFormRelayErrors/_tests_/setFormRelayErrors.test.ts (1)

40-55: Well-structured test for null or blank fields.

This new test thoroughly validates how errors are set for fields that can be null or blank. As a future enhancement, you might consider adding a case for undefined fields to confirm consistent handling under all possible field states.

packages/components/modules/messages/CreateChatRoomList/ChatRoomListItem/types.ts (1)

5-5: Prefer descriptive callback naming for better readability.
Using onChatCreation is good. Consider ensuring consistent naming across the codebase, such as onCreateChatRoom, to align with domain terminology.

packages/components/modules/messages/graphql/mutations/UpdateChatRoom.ts (1)

24-50: Robust error handling in custom hook.
Great approach for auto-handling errors. Consider logging them or providing additional context for more precise debugging (e.g., correlation IDs) if the application’s architecture supports it.

packages/components/modules/messages/ChatRoom/ChatRoomHeader/index.tsx (2)

15-15: Centralize utility imports.
The getParticipantCountString function is used here. If more utility functions for formatting or display logic are added, consider grouping them into a dedicated file or directory (if not already done).


50-67: Refine layout for participant info.
Displaying group name and member count is intuitive. If future requirements expand, consider placing group stats and actions (e.g., “Add Member”) in a well-structured layout.

packages/components/schema.graphql (2)

183-183: Consider using an enum for the role field.

The role field in ChatRoomParticipant type is defined as a String, which could lead to inconsistent values. Consider defining an enum type (e.g., ChatRoomParticipantRole) with predefined values like "ADMIN", "MEMBER", etc.

-  role: String
+  """Role of the participant in the chat room"""
+  role: ChatRoomParticipantRole

And add the enum type:

"""An enumeration."""
enum ChatRoomParticipantRole {
  """Administrator of the chat room"""
  ADMIN
  """Regular member of the chat room"""
  MEMBER
}

273-281: Add descriptions to input fields.

The input type looks good and supports the group editing functionality well. Consider adding descriptions to document the purpose of each field.

input ChatRoomUpdateInput {
+  """ID of the chat room to update"""
  roomId: ID!
+  """ID of the profile performing the update"""
  profileId: ID!
+  """List of participant IDs to add to the chat room"""
  addParticipants: [ID]
+  """Whether to delete the chat room's image"""
  deleteImage: Boolean
+  """List of participant IDs to remove from the chat room"""
  removeParticipants: [ID]
+  """New title for the chat room"""
  title: String
  clientMutationId: String
}
packages/components/modules/messages/__shared__/EditGroupTitleAndImage/constants.tsx (1)

1-4: Consider a more flexible configuration approach for image limits.

Using hardcoded constants is fine for now, but if these values need to be changed dynamically or vary by environment, consider loading them from config or environment variables.

packages/components/modules/messages/__shared__/EditGroupTitleAndImage/types.ts (2)

1-2: Consider avoiding the generic any type.

The second generic in Control<TitleAndImage, any> is set to any. This can weaken type safety. You might consider specifying a more precise type, if possible, to ensure more robust static analysis.


14-17: Allow further extension of TitleAndImage.

The union type for image is flexible. However, if there’s a known set of file-like objects used in your app, consider narrowing the type or providing a discriminating approach to avoid potential runtime mishandling.

packages/components/modules/messages/EditGroup/types.ts (1)

15-20: Refine participant array type.

any[] for addParticipants and removeParticipants might obscure the actual participant shape. If you have a well-defined participant interface, consider replacing any[] with a more specific type to improve clarity and type safety.

packages/components/modules/messages/CreateGroup/constants.ts (1)

11-12: Address the inline comment about using [FORM_VALUE.title].

If dynamic key access is preferred, you could do something like:

export const DEFAULT_FORM_VALUES: CreateGroupUpload = {
  [FORM_VALUE.title]: '',
  [FORM_VALUE.participants]: [],
  [FORM_VALUE.image]: '',
}

However, your current approach is a valid, more direct access pattern. Either way, keep it consistent across your application.

packages/components/modules/messages/CreateGroup/index.tsx (1)

178-181: Graceful image removal
Clearing errors and resetting the image field to null is straightforward and aligns with a typical react-hook-form usage pattern. Verify that any placeholders or UI elements correctly handle the null state for the image.

packages/components/modules/messages/GroupDetails/index.tsx (2)

34-43: Consider adding error handling for pagination.

Currently, when loadNext is invoked, there is no dedicated error handling logic in place. While this might be acceptable in some contexts, it could be beneficial to detect and handle potential errors (e.g., a network failure) to enhance user experience and resilience.

You could, for instance, wrap the loadNext call with a try/catch or integrate Relay’s built-in error boundary to surface errors gracefully.


81-119: UI fallback for empty group title or missing data.

While the code is likely guarded by Suspense’s data requirements, consider verifying that you gracefully handle scenarios where group?.title might be null or undefined. This ensures robust UI display in edge cases (e.g., newly created group without a title).

packages/components/modules/messages/GroupDetails/GroupDetailsHeader/index.tsx (1)

23-25: Consider i18n support for user-facing text.

“Group View” is hardcoded. If your application supports multiple locales, consider using a translation library like i18n for better localization.

packages/components/modules/messages/GroupDetails/ProfileCard/index.tsx (2)

14-14: Consider removing the FC type for simplicity.
Although using FC is not inherently wrong, some TypeScript guidelines recommend regular function declarations or arrow functions without FC for cleaner, more flexible typings.


50-51: Localize user-facing text for improved internationalization.
The 'Admin' text is displayed directly. If your project supports i18n, consider localizing it to accommodate users in different locales.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 6c8666c and 8f55aa6c25abcf96bd43fbb67d531013e8fea060.

⛔ Files ignored due to path filters (14)
  • packages/components/__generated__/ChatRoomHeaderFragment.graphql.ts is excluded by !**/__generated__/**
  • packages/components/__generated__/ChatRoomMessagesListPaginationQuery.graphql.ts is excluded by !**/__generated__/**
  • packages/components/__generated__/ChatRoomParticipantsPaginationQuery.graphql.ts is excluded by !**/__generated__/**
  • packages/components/__generated__/ChatRoomQuery.graphql.ts is excluded by !**/__generated__/**
  • packages/components/__generated__/ChatRoomsQuery.graphql.ts is excluded by !**/__generated__/**
  • packages/components/__generated__/CreateChatRoomMutation.graphql.ts is excluded by !**/__generated__/**
  • packages/components/__generated__/GroupDetailsQuery.graphql.ts is excluded by !**/__generated__/**
  • packages/components/__generated__/MembersListFragment.graphql.ts is excluded by !**/__generated__/**
  • packages/components/__generated__/MessagesListFragment.graphql.ts is excluded by !**/__generated__/**
  • packages/components/__generated__/ReadMessagesMutation.graphql.ts is excluded by !**/__generated__/**
  • packages/components/__generated__/UpdateChatRoomMutation.graphql.ts is excluded by !**/__generated__/**
  • packages/components/__generated__/chatRoomsPaginationQuery.graphql.ts is excluded by !**/__generated__/**
  • packages/components/__generated__/useMessageCountUpdateSubscription.graphql.ts is excluded by !**/__generated__/**
  • packages/components/__generated__/useRoomListSubscription.graphql.ts is excluded by !**/__generated__/**
📒 Files selected for processing (43)
  • packages/components/modules/messages/ChatRoom/ChatRoomHeader/index.tsx (1 hunks)
  • packages/components/modules/messages/ChatRoom/ChatRoomHeader/styled.tsx (1 hunks)
  • packages/components/modules/messages/ChatRoom/ChatRoomHeader/types.ts (1 hunks)
  • packages/components/modules/messages/ChatRoom/ChatRoomHeader/utils.ts (0 hunks)
  • packages/components/modules/messages/ChatRoom/index.tsx (2 hunks)
  • packages/components/modules/messages/ChatRoom/types.ts (1 hunks)
  • packages/components/modules/messages/CreateChatRoomList/ChatRoomListItem/index.tsx (2 hunks)
  • packages/components/modules/messages/CreateChatRoomList/ChatRoomListItem/types.ts (1 hunks)
  • packages/components/modules/messages/CreateChatRoomList/index.tsx (3 hunks)
  • packages/components/modules/messages/CreateChatRoomList/types.ts (2 hunks)
  • packages/components/modules/messages/CreateGroup/constants.ts (1 hunks)
  • packages/components/modules/messages/CreateGroup/index.tsx (7 hunks)
  • packages/components/modules/messages/CreateGroup/styled.tsx (0 hunks)
  • packages/components/modules/messages/CreateGroup/types.ts (2 hunks)
  • packages/components/modules/messages/EditGroup/constants.ts (1 hunks)
  • packages/components/modules/messages/EditGroup/index.tsx (1 hunks)
  • packages/components/modules/messages/EditGroup/styled.tsx (1 hunks)
  • packages/components/modules/messages/EditGroup/types.ts (1 hunks)
  • packages/components/modules/messages/GroupDetails/GroupDetailsHeader/index.tsx (1 hunks)
  • packages/components/modules/messages/GroupDetails/GroupDetailsHeader/styled.tsx (1 hunks)
  • packages/components/modules/messages/GroupDetails/GroupDetailsHeader/types.ts (1 hunks)
  • packages/components/modules/messages/GroupDetails/ProfileCard/index.tsx (1 hunks)
  • packages/components/modules/messages/GroupDetails/ProfileCard/styled.tsx (1 hunks)
  • packages/components/modules/messages/GroupDetails/ProfileCard/types.ts (1 hunks)
  • packages/components/modules/messages/GroupDetails/index.tsx (1 hunks)
  • packages/components/modules/messages/GroupDetails/styled.tsx (1 hunks)
  • packages/components/modules/messages/GroupDetails/types.ts (1 hunks)
  • packages/components/modules/messages/__shared__/EditGroupTitleAndImage/constants.tsx (1 hunks)
  • packages/components/modules/messages/__shared__/EditGroupTitleAndImage/index.tsx (1 hunks)
  • packages/components/modules/messages/__shared__/EditGroupTitleAndImage/styled.tsx (1 hunks)
  • packages/components/modules/messages/__shared__/EditGroupTitleAndImage/types.ts (1 hunks)
  • packages/components/modules/messages/__shared__/index.ts (1 hunks)
  • packages/components/modules/messages/graphql/mutations/CreateChatRoom.ts (0 hunks)
  • packages/components/modules/messages/graphql/mutations/UpdateChatRoom.ts (1 hunks)
  • packages/components/modules/messages/graphql/queries/ChatRoomHeaderFragment.ts (1 hunks)
  • packages/components/modules/messages/graphql/queries/GroupDetailsQuery.ts (1 hunks)
  • packages/components/modules/messages/graphql/queries/MembersList.ts (1 hunks)
  • packages/components/modules/messages/graphql/queries/MessagesList.ts (0 hunks)
  • packages/components/modules/messages/index.ts (1 hunks)
  • packages/components/modules/messages/utils.ts (2 hunks)
  • packages/components/schema.graphql (3 hunks)
  • packages/utils/functions/form/setFormRelayErrors/_tests_/setFormRelayErrors.test.ts (2 hunks)
  • packages/utils/functions/form/setFormRelayErrors/index.ts (1 hunks)
💤 Files with no reviewable changes (4)
  • packages/components/modules/messages/CreateGroup/styled.tsx
  • packages/components/modules/messages/graphql/mutations/CreateChatRoom.ts
  • packages/components/modules/messages/ChatRoom/ChatRoomHeader/utils.ts
  • packages/components/modules/messages/graphql/queries/MessagesList.ts
✅ Files skipped from review due to trivial changes (1)
  • packages/components/modules/messages/GroupDetails/styled.tsx
🧰 Additional context used
🪛 Biome (1.9.4)
packages/components/modules/messages/GroupDetails/GroupDetailsHeader/types.ts

[error] 2-2: Don't use '{}' as a type.

Prefer explicitly define the object shape. '{}' means "any non-nullable value".

(lint/complexity/noBannedTypes)


[error] 3-3: Don't use '{}' as a type.

Prefer explicitly define the object shape. '{}' means "any non-nullable value".

(lint/complexity/noBannedTypes)

packages/components/modules/messages/GroupDetails/types.ts

[error] 16-16: Don't use '{}' as a type.

Prefer explicitly define the object shape. '{}' means "any non-nullable value".

(lint/complexity/noBannedTypes)


[error] 17-17: Don't use '{}' as a type.

Prefer explicitly define the object shape. '{}' means "any non-nullable value".

(lint/complexity/noBannedTypes)

packages/components/modules/messages/EditGroup/index.tsx

[error] 57-57: Avoid the delete operator which can impact performance.

Unsafe fix: Use an undefined assignment instead.

(lint/performance/noDelete)

🔇 Additional comments (64)
packages/utils/functions/form/setFormRelayErrors/_tests_/setFormRelayErrors.test.ts (1)

14-16: Great addition for handling null and empty string fields.

Defining these default values in mockForm ensures that the subsequent tests accurately emulate real-world scenarios where some fields may be null or blank.

packages/components/modules/messages/CreateChatRoomList/types.ts (1)

17-18: Event handlers improve flexibility and decouple internal state from parent components.
These new props (onChatCreation and onGroupChatCreationButtonClicked) are a cleaner approach than passing around setState functions.

packages/components/modules/messages/CreateChatRoomList/ChatRoomListItem/index.tsx (2)

17-17: Swapping out setState in favor of callbacks streamlines component interactions.
Replacing setIsInExistingChatRoomsView with the onChatCreation callback is a welcome change, improving modularity.


57-57: Verify any fallback or error-handling approach for the mutation flow.
Currently, onCompleted is set to onChatCreation. Verify no additional logic is necessary to handle error states or partial completions.

packages/components/modules/messages/CreateChatRoomList/index.tsx (3)

32-33: Great shift away from setState to callbacks.
Replacing setIsInExistingChatRoomsView and setIsInGroupChatCreation with these event handlers (onChatCreation, onGroupChatCreationButtonClicked) is more flexible and clean.


87-87: Ensure onChatCreation aligns consistently with the item’s usage.
onChatCreation passed to the list item is cohesive with the newly introduced callback approach. No issues found.


132-132: Confirm follow-up logic for group creation flows.
Invoking onGroupChatCreationButtonClicked from the container is clear. Verify that subsequent steps (e.g., transition, group ID retrieval) are handled downstream.

packages/components/modules/messages/ChatRoom/ChatRoomHeader/types.ts (3)

1-2: Import statement aligns well with current usage.
The new import from '@mui/material' is appropriate for leveraging MUI's BoxProps in the subsequent interface.


7-8: New prop for displaying group details is clear and well-defined.
The onDisplayGroupDetailsClicked callback is succinct and straightforward, which is good for code readability and maintainability.


10-11: New interface extends BoxProps cleanly.
The ChatTitleContainerProps with an isClickable boolean neatly enforces the clickable nature of the container without bundling too many concerns.

packages/components/modules/messages/ChatRoom/types.ts (1)

12-12: Callback for displaying group details is well introduced.
Adding onDisplayGroupDetailsClicked to the ChatRoomProps interface keeps responsibility clear and makes the codebase more modular.

packages/components/modules/messages/graphql/queries/ChatRoomHeaderFragment.ts (2)

5-6: Added id and updated image dimensions.
Including the id field enhances clarity for referencing chat rooms. The updated image dimensions (144 × 144) are consistent with typical UI avatar sizing.


11-12: Pagination and total count now available for participants.
Limiting participants to the first 5 helps manage data requests, and introducing a totalCount field improves the ability to display or paginate participants.

packages/components/modules/messages/ChatRoom/ChatRoomHeader/styled.tsx (4)

4-5: New import for typed props is coherent.
Importing ChatTitleContainerProps from ./types aligns types with implementation, ensuring better maintainability.


10-11: Reduced gap to 0 and simplified grid columns.
Switching to 'min-content 1fr' for ChatHeaderContainer appropriately accommodates the new layout. Just verify whether the zero gap meets all design requirements.


20-31: New ChatTitleContainer fosters flexibility.
The styled container with optional isClickable is a neat approach. This separation of display concerns from logic is good for maintainability.


33-35: BackButtonContainer refines layout.
Providing a dedicated container for the back button ensures consistent spacing. This is a solid UI practice.

packages/components/modules/messages/utils.ts (2)

15-15: Ensure consistent fallback messages.
The updated error message is concise and user-friendly; however, confirm that this fallback scenario won't mask potential edge cases for non-group chats without participants.


28-33: Return type clarity for getParticipantCountString.
When participantCount is null or undefined, the function returns undefined. Callers must handle this case gracefully; otherwise, it might result in displaying no text instead of a user-friendly fallback.

packages/components/modules/messages/graphql/mutations/UpdateChatRoom.ts (1)

7-22: Confirm granular update fields in the GraphQL schema.
This mutation references ChatRoomUpdateInput. Ensure relevant GraphQL fields (e.g., title, image, membership changes) are included so that future updates don’t require schema changes.

packages/components/modules/messages/ChatRoom/index.tsx (2)

24-24: Prop naming alignment.
onDisplayGroupDetailsClicked is expressive. Ensure naming consistency across the codebase so that related callbacks follow similar patterns (e.g., “onXxxClicked”).


45-48: Single responsibility for managing group details click.
This prop is simply forwarded to the header component. Confirm that parent components correctly handle navigation or modal opening for group details to maintain a clear component boundary.

packages/components/modules/messages/ChatRoom/ChatRoomHeader/index.tsx (4)

19-22: Flexible typing for new prop.
The new onDisplayGroupDetailsClicked callback is optional but recommended for group chats. Ensuring it’s typed as optional (or required only in the context of group chats) can help prevent misuse.


29-30: Avoid confusion for 1-member groups.
The returned string from getParticipantCountString may read “1 members.” Please verify the logic to display singular vs. plural text is correct for edge cases.


36-44: Responsiveness is well-handled.
Using useResponsive to conditionally render the back button is a clean approach. Keep ensuring that mobile vs. desktop rendering states remain consistent with design specs.


46-49: Click handler for group vs. direct chat.
Applying onDisplayGroupDetailsClicked only if roomHeader.isGroup is a great approach to avoid triggering irrelevant logic in direct chats. Just confirm the parent is aware that this callback won’t be fired in direct chats.

packages/components/schema.graphql (2)

283-289: LGTM! Well-structured payload type.

The payload type follows best practices with proper error handling and debug support.


671-671: LGTM! Mutation is properly integrated.

The chatRoomUpdate mutation is well-placed and follows the established pattern of other mutations in the schema.

packages/components/modules/messages/__shared__/index.ts (1)

1-2: Good use of re-exports for a cleaner import structure.

No issues found here. Keeping your imports consolidated under a single export file improves maintainability within the codebase.

packages/components/modules/messages/EditGroup/styled.tsx (1)

4-10: Grid-based layout looks concise and maintainable.

This styled component is straightforward and adheres to MUI best practices. No concerns.

packages/components/modules/messages/__shared__/EditGroupTitleAndImage/styled.tsx (1)

4-11: Responsive layout appears well-structured.

The grid setup with centered items and spacing from the theme is a good pattern for consistent styling. No issues detected.

packages/components/modules/messages/__shared__/EditGroupTitleAndImage/types.ts (1)

3-12: Great definition of form-related props.

The interface cleanly captures various form-related functionalities (like control, setValue, etc.) for react-hook-form, making the component’s contract clear. Keep it consistent with your form-handling approach in other components.

packages/components/modules/messages/EditGroup/types.ts (1)

7-13: Interface structure looks solid.

Your EditGroupProps concisely defines the necessary query reference, callbacks, and a roomId. Using PropsWithChildren is a good approach for flexible child components.

packages/components/modules/messages/CreateGroup/constants.ts (2)

3-3: Import naming fix is correct.

Switching to CreateGroupUpload ensures type consistency throughout the codebase. Good alignment with the interface name.


5-5: Enforces a well-defined mapping.

FORM_VALUE acts as a helpful reference for form field names, ensuring consistency in validation and default values. This is a good practice, especially when referencing fields across multiple parts of the codebase.

packages/components/modules/messages/EditGroup/constants.ts (3)

5-10: Well-organized mapping usage.

Defining FORM_VALUE with Record<keyof EditGroupUpload, keyof EditGroupUpload> ensures type correctness between your domain model and form fields. Nicely done.


12-20: Function getDefaultFormValues is helpful.

This read-friendly approach provides a single source for initializing form data. It avoids repetition and keeps defaults consistent across usage locations.


22-27: Validation schema coverage is excellent.

Each field is validated, preventing empty titles and ensuring arrays are used for participants. This thoroughness reduces the likelihood of runtime errors and ensures a better user experience.

packages/components/modules/messages/CreateGroup/types.ts (2)

17-18: Good practice in naming callbacks

The introduction of onValidSubmission and onBackButtonClicked as event handler props is consistent and clear. This positively improves the readability and consistency in how callback props are named. Good job!


23-23: Optional participants property

Making participants optional (participants?: any[]) is a good design choice since it allows more flexibility. If there's a scenario where participants aren't required, it prevents extraneous data handling.

packages/components/modules/messages/index.ts (2)

19-20: Exporting EditGroup

Exporting EditGroup and its types here allows for easier external usage. This maintains a consistent pattern of centralizing exports for your messaging-related components.


22-23: Exporting GroupDetails

Likewise, providing a single place to import GroupDetails and its types from is beneficial for code organization and discoverability across the codebase.

packages/components/modules/messages/__shared__/EditGroupTitleAndImage/index.tsx (3)

12-21: Compositional approach for image and title editing

Great approach to encapsulate image and title editing within a dedicated component. This promotes reusability and reduces clutter in higher-level components.


26-75: Key validations and constraints

You handle image upload, error states, and label changes effectively. This design keeps the component robust and user-friendly, neatly reflecting the image state transitions.


77-77: Clean default export

Exporting EditGroupTitleAndImage as default is straightforward and aligns with the rest of the architecture in the PR.

packages/components/modules/messages/EditGroup/index.tsx (3)

26-30: Concise form initialization

Using getDefaultFormValues along with zodResolver(DEFAULT_FORM_VALIDATION) keeps the form's defaults neatly organized and validated. This separation of concerns (constants + validation) simplifies maintenance.


93-113: Header structure is intuitive

This layout with a cancel button on the left, a title in the center, and a submit action (or loading state) on the right, is a clear and standard approach to editing flows. This significantly aids user experience.


81-88: Robust image removal flow

Clearing errors first and then resetting the image field ensures a reliable flow when removing selected images from the form state.

packages/components/modules/messages/CreateGroup/index.tsx (7)

20-20: Good import usage for shared functionality
Utilizing EditGroupTitleAndImage from ../__shared__ helps keep group image/title editing logic reusable and consistent across different components.


38-39: Ensure prop usage consistency
By introducing onValidSubmission and onBackButtonClicked in lieu of local state setters, the component logic becomes more flexible and decoupled. Make sure callers of CreateGroup provide these props correctly to avoid runtime errors.


79-82: Potential undefined participants
You’ve handled the possibility of participants being undefined by defaulting to an empty array ((participants || [])). Good practice! Just ensure that the rest of your code also safely handles these cases, especially within advanced use cases.


84-84: Conditional check on image upload
Checking if (FORM_VALUE.image in dirtyValues && image && typeof image !== 'string') is a clear approach for verifying whether an image was updated and is a file rather than a URL. Make sure that any external usage of image also accounts for string vs. non-string types.


110-110: Confirmation callback
Calling onValidSubmission() triggers the parent component’s success flow. This is consistent with typical prop-driven component patterns.


193-193: Use descriptive aria-label
Using the aria-label “cancel group creation” clarifies the button’s purpose to screen readers, improving accessibility. Good job!


209-218: Delegating group title and image editing
Incorporating EditGroupTitleAndImage centralizes all logic for editing the group’s main attributes. Passing react-hook-form’s props (control, setValue, trigger, watch) into a shared component is a great way to ensure consistent validation. Confirm that these form references are used carefully to avoid potential synchronization issues in large forms.

packages/components/modules/messages/GroupDetails/index.tsx (2)

64-79: Efficient list rendering approach looks good.

The usage of Virtuoso for rendering the member list and the item render function is a solid approach for large datasets. The incremental fetching logic also ensures a smooth user experience.


122-138: Suspense usage is appropriately structured.

The SuspendedGroupDetails wraps the main component and supplies a header/loading fallback. This approach ensures a clean user experience and a clear separation of concerns for loading states.

packages/components/modules/messages/GroupDetails/ProfileCard/types.ts (1)

3-6: Props interface is nicely typed.

Defining a clear interface with typed fields increases maintainability and prevents usage errors in the consuming component.

packages/components/modules/messages/graphql/queries/GroupDetailsQuery.ts (1)

1-14: Query definition appears valid.

The GraphQL query is properly constructed, retrieving necessary chat room details, image, and participant fragment. Everything looks consistent with Relay patterns.

packages/components/modules/messages/GroupDetails/GroupDetailsHeader/styled.tsx (1)

4-15: Clean use of Material-UI styling system.

The responsive design approach with breakpoints is well-structured and consistent with theming best practices.

packages/components/modules/messages/GroupDetails/ProfileCard/styled.tsx (1)

1-17: Consistent styling approach.

Your usage of the theme’s spacing, breakpoints, and grid layout is consistent and clean. This layout should work well with responsive requirements.

packages/components/modules/messages/graphql/queries/MembersList.ts (1)

1-25: Looks good with Relay pagination.

The pagination pattern here aligns well with Relay best practices, and the fragment includes all necessary fields for members’ data. Good job!

packages/components/modules/messages/GroupDetails/ProfileCard/index.tsx (2)

19-19: Validate the need for key prop in this single-instance component.
Unless you are rendering multiple ProfileCard components in a list or dynamic context, the key prop in <MainContainer key={profile-${id}}> is not strictly necessary. Consider removing it if this is always a standalone component to avoid confusion.


35-37: Consider XSS safety if urlPath.path is user-generated.
If urlPath.path originates from user input, ensure that it undergoes the proper sanitization before string interpolation to avoid potential cross-site scripting issues.

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/utils/CHANGELOG.md (1)

3-8: Enhance changelog entry with more details.

While the changelog entry correctly documents the change, it would be more helpful to include:

  • Definition of what constitutes a "blank" field (e.g., empty string, whitespace-only)
  • The previous behavior for comparison
  • The motivation behind this change
  • Example scenarios where this enhancement is beneficial

This additional context would help developers understand the impact and proper usage of this change.

Consider expanding the entry like this:

 ## 3.0.6

 ### Patch Changes

-Display form relay errors also on null and blank fields
+Display form relay errors also on null and blank fields (empty string or whitespace-only).
+Previously, form relay errors were only displayed for null fields, which could lead to
+inconsistent error handling in forms. This change ensures consistent error display
+across all empty field scenarios, improving form validation feedback.
+
+Example scenarios:
+- Empty string input: ""
+- Whitespace-only input: "   "
+- Null value: null
packages/components/CHANGELOG.md (1)

7-7: Enhance the changelog entry with more details.

The current description "Group details and group edit pages added" is too brief. Consider expanding it to include the key features implemented, such as:

  • Addition of GroupDetails and EditGroup components
  • Implementation of infinite scroll for member list
  • Extraction of shared components to __shared__ folder
  • Addition of group profile picture and name editing capabilities
-- Group details and group edit pages added
+- Added group details and edit functionality:
+  - New GroupDetails component for viewing group information
+  - New EditGroup component for modifying group settings
+  - Infinite scroll implementation for member lists
+  - Extracted shared components to __shared__ folder
+  - Added group profile picture and name editing capabilities
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 8f55aa6c25abcf96bd43fbb67d531013e8fea060 and 003efb45ecea8dc90536011378230fb7f98cd670.

📒 Files selected for processing (14)
  • packages/authentication/CHANGELOG.md (1 hunks)
  • packages/authentication/package.json (1 hunks)
  • packages/components/CHANGELOG.md (1 hunks)
  • packages/components/package.json (1 hunks)
  • packages/design-system/CHANGELOG.md (1 hunks)
  • packages/design-system/package.json (1 hunks)
  • packages/graphql/CHANGELOG.md (1 hunks)
  • packages/graphql/package.json (1 hunks)
  • packages/provider/CHANGELOG.md (1 hunks)
  • packages/provider/package.json (1 hunks)
  • packages/utils/CHANGELOG.md (1 hunks)
  • packages/utils/package.json (1 hunks)
  • packages/wagtail/CHANGELOG.md (1 hunks)
  • packages/wagtail/package.json (1 hunks)
✅ Files skipped from review due to trivial changes (12)
  • packages/components/package.json
  • packages/provider/package.json
  • packages/authentication/package.json
  • packages/graphql/CHANGELOG.md
  • packages/design-system/package.json
  • packages/utils/package.json
  • packages/wagtail/package.json
  • packages/design-system/CHANGELOG.md
  • packages/graphql/package.json
  • packages/wagtail/CHANGELOG.md
  • packages/authentication/CHANGELOG.md
  • packages/provider/CHANGELOG.md
🔇 Additional comments (1)
packages/components/CHANGELOG.md (1)

9-12: Verify dependency version compatibility.

The dependencies have been updated to specific versions. Let's verify these updates are necessary and compatible.

✅ Verification successful

Let me gather more specific information about the dependency usage in these files.


Dependencies are correctly configured as peer dependencies with workspace versioning

The verification shows that:

  1. The packages are properly set up as peer dependencies using workspace versioning (workspace:*)
  2. The dependencies are actively used across group-related components with clear import patterns
  3. The version updates in CHANGELOG.md reflect changes in the workspace packages, which is expected for interdependent modules

Since the packages are using workspace versioning (workspace:*), the specific versions mentioned in the CHANGELOG.md are automatically managed by the workspace system, ensuring compatibility between packages.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Check if the dependency updates are related to the group details feature
# and if there are any compatibility issues between the versions.

# Check package.json files for these dependencies
echo "Checking package.json files for dependency declarations:"
fd -e json -x jq -r '.dependencies | select(."@baseapp-frontend/utils" or ."@baseapp-frontend/authentication" or ."@baseapp-frontend/design-system" or ."@baseapp-frontend/graphql")'

# Look for imports of these packages in the new group-related components
echo -e "\nChecking usage of updated dependencies in group-related code:"
rg -l "@baseapp-frontend/(utils|authentication|design-system|graphql)" | grep -i "group"

Length of output: 1561


Script:

#!/bin/bash
# Check the actual imports from these packages in group-related files
echo "Checking specific imports from updated dependencies in group-related files:"
rg -A 1 "from '@baseapp-frontend/(utils|authentication|design-system|graphql)" packages/components/modules/messages/GroupDetails/ packages/components/modules/messages/CreateGroup/

# Check package.json for current versions
echo -e "\nChecking current package versions:"
cat packages/components/package.json | jq '.dependencies'

# Check for any peer dependencies
echo -e "\nChecking peer dependencies:"
cat packages/components/package.json | jq '.peerDependencies'

Length of output: 3653

@tsl-ps2 tsl-ps2 changed the title BA-2024 group details page BA-2024: group details page Jan 3, 2025
@tsl-ps2 tsl-ps2 force-pushed the BA-2024-group-details-page-frontend-packages branch from 003efb4 to 26c2262 Compare January 10, 2025 15:46
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 (13)
packages/components/modules/messages/GroupDetails/GroupDetailsHeader/types.ts (1)

1-5: Consider strengthening prop type dependencies.

When shouldDisplayEditButton is true, onEditButtonClicked should be required. Consider using a discriminated union type to enforce this relationship:

type BaseGroupDetailsHeaderProps = {
  onBackButtonClicked: () => void;
};

type EditableGroupDetailsHeaderProps = BaseGroupDetailsHeaderProps & {
  shouldDisplayEditButton: true;
  onEditButtonClicked: () => void;
};

type NonEditableGroupDetailsHeaderProps = BaseGroupDetailsHeaderProps & {
  shouldDisplayEditButton: false;
  onEditButtonClicked?: never;
};

export type GroupDetailsHeaderProps = EditableGroupDetailsHeaderProps | NonEditableGroupDetailsHeaderProps;

This ensures that:

  • When shouldDisplayEditButton is true, onEditButtonClicked must be provided
  • When shouldDisplayEditButton is false, onEditButtonClicked cannot be provided
🧰 Tools
🪛 Biome (1.9.4)

[error] 2-2: Don't use '{}' as a type.

Prefer explicitly define the object shape. '{}' means "any non-nullable value".

(lint/complexity/noBannedTypes)


[error] 3-3: Don't use '{}' as a type.

Prefer explicitly define the object shape. '{}' means "any non-nullable value".

(lint/complexity/noBannedTypes)

packages/components/schema.graphql (1)

183-183: Consider using an enum for the role field.

The role field in ChatRoomParticipant is defined as a String type. Consider using an enum type (like ProfileRoles) to ensure consistent role values across the application.

-  role: String
+  role: ChatRoomRoles

And add the enum type:

enum ChatRoomRoles {
  """admin"""
  ADMIN
  """member"""
  MEMBER
}
packages/components/modules/messages/CreateChatRoomList/index.tsx (1)

Line range hint 108-108: Consider implementing a dynamic height calculation.

The current hard-coded height calculation (calc(100vh - 72px - 57px - 61px - 72px)) is brittle and may break if header heights change. Consider using a more dynamic approach.

Would you like me to propose a more robust solution using:

  1. CSS Grid/Flexbox for automatic height distribution
  2. ResizeObserver for dynamic height calculations
  3. CSS custom properties (variables) for maintaining header heights in one place
packages/components/modules/messages/ChatRoom/ChatRoomHeader/index.tsx (1)

46-67: Consider some UI/UX improvements.

While the implementation is solid, here are some suggestions to enhance the component:

  1. The aria-label could be more descriptive for better accessibility
  2. Consider moving inline styles to styled components
  3. The float/clear layout approach could be replaced with flexbox or grid for better maintainability

Here's a suggested improvement:

 <ChatTitleContainer
   onClick={roomHeader.isGroup ? onDisplayGroupDetailsClicked : undefined}
   isClickable={roomHeader.isGroup}
 >
   <AvatarWithPlaceholder
-    className="self-start justify-self-center"
     width={32}
     height={32}
     src={avatar}
-    sx={{ border: 'none', alignSelf: 'center' }}
   />
   <Box>
-    <Typography component="span" variant="subtitle2" sx={{ float: 'left', clear: 'left' }}>
+    <Typography component="span" variant="subtitle2">
       {title}
     </Typography>
     {roomHeader.isGroup && (
-      <Typography component="span" variant="caption" sx={{ float: 'left', clear: 'left' }}>
+      <Typography component="span" variant="caption">
         {members}
       </Typography>
     )}
   </Box>
 </ChatTitleContainer>

And update the styled components:

// in styled.tsx
export const ChatTitleContainer = styled(Box)<{ isClickable?: boolean }>`
  display: flex;
  gap: 8px;
  align-items: center;
  cursor: ${({ isClickable }) => (isClickable ? 'pointer' : 'default')};

  ${Typography} {
    display: block;
  }

  ${AvatarWithPlaceholder} {
    border: none;
  }
`;
packages/components/modules/messages/GroupDetails/types.ts (1)

21-21: Consider using more specific types for VirtuosoProps.

The any type in VirtuosoProps<any, any> could be replaced with more specific types to improve type safety.

Consider defining specific types for the data and context generics of VirtuosoProps based on your usage in the component:

-  VirtuosoProps?: Partial<VirtuosoProps<any, any>>
+  VirtuosoProps?: Partial<VirtuosoProps<GroupMembersEdge, unknown>>
packages/components/modules/messages/GroupDetails/index.tsx (3)

64-79: Optimize Virtuoso list rendering performance.

Consider the following optimizations for the virtualized list:

  1. Add overscan prop to pre-render items outside the viewport.
  2. Memoize the itemContent callback to prevent unnecessary re-renders.

Apply these optimizations:

+ const memoizedItemContent = useCallback(
+   (_index: number, item: GroupMembersEdge) => renderItem(item),
+   [renderItem]
+ )

  const renderMembers = () => (
    <Virtuoso
      data={members?.edges}
-     itemContent={(_index, item: GroupMembersEdge) => renderItem(item)}
+     itemContent={memoizedItemContent}
+     overscan={200}
      style={{ scrollbarWidth: 'none' }}
      components={{
        Footer: renderLoadingState,
      }}

101-112: Enhance accessibility for the members list section.

The members list section could benefit from improved ARIA attributes and landmarks.

Apply these accessibility enhancements:

- <Box role="list" aria-label="group members">
+ <Box 
+   role="region"
+   aria-labelledby="members-heading"
+ >
    <Typography
+     id="members-heading"
      variant="subtitle2"
      color="text.primary"

95-97: Internationalize member count text.

The member count text should be internationalized to support multiple languages.

Consider using your i18n solution:

  <Typography variant="body2" color="text.secondary">
-   {members?.totalCount} member{members?.totalCount !== 1 ? 's' : ''}
+   {t('groupDetails.memberCount', { count: members?.totalCount })}
  </Typography>
packages/components/modules/messages/EditGroup/constants.ts (1)

25-28: Consider strengthening the validation schema.

The current validation schema accepts any type for addParticipants, removeParticipants, and image. Consider:

  • Restricting participants arrays to contain only valid participant objects
  • Adding image file type and size validation
 export const DEFAULT_FORM_VALIDATION = z.object({
   [FORM_VALUE.title]: z.string().min(1, { message: 'Please enter a title' }),
-  [FORM_VALUE.addParticipants]: z.array(z.any()),
-  [FORM_VALUE.removeParticipants]: z.array(z.any()),
-  [FORM_VALUE.image]: z.any(),
+  [FORM_VALUE.addParticipants]: z.array(z.object({
+    id: z.string(),
+    // Add other required participant fields
+  })),
+  [FORM_VALUE.removeParticipants]: z.array(z.object({
+    id: z.string(),
+    // Add other required participant fields
+  })),
+  [FORM_VALUE.image]: z.union([
+    z.instanceof(File),
+    z.instanceof(Blob),
+    z.string(),
+    z.null()
+  ]),
 })
packages/components/modules/messages/__shared__/EditGroupTitleAndImage/index.tsx (2)

39-41: Add error message localization.

The error message is hardcoded. Consider using a localization system for better internationalization support.


69-71: Consider debouncing the validation trigger.

The validation is triggered on every keyup event, which might cause unnecessary re-renders for large forms.

import { debounce } from 'lodash'

// Add this before the return statement
const debouncedTrigger = useMemo(
  () => debounce((name: string) => trigger(name), 300),
  [trigger]
)

// Use in the TextField
onKeyUp={() => debouncedTrigger(FORM_VALUE.title)}
packages/components/modules/messages/EditGroup/index.tsx (1)

69-79: Enhance error handling in mutation response.

The error handling could be more informative to users.

 onCompleted: (response) => {
   const errors = response?.chatRoomUpdate?.errors
   if (errors) {
-    sendToast('Something went wrong', { type: 'error' })
+    const errorMessage = errors.map(e => e.message).join('. ')
+    sendToast(errorMessage || 'Failed to update group', { type: 'error' })
     setFormRelayErrors(formReturn, errors)
   } else {
+    sendToast('Group updated successfully', { type: 'success' })
     onValidSubmission()
   }
 },
packages/components/modules/messages/CreateGroup/index.tsx (1)

Line range hint 115-127: Consider debouncing the search functionality.

The search triggers a refetch on every input change, which could lead to unnecessary API calls.

const debouncedRefetch = useMemo(
  () => debounce((query: string) => refetch({ q: query }), 300),
  [refetch]
)

const handleSearchChange: ChangeEventHandler<HTMLInputElement> = (e) => {
  const value = e.target.value || ''
  startTransition(() => {
    debouncedRefetch(value)
  })
}
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 003efb45ecea8dc90536011378230fb7f98cd670 and 26c2262.

⛔ Files ignored due to path filters (13)
  • packages/components/__generated__/ChatRoomHeaderFragment.graphql.ts is excluded by !**/__generated__/**
  • packages/components/__generated__/ChatRoomMessagesListPaginationQuery.graphql.ts is excluded by !**/__generated__/**
  • packages/components/__generated__/ChatRoomParticipantsPaginationQuery.graphql.ts is excluded by !**/__generated__/**
  • packages/components/__generated__/ChatRoomQuery.graphql.ts is excluded by !**/__generated__/**
  • packages/components/__generated__/ChatRoomsQuery.graphql.ts is excluded by !**/__generated__/**
  • packages/components/__generated__/CreateChatRoomMutation.graphql.ts is excluded by !**/__generated__/**
  • packages/components/__generated__/GroupDetailsQuery.graphql.ts is excluded by !**/__generated__/**
  • packages/components/__generated__/MembersListFragment.graphql.ts is excluded by !**/__generated__/**
  • packages/components/__generated__/MessagesListFragment.graphql.ts is excluded by !**/__generated__/**
  • packages/components/__generated__/ReadMessagesMutation.graphql.ts is excluded by !**/__generated__/**
  • packages/components/__generated__/UpdateChatRoomMutation.graphql.ts is excluded by !**/__generated__/**
  • packages/components/__generated__/chatRoomsPaginationQuery.graphql.ts is excluded by !**/__generated__/**
  • packages/components/__generated__/useRoomListSubscription.graphql.ts is excluded by !**/__generated__/**
📒 Files selected for processing (44)
  • packages/components/modules/messages/ChatRoom/ChatRoomHeader/index.tsx (1 hunks)
  • packages/components/modules/messages/ChatRoom/ChatRoomHeader/styled.tsx (1 hunks)
  • packages/components/modules/messages/ChatRoom/ChatRoomHeader/types.ts (1 hunks)
  • packages/components/modules/messages/ChatRoom/ChatRoomHeader/utils.ts (0 hunks)
  • packages/components/modules/messages/ChatRoom/index.tsx (2 hunks)
  • packages/components/modules/messages/ChatRoom/types.ts (1 hunks)
  • packages/components/modules/messages/CreateChatRoomList/ChatRoomListItem/index.tsx (2 hunks)
  • packages/components/modules/messages/CreateChatRoomList/ChatRoomListItem/types.ts (1 hunks)
  • packages/components/modules/messages/CreateChatRoomList/index.tsx (3 hunks)
  • packages/components/modules/messages/CreateChatRoomList/types.ts (2 hunks)
  • packages/components/modules/messages/CreateGroup/constants.ts (1 hunks)
  • packages/components/modules/messages/CreateGroup/index.tsx (7 hunks)
  • packages/components/modules/messages/CreateGroup/styled.tsx (0 hunks)
  • packages/components/modules/messages/CreateGroup/types.ts (2 hunks)
  • packages/components/modules/messages/EditGroup/constants.ts (1 hunks)
  • packages/components/modules/messages/EditGroup/index.tsx (1 hunks)
  • packages/components/modules/messages/EditGroup/styled.tsx (1 hunks)
  • packages/components/modules/messages/EditGroup/types.ts (1 hunks)
  • packages/components/modules/messages/GroupDetails/GroupDetailsHeader/index.tsx (1 hunks)
  • packages/components/modules/messages/GroupDetails/GroupDetailsHeader/styled.tsx (1 hunks)
  • packages/components/modules/messages/GroupDetails/GroupDetailsHeader/types.ts (1 hunks)
  • packages/components/modules/messages/GroupDetails/ProfileCard/index.tsx (1 hunks)
  • packages/components/modules/messages/GroupDetails/ProfileCard/styled.tsx (1 hunks)
  • packages/components/modules/messages/GroupDetails/ProfileCard/types.ts (1 hunks)
  • packages/components/modules/messages/GroupDetails/index.tsx (1 hunks)
  • packages/components/modules/messages/GroupDetails/styled.tsx (1 hunks)
  • packages/components/modules/messages/GroupDetails/types.ts (1 hunks)
  • packages/components/modules/messages/MessagesList/index.tsx (0 hunks)
  • packages/components/modules/messages/__shared__/EditGroupTitleAndImage/constants.tsx (1 hunks)
  • packages/components/modules/messages/__shared__/EditGroupTitleAndImage/index.tsx (1 hunks)
  • packages/components/modules/messages/__shared__/EditGroupTitleAndImage/styled.tsx (1 hunks)
  • packages/components/modules/messages/__shared__/EditGroupTitleAndImage/types.ts (1 hunks)
  • packages/components/modules/messages/__shared__/index.ts (1 hunks)
  • packages/components/modules/messages/graphql/mutations/CreateChatRoom.ts (0 hunks)
  • packages/components/modules/messages/graphql/mutations/UpdateChatRoom.ts (1 hunks)
  • packages/components/modules/messages/graphql/queries/ChatRoomHeaderFragment.ts (1 hunks)
  • packages/components/modules/messages/graphql/queries/GroupDetailsQuery.ts (1 hunks)
  • packages/components/modules/messages/graphql/queries/MembersList.ts (1 hunks)
  • packages/components/modules/messages/graphql/queries/MessagesList.ts (0 hunks)
  • packages/components/modules/messages/index.ts (1 hunks)
  • packages/components/modules/messages/utils.ts (2 hunks)
  • packages/components/schema.graphql (3 hunks)
  • packages/utils/functions/form/setFormRelayErrors/_tests_/setFormRelayErrors.test.ts (2 hunks)
  • packages/utils/functions/form/setFormRelayErrors/index.ts (1 hunks)
💤 Files with no reviewable changes (5)
  • packages/components/modules/messages/ChatRoom/ChatRoomHeader/utils.ts
  • packages/components/modules/messages/graphql/queries/MessagesList.ts
  • packages/components/modules/messages/CreateGroup/styled.tsx
  • packages/components/modules/messages/MessagesList/index.tsx
  • packages/components/modules/messages/graphql/mutations/CreateChatRoom.ts
🚧 Files skipped from review as they are similar to previous changes (29)
  • packages/components/modules/messages/ChatRoom/types.ts
  • packages/components/modules/messages/shared/index.ts
  • packages/components/modules/messages/GroupDetails/GroupDetailsHeader/styled.tsx
  • packages/components/modules/messages/GroupDetails/styled.tsx
  • packages/utils/functions/form/setFormRelayErrors/index.ts
  • packages/components/modules/messages/ChatRoom/index.tsx
  • packages/components/modules/messages/graphql/queries/MembersList.ts
  • packages/components/modules/messages/ChatRoom/ChatRoomHeader/types.ts
  • packages/components/modules/messages/GroupDetails/ProfileCard/styled.tsx
  • packages/components/modules/messages/GroupDetails/ProfileCard/types.ts
  • packages/components/modules/messages/CreateChatRoomList/ChatRoomListItem/types.ts
  • packages/components/modules/messages/index.ts
  • packages/components/modules/messages/graphql/queries/GroupDetailsQuery.ts
  • packages/components/modules/messages/EditGroup/types.ts
  • packages/components/modules/messages/utils.ts
  • packages/utils/functions/form/setFormRelayErrors/tests/setFormRelayErrors.test.ts
  • packages/components/modules/messages/GroupDetails/GroupDetailsHeader/index.tsx
  • packages/components/modules/messages/ChatRoom/ChatRoomHeader/styled.tsx
  • packages/components/modules/messages/CreateChatRoomList/ChatRoomListItem/index.tsx
  • packages/components/modules/messages/shared/EditGroupTitleAndImage/styled.tsx
  • packages/components/modules/messages/CreateGroup/constants.ts
  • packages/components/modules/messages/EditGroup/styled.tsx
  • packages/components/modules/messages/graphql/queries/ChatRoomHeaderFragment.ts
  • packages/components/modules/messages/GroupDetails/ProfileCard/index.tsx
  • packages/components/modules/messages/graphql/mutations/UpdateChatRoom.ts
  • packages/components/modules/messages/shared/EditGroupTitleAndImage/constants.tsx
  • packages/components/modules/messages/shared/EditGroupTitleAndImage/types.ts
  • packages/components/modules/messages/CreateChatRoomList/types.ts
  • packages/components/modules/messages/CreateGroup/types.ts
🧰 Additional context used
🪛 Biome (1.9.4)
packages/components/modules/messages/EditGroup/index.tsx

[error] 57-57: Avoid the delete operator which can impact performance.

Unsafe fix: Use an undefined assignment instead.

(lint/performance/noDelete)

packages/components/modules/messages/GroupDetails/GroupDetailsHeader/types.ts

[error] 2-2: Don't use '{}' as a type.

Prefer explicitly define the object shape. '{}' means "any non-nullable value".

(lint/complexity/noBannedTypes)


[error] 3-3: Don't use '{}' as a type.

Prefer explicitly define the object shape. '{}' means "any non-nullable value".

(lint/complexity/noBannedTypes)

packages/components/modules/messages/GroupDetails/types.ts

[error] 16-16: Don't use '{}' as a type.

Prefer explicitly define the object shape. '{}' means "any non-nullable value".

(lint/complexity/noBannedTypes)


[error] 17-17: Don't use '{}' as a type.

Prefer explicitly define the object shape. '{}' means "any non-nullable value".

(lint/complexity/noBannedTypes)

🔇 Additional comments (12)
packages/components/modules/messages/GroupDetails/GroupDetailsHeader/types.ts (1)

2-3: Avoid using empty object type {} for function return types.

Static analysis tools have flagged these lines. Replacing () => {} with () => void clarifies that no value is returned, improving type safety.

- onBackButtonClicked: () => {}
- onEditButtonClicked?: () => {}
+ onBackButtonClicked: () => void
+ onEditButtonClicked?: () => void
🧰 Tools
🪛 Biome (1.9.4)

[error] 2-2: Don't use '{}' as a type.

Prefer explicitly define the object shape. '{}' means "any non-nullable value".

(lint/complexity/noBannedTypes)


[error] 3-3: Don't use '{}' as a type.

Prefer explicitly define the object shape. '{}' means "any non-nullable value".

(lint/complexity/noBannedTypes)

packages/components/schema.graphql (2)

273-281: LGTM! Well-structured input type.

The ChatRoomUpdateInput type is well-designed with:

  • Required fields for identification (roomId, profileId)
  • Optional fields for flexible updates
  • Support for participant management and image handling

671-671: LGTM! Mutation follows GraphQL conventions.

The chatRoomUpdate mutation is well-integrated into the schema with proper input and payload types.

packages/components/modules/messages/CreateChatRoomList/index.tsx (3)

32-33: LGTM! Good improvement in prop naming and component architecture.

The change from state setters to callback props improves component reusability and makes the component's contract clearer.


87-89: LGTM! Proper prop forwarding implementation.

The callback is correctly passed to the child component while maintaining flexibility through prop spreading.


132-132: LGTM! Clean implementation of group chat creation trigger.

The click handler is properly implemented on the container level, maintaining good UX by making the entire group chat creation area clickable.

packages/components/modules/messages/ChatRoom/ChatRoomHeader/index.tsx (3)

15-16: LGTM! Clean import organization and prop structure.

The new imports and prop additions align well with the PR's objective of enhancing group details functionality.

Also applies to: 19-22


29-30: LGTM! Clean implementation of member count display.

The use of getParticipantCountString helper function keeps the component logic clean and maintainable.


36-44: LGTM! Semantic markup with BackButtonContainer.

The back button implementation is clean and follows good accessibility practices.

packages/components/modules/messages/GroupDetails/types.ts (1)

16-17: Replace {} with void for callback types.

According to static analysis, please replace () => {} with () => void for better type safety.

Apply this diff:

-  onBackButtonClicked: () => {}
-  onEditButtonClicked: () => {}
+  onBackButtonClicked: () => void
+  onEditButtonClicked: () => void
🧰 Tools
🪛 Biome (1.9.4)

[error] 16-16: Don't use '{}' as a type.

Prefer explicitly define the object shape. '{}' means "any non-nullable value".

(lint/complexity/noBannedTypes)


[error] 17-17: Don't use '{}' as a type.

Prefer explicitly define the object shape. '{}' means "any non-nullable value".

(lint/complexity/noBannedTypes)

packages/components/modules/messages/EditGroup/index.tsx (1)

47-58: ⚠️ Potential issue

Improve type safety and performance in form submission.

Issues found:

  1. data: any type is too permissive
  2. delete operator usage impacts performance (as noted in static analysis)

Apply these changes:

-const onSubmit = handleSubmit((data: any) => {
+const onSubmit = handleSubmit((data: EditGroupUpload) => {
   const dirtyValues = filterDirtyValues({ values: data, dirtyFields })
   const { image } = data
   const uploadables: { image?: File | Blob } = {}
   if ('image' in dirtyValues) {
     if (image) {
       uploadables.image = image
     } else {
       dirtyValues.deleteImage = true
     }
-    delete dirtyValues.image
+    dirtyValues.image = undefined
   }

Likely invalid or redundant comment.

🧰 Tools
🪛 Biome (1.9.4)

[error] 57-57: Avoid the delete operator which can impact performance.

Unsafe fix: Use an undefined assignment instead.

(lint/performance/noDelete)

packages/components/modules/messages/CreateGroup/index.tsx (1)

209-218: LGTM! Good use of shared component.

The implementation of EditGroupTitleAndImage promotes code reuse and maintains consistency across create and edit flows.

Comment on lines +79 to 86
const onSubmit = handleSubmit((data: CreateGroupUpload) => {
const dirtyValues = filterDirtyValues({ values: data, dirtyFields })
const { title, participants, image } = data
const participantsIds = participants.map((member) => member.id)
const participantsIds = (participants || []).map((member) => member.id)
const uploadables: { image?: File | Blob } = {}
if ('image' in dirtyValues && image && typeof image !== 'string') {
if (FORM_VALUE.image in dirtyValues && image && typeof image !== 'string') {
uploadables.image = image
}
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Improve type safety and null checks in form submission.

The participant handling could be more robust:

-  const participantsIds = (participants || []).map((member) => member.id)
+  const participantsIds = participants?.filter(Boolean).map((member) => member.id) ?? []

Also, consider adding a type guard for the image check:

-  if (FORM_VALUE.image in dirtyValues && image && typeof image !== 'string') {
+  if (FORM_VALUE.image in dirtyValues && image instanceof File) {
📝 Committable suggestion

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

Suggested change
const onSubmit = handleSubmit((data: CreateGroupUpload) => {
const dirtyValues = filterDirtyValues({ values: data, dirtyFields })
const { title, participants, image } = data
const participantsIds = participants.map((member) => member.id)
const participantsIds = (participants || []).map((member) => member.id)
const uploadables: { image?: File | Blob } = {}
if ('image' in dirtyValues && image && typeof image !== 'string') {
if (FORM_VALUE.image in dirtyValues && image && typeof image !== 'string') {
uploadables.image = image
}
const onSubmit = handleSubmit((data: CreateGroupUpload) => {
const dirtyValues = filterDirtyValues({ values: data, dirtyFields })
const { title, participants, image } = data
const participantsIds = participants?.filter(Boolean).map((member) => member.id) ?? []
const uploadables: { image?: File | Blob } = {}
if (FORM_VALUE.image in dirtyValues && image instanceof File) {
uploadables.image = image
}

Copy link
Collaborator

@anicioalexandre anicioalexandre left a comment

Choose a reason for hiding this comment

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

let's do a rebase with master

errors.forEach((error) => {
const errorField = error?.field as Path<T> | undefined
if (errorField && !!form.getValues(errorField)) {
if (errorField && form.getValues(errorField) !== undefined) {
Copy link
Collaborator

Choose a reason for hiding this comment

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

we should probably bump a new patch version for that

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

I had already done so, but got a whole lot of conflicts when rebasing onto master on Friday. I decided that it was easiest to remove the versioning for the rebasing and add it again at the very end before merging.

@tsl-ps2 tsl-ps2 force-pushed the BA-2024-group-details-page-frontend-packages branch from 26c2262 to 9d982a0 Compare January 13, 2025 11:10
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: 3

🧹 Nitpick comments (13)
packages/components/modules/messages/CreateChatRoomList/index.tsx (3)

87-89: Consider prop ordering to prevent overrides.

The spread operator after explicit props could potentially override onChatCreation. Consider moving the spread before the explicit prop:

-        onChatCreation={onChatCreation}
-        {...ChatRoomListItemProps}
+        {...ChatRoomListItemProps}
+        onChatCreation={onChatCreation}

Line range hint 132-150: Enhance accessibility for the group chat button.

The group chat container is clickable but lacks proper accessibility attributes. Consider these improvements:

-      <GroupChatContainer onClick={onGroupChatCreationButtonClicked}>
+      <GroupChatContainer
+        onClick={onGroupChatCreationButtonClicked}
+        role="button"
+        tabIndex={0}
+        onKeyPress={(e) => {
+          if (e.key === 'Enter' || e.key === ' ') {
+            onGroupChatCreationButtonClicked();
+          }
+        }}
+        aria-label="Create new group chat"
+      >

Line range hint 107-107: Address the TODO comment for layout calculations.

The current height calculation for the virtualized list doesn't account for different header types, which could lead to layout issues.

Would you like me to help create a GitHub issue to track this technical debt and propose a more robust height calculation solution?

packages/components/modules/messages/EditGroup/index.tsx (1)

94-124: Clean UI implementation with good accessibility!

The UI follows best practices with proper ARIA labels and loading states.

Consider adding a disabled state to the form inputs during mutation:

       <EditGroupTitleAndImage
         control={control}
         FORM_VALUE={FORM_VALUE}
         handleRemoveImage={handleRemoveImage}
         imageError={getFieldState(FORM_VALUE.image).error}
         isMutationInFlight={isMutationInFlight}
+        disabled={isMutationInFlight}
         setValue={setValue}
         trigger={trigger}
         watch={watch}
       />
packages/components/modules/messages/GroupDetails/ProfileCard/AdminOptionsMenu/types.ts (1)

1-4: Add JSDoc documentation for better developer experience.

Consider adding JSDoc comments to document the interface and its properties, providing context about when these callbacks are triggered and any side effects.

+/**
+ * Props for the AdminOptionsMenu component that handles group member management actions
+ */
 export interface AdminOptionsProps {
+  /** Callback triggered when making a member an admin */
   onMakeAdminClicked: () => void
+  /** Callback triggered when removing a member from the group */
   onRemoveClicked: () => void
 }
packages/components/modules/messages/GroupDetails/ProfileCard/constants.ts (1)

3-8: Consider using TypeScript enum for better type safety.

While the current implementation works, using an enum would provide better type safety and IDE support.

-export const CHAT_ROOM_PARTICIPANT_ROLES = {
-  admin: 'ADMIN',
-  member: 'MEMBER',
-} as const
+export enum ChatRoomParticipantRole {
+  ADMIN = 'ADMIN',
+  MEMBER = 'MEMBER',
+}

-export type ChatRoomParticipantRoles = ValueOf<typeof CHAT_ROOM_PARTICIPANT_ROLES>
+export type ChatRoomParticipantRoles = `${ChatRoomParticipantRole}`
packages/components/modules/messages/GroupDetails/ProfileCard/AdminOptionsMenu/index.tsx (1)

7-18: Enhance accessibility and testability.

The menu items should have proper ARIA labels and test IDs for better accessibility and testing.

 const AdminOptionsMenu: FC<AdminOptionsProps> = ({ onMakeAdminClicked, onRemoveClicked }) => (
   <MenuList>
-    <MenuItem onClick={onMakeAdminClicked}>
+    <MenuItem 
+      onClick={onMakeAdminClicked}
+      aria-label="Make user an admin"
+      data-testid="make-admin-button"
+    >
       <Typography variant="body2">Make Admin</Typography>
     </MenuItem>
-    <MenuItem onClick={onRemoveClicked}>
+    <MenuItem 
+      onClick={onRemoveClicked}
+      aria-label="Remove user from group"
+      data-testid="remove-user-button"
+    >
       <Typography variant="body2" color="error">
         Remove
       </Typography>
packages/components/modules/messages/utils.ts (1)

15-15: Consider using a custom error type.

Instead of returning a string error message, consider creating a custom error type for better error handling.

+export class ChatRoomError extends Error {
+  constructor(message: string) {
+    super(message);
+    this.name = 'ChatRoomError';
+  }
+}

 if (!roomHeader.participants) {
   return {
-    title: 'Error: No participants',
+    title: new ChatRoomError('No participants').message,
   }
 }
packages/components/modules/messages/ChatRoom/ChatRoomHeader/index.tsx (2)

19-22: Consider adding prop type validation.

The onDisplayGroupDetailsClicked prop should be marked as optional since it's only used for group chats.

const ChatRoomHeader: FC<ChatRoomHeaderProps> = ({
  roomHeaderRef,
- onDisplayGroupDetailsClicked,
+ onDisplayGroupDetailsClicked?: () => void,
}) => {

57-66: Consider extracting title section into a separate component.

The title and subtitle section could be extracted into a reusable component for better maintainability.

+ const ChatTitle: FC<{ title: string; isGroup: boolean; members?: string }> = ({
+   title,
+   isGroup,
+   members,
+ }) => (
+   <Box>
+     <Typography component="span" variant="subtitle2" sx={{ float: 'left', clear: 'left' }}>
+       {title}
+     </Typography>
+     {isGroup && (
+       <Typography component="span" variant="caption" sx={{ float: 'left', clear: 'left' }}>
+         {members}
+       </Typography>
+     )}
+   </Box>
+ )
packages/components/modules/messages/GroupDetails/ProfileCard/index.tsx (2)

73-74: Implement admin functionality marked as TODO.

The admin actions are currently placeholder functions. These need to be implemented to enable admin management of group members.

Would you like me to help implement the admin functionality or create GitHub issues to track these TODOs?


31-36: Add loading state for avatar images.

Consider adding a loading state for the avatar to prevent layout shifts and improve user experience.

<AvatarWithPlaceholder
  width={48}
  height={48}
  src={image?.url}
+ loading="lazy"
+ alt={`${name}'s avatar`}
  sx={{ alignSelf: 'center', justifySelf: 'center' }}
/>
packages/components/modules/messages/GroupDetails/index.tsx (1)

81-83: Optimize pagination load size.

Loading 5 items at a time might cause frequent API calls. Consider increasing the batch size for better performance.

if (hasNext) {
-   loadNext(5)
+   loadNext(20)
}
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 26c2262 and 9d982a0.

⛔ Files ignored due to path filters (13)
  • packages/components/__generated__/ChatRoomHeaderFragment.graphql.ts is excluded by !**/__generated__/**
  • packages/components/__generated__/ChatRoomMessagesListPaginationQuery.graphql.ts is excluded by !**/__generated__/**
  • packages/components/__generated__/ChatRoomParticipantsPaginationQuery.graphql.ts is excluded by !**/__generated__/**
  • packages/components/__generated__/ChatRoomQuery.graphql.ts is excluded by !**/__generated__/**
  • packages/components/__generated__/ChatRoomsQuery.graphql.ts is excluded by !**/__generated__/**
  • packages/components/__generated__/CreateChatRoomMutation.graphql.ts is excluded by !**/__generated__/**
  • packages/components/__generated__/GroupDetailsQuery.graphql.ts is excluded by !**/__generated__/**
  • packages/components/__generated__/MembersListFragment.graphql.ts is excluded by !**/__generated__/**
  • packages/components/__generated__/MessagesListFragment.graphql.ts is excluded by !**/__generated__/**
  • packages/components/__generated__/ReadMessagesMutation.graphql.ts is excluded by !**/__generated__/**
  • packages/components/__generated__/UpdateChatRoomMutation.graphql.ts is excluded by !**/__generated__/**
  • packages/components/__generated__/chatRoomsPaginationQuery.graphql.ts is excluded by !**/__generated__/**
  • packages/components/__generated__/useRoomListSubscription.graphql.ts is excluded by !**/__generated__/**
📒 Files selected for processing (47)
  • packages/components/modules/messages/ChatRoom/ChatRoomHeader/index.tsx (1 hunks)
  • packages/components/modules/messages/ChatRoom/ChatRoomHeader/styled.tsx (1 hunks)
  • packages/components/modules/messages/ChatRoom/ChatRoomHeader/types.ts (1 hunks)
  • packages/components/modules/messages/ChatRoom/ChatRoomHeader/utils.ts (0 hunks)
  • packages/components/modules/messages/ChatRoom/index.tsx (2 hunks)
  • packages/components/modules/messages/ChatRoom/types.ts (1 hunks)
  • packages/components/modules/messages/CreateChatRoomList/ChatRoomListItem/index.tsx (2 hunks)
  • packages/components/modules/messages/CreateChatRoomList/ChatRoomListItem/types.ts (1 hunks)
  • packages/components/modules/messages/CreateChatRoomList/index.tsx (3 hunks)
  • packages/components/modules/messages/CreateChatRoomList/types.ts (2 hunks)
  • packages/components/modules/messages/CreateGroup/constants.ts (1 hunks)
  • packages/components/modules/messages/CreateGroup/index.tsx (7 hunks)
  • packages/components/modules/messages/CreateGroup/styled.tsx (0 hunks)
  • packages/components/modules/messages/CreateGroup/types.ts (2 hunks)
  • packages/components/modules/messages/EditGroup/constants.ts (1 hunks)
  • packages/components/modules/messages/EditGroup/index.tsx (1 hunks)
  • packages/components/modules/messages/EditGroup/styled.tsx (1 hunks)
  • packages/components/modules/messages/EditGroup/types.ts (1 hunks)
  • packages/components/modules/messages/GroupDetails/GroupDetailsHeader/index.tsx (1 hunks)
  • packages/components/modules/messages/GroupDetails/GroupDetailsHeader/styled.tsx (1 hunks)
  • packages/components/modules/messages/GroupDetails/GroupDetailsHeader/types.ts (1 hunks)
  • packages/components/modules/messages/GroupDetails/ProfileCard/AdminOptionsMenu/index.tsx (1 hunks)
  • packages/components/modules/messages/GroupDetails/ProfileCard/AdminOptionsMenu/types.ts (1 hunks)
  • packages/components/modules/messages/GroupDetails/ProfileCard/constants.ts (1 hunks)
  • packages/components/modules/messages/GroupDetails/ProfileCard/index.tsx (1 hunks)
  • packages/components/modules/messages/GroupDetails/ProfileCard/styled.tsx (1 hunks)
  • packages/components/modules/messages/GroupDetails/ProfileCard/types.ts (1 hunks)
  • packages/components/modules/messages/GroupDetails/index.tsx (1 hunks)
  • packages/components/modules/messages/GroupDetails/styled.tsx (1 hunks)
  • packages/components/modules/messages/GroupDetails/types.ts (1 hunks)
  • packages/components/modules/messages/MessagesList/index.tsx (1 hunks)
  • packages/components/modules/messages/__shared__/EditGroupTitleAndImage/constants.tsx (1 hunks)
  • packages/components/modules/messages/__shared__/EditGroupTitleAndImage/index.tsx (1 hunks)
  • packages/components/modules/messages/__shared__/EditGroupTitleAndImage/styled.tsx (1 hunks)
  • packages/components/modules/messages/__shared__/EditGroupTitleAndImage/types.ts (1 hunks)
  • packages/components/modules/messages/__shared__/index.ts (1 hunks)
  • packages/components/modules/messages/graphql/mutations/CreateChatRoom.ts (0 hunks)
  • packages/components/modules/messages/graphql/mutations/UpdateChatRoom.ts (1 hunks)
  • packages/components/modules/messages/graphql/queries/ChatRoomHeaderFragment.ts (1 hunks)
  • packages/components/modules/messages/graphql/queries/GroupDetailsQuery.ts (1 hunks)
  • packages/components/modules/messages/graphql/queries/MembersList.ts (1 hunks)
  • packages/components/modules/messages/graphql/queries/MessagesList.ts (0 hunks)
  • packages/components/modules/messages/index.ts (1 hunks)
  • packages/components/modules/messages/utils.ts (2 hunks)
  • packages/components/schema.graphql (3 hunks)
  • packages/utils/functions/form/setFormRelayErrors/_tests_/setFormRelayErrors.test.ts (2 hunks)
  • packages/utils/functions/form/setFormRelayErrors/index.ts (1 hunks)
💤 Files with no reviewable changes (4)
  • packages/components/modules/messages/CreateGroup/styled.tsx
  • packages/components/modules/messages/graphql/queries/MessagesList.ts
  • packages/components/modules/messages/graphql/mutations/CreateChatRoom.ts
  • packages/components/modules/messages/ChatRoom/ChatRoomHeader/utils.ts
🚧 Files skipped from review as they are similar to previous changes (33)
  • packages/components/modules/messages/ChatRoom/types.ts
  • packages/components/modules/messages/shared/EditGroupTitleAndImage/styled.tsx
  • packages/components/modules/messages/ChatRoom/index.tsx
  • packages/components/modules/messages/GroupDetails/ProfileCard/styled.tsx
  • packages/components/modules/messages/graphql/queries/GroupDetailsQuery.ts
  • packages/components/modules/messages/GroupDetails/ProfileCard/types.ts
  • packages/components/modules/messages/MessagesList/index.tsx
  • packages/components/modules/messages/shared/index.ts
  • packages/components/modules/messages/GroupDetails/GroupDetailsHeader/types.ts
  • packages/components/modules/messages/shared/EditGroupTitleAndImage/constants.tsx
  • packages/components/modules/messages/EditGroup/styled.tsx
  • packages/components/modules/messages/graphql/queries/MembersList.ts
  • packages/utils/functions/form/setFormRelayErrors/tests/setFormRelayErrors.test.ts
  • packages/components/modules/messages/index.ts
  • packages/components/modules/messages/EditGroup/types.ts
  • packages/components/modules/messages/ChatRoom/ChatRoomHeader/types.ts
  • packages/components/modules/messages/GroupDetails/styled.tsx
  • packages/components/modules/messages/GroupDetails/GroupDetailsHeader/index.tsx
  • packages/utils/functions/form/setFormRelayErrors/index.ts
  • packages/components/modules/messages/CreateChatRoomList/ChatRoomListItem/index.tsx
  • packages/components/modules/messages/shared/EditGroupTitleAndImage/types.ts
  • packages/components/modules/messages/graphql/queries/ChatRoomHeaderFragment.ts
  • packages/components/modules/messages/EditGroup/constants.ts
  • packages/components/modules/messages/CreateChatRoomList/ChatRoomListItem/types.ts
  • packages/components/modules/messages/CreateChatRoomList/types.ts
  • packages/components/modules/messages/graphql/mutations/UpdateChatRoom.ts
  • packages/components/modules/messages/ChatRoom/ChatRoomHeader/styled.tsx
  • packages/components/modules/messages/CreateGroup/constants.ts
  • packages/components/schema.graphql
  • packages/components/modules/messages/GroupDetails/GroupDetailsHeader/styled.tsx
  • packages/components/modules/messages/GroupDetails/types.ts
  • packages/components/modules/messages/CreateGroup/types.ts
  • packages/components/modules/messages/shared/EditGroupTitleAndImage/index.tsx
🧰 Additional context used
🪛 Biome (1.9.4)
packages/components/modules/messages/EditGroup/index.tsx

[error] 59-59: Avoid the delete operator which can impact performance.

Unsafe fix: Use an undefined assignment instead.

(lint/performance/noDelete)

⏰ Context from checks skipped due to timeout of 90000ms (1)
  • GitHub Check: Analyze (javascript)
🔇 Additional comments (8)
packages/components/modules/messages/CreateChatRoomList/index.tsx (1)

32-33: Well-structured prop changes!

The transition from state setters to callback props improves component reusability and follows React best practices for component composition.

packages/components/modules/messages/EditGroup/index.tsx (3)

1-46: Well-structured component setup!

The component follows React best practices with proper type definitions, form validation using Zod, and clean separation of concerns.


83-90: Clean image removal implementation!

The function properly handles form state updates and error clearing.


47-81: 🛠️ Refactor suggestion

Optimize form submission logic

The form submission logic is well-structured but has room for improvement:

  1. Replace the delete operator with undefined assignment for better performance:
-      delete dirtyValues.image
+      dirtyValues.image = undefined
  1. Add type safety for image handling:
-    const uploadables: { image?: File | Blob } = {}
+    const uploadables: { image?: File } = {}
-    if ('image' in dirtyValues) {
+    if (FORM_VALUE.image in dirtyValues) {
       if (image) {
-        uploadables.image = image
+        uploadables.image = image instanceof File ? image : undefined
       } else {
         dirtyValues.deleteImage = true
       }

Likely invalid or redundant comment.

🧰 Tools
🪛 Biome (1.9.4)

[error] 59-59: Avoid the delete operator which can impact performance.

Unsafe fix: Use an undefined assignment instead.

(lint/performance/noDelete)

packages/components/modules/messages/CreateGroup/index.tsx (3)

Line range hint 79-110: Improve type safety in form submission

Previous review suggestions still apply:

  1. Add null checks for participants:
-  const participantsIds = (participants || []).map((member) => member.id)
+  const participantsIds = participants?.filter(Boolean).map((member) => member.id) ?? []
  1. Improve type guard for image:
-  if (FORM_VALUE.image in dirtyValues && image && typeof image !== 'string') {
+  if (FORM_VALUE.image in dirtyValues && image instanceof File) {

178-184: Consistent image removal implementation!

The implementation aligns well with the EditGroup component's approach.


209-218: Great component reuse!

The integration of EditGroupTitleAndImage follows the DRY principle and maintains consistency across the application.

packages/components/modules/messages/GroupDetails/index.tsx (1)

130-146: Add error boundary for better error handling.

The suspended component should be wrapped in an error boundary to gracefully handle rendering errors.

Comment on lines +28 to +33
export const getParticipantCountString = (participantCount: number | null | undefined) => {
if (participantCount !== undefined && participantCount !== null) {
return `${participantCount} member${participantCount !== 1 ? 's' : ''}`
}
return undefined
}
Copy link

Choose a reason for hiding this comment

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

💡 Codebase verification

Add unit tests for getParticipantCountString

The verification confirms there are no existing test files for this utility function. Please add tests to cover:

  • Valid number inputs (0, 1, multiple)
  • Null input
  • Undefined input

Would you like help generating the test cases?

🔗 Analysis chain

Add unit tests for getParticipantCountString.

The new utility function needs test coverage to ensure it handles all cases correctly.

Let me check if tests exist:

Please add tests to cover:

  • Valid number inputs (0, 1, multiple)
  • Null input
  • Undefined input

Would you like me to help generate the test cases?

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Search for test files that might contain tests for getParticipantCountString
rg -l "getParticipantCountString" --glob "**/*.test.{ts,tsx}"

Length of output: 61


Script:

#!/bin/bash
# Look for any test files in the messages module directory with various test file patterns
fd -e test.ts -e test.tsx -e spec.ts -e spec.tsx . packages/components/modules/messages/

# Also check if utils.test.ts exists in the same directory as the source file
ls packages/components/modules/messages/utils.test.ts 2>/dev/null || echo "No utils.test.ts file found"

# Search for any file containing "utils" and "test" or "spec" in the messages module
fd "utils.*\.(test|spec)\.(ts|tsx)$" packages/components/modules/messages/

Length of output: 288

Comment on lines +46 to +49
<ChatTitleContainer
onClick={roomHeader.isGroup ? onDisplayGroupDetailsClicked : undefined}
isClickable={roomHeader.isGroup}
>
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Enhance accessibility for clickable group title.

The clickable title container should be a button for better accessibility when it represents a group chat.

- <ChatTitleContainer
-   onClick={roomHeader.isGroup ? onDisplayGroupDetailsClicked : undefined}
-   isClickable={roomHeader.isGroup}
- >
+ <ChatTitleContainer
+   onClick={roomHeader.isGroup ? onDisplayGroupDetailsClicked : undefined}
+   isClickable={roomHeader.isGroup}
+   role={roomHeader.isGroup ? 'button' : undefined}
+   tabIndex={roomHeader.isGroup ? 0 : undefined}
+   aria-label={roomHeader.isGroup ? 'View group details' : undefined}
+ >
📝 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
<ChatTitleContainer
onClick={roomHeader.isGroup ? onDisplayGroupDetailsClicked : undefined}
isClickable={roomHeader.isGroup}
>
<ChatTitleContainer
onClick={roomHeader.isGroup ? onDisplayGroupDetailsClicked : undefined}
isClickable={roomHeader.isGroup}
role={roomHeader.isGroup ? 'button' : undefined}
tabIndex={roomHeader.isGroup ? 0 : undefined}
aria-label={roomHeader.isGroup ? 'View group details' : undefined}
>

Comment on lines +57 to +70
const renderItem = (item: GroupMembersEdge) => {
const profile = item?.node?.profile
if (profile) {
return (
<ProfileCard
role={item?.node?.role}
profile={profile}
hasAdminPermissions={isAdmin}
{...ProfileCardProps}
/>
)
}
return null
}
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Add error handling for missing profile data.

The renderItem function should handle edge cases where node or profile might be undefined.

const renderItem = (item: GroupMembersEdge) => {
+   if (!item?.node) {
+     return null;
+   }
    const profile = item?.node?.profile
    if (profile) {
      return (
        <ProfileCard
          role={item.node.role}
          profile={profile}
          hasAdminPermissions={isAdmin}
          {...ProfileCardProps}
        />
      )
    }
+   // Log error for debugging purposes
+   console.error('Profile data missing for member:', item.node);
    return null
}
📝 Committable suggestion

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

Suggested change
const renderItem = (item: GroupMembersEdge) => {
const profile = item?.node?.profile
if (profile) {
return (
<ProfileCard
role={item?.node?.role}
profile={profile}
hasAdminPermissions={isAdmin}
{...ProfileCardProps}
/>
)
}
return null
}
const renderItem = (item: GroupMembersEdge) => {
if (!item?.node) {
return null;
}
const profile = item.node.profile
if (profile) {
return (
<ProfileCard
role={item.node.role}
profile={profile}
hasAdminPermissions={isAdmin}
{...ProfileCardProps}
/>
)
}
// Log error for debugging purposes
console.error('Profile data missing for member:', item.node);
return null
}

@sonarqubecloud
Copy link

Quality Gate Failed Quality Gate failed

Failed conditions
38.9% Duplication on New Code (required ≤ 3%)

See analysis details on SonarQube Cloud

@tsl-ps2 tsl-ps2 merged commit 2692120 into master Jan 13, 2025
7 of 9 checks passed
@nossila nossila deleted the BA-2024-group-details-page-frontend-packages branch May 26, 2025 21:18
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.

4 participants