Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

BA-1965: implement reaction notification #161

Merged
merged 4 commits into from
Dec 30, 2024

Conversation

priscilladeroode
Copy link
Contributor

@priscilladeroode priscilladeroode commented Dec 16, 2024

  • __package_name__ package update - v __package_version__
    • changelog_info
    • changelog_info

Summary by CodeRabbit

Release Notes v0.0.40

  • New Features

    • Added support for reaction notifications.
    • Introduced new notification components for comment creation and reactions.
    • Enhanced notification rendering with a flexible system for different notification types.
  • Refactoring

    • Restructured notification module for easier addition of notification types.
    • Simplified notification item rendering logic and improved component composition.
  • Documentation

    • Added comprehensive Storybook documentation for the notifications module.
  • Chores

    • Updated package dependencies.
    • Incremented package version to 0.0.40.
    • Added Storybook scripts for various packages.

Copy link

changeset-bot bot commented Dec 16, 2024

⚠️ No Changeset found

Latest commit: 15d281e4b91aa7eba482269e8eaf3dddf5622bf8

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

Copy link

coderabbitai bot commented Dec 16, 2024

Warning

There were issues while running some tools. Please review the errors and either fix the tool’s configuration or disable the tool if it’s a critical failure.

🔧 eslint

If the error stems from missing dependencies, add them to the package.json file. For unrecoverable errors (e.g., due to private dependencies), disable the tool in the CodeRabbit configuration.

packages/components/.storybook/preview.ts

Oops! Something went wrong! :(

ESLint: 8.57.1

Error: Cannot read config file: /packages/components/.eslintrc.js
Error: Cannot find module '@baseapp-frontend/config/.eslintrc.js'
Require stack:

  • /packages/components/.eslintrc.js
  • /node_modules/.pnpm/@eslint+eslintrc@2.1.4/node_modules/@eslint/eslintrc/dist/eslintrc.cjs
  • /node_modules/.pnpm/eslint@8.57.1/node_modules/eslint/lib/cli-engine/cli-engine.js
  • /node_modules/.pnpm/eslint@8.57.1/node_modules/eslint/lib/eslint/eslint.js
  • /node_modules/.pnpm/eslint@8.57.1/node_modules/eslint/lib/eslint/index.js
  • /node_modules/.pnpm/eslint@8.57.1/node_modules/eslint/lib/cli.js
  • /node_modules/.pnpm/eslint@8.57.1/node_modules/eslint/bin/eslint.js
    at Module._resolveFilename (node:internal/modules/cjs/loader:1248:15)
    at Module._load (node:internal/modules/cjs/loader:1074:27)
    at TracingChannel.traceSync (node:diagnostics_channel:315:14)
    at wrapModuleLoad (node:internal/modules/cjs/loader:217:24)
    at Module.require (node:internal/modules/cjs/loader:1339:12)
    at require (node:internal/modules/helpers:135:16)
    at Object. (/packages/components/.eslintrc.js:1:18)
    at Module._compile (node:internal/modules/cjs/loader:1546:14)
    at Module._extensions..js (node:internal/modules/cjs/loader:1691:10)
    at Module.load (node:internal/modules/cjs/loader:1317:32)

Walkthrough

This pull request introduces a comprehensive refactoring of the notifications module in the frontend components library. The changes focus on creating a more modular and extensible notification system by introducing new components like NotificationRoot, NotificationAvatar, NotificationContent, and a dynamic NotificationItemRenderer. The implementation supports multiple notification types, including comments, comment replies, and reactions, with a flexible rendering approach that allows easy addition of new notification types.

Changes

File Change Summary
packages/components/modules/notifications/NotificationsList/NotificationItem/index.tsx Updated to support dynamic notification rendering with optional NotificationItemRenderer
packages/components/modules/notifications/NotificationsList/index.tsx Added NotificationItemProps to enhance NotificationItem configurability
packages/components/modules/notifications/constants.ts Added reactionCreated to NOTIFICATION_VERB
packages/components/modules/notifications/index.ts Expanded exports for notification-related components and types
packages/components/package.json Version bumped to 0.0.40, updated Storybook script
packages/components/modules/notifications/NotificationsList/NotificationItem/CommentCreated/index.tsx Introduced CommentCreated component for comment notifications
packages/components/modules/notifications/NotificationsList/NotificationItem/CommentReply/index.tsx Restructured CommentReply component to use Notification structure
packages/components/modules/notifications/NotificationsList/NotificationItem/ReactionCreated/index.tsx Introduced ReactionCreated component for reaction notifications
packages/components/modules/notifications/NotificationsList/NotificationItem/Notification/index.tsx Created a namespace for notification components
packages/components/modules/notifications/NotificationsList/NotificationItem/NotificationItemRenderer/index.tsx Added NotificationItemRenderer for dynamic notification rendering
packages/components/modules/notifications/NotificationsList/NotificationItem/Notification/NotificationAvatar/index.tsx Introduced NotificationAvatar component for displaying user avatars
packages/components/modules/notifications/NotificationsList/NotificationItem/Notification/NotificationContent/NotificationBody/index.tsx Introduced NotificationBody component for notification content
packages/components/modules/notifications/NotificationsList/NotificationItem/Notification/NotificationContent/NotificationHeader/index.tsx Introduced NotificationHeader component for notification headers
packages/components/modules/notifications/NotificationsList/NotificationItem/Notification/NotificationContent/index.tsx Created NotificationContent component to encapsulate header and body
packages/components/modules/notifications/NotificationsList/NotificationItem/Notification/NotificationRoot/index.tsx Introduced NotificationRoot component for overall notification layout

Possibly related PRs

Suggested reviewers

  • deboracosilveira

Poem

🐰 Notifications hop and dance,
With components both sleek and smart,
Reactions, comments take their stance,
A modular rendering art!
CodeRabbit's magic, rendering bright! 🎉

Tip

CodeRabbit's docstrings feature is now available as part of our Early Access Program! Simply use the command @coderabbitai generate docstrings to have CodeRabbit automatically generate docstrings for your pull request. We would love to hear your feedback on Discord.


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

🔭 Outside diff range comments (2)
packages/components/modules/notifications/NotificationsList/NotificationItem/index.tsx (1)

Line range hint 11-38: Add error handling and loading state for mutation

The mark as read functionality could benefit from some improvements:

  1. Add error handling for failed mutations
  2. Show loading state during mutation
  3. Consider debouncing the click handler to prevent rapid repeated clicks
 const NotificationItem: FC<NotificationItemProps> = ({
   notification: notificationRef,
   NotificationItemRenderer = DefaultNotificationContentRenderer,
 }) => {
   const notification = useFragment(NotificationItemFragment, notificationRef)
+  const [isLoading, setIsLoading] = useState(false)
 
   const commitMutation = useNotificationsMarkAsRead()[0]
-  const markAsRead = () => {
+  const markAsRead = useCallback(debounce(async () => {
     if (notification.unread) {
-      commitMutation({
-        variables: {
-          input: {
-            read: true,
-            notificationIds: [notification.id],
-          },
-        },
-      })
+      try {
+        setIsLoading(true)
+        await commitMutation({
+          variables: {
+            input: {
+              read: true,
+              notificationIds: [notification.id],
+            },
+          },
+        })
+      } catch (error) {
+        console.error('Failed to mark notification as read:', error)
+      } finally {
+        setIsLoading(false)
+      }
     }
-  }
+  }, 300), [notification.id, notification.unread, commitMutation])
packages/components/modules/notifications/NotificationsList/index.tsx (1)

Line range hint 51-78: Add type safety to renderNotificationItem function

The function uses any type for notification parameter which bypasses type checking.

- const renderNotificationItem = (notification: any, index: number) => {
+ const renderNotificationItem = (
+   notification: NotificationsListFragment['me']['notifications']['edges'][number]['node'],
+   index: number
+ ) => {
🧹 Nitpick comments (16)
packages/components/modules/notifications/NotificationsList/NotificationItem/Notification/NotificationCommentBody.tsx (1)

8-14: Consider adding content validation and error handling.

While the implementation is clean, consider these improvements for robustness:

  1. Add validation for empty/null content
  2. Implement error boundary to gracefully handle rendering failures
+import { ErrorBoundary } from '@baseapp-frontend/error-boundary'
+
 const NotificationCommentBody: FC<NotificationCommentBodyProps> = ({ content }) => (
+  <ErrorBoundary fallback={<BodyTypographyContainer>Unable to display comment</BodyTypographyContainer>}>
   <BodyTypographyContainer>
     <TypographyWithEllipsis variant="body2" maxHeight={64} lineClamp={2}>
-      {content}
+      {content || 'No content available'}
     </TypographyWithEllipsis>
   </BodyTypographyContainer>
+  </ErrorBoundary>
 )
packages/components/modules/notifications/NotificationsList/NotificationItem/Notification/NotificationAvatar.tsx (2)

3-9: Consider using a dedicated interface for props

For better maintainability and type safety, consider extracting the props interface.

+interface NotificationAvatarProps {
+  actorAvatar: string
+  actorName: string
+}
+
-const NotificationAvatar = ({
-  actorAvatar,
-  actorName,
-}: {
-  actorAvatar: string
-  actorName: string
-}) => (
+const NotificationAvatar = ({
+  actorAvatar,
+  actorName,
+}: NotificationAvatarProps) => (

11-12: Consider extracting magic numbers

The fixed dimensions (40x40) should be extracted into a constants file or theme for better maintainability.

+const AVATAR_SIZE = 40
+
 <AvatarWithPlaceholder
-  width={40}
-  height={40}
+  width={AVATAR_SIZE}
+  height={AVATAR_SIZE}
packages/components/modules/notifications/NotificationsList/NotificationItemRenderer/types.ts (1)

1-1: Consider using path aliases to simplify import paths

The relative import path with multiple ../ segments can make the code harder to maintain and prone to errors during refactoring. Consider configuring path aliases in your module resolver to simplify imports and improve readability.

Apply this diff to revise the import statement:

- import { NotificationItemFragment$data } from '../../../../__generated__/NotificationItemFragment.graphql'
+ import { NotificationItemFragment$data } from '@generated/NotificationItemFragment.graphql'

Ensure that the path alias @generated is configured in your project's module resolution settings (e.g., tsconfig.json, babel.config.js, or webpack.config.js).

packages/components/modules/notifications/NotificationsList/NotificationItem/Notification/NotificationRoot.tsx (1)

5-9: LGTM! Consider making the layout more configurable.

The component implementation is clean and follows good practices. However, to enhance reusability, consider making the grid template and spacing configurable through props.

-const NotificationRoot: FC<PropsWithChildren> = ({ children }) => (
+interface NotificationRootProps extends PropsWithChildren {
+  gridTemplate?: string;
+  gap?: number;
+  padding?: number | string;
+}
+
+const NotificationRoot: FC<NotificationRootProps> = ({
+  children,
+  gridTemplate = "min-content 1fr",
+  gap = 2,
+  padding = 2.5
+}) => (
-  <Box display="grid" gap={2} gridTemplateColumns="min-content 1fr" padding={2.5}>
+  <Box display="grid" gap={gap} gridTemplateColumns={gridTemplate} padding={padding}>
    {children}
  </Box>
)
packages/components/modules/notifications/NotificationsList/NotificationItem/types.ts (2)

11-11: Add JSDoc documentation for the new renderer prop.

The new NotificationItemRenderer prop would benefit from documentation explaining its purpose and usage.

+  /**
+   * Optional custom renderer for notification items.
+   * If not provided, the default notification renderer will be used.
+   * @param props NotificationItemRendererProps containing notification data
+   */
   NotificationItemRenderer?: FC<NotificationItemRendererProps>

Line range hint 13-15: Consider making notification type more specific.

The GenericItemProps interface uses a generic notification type. Consider creating a union type of specific notification variants for better type safety.

+export type NotificationType = 'COMMENT_CREATED' | 'COMMENT_REPLY' | 'REACTION_CREATED';
+
 export interface GenericItemProps {
-  notification: NotificationItemFragment$data
+  notification: NotificationItemFragment$data & {
+    type: NotificationType;
+  }
 }
packages/components/modules/notifications/NotificationsList/types.ts (1)

8-15: Group related props and add documentation.

The props interface would benefit from logical grouping and documentation of customization options.

+/**
+ * Props for the NotificationsList component
+ */
 export interface NotificationsListProps {
+  // State management
   setIsDrawerOpened: Dispatch<SetStateAction<boolean>>
+
+  // Custom component overrides
   EmptyState?: FC
   LoadingState?: FC<LoadingStateProps>
-  LoadingStateProps?: LoadingStateProps
   NotificationItem?: FC<NotificationItemProps>
   NotificationItemRenderer?: FC<NotificationItemRendererProps>
+
+  // Component props
+  LoadingStateProps?: LoadingStateProps
 }
packages/components/modules/notifications/NotificationsList/NotificationItem/Notification/NotificationContent.tsx (1)

8-11: Consider adding validation for required components

The interface defines Header and Body as required, but there's no runtime validation to ensure they're provided when using the component.

Consider adding PropTypes or a custom validation:

import { createContext, useContext } from 'react'

const NotificationContentContext = createContext<{ hasHeader: boolean; hasBody: boolean } | null>(null)

export interface NotificationContentProps {
  children: React.ReactNode
}
packages/components/modules/notifications/NotificationsList/NotificationItemRenderer/index.tsx (1)

3-7: Consider extracting notification type mapping to a configuration object

The switch statement could be replaced with a more maintainable mapping configuration.

Consider refactoring to:

const NOTIFICATION_COMPONENTS = {
  [NOTIFICATION_VERB.commentCreated]: CommentCreated,
  [NOTIFICATION_VERB.commentReplyCreated]: CommentReply,
  [NOTIFICATION_VERB.reactionCreated]: ReactionCreated,
} as const

const NotificationItemRenderer: FC<NotificationItemRendererProps> = ({ notification }) => {
  const NotificationComponent = NOTIFICATION_COMPONENTS[notification.verb]
  return NotificationComponent ? <NotificationComponent notification={notification} /> : null
}
packages/components/modules/notifications/NotificationsList/NotificationItem/Notification/NotificationHeader.tsx (2)

8-13: Add prop validation for required fields

Consider adding default values or null checks for required props to prevent rendering issues when data is missing.

 const NotificationHeader: FC<NotificationHeaderProps> = ({
-  actorName,
-  message,
+  actorName = '',
+  message = '',
   unread,
-  timestamp,
+  timestamp = '',
 }) => (

14-34: Enhance accessibility and maintainability

A few suggestions to improve the component:

  1. Add aria-label to the header container for screen readers
  2. Consider extracting the grid template columns value to a constant or theme variable
  3. Add data-testid attributes for testing
-  <Box display="grid">
+  <Box 
+    display="grid"
+    role="heading"
+    aria-label="Notification header"
+    data-testid="notification-header"
+  >
     <Box display="flex" alignItems="center" justifyContent="space-between" gap={1}>
       <Box
         display="grid"
         gap={0.5}
         alignItems="center"
-        gridTemplateColumns="repeat(2, max-content)"
+        gridTemplateColumns="auto auto"
         >
packages/components/modules/notifications/NotificationsList/NotificationItem/ReactionCreated/index.tsx (3)

10-11: Remove ESLint disable comment and improve type safety

Instead of disabling ESLint, consider creating a type-safe helper function for handling typename.

-  // eslint-disable-next-line no-underscore-dangle
-  const message = `liked your ${notification.target?.__typename.toLowerCase()}`
+  const getTargetType = (target: typeof notification.target) => {
+    if (!target) return 'content'
+    const type = target.__typename
+    return type.toLowerCase()
+  }
+  const message = `liked your ${getTargetType(notification.target)}`

13-29: Enhance reusability and reduce repetition

Consider extracting repeated null checks and creating a utility for actor data.

+  const actorData = {
+    avatar: notification.actor?.avatar?.url ?? '',
+    name: notification.actor?.fullName ?? '',
+  }
+
   return (
     <Notification.Root>
       <Notification.Avatar
-        actorAvatar={notification.actor?.avatar?.url ?? ''}
-        actorName={notification.actor?.fullName ?? ''}
+        actorAvatar={actorData.avatar}
+        actorName={actorData.name}
       />
       <NotificationContent>
         <NotificationContent.Header
           message={message}
           timestamp={formatRelativeTime(notification.timestamp)}
-          actorName={notification.actor?.fullName ?? ''}
+          actorName={actorData.name}
           unread={notification.unread}
         />

1-32: Consider adding unit tests

This component handles important user interactions and should have comprehensive test coverage.

Would you like me to help generate unit tests for this component? The tests should cover:

  1. Rendering with different notification types
  2. Handling missing actor/target data
  3. Message formatting
packages/components/modules/notifications/index.ts (1)

Line range hint 1-1: Address TODO comment regarding storybook implementation

The comment indicates missing storybook coverage for notification components. This should be tracked and addressed.

Would you like me to help create a GitHub issue to track the storybook implementation task?

📜 Review details

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

📥 Commits

Reviewing files that changed from the base of the PR and between 3c2ea87 and 22604e83744e6a7957e93091cb7fd5371e3df3d8.

⛔ Files ignored due to path filters (1)
  • packages/components/__generated__/NotificationItemFragment.graphql.ts is excluded by !**/__generated__/**
📒 Files selected for processing (19)
  • packages/components/modules/notifications/NotificationsList/NotificationItem/CommentCreated/index.tsx (1 hunks)
  • packages/components/modules/notifications/NotificationsList/NotificationItem/CommentReply/index.tsx (1 hunks)
  • packages/components/modules/notifications/NotificationsList/NotificationItem/Notification/NotificationAvatar.tsx (1 hunks)
  • packages/components/modules/notifications/NotificationsList/NotificationItem/Notification/NotificationCommentBody.tsx (1 hunks)
  • packages/components/modules/notifications/NotificationsList/NotificationItem/Notification/NotificationContent.tsx (1 hunks)
  • packages/components/modules/notifications/NotificationsList/NotificationItem/Notification/NotificationHeader.tsx (1 hunks)
  • packages/components/modules/notifications/NotificationsList/NotificationItem/Notification/NotificationRoot.tsx (1 hunks)
  • packages/components/modules/notifications/NotificationsList/NotificationItem/Notification/index.tsx (1 hunks)
  • packages/components/modules/notifications/NotificationsList/NotificationItem/Notification/types.ts (1 hunks)
  • packages/components/modules/notifications/NotificationsList/NotificationItem/ReactionCreated/index.tsx (1 hunks)
  • packages/components/modules/notifications/NotificationsList/NotificationItem/index.tsx (2 hunks)
  • packages/components/modules/notifications/NotificationsList/NotificationItem/types.ts (1 hunks)
  • packages/components/modules/notifications/NotificationsList/NotificationItemRenderer/index.tsx (1 hunks)
  • packages/components/modules/notifications/NotificationsList/NotificationItemRenderer/types.ts (1 hunks)
  • packages/components/modules/notifications/NotificationsList/index.tsx (3 hunks)
  • packages/components/modules/notifications/NotificationsList/types.ts (1 hunks)
  • packages/components/modules/notifications/constants.ts (1 hunks)
  • packages/components/modules/notifications/graphql/queries/NotificationItem.ts (1 hunks)
  • packages/components/modules/notifications/index.ts (1 hunks)
✅ Files skipped from review due to trivial changes (1)
  • packages/components/modules/notifications/NotificationsList/NotificationItem/Notification/index.tsx
🔇 Additional comments (10)
packages/components/modules/notifications/NotificationsList/NotificationItem/Notification/NotificationCommentBody.tsx (1)

1-16: LGTM! Clean and modular implementation.

The component follows React best practices with:

  • Clear separation of concerns
  • Reuse of design system components
  • Type safety with TypeScript
  • Focused single responsibility
packages/components/modules/notifications/NotificationsList/NotificationItem/Notification/NotificationAvatar.tsx (1)

1-1: Verify design system dependency usage

Ensure that AvatarWithPlaceholder from the design system is the recommended component for avatars in notifications.

✅ Verification successful

AvatarWithPlaceholder is consistently used across notifications

The verification shows that AvatarWithPlaceholder from the design system is indeed the recommended and consistently used component for avatars in notifications:

  • It's properly used in NotificationAvatar component which is shared across all notification types (CommentReply, ReactionCreated, CommentCreated)
  • The implementation follows a consistent pattern with proper sizing and alt text
  • No other avatar components from the design system are used in the notifications module
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Check for consistent avatar component usage across notifications
rg -l "AvatarWithPlaceholder" --type typescript | grep -i "notification"

# Check if there are other avatar components in use
ast-grep --pattern 'import { $_ } from "@baseapp-frontend/design-system"' | grep -i "avatar"

Length of output: 198


Script:

#!/bin/bash
# Check for consistent avatar component usage across notifications
rg -l "AvatarWithPlaceholder"

# Look for other avatar components in notifications
rg "Avatar" --type ts --type tsx | grep -i "notification"

# Check design system imports in notification files
rg "from.*design-system" --type ts --type tsx | grep -i "notification"

Length of output: 1503


Script:

#!/bin/bash
# Search for Avatar usage in notification-related files
rg "Avatar" packages/components/modules/notifications/

# Check design system imports in notification files
rg "from.*design-system" packages/components/modules/notifications/

# Look at the implementation of NotificationAvatar
cat packages/components/modules/notifications/NotificationsList/NotificationItem/Notification/NotificationAvatar.tsx

Length of output: 4182

packages/components/modules/notifications/NotificationsList/NotificationItem/Notification/types.ts (1)

1-10: Interfaces are well-defined and enhance type safety

The NotificationCommentBodyProps and NotificationHeaderProps interfaces are appropriately defined, ensuring that the components receive the correct props. This improves type safety and makes the code more maintainable.

packages/components/modules/notifications/constants.ts (1)

4-4: Addition of reactionCreated constant is appropriate

The new constant reactionCreated: 'REACTIONS.REACTION_CREATED' has been correctly added to NOTIFICATION_VERB. This extends the notification types supported by the system and aligns with the existing naming conventions.

packages/components/modules/notifications/NotificationsList/types.ts (1)

14-14: Verify renderer prop usage consistency.

Let's verify that the NotificationItemRenderer prop is consistently handled across the notification system components.

✅ Verification successful

NotificationItemRenderer is consistently implemented across the notification system

Based on the code analysis, the NotificationItemRenderer prop is consistently handled throughout the notification system components with proper type definitions and implementations:

  • It's properly exported from the root index.ts
  • Types are consistently defined and imported using NotificationItemRendererProps interface
  • Default implementation is provided in NotificationItemRenderer/index.tsx
  • Properly passed down through component hierarchy:
    • NotificationsList -> NotificationItem -> Renderer implementation
  • Default fallbacks are implemented at each level
  • Proper type checking with FC
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Search for NotificationItemRenderer usage in notification-related components
rg -t typescript "NotificationItemRenderer" packages/components/modules/notifications

Length of output: 120


Script:

#!/bin/bash
# Search for NotificationItemRenderer usage in all files
rg "NotificationItemRenderer"

Length of output: 2522


Script:

#!/bin/bash
# Find all TypeScript files in the notifications module and check their content
fd -e ts -e tsx . packages/components/modules/notifications --exec cat {}

Length of output: 67570


Script:

#!/bin/bash
# Search for any renderer-related patterns in notification components
rg "renderer|Renderer" packages/components/modules/notifications/

Length of output: 2560

packages/components/modules/notifications/graphql/queries/NotificationItem.ts (1)

28-32: Verify completeness of Comment fragment fields

The Comment fragment includes basic fields (id, body) but consider if additional fields might be needed for proper rendering, such as:

  • createdAt for timestamp display
  • author information for attribution
  • parentId for reply context
✅ Verification successful

Basic fields are sufficient for notification rendering

The current Comment fragment fields (id, body) are adequate for notification rendering based on the codebase analysis:

  1. The notification components (CommentCreated, CommentReply) only use these exact fields:

    • id for React keys and references
    • body for displaying the comment content
  2. Additional suggested fields are not needed because:

    • timestamp comes from the notification object itself, not the comment
    • Author information comes from the notification's actor field
    • Parent context is handled through the notification's target field

The fragment is properly structured for its specific use case in notifications.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Search for Comment type usage in components to verify field requirements
ast-grep --pattern 'interface Comment {
  $$$
}'

# Search for Comment field access in components
rg -t tsx 'notification\.(target|actionObject)\.' 

Length of output: 130


Script:

#!/bin/bash
# Search for Comment type usage in components to verify field requirements
ast-grep --pattern 'interface Comment {
  $$$
}'

# Search for Comment field access in components with correct file extension
rg 'notification\.(target|actionObject)\.' -g '*.tsx' -g '*.ts'

# Search for Comment type usage in GraphQL fragments
rg '(fragment|type|interface).*Comment' -g '*.graphql' -g '*.ts'

# Search for Comment rendering components
rg 'Comment' -g '*.tsx' -A 5

Length of output: 84258


Script:

#!/bin/bash
# Search for Comment type definition in schema
rg -A 10 'type Comment implements' packages/components/schema.graphql

# Search for Comment fragment usage in notifications
rg -A 10 'fragment.*Comment' packages/components/modules/notifications/graphql/queries/

# Search for notification rendering of comments
rg -A 5 'notification\.(target|actionObject).*Comment' packages/components/modules/notifications/NotificationsList/

Length of output: 528


Script:

#!/bin/bash
# Search for Comment type usage in notification components
rg -A 10 'notification\.(actionObject|target).*Comment' packages/components/modules/notifications/NotificationsList/NotificationItem/

# Search for Comment fragment in notification queries
cat packages/components/modules/notifications/graphql/queries/NotificationItem.ts

# Search for comment-related fields in notification components
rg -A 5 'body|created|author' packages/components/modules/notifications/NotificationsList/NotificationItem/

Length of output: 6781

packages/components/modules/notifications/NotificationsList/NotificationItem/CommentCreated/index.tsx (1)

13-29: Well-structured component with proper null handling

The component follows good practices:

  • Uses composition pattern effectively
  • Handles null cases with nullish coalescing
  • Clear separation of notification parts (avatar, header, body)
packages/components/modules/notifications/index.ts (1)

8-26: Well-organized exports with clear component hierarchy

The exports are logically grouped and follow a clear hierarchy:

  • Core components (NotificationList, NotificationsPopover)
  • Renderer components
  • Individual notification type components
packages/components/modules/notifications/NotificationsList/index.tsx (2)

Line range hint 24-35: Well-structured component with proper default implementations

Good practices observed:

  • Default components provided
  • Clear prop interface
  • Flexible renderer implementation

Line range hint 91-93: Investigate and resolve overscan TODO comment

The TODO comment indicates a potential stack overflow issue with overscan. This should be investigated as it could impact performance.

Let's check if there are any related issues or discussions:

Would you like help investigating the overscan issue or creating a GitHub issue to track this?

✅ Verification successful

Let me gather more context about the virtualization implementation to better understand the overscan issue.


Let me check one more thing to see if there are any reported issues or fixes related to this in the repository.


Overscan configuration disabled due to known stack overflow risk

Based on the findings, this is a known issue affecting multiple virtualized list components (NotificationsList, CommentsList, MessagesList, CommentsReplies). All components have disabled overscan with the same TODO comment, and they all use a consistent batch size of 5 items for loading next content. Since this is a deliberate defensive measure applied consistently across the codebase, the current implementation should be maintained until a proper fix for the stack overflow issue is found.

  • packages/components/modules/notifications/NotificationsList/index.tsx: Current implementation correctly follows the established pattern
  • Similar implementations in:
    • packages/components/modules/comments/CommentsList/index.tsx
    • packages/components/modules/messages/MessagesList/index.tsx
    • packages/components/modules/comments/CommentItem/CommentsReplies/index.tsx
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Search for related overscan discussions or issues
rg -i "overscan|Maximum call stack size exceeded" --type ts

Length of output: 1212


Script:

#!/bin/bash
# Search for Virtuoso component usage and configuration
ast-grep --pattern 'Virtuoso $$$'

# Search for any constants related to overscan configuration
rg "NUMBER_OF_NOTIFICATIONS_TO_LOAD_NEXT|MESSAGES_TO_LOAD_NEXT|NUMBER_OF_COMMENTS_TO_LOAD_NEXT" --type ts

Length of output: 1942


Script:

#!/bin/bash
# Search for any commits or discussions about the stack overflow issue
rg -i "stack.*overflow.*virtuoso|virtuoso.*stack.*overflow" --type-add 'md:*.md' --type md --type ts

# Check the Virtuoso implementation details
ast-grep --pattern 'new Virtuoso({
  $$$
})'

Length of output: 149

<AvatarWithPlaceholder
width={40}
height={40}
alt={actorName ?? `Notification's user avatar`}
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 alt text for accessibility

The nullish coalescing operator implies actorName could be undefined, but the type definition marks it as required. Additionally, the fallback alt text could be more descriptive.

-    alt={actorName ?? `Notification's user avatar`}
+    alt={actorName || 'Avatar for notification sender'}

If actorName can indeed be optional, update the interface:

interface NotificationAvatarProps {
  actorAvatar: string
  actorName?: string  // Mark as optional
}

// eslint-disable-next-line no-underscore-dangle
const message = `added a comment to your ${notification.target?.__typename.toLowerCase()}`
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Avoid using __typename directly; consider mapping to user-friendly strings

Accessing __typename directly is not recommended for application logic as it is an internal GraphQL implementation detail. It may also pose issues with minification in production builds and complicates internationalization. Instead, consider mapping the __typename to a user-friendly, localized string.

Apply this diff to refactor the code:

- // eslint-disable-next-line no-underscore-dangle
  const message = `added a comment to your ${notification.target?.__typename.toLowerCase()}`
+ const targetTypeName = getTargetTypeName(notification.target)
+ const message = `added a comment to your ${targetTypeName}`

And define the getTargetTypeName function:

function getTargetTypeName(target: NotificationTargetType): string {
  switch (target?.__typename) {
    case 'Post':
      return 'post'
    case 'Comment':
      return 'comment'
    // Add other cases as necessary
    default:
      return 'item'
  }
}

Optionally, for better internationalization support, use a translation function:

+ import { t } from 'i18next'

- const message = `added a comment to your ${targetTypeName}`
+ const message = t('notification.addedCommentToYour', { targetTypeName })

Comment on lines 13 to 17
const NotificationContent: FC<PropsWithChildren> & NotificationContentProps = ({ children }) => (
<Box display="grid" gap={1}>
{children}
</Box>
)
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue

Fix type definition and component structure

The current type definition combining FC with static properties is incorrect and could lead to type errors.

Refactor the component structure:

-const NotificationContent: FC<PropsWithChildren> & NotificationContentProps = ({ children }) => (
+interface NotificationContentComposition {
+  Header: typeof NotificationHeader
+  Body: typeof NotificationCommentBody
+}
+
+const NotificationContent: FC<PropsWithChildren<{}>> & NotificationContentComposition = ({ children }) => (
   <Box display="grid" gap={1}>
     {children}
   </Box>
 )

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

Comment on lines 9 to 20
const NotificationItemRenderer: FC<NotificationItemRendererProps> = ({ notification }) => {
switch (notification.verb) {
case NOTIFICATION_VERB.commentCreated:
return <CommentCreated notification={notification} />
case NOTIFICATION_VERB.commentReplyCreated:
return <CommentReply notification={notification} />
case NOTIFICATION_VERB.reactionCreated:
return <ReactionCreated notification={notification} />
default:
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 and logging for notification rendering

The current implementation silently returns null for unknown notification types and lacks error handling for component rendering failures.

Consider implementing these improvements:

+import { ErrorBoundary } from 'react-error-boundary'
+import { logger } from '@utils/logger'

+const NotificationErrorFallback = ({ error }: { error: Error }) => {
+  logger.error('Failed to render notification:', error)
+  return null
+}

 const NotificationItemRenderer: FC<NotificationItemRendererProps> = ({ notification }) => {
+  const renderNotification = () => {
     switch (notification.verb) {
       case NOTIFICATION_VERB.commentCreated:
         return <CommentCreated notification={notification} />
       case NOTIFICATION_VERB.commentReplyCreated:
         return <CommentReply notification={notification} />
       case NOTIFICATION_VERB.reactionCreated:
         return <ReactionCreated notification={notification} />
       default:
+        logger.warn(`Unhandled notification type: ${notification.verb}`)
         return null
     }
+  }
+
+  return (
+    <ErrorBoundary FallbackComponent={NotificationErrorFallback}>
+      {renderNotification()}
+    </ErrorBoundary>
+  )
 }

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

// eslint-disable-next-line no-underscore-dangle
const message = `added a comment to your ${notification.target?.__typename.toLowerCase()}`
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 type guard for __typename access

The direct access to __typename could cause runtime errors if notification.target is null. Consider adding a type guard.

-  const message = `added a comment to your ${notification.target?.__typename.toLowerCase()}`
+  const message = `added a comment to your ${
+    notification.target && '__typename' in notification.target
+      ? notification.target.__typename.toLowerCase()
+      : 'item'
+  }`
📝 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
// eslint-disable-next-line no-underscore-dangle
const message = `added a comment to your ${notification.target?.__typename.toLowerCase()}`
// eslint-disable-next-line no-underscore-dangle
const message = `added a comment to your ${
notification.target && '__typename' in notification.target
? notification.target.__typename.toLowerCase()
: 'item'
}`

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

📜 Review details

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

📥 Commits

Reviewing files that changed from the base of the PR and between 22604e83744e6a7957e93091cb7fd5371e3df3d8 and 7df4504391682de9986b643c43afc3e3e0bc2314.

⛔ Files ignored due to path filters (1)
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (1)
  • packages/components/package.json (1 hunks)
🔇 Additional comments (2)
packages/components/package.json (2)

53-114: Review major version updates in dev dependencies

Significant updates in testing and development tools:

  1. Storybook ecosystem updated to v8.4.7
  2. Testing libraries (@testing-library/*) updated to latest versions
  3. Build tools (webpack, postcss, etc.) received major version bumps

Consider adding a package-lock.json or yarn.lock file to ensure consistent installations across environments.

✅ Verification successful

Major version updates appear safe to proceed

Based on the verification of the build configuration files and dependencies:

  • The webpack configuration is using standard loaders and plugins that are compatible with webpack 5
  • Babel configuration is minimal and uses standard presets that are maintained
  • PostCSS setup is simple with just tailwindcss and autoprefixer
  • Storybook configuration appears to be consistently updated across all related packages to v8.4.7
  • All build tools are using stable versions with their corresponding peer dependencies

The updates maintain compatibility with the existing build setup and testing infrastructure. No breaking changes that would affect the current configuration were identified.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Verify breaking changes in major tool updates

# Check for breaking changes in Storybook v8
curl -s "https://api.github.com/repos/storybookjs/storybook/releases" | jq '.[] | select(.name | contains("v8.0.0")) | .body'

# Check webpack compatibility
ast-grep --pattern 'webpack.config.$_'

Length of output: 166


Script:

#!/bin/bash
# Let's verify the webpack configuration and build setup

# Find webpack config files
fd -e js -e ts webpack.config

# Check for storybook config files
fd -e js -e ts -e cjs -e mjs '.storybook'

# Look for any build or test setup files that might be affected
fd -e js -e ts -e json "jest.config|babel.config|postcss.config|tsconfig"

# Search for webpack related imports or configurations
rg -l "webpack" --type js --type ts --type json

Length of output: 1664


Script:

#!/bin/bash
# Let's check the webpack configs and build setups for potential breaking changes

# Check webpack config content
cat packages/components/webpack.config.ts

# Check babel config as it's related to the build process
cat packages/components/babel.config.js

# Check postcss config for any custom setup
cat packages/components/postcss.config.js

# Look for storybook main config which might be affected by the v8 upgrade
fd -e js -e ts "main" .storybook

Length of output: 2348


Script:

#!/bin/bash
# Let's check for Storybook configuration and any potential breaking changes

# Find and check Storybook configuration
fd -g "**/storybook/**" -t f
fd -g "**/.storybook/**" -t f

# Look for any Storybook related imports or configurations in the codebase
rg -l "@storybook" --type js --type ts --type jsx --type tsx

# Check package.json scripts related to Storybook
rg "storybook" packages/components/package.json

Length of output: 854


49-50: Verify React version compatibility

The update to React 18.3.1 is significant and needs verification with other dependencies.

✅ Verification successful

Let me gather more information about React dependencies across the codebase.


Let me check the specific React version requirements in the related packages.


Let me check what this "catalog:react18" reference means by looking at the workspace configuration.


React 18.3.1 update appears compatible with the workspace setup

The verification shows that:

  • All dependent packages use catalog:react18 as their peer dependency, indicating a workspace-wide React 18 compatibility requirement
  • No specific version constraints that would conflict with React 18.3.1
  • The official React 18.3.1 release only includes a minor change (exporting act from react)
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Check compatibility of React version with other dependencies

# Check if any dependencies have React version constraints
rg -l "peerDependencies.*react.*18" 

# Check for any React 18.3.1 specific issues
curl -s "https://api.github.com/repos/facebook/react/releases" | jq '.[] | select(.tag_name | contains("18.3.1")) | .body'

Length of output: 282


Script:

#!/bin/bash
# Check for React version references across the codebase
rg -l "\"react\".*18" package.json

# Check for any React-related dependencies in package.json files
fd package.json --exec grep -l "react" {}

# Look for React imports and usage patterns
ast-grep --pattern 'import $_ from "react"'

Length of output: 423


Script:

#!/bin/bash
# Check React version specifications in all package.json files
echo "=== packages/provider/package.json ==="
cat packages/provider/package.json | jq '.dependencies.react, .peerDependencies.react'

echo "=== packages/design-system/package.json ==="
cat packages/design-system/package.json | jq '.dependencies.react, .peerDependencies.react'

echo "=== packages/test/package.json ==="
cat packages/test/package.json | jq '.dependencies.react, .peerDependencies.react'

echo "=== packages/wagtail/package.json ==="
cat packages/wagtail/package.json | jq '.dependencies.react, .peerDependencies.react'

echo "=== packages/graphql/package.json ==="
cat packages/graphql/package.json | jq '.dependencies.react, .peerDependencies.react'

echo "=== packages/utils/package.json ==="
cat packages/utils/package.json | jq '.dependencies.react, .peerDependencies.react'

echo "=== packages/config/package.json ==="
cat packages/config/package.json | jq '.dependencies.react, .peerDependencies.react'

echo "=== packages/authentication/package.json ==="
cat packages/authentication/package.json | jq '.dependencies.react, .peerDependencies.react'

Length of output: 1578


Script:

#!/bin/bash
# Check root package.json for workspace configurations
cat package.json | jq '.catalog'

# Check if there's any workspace configuration file
fd "pnpm-workspace.yaml|lerna.json|rush.json"

# Look for any catalog configuration files
fd "catalog.config.js|catalog.config.json"

Length of output: 150

Comment on lines 24 to 47
"@hookform/resolvers": "^3.6.0",
"@mui/lab": "^5.0.0-alpha.170",
"@mui/material": "^5.15.19",
"@mui/system": "^5.15.19",
"@storybook/react": "^8.4.7",
"@tanstack/react-query": "^5.45.1",
"framer-motion": "^11.5.4",
"graphql": "catalog:graphql",
"js-cookie": "catalog:",
"luxon": "catalog:",
"next": "catalog:",
"react-hook-form": "catalog:",
"react-relay": "catalog:graphql",
"react-virtuoso": "catalog:",
"relay-runtime": "catalog:graphql",
"graphql": "^16.8.1",
"js-cookie": "^3.0.5",
"luxon": "^3.4.4",
"next": "14.3.0-canary.24",
"react-hook-form": "^7.51.5",
"react-relay": "^16.2.0",
"react-virtuoso": "^4.7.11",
"relay-runtime": "^16.2.0",
"slugify": "^1.6.6",
"use-long-press": "^3.2.0",
"zod": "catalog:",
"zustand": "catalog:"
"zod": "^3.23.8",
"zustand": "^4.5.2"
Copy link

Choose a reason for hiding this comment

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

💡 Codebase verification

Dependencies compatibility check reveals critical issues

Several compatibility concerns need to be addressed:

  • @emotion/react and @emotion/styled are missing from dependencies but required by MUI packages
  • React v18.3.1 is being used, but @tanstack/react-query v5.45.1 only supports up to React 18.0.0
  • Next.js canary version (14.3.0-canary.24) poses stability risks for production use

Required actions:

  • Add missing peer dependencies:
    "@emotion/react": "^11.5.0",
    "@emotion/styled": "^11.3.0"
    
  • Downgrade React to a version compatible with react-query (18.0.x)
  • Consider using a stable Next.js release instead of canary
🔗 Analysis chain

Verify compatibility between core dependencies

Several core dependencies have significant version updates that warrant careful review:

  1. Material-UI packages (@mui/*) are being updated to v5.15.x
  2. React Query updated to v5.45.1 (major version bump)
  3. Next.js using a canary version (14.3.0-canary.24)

Run this script to check for any reported compatibility issues:

Consider using a stable version of Next.js instead of a canary release for production deployments.


Let me verify the peer dependencies of other major packages and check for the presence of required dependencies in package.json.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Check for known compatibility issues between major dependencies

# Check npm for any peer dependency warnings for @mui packages
npm info "@mui/material@5.15.19" peerDependencies
npm info "@mui/lab@5.0.0-alpha.170" peerDependencies

# Check for any issues with the Next.js canary version
curl -s "https://api.github.com/repos/vercel/next.js/releases" | jq '.[] | select(.name | contains("14.3.0-canary.24")) | .body'

Length of output: 610


Script:

#!/bin/bash
# Check for required peer dependencies
echo "Checking @tanstack/react-query peer dependencies..."
npm info "@tanstack/react-query@5.45.1" peerDependencies

# Check if required emotion packages are present in package.json
echo -e "\nChecking for required emotion packages..."
grep -A 50 '"dependencies":' packages/components/package.json | grep "@emotion"

# Check React version in package.json
echo -e "\nChecking React version..."
grep -A 2 '"react":' packages/components/package.json | grep -v "react-"

Length of output: 537

@priscilladeroode priscilladeroode force-pushed the BA-1965-bfp-add-reactions-notification branch from 7df4504 to 2db90a4 Compare December 26, 2024 20:34
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🧹 Nitpick comments (6)
packages/components/modules/notifications/NotificationsList/NotificationItem/CommentReply/index.tsx (1)

16-18: Consider adding prop validation for required fields

The component uses nullish coalescing for handling undefined values, but it would be better to validate required fields using PropTypes or TypeScript interfaces.

Example type definition:

interface NotificationActor {
  fullName: string;
  avatar?: {
    url: string;
  };
}

interface NotificationProps extends GenericItemProps {
  actor: NotificationActor;
  unread: boolean;
  timestamp: string;
}

Also applies to: 23-24

packages/components/modules/notifications/index.ts (3)

Line range hint 1-6: Address the TODO comment regarding Storybook integration

The TODO comment indicates a blocker for Storybook integration due to subscription handling. This should be addressed to ensure proper component documentation and testing.

Would you like me to help create an issue to track the Storybook integration task? I can provide suggestions for mocking subscriptions in Storybook stories.


11-17: Consider grouping related notification components

The notification components follow a good hierarchical structure, but the exports could be organized more efficiently.

Consider grouping related exports using a namespace to reduce import complexity:

// Alternative organization using namespaced exports
export * as NotificationComponents from './NotificationsList/NotificationItem/Notification'

This would allow consumers to import related components more cleanly:

import { NotificationComponents } from '@components/notifications'
// Usage: NotificationComponents.Avatar, NotificationComponents.Content, etc.

Line range hint 1-26: Consider implementing a notification factory pattern

The current structure suggests each notification type has its own component. As the number of notification types grows, maintaining individual components might become cumbersome.

Consider implementing a notification factory pattern to:

  1. Centralize notification rendering logic
  2. Make it easier to add new notification types
  3. Reduce code duplication
  4. Improve maintainability

Example approach:

// NotificationFactory.ts
type NotificationConfig = {
  [key in NotificationType]: {
    component: React.ComponentType<NotificationProps>;
    getContent: (data: any) => NotificationContent;
  }
};

const notificationConfig: NotificationConfig = {
  COMMENT_CREATED: {
    component: CommentCreated,
    getContent: (data) => ({ /* ... */ })
  },
  // ... other types
};
packages/components/modules/notifications/NotificationsList/NotificationItem/index.tsx (2)

11-14: Consider adding JSDoc comments for better documentation

The props declaration is well-structured with proper TypeScript typing and default value assignment. However, adding JSDoc comments would improve the component's API documentation.

Add documentation above the component:

+/**
+ * Renders a notification item with customizable content rendering
+ * @param {Object} props
+ * @param {any} props.notification - The notification reference for the Relay fragment
+ * @param {FC<NotificationItemRendererProps>} [props.NotificationItemRenderer] - Optional custom renderer for notification content
+ */
const NotificationItem: FC<NotificationItemProps> = ({
  notification: notificationRef,
  NotificationItemRenderer = DefaultNotificationContentRenderer,
}) => {

38-38: Clean implementation with potential for optimization

The renderer implementation is clean and follows good component composition practices. However, consider memoizing the renderer component if the notification data changes frequently.

Consider wrapping the renderer with useMemo:

+  const memoizedRenderer = useMemo(
+    () => <NotificationItemRenderer notification={notification} />,
+    [notification, NotificationItemRenderer]
+  );

   return (
     <Box
       onClick={markAsRead}
       sx={{
         cursor: 'pointer',
       }}
     >
-      <NotificationItemRenderer notification={notification} />
+      {memoizedRenderer}
     </Box>
   )

Don't forget to add the useMemo import:

-import { FC } from 'react'
+import { FC, useMemo } from 'react'
📜 Review details

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

📥 Commits

Reviewing files that changed from the base of the PR and between 7df4504391682de9986b643c43afc3e3e0bc2314 and 2db90a47145d609cf54b9dce3ac04868f5b2a4d0.

⛔ Files ignored due to path filters (2)
  • packages/components/__generated__/NotificationItemFragment.graphql.ts is excluded by !**/__generated__/**
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (20)
  • packages/components/modules/notifications/NotificationsList/NotificationItem/CommentCreated/index.tsx (1 hunks)
  • packages/components/modules/notifications/NotificationsList/NotificationItem/CommentReply/index.tsx (1 hunks)
  • packages/components/modules/notifications/NotificationsList/NotificationItem/Notification/NotificationAvatar.tsx (1 hunks)
  • packages/components/modules/notifications/NotificationsList/NotificationItem/Notification/NotificationCommentBody.tsx (1 hunks)
  • packages/components/modules/notifications/NotificationsList/NotificationItem/Notification/NotificationContent.tsx (1 hunks)
  • packages/components/modules/notifications/NotificationsList/NotificationItem/Notification/NotificationHeader.tsx (1 hunks)
  • packages/components/modules/notifications/NotificationsList/NotificationItem/Notification/NotificationRoot.tsx (1 hunks)
  • packages/components/modules/notifications/NotificationsList/NotificationItem/Notification/index.tsx (1 hunks)
  • packages/components/modules/notifications/NotificationsList/NotificationItem/Notification/types.ts (1 hunks)
  • packages/components/modules/notifications/NotificationsList/NotificationItem/ReactionCreated/index.tsx (1 hunks)
  • packages/components/modules/notifications/NotificationsList/NotificationItem/index.tsx (2 hunks)
  • packages/components/modules/notifications/NotificationsList/NotificationItem/types.ts (1 hunks)
  • packages/components/modules/notifications/NotificationsList/NotificationItemRenderer/index.tsx (1 hunks)
  • packages/components/modules/notifications/NotificationsList/NotificationItemRenderer/types.ts (1 hunks)
  • packages/components/modules/notifications/NotificationsList/index.tsx (3 hunks)
  • packages/components/modules/notifications/NotificationsList/types.ts (1 hunks)
  • packages/components/modules/notifications/constants.ts (1 hunks)
  • packages/components/modules/notifications/graphql/queries/NotificationItem.ts (1 hunks)
  • packages/components/modules/notifications/index.ts (1 hunks)
  • packages/components/package.json (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (16)
  • packages/components/modules/notifications/NotificationsList/types.ts
  • packages/components/modules/notifications/NotificationsList/NotificationItem/Notification/index.tsx
  • packages/components/modules/notifications/NotificationsList/NotificationItem/types.ts
  • packages/components/modules/notifications/NotificationsList/NotificationItemRenderer/types.ts
  • packages/components/modules/notifications/constants.ts
  • packages/components/modules/notifications/NotificationsList/NotificationItem/Notification/NotificationRoot.tsx
  • packages/components/modules/notifications/NotificationsList/NotificationItemRenderer/index.tsx
  • packages/components/modules/notifications/NotificationsList/index.tsx
  • packages/components/modules/notifications/NotificationsList/NotificationItem/Notification/NotificationAvatar.tsx
  • packages/components/modules/notifications/NotificationsList/NotificationItem/Notification/types.ts
  • packages/components/modules/notifications/graphql/queries/NotificationItem.ts
  • packages/components/modules/notifications/NotificationsList/NotificationItem/ReactionCreated/index.tsx
  • packages/components/modules/notifications/NotificationsList/NotificationItem/Notification/NotificationContent.tsx
  • packages/components/modules/notifications/NotificationsList/NotificationItem/CommentCreated/index.tsx
  • packages/components/modules/notifications/NotificationsList/NotificationItem/Notification/NotificationHeader.tsx
  • packages/components/modules/notifications/NotificationsList/NotificationItem/Notification/NotificationCommentBody.tsx
🔇 Additional comments (9)
packages/components/modules/notifications/NotificationsList/NotificationItem/CommentReply/index.tsx (3)

5-6: LGTM! Clean and well-organized imports

The imports are specific and well-structured, properly importing the new notification components.


10-11: Previous review feedback about __typename usage remains unaddressed

The direct usage of __typename with an eslint disable comment is still present. The previous suggestion to use a type mapping function and i18n support remains valid.


14-28: LGTM! Well-structured notification component

The component follows a clean and modular structure using the new Notification components. Good use of component composition and proper handling of optional values.

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

8-9: LGTM: Well-structured renderer exports

The NotificationItemRenderer and its types are properly exported, following the pattern of keeping component and type exports together.


22-26: Verify notification type handling completeness

The specific notification type components (CommentCreated, CommentReply, ReactionCreated) seem to cover basic interaction types. Let's verify if all notification types are handled.

✅ Verification successful

Let me try different commands to gather the necessary information.


Let me try to find the notification types and their handling in the codebase.


Let me check the notification constants to see all supported notification verbs.


All notification types are properly handled

Based on the verification of the codebase:

  1. The NOTIFICATION_VERB constant defines exactly three notification types:
    • COMMENTS.COMMENT_CREATED
    • COMMENTS.COMMENT_REPLY_CREATED
    • REACTIONS.REACTION_CREATED
  2. The NotificationItemRenderer component handles all three types with corresponding components:
    • CommentCreated
    • CommentReply
    • ReactionCreated
  3. The exports in the reviewed file match exactly with these notification types.
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Search for notification type definitions and verify coverage
echo "Searching for notification type definitions..."
rg -t typescript "type.*NotificationType.*=.*{" 

echo "Searching for notification type usages in renderer..."
ast-grep --pattern 'switch ($expr) {
  $$$
}'  ./packages/components/modules/notifications/NotificationsList/NotificationItemRenderer/index.tsx

Length of output: 534


Script:

#!/bin/bash
# Search for notification type definitions
echo "Searching for notification type definitions..."
rg "NotificationType" -A 5 -B 5

# Search for notification type components
echo "Searching for notification components..."
fd "Notification.*\.tsx?" --type f

# Search for switch statement in renderer
echo "Searching for switch statement in renderer..."
rg "switch.*type" -A 10 packages/components/modules/notifications

Length of output: 2323


Script:

#!/bin/bash
# Look for the notification type components and their implementations
echo "Searching for notification type components..."
rg -t typescript "type.*=.*'.*_CREATED'|type.*=.*'.*_REPLY'" -A 2

# Check the NotificationItemRenderer implementation
echo "Checking NotificationItemRenderer implementation..."
cat packages/components/modules/notifications/NotificationsList/NotificationItemRenderer/index.tsx

# Look for any other notification-related type definitions
echo "Searching for other notification types..."
rg -t typescript "enum.*Notification|type.*Notification" -A 5

Length of output: 1463


Script:

#!/bin/bash
# Check notification constants
echo "Checking notification constants..."
cat packages/components/modules/notifications/constants.ts

# Look for any other notification verb usages
echo "Searching for notification verb usages..."
rg "NOTIFICATION_VERB\." -A 1 -B 1

Length of output: 1528

packages/components/modules/notifications/NotificationsList/NotificationItem/index.tsx (2)

8-8: LGTM! Clean import refactoring

The import changes align well with the new renderer-based architecture, removing specific notification type imports in favor of the new DefaultNotificationContentRenderer.


11-14: Verify renderer pattern implementation

Let's ensure the renderer pattern is consistently implemented across the notification system.

Also applies to: 38-38

✅ Verification successful

Renderer pattern is properly implemented across the notification system

The verification shows that the renderer pattern is consistently implemented:

  • The NotificationItemRendererProps interface is properly defined and used across the codebase
  • The default renderer (DefaultNotificationContentRenderer) is correctly imported and used as a fallback
  • The renderer pattern is properly propagated through the component hierarchy:
    • NotificationsList -> NotificationItem -> NotificationItemRenderer
  • Type definitions and props are consistently used in all related components
  • The pattern allows for custom renderers while maintaining type safety
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Check for proper implementation of notification renderers
echo "Checking renderer implementations..."

# Find all notification renderer implementations
ast-grep --pattern 'export const $_ = ({ notification }: NotificationItemRendererProps) => {
  $$$
}'

# Verify proper imports of the renderer
rg -l "NotificationItemRenderer.*?import" --type typescript

# Check for any direct usage of specific notification components that should use the renderer
rg -l "CommentReply|CommentCreated|ReactionCreated" --type typescript

Length of output: 390


Script:

#!/bin/bash
# Let's try a different approach to verify the renderer pattern implementation

# Find files containing NotificationItemRenderer
rg "NotificationItemRenderer"

# Find all notification-related components and their implementations
fd -e tsx -e ts "Notification"

# Look for renderer-related type definitions
rg "NotificationItemRendererProps|NotificationRenderer"

# Check for DefaultNotificationContentRenderer usage
rg "DefaultNotificationContentRenderer"

Length of output: 5939

packages/components/package.json (2)

24-119: Security advisory check needed

Given the extensive dependency updates, we should verify for any known security vulnerabilities in the specified versions.

Let's check for security advisories:


34-34: ⚠️ Potential issue

Critical version compatibility issues

Several critical compatibility issues need to be addressed:

  1. React v18.3.1 is too new and may cause compatibility issues with other packages
  2. Using Next.js canary version (14.3.0-canary.24) in production is risky
  3. @tanstack/react-query v5.45.1 has specific React version requirements

Recommendations:

  1. Downgrade React to a stable version (18.2.x)
  2. Use a stable Next.js release instead of canary
  3. Verify react-query compatibility with chosen React version

Let's verify the compatibility:

Also applies to: 39-39, 54-55

Comment on lines 77 to 80
"@testing-library/cypress": "^10.0.2",
"@testing-library/jest-dom": "^6.4.6",
"@testing-library/react": "^16.0.0",
"@testing-library/user-event": "^14.5.2",
Copy link

Choose a reason for hiding this comment

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

💡 Codebase verification

Testing Library dependencies need version adjustments

The current setup has compatibility issues:

  • @testing-library/react@16.0.0 requires React ^18.0.0 as a peer dependency, which is compatible with React 18.3.1 in the project
  • However, @testing-library/react version 16.0.0 appears to be incorrect as the latest stable version is 14.x.x. Version 16.0.0 doesn't exist in the npm registry
  • Other testing library versions are up-to-date and compatible:
    • @testing-library/jest-dom@6.4.6
    • @testing-library/user-event@14.5.2
    • @testing-library/cypress@10.0.2

Please update @testing-library/react to the latest 14.x.x version:

"@testing-library/react": "^14.2.1"
🔗 Analysis chain

Verify testing libraries compatibility

The testing libraries have been updated to their latest versions. However, we need to ensure compatibility with React:

  1. @testing-library/react v16.0.0 is a major version jump
  2. jest v29.7.0 and related packages need to be verified with React version

Let's check the compatibility:

Also applies to: 102-103


Let me check the React version in the project to verify compatibility.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Check testing libraries compatibility
echo "Checking @testing-library/react peer dependencies..."
npm info "@testing-library/react@16.0.0" peerDependencies

echo -e "\nChecking jest-environment-jsdom compatibility..."
npm info "jest-environment-jsdom@29.7.0" peerDependencies

Length of output: 512


Script:

#!/bin/bash
# Check React version in package.json
echo "Checking React version..."
rg '"react":' packages/components/package.json

# Also check if there are any other testing library related dependencies
echo -e "\nChecking other testing library dependencies..."
rg '"@testing-library/' packages/components/package.json

Length of output: 473

Comment on lines 24 to 32
"@emotion/cache": "11.11.0",
"@emotion/react": "11.11.4",
"@emotion/styled": "11.11.5",
"@hookform/resolvers": "3.6.0",
"@mui/icons-material": "5.15.19",
"@mui/lab": "5.0.0-alpha.170",
"@mui/material": "5.15.19",
"@mui/system": "5.16.12",
"@mui/x-date-pickers": "7.6.2",
Copy link

Choose a reason for hiding this comment

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

💡 Codebase verification

⚠️ Potential issue

⚠️ Version mismatches and peer dependency conflicts detected

There are several compatibility issues that need to be addressed:

  • The project uses React 18.3.1, which is compatible with all MUI packages (they support ^17.0.0 || ^18.0.0)
  • @mui/x-date-pickers requires @mui/material ^5.15.14, but the project uses 5.15.19
  • @mui/system 5.16.12 is on a different minor version than other MUI packages (5.15.x)
  • @emotion dependencies (11.11.x) satisfy all peer dependency requirements (^11.5.0, ^11.3.0, ^11.9.0, ^11.8.1)

Recommendations:

  • Downgrade @mui/system to 5.15.19 to maintain consistent minor versions across MUI packages
  • Upgrade @mui/material to at least 5.15.14 to satisfy @mui/x-date-pickers requirement
🔗 Analysis chain

Core dependencies compatibility check

The explicit versioning is good, but there are some compatibility concerns:

  1. The @mui packages (v5.15.x) require @emotion/react and @emotion/styled as peer dependencies
  2. All @mui packages should ideally be on the same minor version (currently mixing 5.15.x and 5.16.x)

Let's verify the peer dependencies:


Let me verify the React version and check for any potential conflicts with other packages:

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Check peer dependencies for MUI packages
echo "Checking @mui/material peer dependencies..."
npm info "@mui/material@5.15.19" peerDependencies

echo -e "\nChecking @mui/system peer dependencies..."
npm info "@mui/system@5.16.12" peerDependencies

Length of output: 626


Script:

#!/bin/bash
# Check React version and other relevant dependencies
echo "Checking React version in package.json..."
rg '"react":|"react-dom":' packages/components/package.json

echo -e "\nChecking @mui/lab peer dependencies..."
npm info "@mui/lab@5.0.0-alpha.170" peerDependencies

echo -e "\nChecking @mui/x-date-pickers peer dependencies..."
npm info "@mui/x-date-pickers@7.6.2" peerDependencies

Length of output: 1118

@anicioalexandre anicioalexandre force-pushed the BA-1965-bfp-add-reactions-notification branch from 2db90a4 to 15d281e Compare December 30, 2024 13:39
@anicioalexandre anicioalexandre force-pushed the BA-1965-bfp-add-reactions-notification branch from 15d281e to 4d44a66 Compare December 30, 2024 13:43
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.

Caution

Inline review comments failed to post. This is likely due to GitHub's limits when posting large numbers of comments.

Actionable comments posted: 1

🧹 Nitpick comments (20)
packages/components/CHANGELOG.md (1)

7-8: Enhance changelog entries with architectural details.

While the current entries accurately capture the high-level changes, consider expanding them to better document the architectural improvements:

- Refactors the `notification` module so it is easier to add or modify existing notification types.
- Implement reaction notification.
+ Refactors the `notification` module with new components (NotificationRoot, NotificationAvatar, NotificationContent) for better modularity.
+ Adds NotificationItemRenderer for dynamic notification type handling.
+ Implements reaction notifications with new ReactionCreated component.
packages/design-system/public/mockServiceWorker.js (2)

190-190: Consider avoiding the delete operator for performance reasons

Static analysis flagged the usage of delete at line 190. While this is an effective way to remove the property from the headers object completely, it has a performance overhead. You may consider setting the property to undefined or reconstructing the object without this key. However, note that simply setting it to undefined might still send an undefined header. If total removal is required, the delete operator is acceptable, but keep the performance tradeoff in mind.

- delete headers['x-msw-intention']
+ // Either reconstruct the headers object without this field...
+ const { 'x-msw-intention': _, ...restHeaders } = headers
+ return fetch(requestClone, { headers: restHeaders })

253-253: Leverage optional chaining for cleaner checks

Static analysis suggests using optional chaining here. Since event.data may be undefined, you can simplify the conditional check. This is a minor improvement that reduces nested logical checks.

- if (event.data && event.data.error) {
+ if (event.data?.error) {
    return reject(event.data.error)
 }
🧰 Tools
🪛 Biome (1.9.4)

[error] 253-253: Change to an optional chain.

Unsafe fix: Change to an optional chain.

(lint/complexity/useOptionalChain)

packages/components/modules/notifications/NotificationsList/NotificationItem/Notification/NotificationContent/NotificationBody/types.ts (1)

1-3: Consider simplifying the content type handling

By allowing string | null | undefined, you provide flexibility for various states. For some codebases, it might be simpler to treat absent content as an empty string to reduce null checks. If your UI logic relies on explicitly differentiating these states, this is fine; otherwise, defaulting to "" or making content? an optional property could simplify usage.

packages/components/modules/notifications/NotificationsList/NotificationItem/Notification/NotificationAvatar/types.ts (1)

1-4: Provide a fallback for missing avatar data

Both actorAvatar and actorName allow null or undefined. In the UI layer, consider providing a default avatar image or a placeholder name. This avoids runtime checks or broken images if these props are null or undefined.

packages/components/modules/notifications/NotificationsList/NotificationItem/Notification/NotificationContent/NotificationHeader/types.ts (1)

1-6: Check if actorName should be strictly required

actorName is declared to accept string | null | undefined, implying it can be missing or empty. If your application always provides an actor name, consider making this a string or using an optional property actorName? to clarify usage expectations. Otherwise, ensure the UI handles null or undefined gracefully.

packages/components/modules/notifications/NotificationsList/NotificationItem/Notification/NotificationContent/types.ts (1)

6-9: Consider a more conventional approach to typing.

Currently, NotificationContentProps extends FC<PropsWithChildren> and also specifies static members. Although this pattern technically works, it can be more explicit to separate the component’s prop definitions from its static properties (e.g., define a NotificationContentComponent type for the component, and a NotificationContentProps interface for the public props). This separation can make the code clearer and more maintainable.

packages/components/modules/notifications/NotificationsList/NotificationItem/Notification/NotificationRoot/index.tsx (1)

6-9: Encapsulate layout spacing with theme-aware values.

Using numeric values (e.g., gap={2}, padding={2.5}) can be perfectly fine, but you may consider referencing your theme’s spacing scale to ensure consistent spacing across your UI. For instance, use theme.spacing(2) or define a custom spacing variant in your theme to maintain consistency.

packages/components/modules/notifications/NotificationsList/NotificationItem/Notification/NotificationAvatar/index.tsx (1)

7-14: Validate fallback dimensions for the avatar.

Using hardcoded values (40px) for width and height is acceptable in some contexts. However, you might consider matching the design system’s standard avatar sizes (if any) to improve consistency. If no standard is defined, continue with these numeric values.

packages/components/modules/notifications/NotificationsList/NotificationItem/Notification/NotificationContent/NotificationBody/index.tsx (1)

8-14: Consider configurability of lineClamp or maxHeight.
Allowing these values to be passed in via props (or theme variables) can make the component more flexible and reusable, especially for different notification lengths.

 const NotificationBody: FC<NotificationBodyProps> = ({ content }) => (
-  <BodyTypographyContainer>
-    <TypographyWithEllipsis variant="body2" maxHeight={64} lineClamp={2}>
-      {content ?? ''}
-    </TypographyWithEllipsis>
-  </BodyTypographyContainer>
+  <BodyTypographyContainer>
+    <TypographyWithEllipsis
+      variant="body2"
+      maxHeight={64} // Potentially pass as prop or derive from theme
+      lineClamp={2}  // Potentially pass as prop or derive from theme
+    >
+      {content ?? ''}
+    </TypographyWithEllipsis>
+  </BodyTypographyContainer>
packages/components/modules/notifications/NotificationsList/NotificationItem/NotificationItemRenderer/index.tsx (1)

9-20: Add fallback logging or error monitoring for unknown verbs.
Currently, the default case returns null. Consider at least logging an informative warning or sending to an error tracker for debugging if notification.verb is unexpected.

 default:
-  return null
+  console.warn(`[NotificationItemRenderer] Received unknown notification verb: ${notification.verb}`);
+  return null;
packages/components/modules/notifications/NotificationsList/NotificationItem/Notification/NotificationContent/NotificationHeader/index.tsx (1)

29-30: Inclusivity for screen readers.
Consider adding an accessible label or using an ARIA attribute to indicate that this notification is unread, helping visually impaired users understand the notification’s state.

{unread && (
+  <TimelineDot
+    color="error"
+    aria-label="You have an unread notification."
+  />
)}
packages/components/modules/notifications/NotificationsList/NotificationItem/Notification/index.tsx (1)

5-9: Well-structured component composition pattern!

The use of compound components pattern provides a clean and flexible API for notification rendering.

Consider adding TypeScript types for better type safety:

+import { FC } from 'react'
+
+type NotificationType = {
+  Root: FC<any>  // Replace 'any' with actual prop types
+  Avatar: FC<any>
+  Content: FC<any>
+}
+
-const Notification = {
+const Notification: NotificationType = {
   Root: NotificationRoot,
   Avatar: NotificationAvatar,
   Content: NotificationContent,
}
packages/components/modules/notifications/index.ts (1)

Line range hint 1-1: Address storybook integration TODO.

The TODO comment indicates a need to handle subscriptions for storybook integration. This should be addressed to ensure proper documentation and testing.

Would you like me to help create a solution for handling subscriptions in storybook or create an issue to track this task?

packages/components/modules/notifications/NotificationsList/NotificationItem/index.tsx (2)

Line range hint 17-28: Add error handling to mutation.

The markAsRead mutation should include error handling to manage failed requests gracefully.

Consider adding error handling:

 const markAsRead = () => {
   if (notification.unread) {
     commitMutation({
       variables: {
         input: {
           read: true,
           notificationIds: [notification.id],
         },
       },
+      onError: (error) => {
+        console.error('Failed to mark notification as read:', error);
+        // Add error handling logic (e.g., show error toast)
+      },
     })
   }
 }

31-41: Consider debouncing the onClick handler.

For better performance and to prevent accidental double-clicks, consider debouncing the onClick handler.

Add debouncing using a utility like lodash:

+import { debounce } from 'lodash'
+
 const NotificationItem: FC<NotificationItemProps> = ({
   notification: notificationRef,
   NotificationItemRenderer = DefaultNotificationItemRenderer,
 }) => {
   const notification = useFragment(NotificationItemFragment, notificationRef)
   const [commitMutation] = useNotificationsMarkAsRead()
 
-  const markAsRead = () => {
+  const markAsRead = debounce(() => {
     if (notification.unread) {
       // ... existing code
     }
-  }
+  }, 300)
packages/authentication/package.json (1)

13-13: LGTM! Consider future Storybook implementation.

The addition of the storybook script placeholder is consistent with other packages. While currently there's no storybook implementation, this serves as a good reminder for potential future integration of authentication component stories.

Consider implementing Storybook for authentication components in the future to showcase different authentication states and flows, which could be valuable for development and documentation.

packages/components/modules/notifications/__storybook__/NotificationsModule.mdx (3)

5-10: Enhance the introduction with usage guidelines.

While the introduction provides a good overview, consider adding:

  • When to use this notification system
  • Key features and benefits
  • Any prerequisites or dependencies
 # Notifications Documentation

 ## Notifications System

 The Notifications system is a modular solution for displaying and interacting with notifications. It includes components to handle lists, individual items, and specific notification types, ensuring consistency and scalability across the application.
+
+## When to Use
+
+This notification system is ideal for:
+- Applications requiring real-time user notifications
+- Systems needing modular and extensible notification handling
+- Projects that want to maintain consistent notification UX
+
+## Key Features
+
+- Real-time updates via subscriptions
+- Modular architecture for easy customization
+- Built-in support for common notification types
+- Responsive design with mobile support

23-34: Enhance props documentation with additional details.

The props tables would be more helpful with the following additions:

  • Required/Optional status for each prop
  • Default values where applicable
  • TypeScript type definitions or interfaces

Example enhancement for NotificationsPopover props:

 | Prop Name              | Type               | Description                                |
-|------------------------|--------------------|--------------------------------------------|
-| `Drawer`               | `Component`        | Custom drawer component.                   |
+|------------------------|--------------------|--------------------------------------------|------------|--------------|
+| `Drawer`               | `Component`        | Custom drawer component.                   | Optional   | `undefined`  |

Consider adding a Types section:

#### Types

```typescript
interface NotificationsPopoverProps {
  Drawer?: React.ComponentType<DrawerProps>;
  DrawerProps?: Record<string, unknown>;
  Badge?: React.ComponentType<BadgeProps>;
  BadgeProps?: Record<string, unknown>;
  NotificationBellIcon?: React.ComponentType<IconProps>;
  NotificationBellIconProps?: Record<string, unknown>;
  NotificationsList?: React.ComponentType<NotificationsListProps>;
  NotificationsListProps?: Record<string, unknown>;
}

Also applies to: 45-52, 62-67, 77-82, 92-96


113-186: Add more comprehensive usage examples.

Consider adding examples for:

  • Error handling and fallback UI
  • Subscription setup and cleanup
  • Real-world scenarios with multiple notification types

Add these additional examples:

### Error Handling Example
```typescript
const ErrorFallback = ({ error }) => (
  <div role="alert">
    <p>Something went wrong:</p>
    <pre>{error.message}</pre>
  </div>
);

const Example = () => (
  <ErrorBoundary FallbackComponent={ErrorFallback}>
    <NotificationsPopover 
      LoadingState={CustomLoadingState}
      ErrorState={CustomErrorState}
    />
  </ErrorBoundary>
);

Subscription Example

const Example = () => {
  useEffect(() => {
    const subscription = notificationsSubscription.subscribe({
      next: (notification) => {
        // Handle new notification
      },
      error: (error) => {
        // Handle error
      }
    });

    return () => subscription.unsubscribe();
  }, []);

  return <NotificationsPopover />;
};

</blockquote></details>

</blockquote></details>

<details>
<summary>🛑 Comments failed to post (1)</summary><blockquote>

<details>
<summary>packages/components/modules/notifications/__storybook__/NotificationsModule.mdx (1)</summary><blockquote>

17-22: _:hammer_and_wrench: Refactor suggestion_

**Add accessibility documentation.**

The component documentation should include accessibility considerations:
- ARIA attributes
- Keyboard navigation
- Screen reader support

Add an Accessibility section:

```markdown
## Accessibility

### ARIA Attributes
- The notification bell uses `aria-label="Notifications"` and `aria-expanded` to indicate drawer state
- The notification count uses `aria-live="polite"` for screen reader announcements
- Notifications use `aria-atomic="true"` to ensure complete reading

### Keyboard Navigation
- `Enter` or `Space`: Toggle notifications drawer
- `Tab`: Navigate through notifications
- `Escape`: Close drawer

### Screen Reader Considerations
- Notification timestamps use `aria-label` with relative time (e.g., "2 hours ago")
- Images and icons include descriptive alt text
- Dynamic content updates are announced appropriately

Copy link

Quality Gate Failed Quality Gate failed

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

See analysis details on SonarQube Cloud

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

♻️ Duplicate comments (1)
packages/components/modules/notifications/NotificationsList/NotificationItem/CommentReply/index.tsx (1)

9-10: ⚠️ Potential issue

Avoid using __typename directly in message construction

This issue was previously identified. Direct usage of __typename remains problematic as it's an internal GraphQL implementation detail.

Please refer to the previous review comment for the recommended solution using a getTargetTypeName function and proper i18n support.

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

Line range hint 1-1: Address TODO comment regarding storybook implementation

The TODO comment indicates missing storybook implementation due to subscription handling challenges.

Would you like me to help create a solution for handling subscriptions in storybook, or should I create a GitHub issue to track this task?

packages/components/modules/notifications/__storybook__/NotificationsModule.mdx (1)

117-124: Add TypeScript types to code examples

The code examples would benefit from TypeScript types for better developer experience and documentation.

Example enhancement:

- const Example = () => (
+ const Example: React.FC = () => (
   <NotificationsPopover />
 );

- const NotificationItemRenderer = ({ notification }) => {
+ const NotificationItemRenderer: React.FC<{ notification: NotificationType }> = ({ notification }) => {

Also applies to: 132-143

packages/design-system/public/mockServiceWorker.js (1)

191-191: Consider performance impact of delete operator

The static analyzer flagged the use of the delete operator. While it's intentionally used here for CORS compliance, consider the alternative approach if performance is critical:

-    delete headers['x-msw-intention']
+    headers['x-msw-intention'] = undefined

Note: The current implementation is acceptable as the performance impact is negligible in this testing context.

🧰 Tools
🪛 Biome (1.9.4)

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

Unsafe fix: Use an undefined assignment instead.

(lint/performance/noDelete)

📜 Review details

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

📥 Commits

Reviewing files that changed from the base of the PR and between 15d281e4b91aa7eba482269e8eaf3dddf5622bf8 and 4d44a66.

⛔ Files ignored due to path filters (6)
  • packages/components/__generated__/NotificationItemWithQuery.graphql.ts is excluded by !**/__generated__/**
  • packages/components/__generated__/NotificationsListQuery.graphql.ts is excluded by !**/__generated__/**
  • packages/components/__generated__/notificationsListRefetchable.graphql.ts is excluded by !**/__generated__/**
  • packages/components/__generated__/useMessageCountUpdateSubscription.graphql.ts is excluded by !**/__generated__/**
  • packages/components/__generated__/useNotificationsSubscription.graphql.ts is excluded by !**/__generated__/**
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (34)
  • package.json (1 hunks)
  • packages/authentication/package.json (1 hunks)
  • packages/components/.storybook/preview.ts (1 hunks)
  • packages/components/CHANGELOG.md (1 hunks)
  • packages/components/modules/notifications/NotificationsList/NotificationItem/CommentCreated/index.tsx (1 hunks)
  • packages/components/modules/notifications/NotificationsList/NotificationItem/CommentReply/index.tsx (1 hunks)
  • packages/components/modules/notifications/NotificationsList/NotificationItem/Notification/NotificationAvatar/index.tsx (1 hunks)
  • packages/components/modules/notifications/NotificationsList/NotificationItem/Notification/NotificationAvatar/types.ts (1 hunks)
  • packages/components/modules/notifications/NotificationsList/NotificationItem/Notification/NotificationContent/NotificationBody/index.tsx (1 hunks)
  • packages/components/modules/notifications/NotificationsList/NotificationItem/Notification/NotificationContent/NotificationBody/types.ts (1 hunks)
  • packages/components/modules/notifications/NotificationsList/NotificationItem/Notification/NotificationContent/NotificationHeader/index.tsx (1 hunks)
  • packages/components/modules/notifications/NotificationsList/NotificationItem/Notification/NotificationContent/NotificationHeader/types.ts (1 hunks)
  • packages/components/modules/notifications/NotificationsList/NotificationItem/Notification/NotificationContent/index.tsx (1 hunks)
  • packages/components/modules/notifications/NotificationsList/NotificationItem/Notification/NotificationContent/types.ts (1 hunks)
  • packages/components/modules/notifications/NotificationsList/NotificationItem/Notification/NotificationRoot/index.tsx (1 hunks)
  • packages/components/modules/notifications/NotificationsList/NotificationItem/Notification/index.tsx (1 hunks)
  • packages/components/modules/notifications/NotificationsList/NotificationItem/NotificationItemRenderer/index.tsx (1 hunks)
  • packages/components/modules/notifications/NotificationsList/NotificationItem/NotificationItemRenderer/types.ts (1 hunks)
  • packages/components/modules/notifications/NotificationsList/NotificationItem/ReactionCreated/index.tsx (1 hunks)
  • packages/components/modules/notifications/NotificationsList/NotificationItem/index.tsx (2 hunks)
  • packages/components/modules/notifications/NotificationsList/NotificationItem/types.ts (1 hunks)
  • packages/components/modules/notifications/NotificationsList/index.tsx (2 hunks)
  • packages/components/modules/notifications/NotificationsList/types.ts (1 hunks)
  • packages/components/modules/notifications/__storybook__/NotificationsModule.mdx (1 hunks)
  • packages/components/modules/notifications/index.ts (1 hunks)
  • packages/components/package.json (2 hunks)
  • packages/design-system/.storybook/preview.ts (1 hunks)
  • packages/design-system/public/mockServiceWorker.js (1 hunks)
  • packages/eslint-plugin/package.json (1 hunks)
  • packages/graphql/package.json (1 hunks)
  • packages/provider/package.json (1 hunks)
  • packages/test/package.json (1 hunks)
  • packages/utils/package.json (1 hunks)
  • packages/wagtail/package.json (2 hunks)
🚧 Files skipped from review as they are similar to previous changes (29)
  • packages/components/modules/notifications/NotificationsList/NotificationItem/Notification/NotificationContent/NotificationBody/types.ts
  • packages/graphql/package.json
  • packages/components/modules/notifications/NotificationsList/NotificationItem/Notification/NotificationContent/types.ts
  • packages/components/CHANGELOG.md
  • packages/components/modules/notifications/NotificationsList/NotificationItem/types.ts
  • package.json
  • packages/provider/package.json
  • packages/components/.storybook/preview.ts
  • packages/components/modules/notifications/NotificationsList/NotificationItem/Notification/NotificationRoot/index.tsx
  • packages/wagtail/package.json
  • packages/components/modules/notifications/NotificationsList/NotificationItem/Notification/NotificationContent/NotificationHeader/types.ts
  • packages/components/modules/notifications/NotificationsList/NotificationItem/Notification/NotificationAvatar/types.ts
  • packages/components/modules/notifications/NotificationsList/NotificationItem/Notification/index.tsx
  • packages/authentication/package.json
  • packages/design-system/.storybook/preview.ts
  • packages/components/modules/notifications/NotificationsList/types.ts
  • packages/eslint-plugin/package.json
  • packages/components/modules/notifications/NotificationsList/index.tsx
  • packages/components/modules/notifications/NotificationsList/NotificationItem/NotificationItemRenderer/types.ts
  • packages/utils/package.json
  • packages/test/package.json
  • packages/components/modules/notifications/NotificationsList/NotificationItem/Notification/NotificationAvatar/index.tsx
  • packages/components/modules/notifications/NotificationsList/NotificationItem/ReactionCreated/index.tsx
  • packages/components/modules/notifications/NotificationsList/NotificationItem/CommentCreated/index.tsx
  • packages/components/modules/notifications/NotificationsList/NotificationItem/Notification/NotificationContent/NotificationHeader/index.tsx
  • packages/components/modules/notifications/NotificationsList/NotificationItem/Notification/NotificationContent/index.tsx
  • packages/components/modules/notifications/NotificationsList/NotificationItem/NotificationItemRenderer/index.tsx
  • packages/components/modules/notifications/NotificationsList/NotificationItem/Notification/NotificationContent/NotificationBody/index.tsx
  • packages/components/package.json
🧰 Additional context used
🪛 Biome (1.9.4)
packages/design-system/public/mockServiceWorker.js

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

Unsafe fix: Use an undefined assignment instead.

(lint/performance/noDelete)


[error] 253-253: Change to an optional chain.

Unsafe fix: Change to an optional chain.

(lint/complexity/useOptionalChain)

🔇 Additional comments (11)
packages/components/modules/notifications/NotificationsList/NotificationItem/CommentReply/index.tsx (1)

13-27: Well-structured implementation using compound components

The implementation follows a clean compound component pattern with clear separation of concerns:

  • Root wrapper for layout
  • Avatar section for user representation
  • Content section with header and body
packages/components/modules/notifications/index.ts (1)

8-20: Well-organized export structure

The exports are clearly organized by component type and include both component and type exports, making the module's public API clear and maintainable.

packages/components/modules/notifications/__storybook__/NotificationsModule.mdx (1)

1-186: Comprehensive and well-structured documentation

The documentation provides:

  • Clear component purposes and behaviors
  • Detailed props tables
  • Practical usage examples
  • Implementation guidelines for extensibility
packages/components/modules/notifications/NotificationsList/NotificationItem/index.tsx (4)

8-8: LGTM! Clean import of the new renderer component.

The import of DefaultNotificationItemRenderer aligns with the architectural changes to make the notification system more modular.


17-18: Minor formatting change.


11-14: LGTM! Well-structured component props with proper default assignment.

The component signature changes enhance flexibility while maintaining backward compatibility. The TypeScript types ensure type safety.

Let's verify that the NotificationItemProps interface is properly updated:

✅ Verification successful

Props interface correctly defines the optional NotificationItemRenderer

The verification confirms that the NotificationItemProps interface in types.ts properly includes the optional NotificationItemRenderer prop with the correct type FC<NotificationItemRendererProps>. This matches the component's implementation and ensures type safety.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Verify the NotificationItemProps interface includes the new renderer prop
ast-grep --pattern 'interface NotificationItemProps {
  $$$
  NotificationItemRenderer?: $_
  $$$
}'

Length of output: 608


39-39: Clean implementation of the renderer pattern.

The delegation of rendering logic to a dedicated renderer component follows good separation of concerns. This makes the notification system more maintainable and extensible.

This pattern allows for:

  • Easy addition of new notification types
  • Custom renderers for different contexts
  • Better testability of rendering logic

Let's verify that DefaultNotificationItemRenderer handles all notification types:

✅ Verification successful

Let me verify the available notification verbs to ensure the renderer handles all cases.


NotificationItemRenderer correctly handles all defined notification types

The verification confirms that the NotificationItemRenderer component handles all notification verbs defined in the NOTIFICATION_VERB constants:

  • commentCreated → Rendered by CommentCreated component
  • commentReplyCreated → Rendered by CommentReply component
  • reactionCreated → Rendered by ReactionCreated component

The implementation also includes a default case that returns null for any undefined verbs, making it resilient to future additions. The documentation in NotificationsModule.mdx provides clear instructions for extending the system with new notification types.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Verify the DefaultNotificationItemRenderer handles all notification verbs
ast-grep --pattern 'switch (notification.verb) {
  $$$
}'

Length of output: 1589


Script:

#!/bin/bash
# Find the notification verb enum/constants
rg "NOTIFICATION_VERB" -B 2 -A 5

Length of output: 5465

packages/design-system/public/mockServiceWorker.js (4)

16-90: LGTM! Well-structured service worker lifecycle management

The implementation properly handles:

  • Service worker installation and activation
  • Client validation and management
  • Various mock service commands
  • Cleanup of inactive clients

92-116: LGTM! Robust request filtering and handling

The fetch event handler implements proper request filtering and secure request ID generation.


118-281: LGTM! Comprehensive request handling implementation

The request handling implementation is thorough and well-structured, covering:

  • Proper client resolution
  • Response cloning and transfer
  • Headers management
  • Mock response handling with appropriate status codes
🧰 Tools
🪛 Biome (1.9.4)

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

Unsafe fix: Use an undefined assignment instead.

(lint/performance/noDelete)


[error] 253-253: Change to an optional chain.

Unsafe fix: Change to an optional chain.

(lint/complexity/useOptionalChain)


4-14: Verify MSW version and production safeguards

The Mock Service Worker is at version 2.4.4. Ensure that:

  1. This version is compatible with your testing environment
  2. Proper safeguards are in place to prevent this file from being served in production

Let's verify the production safeguards and version compatibility:

✅ Verification successful

MSW is properly configured for development only

Based on the verification results:

  1. MSW is correctly set up as a development dependency, specifically for Storybook usage ("msw": "catalog:storybook")
  2. The service worker file is properly isolated:
    • It's excluded from production builds via tsconfig.build.json
    • It's only referenced in development configurations (.eslintrc.js)
  3. The version (2.4.4) is managed through Storybook's catalog, ensuring compatibility
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Check if this file is excluded from production builds
fd -t f "webpack|rollup|vite" -x grep -l "mockServiceWorker.js"

# Check package.json for MSW version
fd "package.json" -x jq -r '.dependencies["msw"] // .devDependencies["msw"]'

Length of output: 226


Script:

#!/bin/bash
# Let's check the package.json files directly for MSW dependency
fd "package.json" -x cat {} \; | grep -A 1 -B 1 "msw"

# Check for any build configuration files in the design-system package
fd -t f "webpack|rollup|vite|tsconfig" -d 2 . packages/design-system/

# Check if there are any production build configurations
fd -t f "prod|production" -d 3 . packages/design-system/

Length of output: 872


Script:

#!/bin/bash
# Let's check the tsconfig files content for any production-related configurations
cat packages/design-system/tsconfig.build.json packages/design-system/tsconfig.json

# Check if the mockServiceWorker.js is used only in development/testing
rg -l "mockServiceWorker" -g "*.{js,ts,jsx,tsx}"

# Check storybook configuration as MSW seems to be used with storybook
fd -t f ".storybook" -x cat {} \;

Length of output: 632

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.

2 participants